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

Subversion Repositories openrisc

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

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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