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/] [net/] [if.c] - Blame information for rev 631

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/net/if.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) 1980, 1986, 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
 *      @(#)if.c        8.3 (Berkeley) 1/4/94
55
 * $FreeBSD: src/sys/net/if.c,v 1.85.2.9 2001/07/24 19:10:17 brooks Exp $
56
 */
57
 
58
#include <sys/param.h>
59
#include <sys/malloc.h>
60
#include <sys/mbuf.h>
61
#include <sys/socket.h>
62
#include <sys/socketvar.h>
63
#include <sys/protosw.h>
64
#include <sys/sockio.h>
65
 
66
#include <net/if.h>
67
#include <net/if_arp.h>
68
#include <net/if_dl.h>
69
#include <net/if_types.h>
70
#include <net/radix.h>
71
#include <net/route.h>
72
 
73
#if defined(INET) || defined(INET6)
74
/*XXX*/
75
#include <netinet/in.h>
76
#include <netinet/in_var.h>
77
#ifdef INET6
78
#include <netinet6/in6_var.h>
79
#include <netinet6/in6_ifattach.h>
80
#endif
81
#endif
82
 
83
/*
84
 * System initialization
85
 */
86
 
87
static int ifconf __P((u_long, caddr_t));
88
static void ifinit __P((void *));
89
static void if_qflush __P((struct ifqueue *));
90
static void if_slowtimo __P((void *));
91
static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));
92
static int  if_rtdel __P((struct radix_node *, void *));
93
 
94
SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL)
95
 
96
int     ifqmaxlen = IFQ_MAXLEN;
97
struct  ifnethead ifnet;        /* depend on static init XXX */
98
 
99
#ifdef INET6
100
/*
101
 * XXX: declare here to avoid to include many inet6 related files..
102
 * should be more generalized?
103
 */
104
extern void     nd6_setmtu __P((struct ifnet *));
105
#endif
106
 
107
struct if_clone *if_clone_lookup __P((const char *, int *));
108
int if_clone_list __P((struct if_clonereq *));
109
 
110
LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
111
int if_cloners_count;
112
 
113
/*
114
 * Network interface utility routines.
115
 *
116
 * Routines with ifa_ifwith* names take sockaddr *'s as
117
 * parameters.
118
 */
119
/* ARGSUSED*/
120
void
121
ifinit(dummy)
122
        void *dummy;
123
{
124
        struct ifnet *ifp;
125
        int s;
126
 
127
        s = splimp();
128
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
129
            printf("IFP: %p, next: %p\n", ifp, ifp->if_link.tqe_next);
130
        }
131
        splx(s);
132
        if_slowtimo(0);
133
}
134
 
135
int if_index = 0;
136
struct ifaddr **ifnet_addrs;
137
struct ifnet **ifindex2ifnet = NULL;
138
 
139
char *
140
_sa(struct ifaddr *ifa)
141
{
142
    struct sockaddr *sa = ifa->ifa_addr;
143
    static char _unknown[128];
144
 
145
    switch (sa->sa_family) {
146
    case AF_INET:
147
        return inet_ntoa((struct in_addr)((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr);
148
#ifdef INET6
149
    case AF_INET6:
150
        diag_sprintf(_unknown, "%s/%d", ip6_sprintf(IFA_IN6(ifa)),
151
                     in6_mask2len(&((struct in6_ifaddr *)ifa)->ia_prefixmask.sin6_addr, NULL));
152
        return _unknown;
153
#endif
154
    case AF_LINK:
155
        diag_sprintf(_unknown, "<<%p>>", sa);
156
        return _unknown;
157
    default:
158
        diag_sprintf(_unknown, "[%d]", sa->sa_family);
159
        return _unknown;
160
    }
161
}
162
 
163
void
164
_show_ifp(struct ifnet *ifp)
165
{
166
    log_(LOG_ADDR) {
167
        struct ifaddr *ifa;
168
        diag_printf("IFP: %p (%s%d)\n", ifp, ifp->if_name, ifp->if_unit);
169
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
170
            diag_printf("IFA: %p - %s\n", ifa, _sa(ifa));
171
        }
172
    }
173
}
174
 
175
/*
176
 * Attach an interface to the
177
 * list of "active" interfaces.
178
 */
179
void
180
if_attach(ifp)
181
        struct ifnet *ifp;
182
{
183
        unsigned socksize, ifasize;
184
        int namelen, masklen;
185
        char workbuf[64];
186
        register struct sockaddr_dl *sdl;
187
        register struct ifaddr *ifa;
188
        static int if_indexlim = 8;
189
        static int inited;
190
 
191
        if (!inited) {
192
                TAILQ_INIT(&ifnet);
193
                inited = 1;
194
        }
195
 
196
        if (ifp->if_snd.ifq_maxlen == 0) {
197
            ifp->if_snd.ifq_maxlen = ifqmaxlen;
198
        }
199
 
200
        TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
201
        ifp->if_index = ++if_index;
202
        /*
203
         * XXX -
204
         * The old code would work if the interface passed a pre-existing
205
         * chain of ifaddrs to this code.  We don't trust our callers to
206
         * properly initialize the tailq, however, so we no longer allow
207
         * this unlikely case.
208
         */
209
        TAILQ_INIT(&ifp->if_addrhead);
210
        log_(LOG_ADDR) {
211
            diag_printf("%s.%d - After initialize list %p\n",
212
                        __FUNCTION__, __LINE__,
213
                        &ifp->if_addrlist);
214
            _show_ifp(ifp);
215
        }
216
        TAILQ_INIT(&ifp->if_prefixhead);
217
        LIST_INIT(&ifp->if_multiaddrs);
218
        getmicrotime(&ifp->if_lastchange);
219
        if (ifnet_addrs == 0 || if_index >= if_indexlim) {
220
                unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
221
                caddr_t q = malloc(n, M_IFADDR, M_WAITOK);
222
                bzero(q, n);
223
                if (ifnet_addrs) {
224
                        bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
225
                        free((caddr_t)ifnet_addrs, M_IFADDR);
226
                }
227
                ifnet_addrs = (struct ifaddr **)q;
228
 
229
                /* grow ifindex2ifnet */
230
                n = if_indexlim * sizeof(struct ifnet *);
231
                q = malloc(n, M_IFADDR, M_WAITOK);
232
                bzero(q, n);
233
                if (ifindex2ifnet) {
234
                        bcopy((caddr_t)ifindex2ifnet, q, n/2);
235
                        free((caddr_t)ifindex2ifnet, M_IFADDR);
236
                }
237
                ifindex2ifnet = (struct ifnet **)q;
238
        }
239
 
240
        ifindex2ifnet[if_index] = ifp;
241
 
242
        /*
243
         * create a Link Level name for this device
244
         */
245
        namelen = snprintf(workbuf, sizeof(workbuf),
246
            "%s%d", ifp->if_name, ifp->if_unit);
247
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
248
        masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen;
249
        socksize = masklen + ifp->if_addrlen;
250
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
251
        if (socksize < sizeof(*sdl))
252
                socksize = sizeof(*sdl);
253
        socksize = ROUNDUP(socksize);
254
        ifasize = sizeof(*ifa) + 2 * socksize;
255
        ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
256
        if (ifa) {
257
                bzero((caddr_t)ifa, ifasize);
258
                sdl = (struct sockaddr_dl *)(ifa + 1);
259
                sdl->sdl_len = socksize;
260
                sdl->sdl_family = AF_LINK;
261
                bcopy(workbuf, sdl->sdl_data, namelen);
262
                sdl->sdl_nlen = namelen;
263
                sdl->sdl_index = ifp->if_index;
264
                sdl->sdl_type = ifp->if_type;
265
                ifnet_addrs[if_index - 1] = ifa;
266
                ifa->ifa_ifp = ifp;
267
                ifa->ifa_rtrequest = link_rtrequest;
268
                ifa->ifa_addr = (struct sockaddr *)sdl;
269
                sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
270
                ifa->ifa_netmask = (struct sockaddr *)sdl;
271
                sdl->sdl_len = masklen;
272
                while (namelen != 0)
273
                        sdl->sdl_data[--namelen] = 0xff;
274
                TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
275
                log_(LOG_ADDR) {
276
                    diag_printf("%s.%d - After inserting %p into list %p\n",
277
                                __FUNCTION__, __LINE__,
278
                                ifa, &ifp->if_addrlist);
279
                    _show_ifp(ifp);
280
                }
281
        }
282
#ifdef ALTQ
283
        ifp->if_snd.altq_type = 0;
284
        ifp->if_snd.altq_disc = NULL;
285
        ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
286
        ifp->if_snd.altq_tbr  = NULL;
287
        ifp->if_snd.altq_ifp  = ifp;
288
#endif
289
}
290
 
291
/*
292
 * Detach an interface, removing it from the
293
 * list of "active" interfaces.
294
 */
295
void
296
if_detach(ifp)
297
        struct ifnet *ifp;
298
{
299
        struct ifaddr *ifa;
300
        struct radix_node_head  *rnh;
301
        int s;
302
        int i;
303
 
304
        /*
305
         * Remove routes and flush queues.
306
         */
307
        s = splnet();
308
        if_down(ifp);
309
#ifdef ALTQ
310
        if (ALTQ_IS_ENABLED(&ifp->if_snd))
311
                altq_disable(&ifp->if_snd);
312
        if (ALTQ_IS_ATTACHED(&ifp->if_snd))
313
                altq_detach(&ifp->if_snd);
314
#endif
315
 
316
        /*
317
         * Remove address from ifnet_addrs[] and maybe decrement if_index.
318
         * Clean up all addresses.
319
         */
320
        ifnet_addrs[ifp->if_index - 1] = 0;
321
        while (if_index > 0 && ifnet_addrs[if_index - 1] == 0)
322
                if_index--;
323
 
324
        for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
325
             ifa = TAILQ_FIRST(&ifp->if_addrhead)) {
326
#ifdef INET
327
                /* XXX: Ugly!! ad hoc just for INET */
328
                if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
329
                        struct ifaliasreq ifr;
330
 
331
                        bzero(&ifr, sizeof(ifr));
332
                        ifr.ifra_addr = *ifa->ifa_addr;
333
                        if (ifa->ifa_dstaddr)
334
                                ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
335
                        if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
336
                            NULL) == 0)
337
                                continue;
338
                }
339
#endif /* INET */
340
#ifdef INET6
341
                if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
342
                        in6_purgeaddr(ifa);
343
                        /* ifp_addrhead is already updated */
344
                        continue;
345
                }
346
#endif /* INET6 */
347
                TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
348
                IFAFREE(ifa);
349
        }
350
 
351
#ifdef INET6
352
        /*
353
         * Remove all IPv6 kernel structs related to ifp.  This should be done
354
         * before removing routing entries below, since IPv6 interface direct
355
         * routes are expected to be removed by the IPv6-specific kernel API.
356
         * Otherwise, the kernel will detect some inconsistency and bark it.
357
         */
358
        in6_ifdetach(ifp);
359
#endif
360
 
361
        /*
362
         * Delete all remaining routes using this interface
363
         * Unfortuneatly the only way to do this is to slog through
364
         * the entire routing table looking for routes which point
365
         * to this interface...oh well...
366
         */
367
        for (i = 1; i <= AF_MAX; i++) {
368
                if ((rnh = rt_tables[i]) == NULL)
369
                        continue;
370
                (void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
371
        }
372
 
373
        TAILQ_REMOVE(&ifnet, ifp, if_link);
374
        splx(s);
375
}
376
 
377
/*
378
 * Delete Routes for a Network Interface
379
 *
380
 * Called for each routing entry via the rnh->rnh_walktree() call above
381
 * to delete all route entries referencing a detaching network interface.
382
 *
383
 * Arguments:
384
 *      rn      pointer to node in the routing table
385
 *      arg     argument passed to rnh->rnh_walktree() - detaching interface
386
 *
387
 * Returns:
388
 *      0        successful
389
 *      errno   failed - reason indicated
390
 *
391
 */
392
static int
393
if_rtdel(rn, arg)
394
        struct radix_node       *rn;
395
        void                    *arg;
396
{
397
        struct rtentry  *rt = (struct rtentry *)rn;
398
        struct ifnet    *ifp = arg;
399
        int             err;
400
 
401
        if (rt->rt_ifp == ifp) {
402
 
403
                /*
404
                 * Protect (sorta) against walktree recursion problems
405
                 * with cloned routes
406
                 */
407
                if ((rt->rt_flags & RTF_UP) == 0)
408
                        return (0);
409
 
410
                err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
411
                                rt_mask(rt), rt->rt_flags,
412
                                (struct rtentry **) NULL);
413
                if (err) {
414
                        log(LOG_WARNING, "if_rtdel: error %d\n", err);
415
                }
416
        }
417
 
418
        return (0);
419
}
420
 
421
/*
422
 * Create a clone network interface.
423
 */
424
int
425
if_clone_create(name, len)
426
        char *name;
427
        int len;
428
{
429
        struct if_clone *ifc;
430
        char *dp;
431
        int wildcard;
432
        int unit;
433
        int err;
434
 
435
        ifc = if_clone_lookup(name, &unit);
436
        if (ifc == NULL)
437
                return (EINVAL);
438
 
439
        if (ifunit(name) != NULL)
440
                return (EEXIST);
441
 
442
        wildcard = (unit < 0);
443
 
444
        err = (*ifc->ifc_create)(ifc, &unit);
445
        if (err != 0)
446
                return (err);
447
 
448
        /* In the wildcard case, we need to update the name. */
449
        if (wildcard) {
450
                for (dp = name; *dp != '\0'; dp++);
451
                if (snprintf(dp, len - (dp-name), "%d", unit) >
452
                    len - (dp-name) - 1) {
453
                        /*
454
                         * This can only be a programmer error and
455
                         * there's no straightforward way to recover if
456
                         * it happens.
457
                         */
458
                        panic("if_clone_create(): interface name too long");
459
                }
460
 
461
        }
462
 
463
        return (0);
464
}
465
 
466
/*
467
 * Destroy a clone network interface.
468
 */
469
int
470
if_clone_destroy(name)
471
        const char *name;
472
{
473
        struct if_clone *ifc;
474
        struct ifnet *ifp;
475
 
476
        ifc = if_clone_lookup(name, NULL);
477
        if (ifc == NULL)
478
                return (EINVAL);
479
 
480
        ifp = ifunit(name);
481
        if (ifp == NULL)
482
                return (ENXIO);
483
 
484
        if (ifc->ifc_destroy == NULL)
485
                return (EOPNOTSUPP);
486
 
487
        (*ifc->ifc_destroy)(ifp);
488
        return (0);
489
}
490
 
491
/*
492
 * Look up a network interface cloner.
493
 */
494
struct if_clone *
495
if_clone_lookup(name, unitp)
496
        const char *name;
497
        int *unitp;
498
{
499
        struct if_clone *ifc;
500
        const char *cp;
501
        int i;
502
 
503
        for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) {
504
                for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) {
505
                        if (ifc->ifc_name[i] != *cp)
506
                                goto next_ifc;
507
                }
508
                goto found_name;
509
 next_ifc:
510
                ifc = LIST_NEXT(ifc, ifc_list);
511
        }
512
 
513
        /* No match. */
514
        return ((struct if_clone *)NULL);
515
 
516
 found_name:
517
        if (*cp == '\0') {
518
                i = -1;
519
        } else {
520
                for (i = 0; *cp != '\0'; cp++) {
521
                        if (*cp < '0' || *cp > '9') {
522
                                /* Bogus unit number. */
523
                                return (NULL);
524
                        }
525
                        i = (i * 10) + (*cp - '0');
526
                }
527
        }
528
 
529
        if (unitp != NULL)
530
                *unitp = i;
531
        return (ifc);
532
}
533
 
534
/*
535
 * Register a network interface cloner.
536
 */
537
void
538
if_clone_attach(ifc)
539
        struct if_clone *ifc;
540
{
541
 
542
        LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
543
        if_cloners_count++;
544
}
545
 
546
/*
547
 * Unregister a network interface cloner.
548
 */
549
void
550
if_clone_detach(ifc)
551
        struct if_clone *ifc;
552
{
553
 
554
        LIST_REMOVE(ifc, ifc_list);
555
        if_cloners_count--;
556
}
557
 
558
/*
559
 * Provide list of interface cloners to userspace.
560
 */
561
int
562
if_clone_list(ifcr)
563
        struct if_clonereq *ifcr;
564
{
565
        char outbuf[IFNAMSIZ], *dst;
566
        struct if_clone *ifc;
567
        int count, error = 0;
568
 
569
        ifcr->ifcr_total = if_cloners_count;
570
        if ((dst = ifcr->ifcr_buffer) == NULL) {
571
                /* Just asking how many there are. */
572
                return (0);
573
        }
574
 
575
        if (ifcr->ifcr_count < 0)
576
                return (EINVAL);
577
 
578
        count = (if_cloners_count < ifcr->ifcr_count) ?
579
            if_cloners_count : ifcr->ifcr_count;
580
 
581
        for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
582
             ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
583
                strncpy(outbuf, ifc->ifc_name, IFNAMSIZ);
584
                outbuf[IFNAMSIZ - 1] = '\0';    /* sanity */
585
                error = copyout(outbuf, dst, IFNAMSIZ);
586
                if (error)
587
                        break;
588
        }
589
 
590
        return (error);
591
}
592
 
593
/*
594
 * Locate an interface based on a complete address.
595
 */
596
/*ARGSUSED*/
597
struct ifaddr *
598
ifa_ifwithaddr(addr)
599
        register struct sockaddr *addr;
600
{
601
        register struct ifnet *ifp;
602
        register struct ifaddr *ifa;
603
 
604
#define equal(a1, a2) \
605
  (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
606
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
607
            for (ifa = ifp->if_addrhead.tqh_first; ifa;
608
                 ifa = ifa->ifa_link.tqe_next) {
609
                if (ifa->ifa_addr->sa_family != addr->sa_family)
610
                        continue;
611
                if (equal(addr, ifa->ifa_addr))
612
                        return (ifa);
613
                if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
614
                    /* IP6 doesn't have broadcast */
615
                    ifa->ifa_broadaddr->sa_len != 0 &&
616
                    equal(ifa->ifa_broadaddr, addr))
617
                        return (ifa);
618
        }
619
        return ((struct ifaddr *)0);
620
}
621
/*
622
 * Locate the point to point interface with a given destination address.
623
 */
624
/*ARGSUSED*/
625
struct ifaddr *
626
ifa_ifwithdstaddr(addr)
627
        register struct sockaddr *addr;
628
{
629
        register struct ifnet *ifp;
630
        register struct ifaddr *ifa;
631
 
632
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
633
            if (ifp->if_flags & IFF_POINTOPOINT)
634
                for (ifa = ifp->if_addrhead.tqh_first; ifa;
635
                     ifa = ifa->ifa_link.tqe_next) {
636
                        if (ifa->ifa_addr->sa_family != addr->sa_family)
637
                                continue;
638
                        if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
639
                                return (ifa);
640
        }
641
        return ((struct ifaddr *)0);
642
}
643
 
644
/*
645
 * Find an interface on a specific network.  If many, choice
646
 * is most specific found.
647
 */
648
struct ifaddr *
649
ifa_ifwithnet(addr)
650
        struct sockaddr *addr;
651
{
652
        register struct ifnet *ifp;
653
        register struct ifaddr *ifa;
654
        struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
655
        u_int af = addr->sa_family;
656
        char *addr_data = addr->sa_data, *cplim;
657
 
658
        /*
659
         * AF_LINK addresses can be looked up directly by their index number,
660
         * so do that if we can.
661
         */
662
        if (af == AF_LINK) {
663
            register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
664
            if (sdl->sdl_index && sdl->sdl_index <= if_index)
665
                return (ifnet_addrs[sdl->sdl_index - 1]);
666
        }
667
 
668
        /*
669
         * Scan though each interface, looking for ones that have
670
         * addresses in this address family.
671
         */
672
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
673
                for (ifa = ifp->if_addrhead.tqh_first; ifa;
674
                     ifa = ifa->ifa_link.tqe_next) {
675
                        register char *cp, *cp2, *cp3;
676
 
677
                        if (ifa->ifa_addr->sa_family != af)
678
next:                           continue;
679
                        if (
680
#ifdef INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */
681
                            addr->sa_family != AF_INET6 &&
682
#endif
683
                            ifp->if_flags & IFF_POINTOPOINT) {
684
                                /*
685
                                 * This is a bit broken as it doesn't
686
                                 * take into account that the remote end may
687
                                 * be a single node in the network we are
688
                                 * looking for.
689
                                 * The trouble is that we don't know the
690
                                 * netmask for the remote end.
691
                                 */
692
                                if (ifa->ifa_dstaddr != 0
693
                                    && equal(addr, ifa->ifa_dstaddr))
694
                                        return (ifa);
695
                        } else {
696
                                /*
697
                                 * if we have a special address handler,
698
                                 * then use it instead of the generic one.
699
                                 */
700
                                if (ifa->ifa_claim_addr) {
701
                                        if ((*ifa->ifa_claim_addr)(ifa, addr)) {
702
                                                return (ifa);
703
                                        } else {
704
                                                continue;
705
                                        }
706
                                }
707
 
708
                                /*
709
                                 * Scan all the bits in the ifa's address.
710
                                 * If a bit dissagrees with what we are
711
                                 * looking for, mask it with the netmask
712
                                 * to see if it really matters.
713
                                 * (A byte at a time)
714
                                 */
715
                                if (ifa->ifa_netmask == 0)
716
                                        continue;
717
                                cp = addr_data;
718
                                cp2 = ifa->ifa_addr->sa_data;
719
                                cp3 = ifa->ifa_netmask->sa_data;
720
                                cplim = ifa->ifa_netmask->sa_len
721
                                        + (char *)ifa->ifa_netmask;
722
                                while (cp3 < cplim)
723
                                        if ((*cp++ ^ *cp2++) & *cp3++)
724
                                                goto next; /* next address! */
725
                                /*
726
                                 * If the netmask of what we just found
727
                                 * is more specific than what we had before
728
                                 * (if we had one) then remember the new one
729
                                 * before continuing to search
730
                                 * for an even better one.
731
                                 */
732
                                if (ifa_maybe == 0 ||
733
                                    rn_refines((caddr_t)ifa->ifa_netmask,
734
                                    (caddr_t)ifa_maybe->ifa_netmask))
735
                                        ifa_maybe = ifa;
736
                        }
737
                }
738
        }
739
        return (ifa_maybe);
740
}
741
 
742
/*
743
 * Find an interface address specific to an interface best matching
744
 * a given address.
745
 */
746
struct ifaddr *
747
ifaof_ifpforaddr(addr, ifp)
748
        struct sockaddr *addr;
749
        register struct ifnet *ifp;
750
{
751
        register struct ifaddr *ifa;
752
        register char *cp, *cp2, *cp3;
753
        register char *cplim;
754
        struct ifaddr *ifa_maybe = 0;
755
        u_int af = addr->sa_family;
756
 
757
        if (af >= AF_MAX)
758
                return (0);
759
        for (ifa = ifp->if_addrhead.tqh_first; ifa;
760
             ifa = ifa->ifa_link.tqe_next) {
761
                if (ifa->ifa_addr->sa_family != af)
762
                        continue;
763
                if (ifa_maybe == 0)
764
                        ifa_maybe = ifa;
765
                if (ifa->ifa_netmask == 0) {
766
                        if (equal(addr, ifa->ifa_addr) ||
767
                            (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
768
                                return (ifa);
769
                        continue;
770
                }
771
                if (ifp->if_flags & IFF_POINTOPOINT) {
772
                        if (equal(addr, ifa->ifa_dstaddr))
773
                                return (ifa);
774
                } else {
775
                        cp = addr->sa_data;
776
                        cp2 = ifa->ifa_addr->sa_data;
777
                        cp3 = ifa->ifa_netmask->sa_data;
778
                        cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
779
                        for (; cp3 < cplim; cp3++)
780
                                if ((*cp++ ^ *cp2++) & *cp3)
781
                                        break;
782
                        if (cp3 == cplim)
783
                                return (ifa);
784
                }
785
        }
786
        return (ifa_maybe);
787
}
788
 
789
/*
790
 * Default action when installing a route with a Link Level gateway.
791
 * Lookup an appropriate real ifa to point to.
792
 * This should be moved to /sys/net/link.c eventually.
793
 */
794
static void
795
link_rtrequest(cmd, rt, sa)
796
        int cmd;
797
        register struct rtentry *rt;
798
        struct sockaddr *sa;
799
{
800
        register struct ifaddr *ifa;
801
        struct sockaddr *dst;
802
        struct ifnet *ifp;
803
 
804
        if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
805
            ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
806
                return;
807
        ifa = ifaof_ifpforaddr(dst, ifp);
808
        if (ifa) {
809
                IFAFREE(rt->rt_ifa);
810
                rt->rt_ifa = ifa;
811
                ifa->ifa_refcnt++;
812
                if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
813
                        ifa->ifa_rtrequest(cmd, rt, sa);
814
        }
815
}
816
 
817
/*
818
 * Mark an interface down and notify protocols of
819
 * the transition.
820
 * NOTE: must be called at splnet or eqivalent.
821
 */
822
void
823
if_unroute(ifp, flag, fam)
824
        register struct ifnet *ifp;
825
        int flag, fam;
826
{
827
        register struct ifaddr *ifa;
828
 
829
        ifp->if_flags &= ~flag;
830
        getmicrotime(&ifp->if_lastchange);
831
        TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
832
                if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
833
                        pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
834
        if_qflush(&ifp->if_snd);
835
        rt_ifmsg(ifp);
836
}
837
 
838
/*
839
 * Mark an interface up and notify protocols of
840
 * the transition.
841
 * NOTE: must be called at splnet or eqivalent.
842
 */
843
void
844
if_route(ifp, flag, fam)
845
        register struct ifnet *ifp;
846
        int flag, fam;
847
{
848
        register struct ifaddr *ifa;
849
 
850
        ifp->if_flags |= flag;
851
        getmicrotime(&ifp->if_lastchange);
852
        TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
853
                if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
854
                        pfctlinput(PRC_IFUP, ifa->ifa_addr);
855
        rt_ifmsg(ifp);
856
#ifdef INET6
857
        in6_if_up(ifp);
858
#endif
859
}
860
 
861
/*
862
 * Mark an interface down and notify protocols of
863
 * the transition.
864
 * NOTE: must be called at splnet or eqivalent.
865
 */
866
void
867
if_down(ifp)
868
        register struct ifnet *ifp;
869
{
870
 
871
        if_unroute(ifp, IFF_UP, AF_UNSPEC);
872
}
873
 
874
/*
875
 * Mark an interface up and notify protocols of
876
 * the transition.
877
 * NOTE: must be called at splnet or eqivalent.
878
 */
879
void
880
if_up(ifp)
881
        register struct ifnet *ifp;
882
{
883
 
884
        if_route(ifp, IFF_UP, AF_UNSPEC);
885
}
886
 
887
/*
888
 * Flush an interface queue.
889
 */
890
static void
891
if_qflush(ifq)
892
#ifdef ALTQ
893
        struct ifaltq *ifq;
894
#else
895
        register struct ifqueue *ifq;
896
#endif
897
{
898
        register struct mbuf *m, *n;
899
 
900
#ifdef ALTQ
901
        if (ALTQ_IS_ENABLED(ifq))
902
                ALTQ_PURGE(ifq);
903
#endif
904
        n = ifq->ifq_head;
905
        while ((m = n) != 0) {
906
                n = m->m_act;
907
                m_freem(m);
908
        }
909
        ifq->ifq_head = 0;
910
        ifq->ifq_tail = 0;
911
        ifq->ifq_len = 0;
912
}
913
 
914
/*
915
 * Handle interface watchdog timer routines.  Called
916
 * from softclock, we decrement timers (if set) and
917
 * call the appropriate interface routine on expiration.
918
 */
919
static void
920
if_slowtimo(arg)
921
        void *arg;
922
{
923
        register struct ifnet *ifp;
924
        int s = splimp();
925
 
926
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
927
                if (ifp->if_timer == 0 || --ifp->if_timer)
928
                        continue;
929
                if (ifp->if_watchdog)
930
                        (*ifp->if_watchdog)(ifp);
931
        }
932
        splx(s);
933
        timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
934
}
935
 
936
/*
937
 * Map interface name to
938
 * interface structure pointer.
939
 */
940
struct ifnet *
941
ifunit(const char *name)
942
{
943
        char namebuf[IFNAMSIZ + 1];
944
        const char *cp;
945
        struct ifnet *ifp;
946
        int unit;
947
        unsigned len, m;
948
        char c;
949
 
950
        len = strlen(name);
951
        if (len < 2 || len > IFNAMSIZ)
952
                return NULL;
953
        cp = name + len - 1;
954
        c = *cp;
955
        if (c < '0' || c > '9')
956
                return NULL;            /* trailing garbage */
957
        unit = 0;
958
        m = 1;
959
        do {
960
                if (cp == name)
961
                        return NULL;    /* no interface name */
962
                unit += (c - '0') * m;
963
                if (unit > 1000000)
964
                        return NULL;    /* number is unreasonable */
965
                m *= 10;
966
                c = *--cp;
967
        } while (c >= '0' && c <= '9');
968
        len = cp - name + 1;
969
        bcopy(name, namebuf, len);
970
        namebuf[len] = '\0';
971
        /*
972
         * Now search all the interfaces for this name/number
973
         */
974
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
975
                if (strcmp(ifp->if_name, namebuf))
976
                        continue;
977
                if (unit == ifp->if_unit)
978
                        break;
979
        }
980
        return (ifp);
981
}
982
 
983
 
984
/*
985
 * Map interface name in a sockaddr_dl to
986
 * interface structure pointer.
987
 */
988
struct ifnet *
989
if_withname(sa)
990
        struct sockaddr *sa;
991
{
992
        char ifname[IFNAMSIZ+1];
993
        struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
994
 
995
        if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
996
             (sdl->sdl_nlen > IFNAMSIZ) )
997
                return NULL;
998
 
999
        /*
1000
         * ifunit wants a null-terminated name.  It may not be null-terminated
1001
         * in the sockaddr.  We don't want to change the caller's sockaddr,
1002
         * and there might not be room to put the trailing null anyway, so we
1003
         * make a local copy that we know we can null terminate safely.
1004
         */
1005
 
1006
        bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
1007
        ifname[sdl->sdl_nlen] = '\0';
1008
        return ifunit(ifname);
1009
}
1010
 
1011
 
1012
// TEMP?
1013
#define _NAME(s) \
1014
  case s: return #s; break; 
1015
char *
1016
_ioctl_name(u_long cmd)
1017
{
1018
    static char unknown[32];
1019
 
1020
    switch (cmd) {
1021
        _NAME(SIOCSHIWAT);
1022
        _NAME(SIOCGHIWAT);
1023
        _NAME(SIOCSLOWAT);
1024
        _NAME(SIOCGLOWAT);
1025
        _NAME(SIOCATMARK);
1026
        _NAME(SIOCSPGRP);
1027
        _NAME(SIOCGPGRP);
1028
        _NAME(SIOCADDRT);
1029
        _NAME(SIOCDELRT);
1030
//_NAME(SIOCGETVIFCNT);
1031
//_NAME(SIOCGETSGCNT);
1032
        _NAME(SIOCSIFADDR);
1033
        _NAME(OSIOCGIFADDR);
1034
        _NAME(SIOCGIFADDR);
1035
        _NAME(SIOCSIFDSTADDR);
1036
        _NAME(OSIOCGIFDSTADDR);
1037
        _NAME(SIOCGIFDSTADDR);
1038
        _NAME(SIOCSIFFLAGS);
1039
        _NAME(SIOCGIFFLAGS);
1040
        _NAME(OSIOCGIFBRDADDR);
1041
        _NAME(SIOCGIFBRDADDR);
1042
        _NAME(SIOCSIFBRDADDR);
1043
        _NAME(OSIOCGIFCONF);
1044
        _NAME(SIOCGIFCONF);
1045
        _NAME(OSIOCGIFNETMASK);
1046
        _NAME(SIOCGIFNETMASK);
1047
        _NAME(SIOCSIFNETMASK);
1048
        _NAME(SIOCGIFMETRIC);
1049
        _NAME(SIOCSIFMETRIC);
1050
        _NAME(SIOCDIFADDR);
1051
        _NAME(SIOCAIFADDR);
1052
        _NAME(SIOCALIFADDR);
1053
        _NAME(SIOCGLIFADDR);
1054
        _NAME(SIOCDLIFADDR);
1055
        _NAME(SIOCADDMULTI);
1056
        _NAME(SIOCDELMULTI);
1057
        _NAME(SIOCGIFMTU);
1058
        _NAME(SIOCSIFMTU);
1059
        _NAME(SIOCGIFPHYS);
1060
        _NAME(SIOCSIFPHYS);
1061
        _NAME(SIOCSIFMEDIA);
1062
        _NAME(SIOCGIFMEDIA);
1063
        _NAME(SIOCSIFPHYADDR  );
1064
        _NAME(SIOCGIFPSRCADDR);
1065
        _NAME(SIOCGIFPDSTADDR);
1066
        _NAME(SIOCDIFPHYADDR);
1067
        _NAME(SIOCSLIFPHYADDR);
1068
        _NAME(SIOCGLIFPHYADDR);
1069
        _NAME(SIOCSIFGENERIC);
1070
        _NAME(SIOCGIFGENERIC);
1071
        _NAME(SIOCGIFSTATUS);
1072
        _NAME(SIOCSIFLLADDR);
1073
        _NAME(SIOCIFCREATE);
1074
        _NAME(SIOCIFDESTROY);
1075
        _NAME(SIOCIFGCLONERS);
1076
        _NAME(FIONBIO);
1077
        _NAME(FIOASYNC);
1078
        _NAME(FIONREAD);
1079
        _NAME(SIOCGIFHWADDR);
1080
        _NAME(SIOCSIFHWADDR);
1081
        _NAME(SIOCGIFSTATSUD);
1082
        _NAME(SIOCGIFSTATS);
1083
    default:
1084
        diag_sprintf(unknown, "0x%08x", cmd);
1085
        return unknown;
1086
    }
1087
}
1088
// TEMP?
1089
 
1090
/*
1091
 * Interface ioctls.
1092
 */
1093
int
1094
ifioctl(so, cmd, data, p)
1095
        struct socket *so;
1096
        u_long cmd;
1097
        caddr_t data;
1098
        struct proc *p;
1099
{
1100
        register struct ifnet *ifp;
1101
        register struct ifreq *ifr;
1102
        struct ifstat *ifs;
1103
        int error;
1104
        short oif_flags;
1105
 
1106
        log(LOG_IOCTL, "%s: cmd: %s, data:\n", __FUNCTION__, _ioctl_name(cmd));
1107
        switch (cmd) {
1108
 
1109
        case SIOCGIFCONF:
1110
        case OSIOCGIFCONF:
1111
                return (ifconf(cmd, data));
1112
        }
1113
        ifr = (struct ifreq *)data;
1114
 
1115
        switch (cmd) {
1116
        case SIOCIFCREATE:
1117
        case SIOCIFDESTROY:
1118
                return ((cmd == SIOCIFCREATE) ?
1119
                        if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
1120
                        if_clone_destroy(ifr->ifr_name));
1121
 
1122
        case SIOCIFGCLONERS:
1123
                return (if_clone_list((struct if_clonereq *)data));
1124
        }
1125
 
1126
        ifp = ifunit(ifr->ifr_name);
1127
        if (ifp == 0)
1128
                return (ENXIO);
1129
        switch (cmd) {
1130
 
1131
        case SIOCGIFFLAGS:
1132
                ifr->ifr_flags = ifp->if_flags;
1133
                break;
1134
 
1135
        case SIOCGIFMETRIC:
1136
                ifr->ifr_metric = ifp->if_metric;
1137
                break;
1138
 
1139
        case SIOCGIFMTU:
1140
                ifr->ifr_mtu = ifp->if_mtu;
1141
                break;
1142
 
1143
        case SIOCGIFPHYS:
1144
                ifr->ifr_phys = ifp->if_physical;
1145
                break;
1146
 
1147
        case SIOCSIFFLAGS:
1148
                ifr->ifr_prevflags = ifp->if_flags;
1149
                if (ifp->if_flags & IFF_SMART) {
1150
                        /* Smart drivers twiddle their own routes */
1151
                } else if (ifp->if_flags & IFF_UP &&
1152
                    (ifr->ifr_flags & IFF_UP) == 0) {
1153
                        int s = splimp();
1154
                        if_down(ifp);
1155
                        splx(s);
1156
                } else if (ifr->ifr_flags & IFF_UP &&
1157
                    (ifp->if_flags & IFF_UP) == 0) {
1158
                        int s = splimp();
1159
                        if_up(ifp);
1160
                        splx(s);
1161
                }
1162
                ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
1163
                        (ifr->ifr_flags &~ IFF_CANTCHANGE);
1164
                if (ifp->if_ioctl)
1165
                        (void) (*ifp->if_ioctl)(ifp, cmd, data);
1166
                getmicrotime(&ifp->if_lastchange);
1167
                break;
1168
 
1169
        case SIOCSIFMETRIC:
1170
                ifp->if_metric = ifr->ifr_metric;
1171
                getmicrotime(&ifp->if_lastchange);
1172
                break;
1173
 
1174
        case SIOCSIFPHYS:
1175
                if (!ifp->if_ioctl)
1176
                        return EOPNOTSUPP;
1177
                error = (*ifp->if_ioctl)(ifp, cmd, data);
1178
                if (error == 0)
1179
                        getmicrotime(&ifp->if_lastchange);
1180
                return(error);
1181
 
1182
        case SIOCSIFMTU:
1183
        {
1184
                u_long oldmtu = ifp->if_mtu;
1185
 
1186
                if (ifp->if_ioctl == NULL)
1187
                        return (EOPNOTSUPP);
1188
                if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
1189
                        return (EINVAL);
1190
                error = (*ifp->if_ioctl)(ifp, cmd, data);
1191
                if (error == 0) {
1192
                        getmicrotime(&ifp->if_lastchange);
1193
                        rt_ifmsg(ifp);
1194
                }
1195
                /*
1196
                 * If the link MTU changed, do network layer specific procedure.
1197
                 */
1198
                if (ifp->if_mtu != oldmtu) {
1199
#ifdef INET6
1200
                        nd6_setmtu(ifp);
1201
#endif
1202
                }
1203
                return (error);
1204
        }
1205
 
1206
        case SIOCADDMULTI:
1207
        case SIOCDELMULTI:
1208
 
1209
                /* Don't allow group membership on non-multicast interfaces. */
1210
                if ((ifp->if_flags & IFF_MULTICAST) == 0)
1211
                        return EOPNOTSUPP;
1212
 
1213
                /* Don't let users screw up protocols' entries. */
1214
                if (ifr->ifr_addr.sa_family != AF_LINK)
1215
                        return EINVAL;
1216
 
1217
                log(LOG_IOCTL, "%s: %s Multi\n", __FUNCTION__,
1218
                    (cmd == SIOCADDMULTI) ? "Add" : "Del");
1219
                log_dump(LOG_IOCTL, &ifr->ifr_addr, 32);
1220
                if (cmd == SIOCADDMULTI) {
1221
                        struct ifmultiaddr *ifma;
1222
                        error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
1223
                } else {
1224
                        error = if_delmulti(ifp, &ifr->ifr_addr);
1225
                }
1226
                if (error == 0)
1227
                        getmicrotime(&ifp->if_lastchange);
1228
                return error;
1229
 
1230
        case SIOCSIFPHYADDR:
1231
        case SIOCDIFPHYADDR:
1232
#ifdef INET6
1233
        case SIOCSIFPHYADDR_IN6:
1234
#endif
1235
        case SIOCSLIFPHYADDR:
1236
        case SIOCSIFMEDIA:
1237
        case SIOCSIFGENERIC:
1238
                if (ifp->if_ioctl == 0)
1239
                        return (EOPNOTSUPP);
1240
                error = (*ifp->if_ioctl)(ifp, cmd, data);
1241
                if (error == 0)
1242
                        getmicrotime(&ifp->if_lastchange);
1243
                return error;
1244
 
1245
        case SIOCGIFSTATUS:
1246
                ifs = (struct ifstat *)data;
1247
                ifs->ascii[0] = '\0';
1248
 
1249
        case SIOCGIFPSRCADDR:
1250
        case SIOCGIFPDSTADDR:
1251
        case SIOCGLIFPHYADDR:
1252
        case SIOCGIFMEDIA:
1253
        case SIOCGIFGENERIC:
1254
                if (ifp->if_ioctl == 0)
1255
                        return (EOPNOTSUPP);
1256
                return ((*ifp->if_ioctl)(ifp, cmd, data));
1257
 
1258
        case SIOCSIFLLADDR:
1259
                return if_setlladdr(ifp,
1260
                    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
1261
 
1262
        default:
1263
                oif_flags = ifp->if_flags;
1264
                if (so->so_proto == 0)
1265
                        return (EOPNOTSUPP);
1266
#ifndef COMPAT_43
1267
                error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
1268
                                                                 data,
1269
                                                                 ifp, p));
1270
#else
1271
            {
1272
                int ocmd = cmd;
1273
 
1274
                switch (cmd) {
1275
 
1276
                case SIOCSIFDSTADDR:
1277
                case SIOCSIFADDR:
1278
                case SIOCSIFBRDADDR:
1279
                case SIOCSIFNETMASK:
1280
#if BYTE_ORDER != BIG_ENDIAN
1281
                        if (ifr->ifr_addr.sa_family == 0 &&
1282
                            ifr->ifr_addr.sa_len < 16) {
1283
                                ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
1284
                                ifr->ifr_addr.sa_len = 16;
1285
                        }
1286
#else
1287
                        if (ifr->ifr_addr.sa_len == 0)
1288
                                ifr->ifr_addr.sa_len = 16;
1289
#endif
1290
                        break;
1291
 
1292
                case OSIOCGIFADDR:
1293
                        cmd = SIOCGIFADDR;
1294
                        break;
1295
 
1296
                case OSIOCGIFDSTADDR:
1297
                        cmd = SIOCGIFDSTADDR;
1298
                        break;
1299
 
1300
                case OSIOCGIFBRDADDR:
1301
                        cmd = SIOCGIFBRDADDR;
1302
                        break;
1303
 
1304
                case OSIOCGIFNETMASK:
1305
                        cmd = SIOCGIFNETMASK;
1306
                }
1307
                error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,
1308
                                                                   cmd,
1309
                                                                   data,
1310
                                                                   ifp, p));
1311
                switch (ocmd) {
1312
 
1313
                case OSIOCGIFADDR:
1314
                case OSIOCGIFDSTADDR:
1315
                case OSIOCGIFBRDADDR:
1316
                case OSIOCGIFNETMASK:
1317
                        *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
1318
 
1319
                }
1320
            }
1321
#endif /* COMPAT_43 */
1322
 
1323
                if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
1324
#ifdef INET6
1325
#define DELAY cyg_thread_delay
1326
                        DELAY(100);/* XXX: temporary workaround for fxp issue*/
1327
                        if (ifp->if_flags & IFF_UP) {
1328
                                int s = splimp();
1329
                                in6_if_up(ifp);
1330
                                splx(s);
1331
                        }
1332
#endif
1333
                }
1334
                return (error);
1335
 
1336
        }
1337
        return (0);
1338
}
1339
 
1340
/*
1341
 * Set/clear promiscuous mode on interface ifp based on the truth value
1342
 * of pswitch.  The calls are reference counted so that only the first
1343
 * "on" request actually has an effect, as does the final "off" request.
1344
 * Results are undefined if the "off" and "on" requests are not matched.
1345
 */
1346
int
1347
ifpromisc(ifp, pswitch)
1348
        struct ifnet *ifp;
1349
        int pswitch;
1350
{
1351
        struct ifreq ifr;
1352
        int error;
1353
        int oldflags;
1354
 
1355
        oldflags = ifp->if_flags;
1356
        if (pswitch) {
1357
                /*
1358
                 * If the device is not configured up, we cannot put it in
1359
                 * promiscuous mode.
1360
                 */
1361
                if ((ifp->if_flags & IFF_UP) == 0)
1362
                        return (ENETDOWN);
1363
                if (ifp->if_pcount++ != 0)
1364
                        return (0);
1365
                ifp->if_flags |= IFF_PROMISC;
1366
                log(LOG_INFO, "%s%d: promiscuous mode enabled\n",
1367
                    ifp->if_name, ifp->if_unit);
1368
        } else {
1369
                if (--ifp->if_pcount > 0)
1370
                        return (0);
1371
                ifp->if_flags &= ~IFF_PROMISC;
1372
                log(LOG_INFO, "%s%d: promiscuous mode disabled\n",
1373
                    ifp->if_name, ifp->if_unit);
1374
        }
1375
        ifr.ifr_flags = ifp->if_flags;
1376
        error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
1377
        if (error == 0)
1378
                rt_ifmsg(ifp);
1379
        else
1380
                ifp->if_flags = oldflags;
1381
        return error;
1382
}
1383
 
1384
/*
1385
 * Return interface configuration
1386
 * of system.  List may be used
1387
 * in later ioctl's (above) to get
1388
 * other information.
1389
 */
1390
/*ARGSUSED*/
1391
static int
1392
ifconf(cmd, data)
1393
        u_long cmd;
1394
        caddr_t data;
1395
{
1396
        register struct ifconf *ifc = (struct ifconf *)data;
1397
        register struct ifnet *ifp = ifnet.tqh_first;
1398
        register struct ifaddr *ifa;
1399
        struct ifreq ifr, *ifrp;
1400
        int space = ifc->ifc_len, error = 0;
1401
 
1402
        ifrp = ifc->ifc_req;
1403
        for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) {
1404
                char workbuf[64];
1405
                int ifnlen, addrs;
1406
 
1407
                ifnlen = snprintf(workbuf, sizeof(workbuf),
1408
                    "%s%d", ifp->if_name, ifp->if_unit);
1409
                if(ifnlen + 1 > sizeof ifr.ifr_name) {
1410
                        error = ENAMETOOLONG;
1411
                        break;
1412
                } else {
1413
                        strcpy(ifr.ifr_name, workbuf);
1414
                }
1415
 
1416
                addrs = 0;
1417
                ifa = ifp->if_addrhead.tqh_first;
1418
                for ( ; space > sizeof (ifr) && ifa;
1419
                    ifa = ifa->ifa_link.tqe_next) {
1420
                        register struct sockaddr *sa = ifa->ifa_addr;
1421
                        addrs++;
1422
#ifdef COMPAT_43
1423
                        if (cmd == OSIOCGIFCONF) {
1424
                                struct osockaddr *osa =
1425
                                         (struct osockaddr *)&ifr.ifr_addr;
1426
                                ifr.ifr_addr = *sa;
1427
                                osa->sa_family = sa->sa_family;
1428
                                error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1429
                                                sizeof (ifr));
1430
                                ifrp++;
1431
                        } else
1432
#endif
1433
                        if (sa->sa_len <= sizeof(*sa)) {
1434
                                ifr.ifr_addr = *sa;
1435
                                error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1436
                                                sizeof (ifr));
1437
                                ifrp++;
1438
                        } else {
1439
                                if (space < sizeof (ifr) + sa->sa_len -
1440
                                            sizeof(*sa))
1441
                                        break;
1442
                                space -= sa->sa_len - sizeof(*sa);
1443
                                error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1444
                                                sizeof (ifr.ifr_name));
1445
                                if (error == 0)
1446
                                    error = copyout((caddr_t)sa,
1447
                                      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
1448
                                ifrp = (struct ifreq *)
1449
                                        (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
1450
                        }
1451
                        if (error)
1452
                                break;
1453
                        space -= sizeof (ifr);
1454
                }
1455
                if (error)
1456
                        break;
1457
                if (!addrs) {
1458
                        bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
1459
                        error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1460
                            sizeof (ifr));
1461
                        if (error)
1462
                                break;
1463
                        space -= sizeof (ifr);
1464
                        ifrp++;
1465
                }
1466
        }
1467
        ifc->ifc_len -= space;
1468
        return (error);
1469
}
1470
 
1471
/*
1472
 * Just like if_promisc(), but for all-multicast-reception mode.
1473
 */
1474
int
1475
if_allmulti(ifp, onswitch)
1476
        struct ifnet *ifp;
1477
        int onswitch;
1478
{
1479
        int error = 0;
1480
        int s = splimp();
1481
 
1482
        if (onswitch) {
1483
                if (ifp->if_amcount++ == 0) {
1484
                        ifp->if_flags |= IFF_ALLMULTI;
1485
                        error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0);
1486
                }
1487
        } else {
1488
                if (ifp->if_amcount > 1) {
1489
                        ifp->if_amcount--;
1490
                } else {
1491
                        ifp->if_amcount = 0;
1492
                        ifp->if_flags &= ~IFF_ALLMULTI;
1493
                        error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0);
1494
                }
1495
        }
1496
        splx(s);
1497
 
1498
        if (error == 0)
1499
                rt_ifmsg(ifp);
1500
        return error;
1501
}
1502
 
1503
/*
1504
 * Add a multicast listenership to the interface in question.
1505
 * The link layer provides a routine which converts
1506
 */
1507
int
1508
if_addmulti(ifp, sa, retifma)
1509
        struct ifnet *ifp;      /* interface to manipulate */
1510
        struct sockaddr *sa;    /* address to add */
1511
        struct ifmultiaddr **retifma;
1512
{
1513
        struct sockaddr *llsa, *dupsa;
1514
        int error, s;
1515
        struct ifmultiaddr *ifma;
1516
 
1517
        /*
1518
         * If the matching multicast address already exists
1519
         * then don't add a new one, just add a reference
1520
         */
1521
        for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1522
             ifma = ifma->ifma_link.le_next) {
1523
                if (equal(sa, ifma->ifma_addr)) {
1524
                        ifma->ifma_refcount++;
1525
                        if (retifma)
1526
                                *retifma = ifma;
1527
                        return 0;
1528
                }
1529
        }
1530
 
1531
        /*
1532
         * Give the link layer a chance to accept/reject it, and also
1533
         * find out which AF_LINK address this maps to, if it isn't one
1534
         * already.
1535
         */
1536
        if (ifp->if_resolvemulti) {
1537
                error = ifp->if_resolvemulti(ifp, &llsa, sa);
1538
                if (error) return error;
1539
        } else {
1540
                llsa = 0;
1541
        }
1542
 
1543
        MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
1544
        MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
1545
        bcopy(sa, dupsa, sa->sa_len);
1546
 
1547
        ifma->ifma_addr = dupsa;
1548
        ifma->ifma_lladdr = llsa;
1549
        ifma->ifma_ifp = ifp;
1550
        ifma->ifma_refcount = 1;
1551
        ifma->ifma_protospec = 0;
1552
        rt_newmaddrmsg(RTM_NEWMADDR, ifma);
1553
 
1554
        /*
1555
         * Some network interfaces can scan the address list at
1556
         * interrupt time; lock them out.
1557
         */
1558
        s = splimp();
1559
        LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
1560
        splx(s);
1561
        *retifma = ifma;
1562
 
1563
        if (llsa != 0) {
1564
                for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1565
                     ifma = ifma->ifma_link.le_next) {
1566
                        if (equal(ifma->ifma_addr, llsa))
1567
                                break;
1568
                }
1569
                if (ifma) {
1570
                        ifma->ifma_refcount++;
1571
                } else {
1572
                        MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
1573
                               M_IFMADDR, M_WAITOK);
1574
                        MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
1575
                               M_IFMADDR, M_WAITOK);
1576
                        bcopy(llsa, dupsa, llsa->sa_len);
1577
                        ifma->ifma_addr = dupsa;
1578
                        ifma->ifma_ifp = ifp;
1579
                        ifma->ifma_refcount = 1;
1580
                        s = splimp();
1581
                        LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
1582
                        splx(s);
1583
                }
1584
        }
1585
        /*
1586
         * We are certain we have added something, so call down to the
1587
         * interface to let them know about it.
1588
         */
1589
        s = splimp();
1590
        ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
1591
        splx(s);
1592
 
1593
        return 0;
1594
}
1595
 
1596
/*
1597
 * Remove a reference to a multicast address on this interface.  Yell
1598
 * if the request does not match an existing membership.
1599
 */
1600
int
1601
if_delmulti(ifp, sa)
1602
        struct ifnet *ifp;
1603
        struct sockaddr *sa;
1604
{
1605
        struct ifmultiaddr *ifma;
1606
        int s;
1607
 
1608
        for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1609
             ifma = ifma->ifma_link.le_next)
1610
                if (equal(sa, ifma->ifma_addr))
1611
                        break;
1612
        if (ifma == 0)
1613
                return ENOENT;
1614
 
1615
        if (ifma->ifma_refcount > 1) {
1616
                ifma->ifma_refcount--;
1617
                return 0;
1618
        }
1619
 
1620
        rt_newmaddrmsg(RTM_DELMADDR, ifma);
1621
        sa = ifma->ifma_lladdr;
1622
        s = splimp();
1623
        LIST_REMOVE(ifma, ifma_link);
1624
        /*
1625
         * Make sure the interface driver is notified
1626
         * in the case of a link layer mcast group being left.
1627
         */
1628
        if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0)
1629
                ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
1630
        splx(s);
1631
        free(ifma->ifma_addr, M_IFMADDR);
1632
        free(ifma, M_IFMADDR);
1633
        if (sa == 0)
1634
                return 0;
1635
 
1636
        /*
1637
         * Now look for the link-layer address which corresponds to
1638
         * this network address.  It had been squirreled away in
1639
         * ifma->ifma_lladdr for this purpose (so we don't have
1640
         * to call ifp->if_resolvemulti() again), and we saved that
1641
         * value in sa above.  If some nasty deleted the
1642
         * link-layer address out from underneath us, we can deal because
1643
         * the address we stored was is not the same as the one which was
1644
         * in the record for the link-layer address.  (So we don't complain
1645
         * in that case.)
1646
         */
1647
        for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1648
             ifma = ifma->ifma_link.le_next)
1649
                if (equal(sa, ifma->ifma_addr))
1650
                        break;
1651
        if (ifma == 0)
1652
                return 0;
1653
 
1654
        if (ifma->ifma_refcount > 1) {
1655
                ifma->ifma_refcount--;
1656
                return 0;
1657
        }
1658
 
1659
        s = splimp();
1660
        LIST_REMOVE(ifma, ifma_link);
1661
        ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
1662
        splx(s);
1663
        free(ifma->ifma_addr, M_IFMADDR);
1664
        free(sa, M_IFMADDR);
1665
        free(ifma, M_IFMADDR);
1666
 
1667
        return 0;
1668
}
1669
 
1670
/*
1671
 * Set the link layer address on an interface.
1672
 *
1673
 * At this time we only support certain types of interfaces,
1674
 * and we don't allow the length of the address to change.
1675
 */
1676
int
1677
if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
1678
{
1679
        struct sockaddr_dl *sdl;
1680
        struct ifaddr *ifa;
1681
 
1682
        ifa = ifnet_addrs[ifp->if_index - 1];
1683
        if (ifa == NULL)
1684
                return (EINVAL);
1685
        sdl = (struct sockaddr_dl *)ifa->ifa_addr;
1686
        if (sdl == NULL)
1687
                return (EINVAL);
1688
        if (len != sdl->sdl_alen)       /* don't allow length to change */
1689
                return (EINVAL);
1690
        switch (ifp->if_type) {
1691
        case IFT_ETHER:                 /* these types use struct arpcom */
1692
        case IFT_FDDI:
1693
        case IFT_XETHER:
1694
        case IFT_ISO88025:
1695
        case IFT_L2VLAN:
1696
                bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len);
1697
                bcopy(lladdr, LLADDR(sdl), len);
1698
                break;
1699
        default:
1700
                return (ENODEV);
1701
        }
1702
        /*
1703
         * If the interface is already up, we need
1704
         * to re-init it in order to reprogram its
1705
         * address filter.
1706
         */
1707
        if ((ifp->if_flags & IFF_UP) != 0) {
1708
                ifp->if_flags &= ~IFF_UP;
1709
                (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL);
1710
                ifp->if_flags |= IFF_UP;
1711
                (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL);
1712
        }
1713
        return (0);
1714
}
1715
 
1716
struct ifmultiaddr *
1717
ifmaof_ifpforaddr(sa, ifp)
1718
        struct sockaddr *sa;
1719
        struct ifnet *ifp;
1720
{
1721
        struct ifmultiaddr *ifma;
1722
 
1723
        for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1724
             ifma = ifma->ifma_link.le_next)
1725
                if (equal(ifma->ifma_addr, sa))
1726
                        break;
1727
 
1728
        return ifma;
1729
}

powered by: WebSVN 2.1.0

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