OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [src/] [sys/] [netinet/] [in.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      sys/netinet/in.c
4
//
5
//     
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas
23
// Date:         2000-01-10
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
 
33
/*      $OpenBSD: in.c,v 1.14 1999/12/08 06:50:19 itojun Exp $  */
34
/*      $NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $ */
35
 
36
/*
37
 * Copyright (c) 1982, 1986, 1991, 1993
38
 *      The Regents of the University of California.  All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. All advertising materials mentioning features or use of this software
49
 *    must display the following acknowledgement:
50
 *      This product includes software developed by the University of
51
 *      California, Berkeley and its contributors.
52
 * 4. Neither the name of the University nor the names of its contributors
53
 *    may be used to endorse or promote products derived from this software
54
 *    without specific prior written permission.
55
 *
56
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66
 * SUCH DAMAGE.
67
 *
68
 *      @(#)in.c        8.2 (Berkeley) 11/15/93
69
 */
70
 
71
#ifdef __ECOS
72
#include <pkgconf/net.h>
73
#else
74
#include "ether.h"
75
#include "gif.h"
76
#endif
77
 
78
#include <sys/param.h>
79
#include <sys/ioctl.h>
80
#include <sys/errno.h>
81
#include <sys/malloc.h>
82
#include <sys/socket.h>
83
#include <sys/socketvar.h>
84
#ifndef __ECOS
85
#include <sys/systm.h>
86
#endif
87
 
88
#include <net/if.h>
89
#include <net/if_types.h>
90
#include <net/route.h>
91
#if NGIF > 0
92
#include <net/if_gif.h>
93
#endif
94
 
95
#include <netinet/in_systm.h>
96
#include <netinet/in.h>
97
#include <netinet/in_var.h>
98
#include <netinet/if_ether.h>
99
#include <netinet/igmp_var.h>
100
 
101
#ifdef MROUTING
102
#include <netinet/ip_mroute.h>
103
#endif
104
 
105
#ifdef INET
106
 
107
static int in_mask2len __P((struct in_addr *));
108
static void in_len2mask __P((struct in_addr *, int));
109
static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
110
        struct ifnet *));
111
 
112
#ifndef SUBNETSARELOCAL
113
#define SUBNETSARELOCAL 0
114
#endif
115
int subnetsarelocal = SUBNETSARELOCAL;
116
/*
117
 * Return 1 if an internet address is for a ``local'' host
118
 * (one to which we have a connection).  If subnetsarelocal
119
 * is true, this includes other subnets of the local net.
120
 * Otherwise, it includes only the directly-connected (sub)nets.
121
 */
122
int
123
in_localaddr(in)
124
        struct in_addr in;
125
{
126
        register struct in_ifaddr *ia;
127
 
128
        if (subnetsarelocal) {
129
                for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
130
                        if ((in.s_addr & ia->ia_netmask) == ia->ia_net)
131
                                return (1);
132
        } else {
133
                for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
134
                        if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet)
135
                                return (1);
136
        }
137
        return (0);
138
}
139
 
140
/*
141
 * Determine whether an IP address is in a reserved set of addresses
142
 * that may not be forwarded, or whether datagrams to that destination
143
 * may be forwarded.
144
 */
145
int
146
in_canforward(in)
147
        struct in_addr in;
148
{
149
        register u_int32_t net;
150
 
151
        if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
152
                return (0);
153
        if (IN_CLASSA(in.s_addr)) {
154
                net = in.s_addr & IN_CLASSA_NET;
155
                if (net == 0 || net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
156
                        return (0);
157
        }
158
        return (1);
159
}
160
 
161
/*
162
 * Trim a mask in a sockaddr
163
 */
164
void
165
in_socktrim(ap)
166
        struct sockaddr_in *ap;
167
{
168
        register char *cplim = (char *) &ap->sin_addr;
169
        register char *cp = (char *) (&ap->sin_addr + 1);
170
 
171
        ap->sin_len = 0;
172
        while (--cp >= cplim)
173
                if (*cp) {
174
                        (ap)->sin_len = cp - (char *) (ap) + 1;
175
                        break;
176
                }
177
}
178
 
179
static int
180
in_mask2len(mask)
181
        struct in_addr *mask;
182
{
183
        int x, y;
184
        u_char *p;
185
 
186
        p = (u_char *)mask;
187
        for (x = 0; x < sizeof(*mask); x++) {
188
                if (p[x] != 0xff)
189
                        break;
190
        }
191
        y = 0;
192
        if (x < sizeof(*mask)) {
193
                for (y = 0; y < 8; y++) {
194
                        if ((p[x] & (0x80 >> y)) == 0)
195
                                break;
196
                }
197
        }
198
        return x * 8 + y;
199
}
200
 
201
static void
202
in_len2mask(mask, len)
203
        struct in_addr *mask;
204
        int len;
205
{
206
        int i;
207
        u_char *p;
208
 
209
        p = (u_char *)mask;
210
        bzero(mask, sizeof(*mask));
211
        for (i = 0; i < len / 8; i++)
212
                p[i] = 0xff;
213
        if (len % 8)
214
                p[i] = (0xff00 >> (len % 8)) & 0xff;
215
}
216
 
217
int     in_interfaces;          /* number of external internet interfaces */
218
 
219
/*
220
 * Generic internet control operations (ioctl's).
221
 * Ifp is 0 if not an interface-specific ioctl.
222
 */
223
/* ARGSUSED */
224
int
225
in_control(so, cmd, data, ifp)
226
        struct socket *so;
227
        u_long cmd;
228
        caddr_t data;
229
        register struct ifnet *ifp;
230
{
231
        register struct ifreq *ifr = (struct ifreq *)data;
232
        register struct in_ifaddr *ia = 0;
233
        struct in_aliasreq *ifra = (struct in_aliasreq *)data;
234
        struct sockaddr_in oldaddr;
235
        int error, hostIsNew, maskIsNew;
236
 
237
#if NGIF > 0
238
        if (ifp && ifp->if_type == IFT_GIF) {
239
                switch (cmd) {
240
                case SIOCSIFPHYADDR:
241
                        if ((so->so_state & SS_PRIV) == 0)
242
                                return(EPERM);
243
                case SIOCGIFPSRCADDR:
244
                case SIOCGIFPDSTADDR:
245
                        return gif_ioctl(ifp, cmd, data);
246
                }
247
        }
248
#endif
249
 
250
        switch (cmd) {
251
        case SIOCALIFADDR:
252
        case SIOCDLIFADDR:
253
                if ((so->so_state & SS_PRIV) == 0)
254
                        return(EPERM);
255
                /*fall through*/
256
        case SIOCGLIFADDR:
257
                if (!ifp)
258
                        return EINVAL;
259
                return in_lifaddr_ioctl(so, cmd, data, ifp);
260
        }
261
 
262
        /*
263
         * Find address for this interface, if it exists.
264
         */
265
        if (ifp)
266
                for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next)
267
                        if (ia->ia_ifp == ifp)
268
                                break;
269
 
270
        switch (cmd) {
271
 
272
        case SIOCAIFADDR:
273
        case SIOCDIFADDR:
274
 
275
        case SIOCSIFADDR: // Moved from after this search, otherwise repeated
276
            // identical SIOCSIFADDRs leaked the previously allocated record.
277
 
278
                if (ifra->ifra_addr.sin_family == AF_INET)
279
                    for (; ia != 0; ia = ia->ia_list.tqe_next) {
280
                        if (ia->ia_ifp == ifp  &&
281
                            ia->ia_addr.sin_addr.s_addr ==
282
                                ifra->ifra_addr.sin_addr.s_addr)
283
                            break;
284
                }
285
                if (cmd == SIOCDIFADDR && ia == 0)
286
                        return (EADDRNOTAVAIL);
287
                /* FALLTHROUGH */
288
        case SIOCSIFNETMASK:
289
        case SIOCSIFDSTADDR:
290
                if ((so->so_state & SS_PRIV) == 0)
291
                        return (EPERM);
292
 
293
                if (ifp == 0)
294
                        panic("in_control");
295
                if (ia == (struct in_ifaddr *)0) {
296
                        ia = (struct in_ifaddr *)
297
                                malloc(sizeof *ia, M_IFADDR, M_WAITOK); // This alloc was leaked
298
                        if (ia == (struct in_ifaddr *)0)
299
                                return (ENOBUFS);
300
                        bzero((caddr_t)ia, sizeof *ia);
301
                        TAILQ_INSERT_TAIL(&in_ifaddr, ia, ia_list);
302
                        TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
303
                            ifa_list);
304
                        ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
305
                        ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
306
                        ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
307
                        ia->ia_sockmask.sin_len = 8;
308
                        if (ifp->if_flags & IFF_BROADCAST) {
309
                                ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
310
                                ia->ia_broadaddr.sin_family = AF_INET;
311
                        }
312
                        ia->ia_ifp = ifp;
313
                        LIST_INIT(&ia->ia_multiaddrs);
314
                        if ((ifp->if_flags & IFF_LOOPBACK) == 0)
315
                                in_interfaces++;
316
                }
317
                break;
318
 
319
        case SIOCSIFBRDADDR:
320
                if ((so->so_state & SS_PRIV) == 0)
321
                        return (EPERM);
322
                /* FALLTHROUGH */
323
 
324
        case SIOCGIFADDR:
325
        case SIOCGIFNETMASK:
326
        case SIOCGIFDSTADDR:
327
        case SIOCGIFBRDADDR:
328
                if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
329
                        struct in_ifaddr *ia2;
330
 
331
                        for (ia2 = ia; ia2; ia2 = ia2->ia_list.tqe_next) {
332
                                if (ia2->ia_ifp == ifp &&
333
                                    ia2->ia_addr.sin_addr.s_addr ==
334
                                    satosin(&ifr->ifr_addr)->sin_addr.s_addr)
335
                                        break;
336
                        }
337
                        if (ia2 && ia2->ia_ifp == ifp)
338
                                ia = ia2;
339
                }
340
                if (ia == (struct in_ifaddr *)0)
341
                        return (EADDRNOTAVAIL);
342
                break;
343
        }
344
        switch (cmd) {
345
 
346
        case SIOCGIFADDR:
347
                *satosin(&ifr->ifr_addr) = ia->ia_addr;
348
                break;
349
 
350
        case SIOCGIFBRDADDR:
351
                if ((ifp->if_flags & IFF_BROADCAST) == 0)
352
                        return (EINVAL);
353
                *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
354
                break;
355
 
356
        case SIOCGIFDSTADDR:
357
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
358
                        return (EINVAL);
359
                *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
360
                break;
361
 
362
        case SIOCGIFNETMASK:
363
                *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
364
                break;
365
 
366
        case SIOCSIFDSTADDR:
367
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
368
                        return (EINVAL);
369
                oldaddr = ia->ia_dstaddr;
370
                ia->ia_dstaddr = *satosin(&ifr->ifr_dstaddr);
371
                if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
372
                                        (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
373
                        ia->ia_dstaddr = oldaddr;
374
                        return (error);
375
                }
376
                if (ia->ia_flags & IFA_ROUTE) {
377
                        ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr);
378
                        rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
379
                        ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
380
                        rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
381
                }
382
                break;
383
 
384
        case SIOCSIFBRDADDR:
385
                if ((ifp->if_flags & IFF_BROADCAST) == 0)
386
                        return (EINVAL);
387
                ia->ia_broadaddr = *satosin(&ifr->ifr_broadaddr);
388
                break;
389
 
390
        case SIOCSIFADDR:
391
                return (in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1));
392
 
393
        case SIOCSIFNETMASK:
394
                ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr =
395
                    ifra->ifra_addr.sin_addr.s_addr;
396
                break;
397
 
398
        case SIOCAIFADDR:
399
                maskIsNew = 0;
400
                hostIsNew = 1;
401
                error = 0;
402
                if (ia->ia_addr.sin_family == AF_INET) {
403
                        if (ifra->ifra_addr.sin_len == 0) {
404
                                ifra->ifra_addr = ia->ia_addr;
405
                                hostIsNew = 0;
406
                        } else if (ifra->ifra_addr.sin_addr.s_addr ==
407
                                               ia->ia_addr.sin_addr.s_addr)
408
                                hostIsNew = 0;
409
                }
410
                if (ifra->ifra_mask.sin_len) {
411
                        in_ifscrub(ifp, ia);
412
                        ia->ia_sockmask = ifra->ifra_mask;
413
                        ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
414
                        maskIsNew = 1;
415
                }
416
                if ((ifp->if_flags & IFF_POINTOPOINT) &&
417
                    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
418
                        in_ifscrub(ifp, ia);
419
                        ia->ia_dstaddr = ifra->ifra_dstaddr;
420
                        maskIsNew  = 1; /* We lie; but the effect's the same */
421
                }
422
                if (ifra->ifra_addr.sin_family == AF_INET &&
423
                    (hostIsNew || maskIsNew))
424
                        error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
425
                if ((ifp->if_flags & IFF_BROADCAST) &&
426
                    (ifra->ifra_broadaddr.sin_family == AF_INET))
427
                        ia->ia_broadaddr = ifra->ifra_broadaddr;
428
                return (error);
429
 
430
        case SIOCDIFADDR:
431
                in_ifscrub(ifp, ia);
432
                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
433
                TAILQ_REMOVE(&in_ifaddr, ia, ia_list);
434
                IFAFREE((&ia->ia_ifa));
435
                break;
436
 
437
#ifdef MROUTING
438
        case SIOCGETVIFCNT:
439
        case SIOCGETSGCNT:
440
                return (mrt_ioctl(cmd, data));
441
#endif /* MROUTING */
442
 
443
        default:
444
                if (ifp == 0 || ifp->if_ioctl == 0)
445
                        return (EOPNOTSUPP);
446
                return ((*ifp->if_ioctl)(ifp, cmd, data));
447
        }
448
        return (0);
449
}
450
 
451
/*
452
 * SIOC[GAD]LIFADDR.
453
 *      SIOCGLIFADDR: get first address. ( ??? )
454
 *      SIOCGLIFADDR with IFLR_PREFIX:
455
 *              get first address that matches the specified prefix.
456
 *      SIOCALIFADDR: add the specified address.
457
 *      SIOCALIFADDR with IFLR_PREFIX:
458
 *              EINVAL since we can't deduce hostid part of the address.
459
 *      SIOCDLIFADDR: delete the specified address.
460
 *      SIOCDLIFADDR with IFLR_PREFIX:
461
 *              delete the first address that matches the specified prefix.
462
 * return values:
463
 *      EINVAL on invalid parameters
464
 *      EADDRNOTAVAIL on prefix match failed/specified address not found
465
 *      other values may be returned from in_ioctl()
466
 */
467
static int
468
in_lifaddr_ioctl(so, cmd, data, ifp)
469
        struct socket *so;
470
        u_long cmd;
471
        caddr_t data;
472
        struct ifnet *ifp;
473
{
474
        struct if_laddrreq *iflr = (struct if_laddrreq *)data;
475
        struct ifaddr *ifa;
476
        struct sockaddr *sa;
477
 
478
        /* sanity checks */
479
        if (!data || !ifp) {
480
                panic("invalid argument to in_lifaddr_ioctl");
481
                /*NOTRECHED*/
482
        }
483
 
484
        switch (cmd) {
485
        case SIOCGLIFADDR:
486
                /* address must be specified on GET with IFLR_PREFIX */
487
                if ((iflr->flags & IFLR_PREFIX) == 0)
488
                        break;
489
                /*FALLTHROUGH*/
490
        case SIOCALIFADDR:
491
        case SIOCDLIFADDR:
492
                /* address must be specified on ADD and DELETE */
493
                sa = (struct sockaddr *)&iflr->addr;
494
                if (sa->sa_family != AF_INET)
495
                        return EINVAL;
496
                if (sa->sa_len != sizeof(struct sockaddr_in))
497
                        return EINVAL;
498
                /* XXX need improvement */
499
                sa = (struct sockaddr *)&iflr->dstaddr;
500
                if (sa->sa_family
501
                 && sa->sa_family != AF_INET)
502
                        return EINVAL;
503
                if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in))
504
                        return EINVAL;
505
                break;
506
        default: /*shouldn't happen*/
507
#if 0
508
                panic("invalid cmd to in_lifaddr_ioctl");
509
                /*NOTREACHED*/
510
#else
511
                return EOPNOTSUPP;
512
#endif
513
        }
514
        if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
515
                return EINVAL;
516
 
517
        switch (cmd) {
518
        case SIOCALIFADDR:
519
            {
520
                struct in_aliasreq ifra;
521
 
522
                if (iflr->flags & IFLR_PREFIX)
523
                        return EINVAL;
524
 
525
                /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
526
                bzero(&ifra, sizeof(ifra));
527
                bcopy(iflr->iflr_name, ifra.ifra_name,
528
                        sizeof(ifra.ifra_name));
529
 
530
                bcopy(&iflr->addr, &ifra.ifra_addr,
531
                        ((struct sockaddr *)&iflr->addr)->sa_len);
532
 
533
                if (((struct sockaddr *)&iflr->dstaddr)->sa_family) {   /*XXX*/
534
                        bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
535
                                ((struct sockaddr *)&iflr->dstaddr)->sa_len);
536
                }
537
 
538
                ifra.ifra_mask.sin_family = AF_INET;
539
                ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
540
                in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
541
 
542
                return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp);
543
            }
544
        case SIOCGLIFADDR:
545
        case SIOCDLIFADDR:
546
            {
547
                struct in_ifaddr *ia;
548
                struct in_addr mask, candidate, match;
549
                struct sockaddr_in *sin;
550
                int cmp;
551
 
552
                bzero(&mask, sizeof(mask));
553
                if (iflr->flags & IFLR_PREFIX) {
554
                        /* lookup a prefix rather than address. */
555
                        in_len2mask(&mask, iflr->prefixlen);
556
 
557
                        sin = (struct sockaddr_in *)&iflr->addr;
558
                        match.s_addr = sin->sin_addr.s_addr;
559
                        match.s_addr &= mask.s_addr;
560
 
561
                        /* if you set extra bits, that's wrong */
562
                        if (match.s_addr != sin->sin_addr.s_addr)
563
                                return EINVAL;
564
 
565
                        cmp = 1;
566
                } else {
567
                        if (cmd == SIOCGLIFADDR) {
568
                                /* on getting an address, take the 1st match */
569
                                cmp = 0; /*XXX*/
570
                        } else {
571
                                /* on deleting an address, do exact match */
572
                                in_len2mask(&mask, 32);
573
                                sin = (struct sockaddr_in *)&iflr->addr;
574
                                match.s_addr = sin->sin_addr.s_addr;
575
 
576
                                cmp = 1;
577
                        }
578
                }
579
 
580
                for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) {
581
                        if (ifa->ifa_addr->sa_family != AF_INET6)
582
                                continue;
583
                        if (!cmp)
584
                                break;
585
                        candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
586
                        candidate.s_addr &= mask.s_addr;
587
                        if (candidate.s_addr == match.s_addr)
588
                                break;
589
                }
590
                if (!ifa)
591
                        return EADDRNOTAVAIL;
592
                ia = (struct in_ifaddr *)ifa;
593
 
594
                if (cmd == SIOCGLIFADDR) {
595
                        /* fill in the if_laddrreq structure */
596
                        bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
597
 
598
                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
599
                                bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
600
                                        ia->ia_dstaddr.sin_len);
601
                        } else
602
                                bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
603
 
604
                        iflr->prefixlen =
605
                                in_mask2len(&ia->ia_sockmask.sin_addr);
606
 
607
                        iflr->flags = 0; /*XXX*/
608
 
609
                        return 0;
610
                } else {
611
                        struct in_aliasreq ifra;
612
 
613
                        /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
614
                        bzero(&ifra, sizeof(ifra));
615
                        bcopy(iflr->iflr_name, ifra.ifra_name,
616
                                sizeof(ifra.ifra_name));
617
 
618
                        bcopy(&ia->ia_addr, &ifra.ifra_addr,
619
                                ia->ia_addr.sin_len);
620
                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
621
                                bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
622
                                        ia->ia_dstaddr.sin_len);
623
                        }
624
                        bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
625
                                ia->ia_sockmask.sin_len);
626
 
627
                        return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, ifp);
628
                }
629
            }
630
        }
631
 
632
        return EOPNOTSUPP;      /*just for safety*/
633
}
634
 
635
/*
636
 * Delete any existing route for an interface.
637
 */
638
void
639
in_ifscrub(ifp, ia)
640
        register struct ifnet *ifp;
641
        register struct in_ifaddr *ia;
642
{
643
 
644
        if ((ia->ia_flags & IFA_ROUTE) == 0)
645
                return;
646
        if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
647
                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
648
        else
649
                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
650
        ia->ia_flags &= ~IFA_ROUTE;
651
}
652
 
653
/*
654
 * Initialize an interface's internet address
655
 * and routing table entry.
656
 */
657
int
658
in_ifinit(ifp, ia, sin, scrub)
659
        register struct ifnet *ifp;
660
        register struct in_ifaddr *ia;
661
        struct sockaddr_in *sin;
662
        int scrub;
663
{
664
        register u_int32_t i = sin->sin_addr.s_addr;
665
        struct sockaddr_in oldaddr;
666
        int s = splimp(), flags = RTF_UP, error;
667
 
668
        oldaddr = ia->ia_addr;
669
        ia->ia_addr = *sin;
670
        /*
671
         * Give the interface a chance to initialize
672
         * if this is its first address,
673
         * and to validate the address if necessary.
674
         */
675
        if (ifp->if_ioctl &&
676
            (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
677
                splx(s);
678
                ia->ia_addr = oldaddr;
679
                return (error);
680
        }
681
        splx(s);
682
        if (scrub) {
683
                ia->ia_ifa.ifa_addr = sintosa(&oldaddr);
684
                in_ifscrub(ifp, ia);
685
                ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
686
        }
687
        if (IN_CLASSA(i))
688
                ia->ia_netmask = IN_CLASSA_NET;
689
        else if (IN_CLASSB(i))
690
                ia->ia_netmask = IN_CLASSB_NET;
691
        else
692
                ia->ia_netmask = IN_CLASSC_NET;
693
        /*
694
         * The subnet mask usually includes at least the standard network part,
695
         * but may may be smaller in the case of supernetting.
696
         * If it is set, we believe it.
697
         */
698
        if (ia->ia_subnetmask == 0) {
699
                ia->ia_subnetmask = ia->ia_netmask;
700
                ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask;
701
        } else
702
                ia->ia_netmask &= ia->ia_subnetmask;
703
        ia->ia_net = i & ia->ia_netmask;
704
        ia->ia_subnet = i & ia->ia_subnetmask;
705
        in_socktrim(&ia->ia_sockmask);
706
        /*
707
         * Add route for the network.
708
         */
709
        ia->ia_ifa.ifa_metric = ifp->if_metric;
710
        if (ifp->if_flags & IFF_BROADCAST) {
711
                ia->ia_broadaddr.sin_addr.s_addr =
712
                        ia->ia_subnet | ~ia->ia_subnetmask;
713
                ia->ia_netbroadcast.s_addr =
714
                        ia->ia_net | ~ia->ia_netmask;
715
        } else if (ifp->if_flags & IFF_LOOPBACK) {
716
                ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
717
                flags |= RTF_HOST;
718
        } else if (ifp->if_flags & IFF_POINTOPOINT) {
719
                if (ia->ia_dstaddr.sin_family != AF_INET)
720
                        return (0);
721
                flags |= RTF_HOST;
722
        }
723
        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
724
                ia->ia_flags |= IFA_ROUTE;
725
        /*
726
         * If the interface supports multicast, join the "all hosts"
727
         * multicast group on that interface.
728
         */
729
        if (ifp->if_flags & IFF_MULTICAST) {
730
                struct in_addr addr;
731
 
732
                addr.s_addr = INADDR_ALLHOSTS_GROUP;
733
                in_addmulti(&addr, ifp);
734
        }
735
        return (error);
736
}
737
 
738
 
739
/*
740
 * Return 1 if the address might be a local broadcast address.
741
 */
742
int
743
in_broadcast(in, ifp)
744
        struct in_addr in;
745
        struct ifnet *ifp;
746
{
747
        struct ifnet *ifn, *if_first, *if_target;
748
        register struct ifaddr *ifa;
749
 
750
        if (in.s_addr == INADDR_BROADCAST ||
751
            in.s_addr == INADDR_ANY)
752
                return 1;
753
        if (ifp && ((ifp->if_flags & IFF_BROADCAST) == 0))
754
                return 0;
755
 
756
        if (ifp == NULL)
757
        {
758
                if_first = ifnet.tqh_first;
759
                if_target = 0;
760
        }
761
        else
762
        {
763
                if_first = ifp;
764
                if_target = ifp->if_list.tqe_next;
765
        }
766
 
767
#define ia (ifatoia(ifa))
768
        /*
769
         * Look through the list of addresses for a match
770
         * with a broadcast address.
771
         * If ifp is NULL, check against all the interfaces.
772
         */
773
        for (ifn = if_first; ifn != if_target; ifn = ifn->if_list.tqe_next)
774
          for (ifa = ifn->if_addrlist.tqh_first; ifa;
775
               ifa = ifa->ifa_list.tqe_next)
776
              if (!ifp)
777
              {
778
                  if (ifa->ifa_addr->sa_family == AF_INET &&
779
                      ((ia->ia_subnetmask != 0xffffffff &&
780
                      (((ifn->if_flags & IFF_BROADCAST) &&
781
                        in.s_addr == ia->ia_broadaddr.sin_addr.s_addr) ||
782
                         in.s_addr == ia->ia_subnet)) ||
783
                       /*
784
                        * Check for old-style (host 0) broadcast.
785
                        */
786
                       (in.s_addr == ia->ia_netbroadcast.s_addr ||
787
                        in.s_addr == ia->ia_net)))
788
                              return 1;
789
              }
790
              else
791
                  if (ifa->ifa_addr->sa_family == AF_INET &&
792
                      (((ifn->if_flags & IFF_BROADCAST) &&
793
                      in.s_addr == ia->ia_broadaddr.sin_addr.s_addr) ||
794
                       in.s_addr == ia->ia_netbroadcast.s_addr ||
795
                       /*
796
                        * Check for old-style (host 0) broadcast.
797
                        */
798
                       in.s_addr == ia->ia_subnet ||
799
                       in.s_addr == ia->ia_net))
800
                              return 1;
801
        return (0);
802
#undef ia
803
}
804
 
805
/*
806
 * Add an address to the list of IP multicast addresses for a given interface.
807
 */
808
struct in_multi *
809
in_addmulti(ap, ifp)
810
        register struct in_addr *ap;
811
        register struct ifnet *ifp;
812
{
813
        register struct in_multi *inm;
814
        struct ifreq ifr;
815
        struct in_ifaddr *ia;
816
        int s = splsoftnet();
817
 
818
        /*
819
         * See if address already in list.
820
         */
821
        IN_LOOKUP_MULTI(*ap, ifp, inm);
822
        if (inm != NULL) {
823
                /*
824
                 * Found it; just increment the reference count.
825
                 */
826
                ++inm->inm_refcount;
827
        } else {
828
                /*
829
                 * New address; allocate a new multicast record
830
                 * and link it into the interface's multicast list.
831
                 */
832
                inm = (struct in_multi *)malloc(sizeof(*inm),
833
                    M_IPMADDR, M_NOWAIT);
834
                if (inm == NULL) {
835
                        splx(s);
836
                        return (NULL);
837
                }
838
                inm->inm_addr = *ap;
839
                inm->inm_ifp = ifp;
840
                inm->inm_refcount = 1;
841
                IFP_TO_IA(ifp, ia);
842
                if (ia == NULL) {
843
                        free(inm, M_IPMADDR);
844
                        splx(s);
845
                        return (NULL);
846
                }
847
                inm->inm_ia = ia;
848
                LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_list);
849
                /*
850
                 * Ask the network driver to update its multicast reception
851
                 * filter appropriately for the new address.
852
                 */
853
                satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
854
                satosin(&ifr.ifr_addr)->sin_family = AF_INET;
855
                satosin(&ifr.ifr_addr)->sin_addr = *ap;
856
                if ((ifp->if_ioctl == NULL) ||
857
                    (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
858
                        LIST_REMOVE(inm, inm_list);
859
                        free(inm, M_IPMADDR);
860
                        splx(s);
861
                        return (NULL);
862
                }
863
                /*
864
                 * Let IGMP know that we have joined a new IP multicast group.
865
                 */
866
                igmp_joingroup(inm);
867
        }
868
        splx(s);
869
        return (inm);
870
}
871
 
872
/*
873
 * Delete a multicast address record.
874
 */
875
void
876
in_delmulti(inm)
877
        register struct in_multi *inm;
878
{
879
        struct ifreq ifr;
880
        int s = splsoftnet();
881
 
882
        if (--inm->inm_refcount == 0) {
883
                /*
884
                 * No remaining claims to this record; let IGMP know that
885
                 * we are leaving the multicast group.
886
                 */
887
                igmp_leavegroup(inm);
888
                /*
889
                 * Unlink from list.
890
                 */
891
                LIST_REMOVE(inm, inm_list);
892
                /*
893
                 * Notify the network driver to update its multicast reception
894
                 * filter.
895
                 */
896
                satosin(&ifr.ifr_addr)->sin_family = AF_INET;
897
                satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
898
                (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
899
                                                             (caddr_t)&ifr);
900
                free(inm, M_IPMADDR);
901
        }
902
        splx(s);
903
}
904
 
905
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.