Annotation of sys/net/if.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if.c,v 1.165 2007/07/06 14:00:59 naddy Exp $ */
! 2: /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the project nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Copyright (c) 1980, 1986, 1993
! 35: * The Regents of the University of California. All rights reserved.
! 36: *
! 37: * Redistribution and use in source and binary forms, with or without
! 38: * modification, are permitted provided that the following conditions
! 39: * are met:
! 40: * 1. Redistributions of source code must retain the above copyright
! 41: * notice, this list of conditions and the following disclaimer.
! 42: * 2. Redistributions in binary form must reproduce the above copyright
! 43: * notice, this list of conditions and the following disclaimer in the
! 44: * documentation and/or other materials provided with the distribution.
! 45: * 3. Neither the name of the University nor the names of its contributors
! 46: * may be used to endorse or promote products derived from this software
! 47: * without specific prior written permission.
! 48: *
! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 59: * SUCH DAMAGE.
! 60: *
! 61: * @(#)if.c 8.3 (Berkeley) 1/4/94
! 62: */
! 63:
! 64: #include "bluetooth.h"
! 65: #include "bpfilter.h"
! 66: #include "bridge.h"
! 67: #include "carp.h"
! 68: #include "pf.h"
! 69: #include "trunk.h"
! 70:
! 71: #include <sys/param.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/mbuf.h>
! 74: #include <sys/proc.h>
! 75: #include <sys/socket.h>
! 76: #include <sys/socketvar.h>
! 77: #include <sys/protosw.h>
! 78: #include <sys/kernel.h>
! 79: #include <sys/ioctl.h>
! 80: #include <sys/domain.h>
! 81: #include <sys/sysctl.h>
! 82:
! 83: #include <net/if.h>
! 84: #include <net/if_dl.h>
! 85: #include <net/if_media.h>
! 86: #include <net/if_types.h>
! 87: #include <net/route.h>
! 88: #include <net/netisr.h>
! 89:
! 90: #include <dev/rndvar.h>
! 91:
! 92: #ifdef INET
! 93: #include <netinet/in.h>
! 94: #include <netinet/in_var.h>
! 95: #include <netinet/if_ether.h>
! 96: #include <netinet/igmp.h>
! 97: #ifdef MROUTING
! 98: #include <netinet/ip_mroute.h>
! 99: #endif
! 100: #endif
! 101:
! 102: #ifdef INET6
! 103: #ifndef INET
! 104: #include <netinet/in.h>
! 105: #endif
! 106: #include <netinet6/in6_ifattach.h>
! 107: #include <netinet6/nd6.h>
! 108: #endif
! 109:
! 110: #if NBPFILTER > 0
! 111: #include <net/bpf.h>
! 112: #endif
! 113:
! 114: #if NTRUNK > 0
! 115: #include <net/if_trunk.h>
! 116: #endif
! 117:
! 118: #if NBRIDGE > 0
! 119: #include <net/if_bridge.h>
! 120: #endif
! 121:
! 122: #if NCARP > 0
! 123: #include <netinet/ip_carp.h>
! 124: #endif
! 125:
! 126: #if NPF > 0
! 127: #include <net/pfvar.h>
! 128: #endif
! 129:
! 130: void if_attachsetup(struct ifnet *);
! 131: void if_attachdomain1(struct ifnet *);
! 132:
! 133: int ifqmaxlen = IFQ_MAXLEN;
! 134:
! 135: void if_detach_queues(struct ifnet *, struct ifqueue *);
! 136: void if_detached_start(struct ifnet *);
! 137: int if_detached_ioctl(struct ifnet *, u_long, caddr_t);
! 138: int if_detached_init(struct ifnet *);
! 139: void if_detached_watchdog(struct ifnet *);
! 140:
! 141: int if_getgroup(caddr_t, struct ifnet *);
! 142: int if_getgroupmembers(caddr_t);
! 143: int if_getgroupattribs(caddr_t);
! 144: int if_setgroupattribs(caddr_t);
! 145:
! 146: int if_clone_list(struct if_clonereq *);
! 147: struct if_clone *if_clone_lookup(const char *, int *);
! 148:
! 149: void if_congestion_clear(void *);
! 150: int if_group_egress_build(void);
! 151:
! 152: TAILQ_HEAD(, ifg_group) ifg_head;
! 153: LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
! 154: int if_cloners_count;
! 155:
! 156: /*
! 157: * Network interface utility routines.
! 158: *
! 159: * Routines with ifa_ifwith* names take sockaddr *'s as
! 160: * parameters.
! 161: */
! 162: void
! 163: ifinit()
! 164: {
! 165: static struct timeout if_slowtim;
! 166:
! 167: timeout_set(&if_slowtim, if_slowtimo, &if_slowtim);
! 168:
! 169: if_slowtimo(&if_slowtim);
! 170: }
! 171:
! 172: static int if_index = 0;
! 173: int if_indexlim = 0;
! 174: struct ifaddr **ifnet_addrs = NULL;
! 175: struct ifnet **ifindex2ifnet = NULL;
! 176: struct ifnet_head ifnet;
! 177: struct ifnet *lo0ifp;
! 178:
! 179: /*
! 180: * Attach an interface to the
! 181: * list of "active" interfaces.
! 182: */
! 183: void
! 184: if_attachsetup(struct ifnet *ifp)
! 185: {
! 186: struct ifaddr *ifa;
! 187: int wrapped = 0;
! 188:
! 189: if (ifindex2ifnet == 0)
! 190: if_index = 1;
! 191: else {
! 192: while (if_index < if_indexlim &&
! 193: ifindex2ifnet[if_index] != NULL) {
! 194: if_index++;
! 195: /*
! 196: * If we hit USHRT_MAX, we skip back to 1 since
! 197: * there are a number of places where the value
! 198: * of ifp->if_index or if_index itself is compared
! 199: * to or stored in an unsigned short. By
! 200: * jumping back, we won't botch those assignments
! 201: * or comparisons.
! 202: */
! 203: if (if_index == USHRT_MAX) {
! 204: if_index = 1;
! 205: /*
! 206: * However, if we have to jump back to 1
! 207: * *twice* without finding an empty
! 208: * slot in ifindex2ifnet[], then there
! 209: * there are too many (>65535) interfaces.
! 210: */
! 211: if (wrapped++)
! 212: panic("too many interfaces");
! 213: }
! 214: }
! 215: }
! 216: ifp->if_index = if_index;
! 217:
! 218: /*
! 219: * We have some arrays that should be indexed by if_index.
! 220: * since if_index will grow dynamically, they should grow too.
! 221: * struct ifaddr **ifnet_addrs
! 222: * struct ifnet **ifindex2ifnet
! 223: */
! 224: if (ifnet_addrs == 0 || ifindex2ifnet == 0 || if_index >= if_indexlim) {
! 225: size_t m, n, oldlim;
! 226: caddr_t q;
! 227:
! 228: oldlim = if_indexlim;
! 229: if (if_indexlim == 0)
! 230: if_indexlim = 8;
! 231: while (if_index >= if_indexlim)
! 232: if_indexlim <<= 1;
! 233:
! 234: /* grow ifnet_addrs */
! 235: m = oldlim * sizeof(ifa);
! 236: n = if_indexlim * sizeof(ifa);
! 237: q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
! 238: bzero(q, n);
! 239: if (ifnet_addrs) {
! 240: bcopy((caddr_t)ifnet_addrs, q, m);
! 241: free((caddr_t)ifnet_addrs, M_IFADDR);
! 242: }
! 243: ifnet_addrs = (struct ifaddr **)q;
! 244:
! 245: /* grow ifindex2ifnet */
! 246: m = oldlim * sizeof(struct ifnet *);
! 247: n = if_indexlim * sizeof(struct ifnet *);
! 248: q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
! 249: bzero(q, n);
! 250: if (ifindex2ifnet) {
! 251: bcopy((caddr_t)ifindex2ifnet, q, m);
! 252: free((caddr_t)ifindex2ifnet, M_IFADDR);
! 253: }
! 254: ifindex2ifnet = (struct ifnet **)q;
! 255: }
! 256:
! 257: TAILQ_INIT(&ifp->if_groups);
! 258:
! 259: if_addgroup(ifp, IFG_ALL);
! 260:
! 261: ifindex2ifnet[if_index] = ifp;
! 262:
! 263: if (ifp->if_snd.ifq_maxlen == 0)
! 264: ifp->if_snd.ifq_maxlen = ifqmaxlen;
! 265: #ifdef ALTQ
! 266: ifp->if_snd.altq_type = 0;
! 267: ifp->if_snd.altq_disc = NULL;
! 268: ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
! 269: ifp->if_snd.altq_tbr = NULL;
! 270: ifp->if_snd.altq_ifp = ifp;
! 271: #endif
! 272:
! 273: if (domains)
! 274: if_attachdomain1(ifp);
! 275: #if NPF > 0
! 276: pfi_attach_ifnet(ifp);
! 277: #endif
! 278:
! 279: /* Announce the interface. */
! 280: rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
! 281: }
! 282:
! 283: /*
! 284: * Allocate the link level name for the specified interface. This
! 285: * is an attachment helper. It must be called after ifp->if_addrlen
! 286: * is initialized, which may not be the case when if_attach() is
! 287: * called.
! 288: */
! 289: void
! 290: if_alloc_sadl(struct ifnet *ifp)
! 291: {
! 292: unsigned socksize, ifasize;
! 293: int namelen, masklen;
! 294: struct sockaddr_dl *sdl;
! 295: struct ifaddr *ifa;
! 296:
! 297: /*
! 298: * If the interface already has a link name, release it
! 299: * now. This is useful for interfaces that can change
! 300: * link types, and thus switch link names often.
! 301: */
! 302: if (ifp->if_sadl != NULL)
! 303: if_free_sadl(ifp);
! 304:
! 305: namelen = strlen(ifp->if_xname);
! 306: #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
! 307: masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen;
! 308: socksize = masklen + ifp->if_addrlen;
! 309: #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
! 310: if (socksize < sizeof(*sdl))
! 311: socksize = sizeof(*sdl);
! 312: socksize = ROUNDUP(socksize);
! 313: ifasize = sizeof(*ifa) + 2 * socksize;
! 314: ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
! 315: bzero((caddr_t)ifa, ifasize);
! 316: sdl = (struct sockaddr_dl *)(ifa + 1);
! 317: sdl->sdl_len = socksize;
! 318: sdl->sdl_family = AF_LINK;
! 319: bcopy(ifp->if_xname, sdl->sdl_data, namelen);
! 320: sdl->sdl_nlen = namelen;
! 321: sdl->sdl_alen = ifp->if_addrlen;
! 322: sdl->sdl_index = ifp->if_index;
! 323: sdl->sdl_type = ifp->if_type;
! 324: ifnet_addrs[ifp->if_index] = ifa;
! 325: ifa->ifa_ifp = ifp;
! 326: ifa->ifa_rtrequest = link_rtrequest;
! 327: TAILQ_INSERT_HEAD(&ifp->if_addrlist, ifa, ifa_list);
! 328: ifa->ifa_addr = (struct sockaddr *)sdl;
! 329: ifp->if_sadl = sdl;
! 330: sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
! 331: ifa->ifa_netmask = (struct sockaddr *)sdl;
! 332: sdl->sdl_len = masklen;
! 333: while (namelen != 0)
! 334: sdl->sdl_data[--namelen] = 0xff;
! 335: }
! 336:
! 337: /*
! 338: * Free the link level name for the specified interface. This is
! 339: * a detach helper. This is called from if_detach() or from
! 340: * link layer type specific detach functions.
! 341: */
! 342: void
! 343: if_free_sadl(struct ifnet *ifp)
! 344: {
! 345: struct ifaddr *ifa;
! 346: int s;
! 347:
! 348: ifa = ifnet_addrs[ifp->if_index];
! 349: if (ifa == NULL)
! 350: return;
! 351:
! 352: s = splnet();
! 353: rtinit(ifa, RTM_DELETE, 0);
! 354: #if 0
! 355: TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
! 356: ifnet_addrs[ifp->if_index] = NULL;
! 357: #endif
! 358: ifp->if_sadl = NULL;
! 359:
! 360: splx(s);
! 361: }
! 362:
! 363: void
! 364: if_attachdomain()
! 365: {
! 366: struct ifnet *ifp;
! 367: int s;
! 368:
! 369: s = splnet();
! 370: for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
! 371: if_attachdomain1(ifp);
! 372: splx(s);
! 373: }
! 374:
! 375: void
! 376: if_attachdomain1(struct ifnet *ifp)
! 377: {
! 378: struct domain *dp;
! 379: int s;
! 380:
! 381: s = splnet();
! 382:
! 383: /* address family dependent data region */
! 384: bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
! 385: for (dp = domains; dp; dp = dp->dom_next) {
! 386: if (dp->dom_ifattach)
! 387: ifp->if_afdata[dp->dom_family] =
! 388: (*dp->dom_ifattach)(ifp);
! 389: }
! 390:
! 391: splx(s);
! 392: }
! 393:
! 394: void
! 395: if_attachhead(struct ifnet *ifp)
! 396: {
! 397: if (if_index == 0) {
! 398: TAILQ_INIT(&ifnet);
! 399: TAILQ_INIT(&ifg_head);
! 400: }
! 401: TAILQ_INIT(&ifp->if_addrlist);
! 402: ifp->if_addrhooks = malloc(sizeof(*ifp->if_addrhooks),
! 403: M_TEMP, M_NOWAIT);
! 404: if (ifp->if_addrhooks == NULL)
! 405: panic("if_attachhead: malloc");
! 406: TAILQ_INIT(ifp->if_addrhooks);
! 407: ifp->if_linkstatehooks = malloc(sizeof(*ifp->if_linkstatehooks),
! 408: M_TEMP, M_NOWAIT);
! 409: if (ifp->if_linkstatehooks == NULL)
! 410: panic("if_attachhead: malloc");
! 411: TAILQ_INIT(ifp->if_linkstatehooks);
! 412: ifp->if_detachhooks = malloc(sizeof(*ifp->if_detachhooks),
! 413: M_TEMP, M_NOWAIT);
! 414: if (ifp->if_detachhooks == NULL)
! 415: panic("if_attachhead: malloc");
! 416: TAILQ_INIT(ifp->if_detachhooks);
! 417: TAILQ_INSERT_HEAD(&ifnet, ifp, if_list);
! 418: if_attachsetup(ifp);
! 419: }
! 420:
! 421: void
! 422: if_attach(struct ifnet *ifp)
! 423: {
! 424: #if NCARP > 0
! 425: struct ifnet *before = NULL;
! 426: #endif
! 427:
! 428: if (if_index == 0) {
! 429: TAILQ_INIT(&ifnet);
! 430: TAILQ_INIT(&ifg_head);
! 431: }
! 432: TAILQ_INIT(&ifp->if_addrlist);
! 433: ifp->if_addrhooks = malloc(sizeof(*ifp->if_addrhooks),
! 434: M_TEMP, M_NOWAIT);
! 435: if (ifp->if_addrhooks == NULL)
! 436: panic("if_attach: malloc");
! 437: TAILQ_INIT(ifp->if_addrhooks);
! 438: ifp->if_linkstatehooks = malloc(sizeof(*ifp->if_linkstatehooks),
! 439: M_TEMP, M_NOWAIT);
! 440: if (ifp->if_linkstatehooks == NULL)
! 441: panic("if_attach: malloc");
! 442: TAILQ_INIT(ifp->if_linkstatehooks);
! 443: ifp->if_detachhooks = malloc(sizeof(*ifp->if_detachhooks),
! 444: M_TEMP, M_NOWAIT);
! 445: if (ifp->if_detachhooks == NULL)
! 446: panic("if_attach: malloc");
! 447: TAILQ_INIT(ifp->if_detachhooks);
! 448:
! 449: #if NCARP > 0
! 450: if (ifp->if_type != IFT_CARP)
! 451: TAILQ_FOREACH(before, &ifnet, if_list)
! 452: if (before->if_type == IFT_CARP)
! 453: break;
! 454: if (before == NULL)
! 455: TAILQ_INSERT_TAIL(&ifnet, ifp, if_list);
! 456: else
! 457: TAILQ_INSERT_BEFORE(before, ifp, if_list);
! 458: #else
! 459: TAILQ_INSERT_TAIL(&ifnet, ifp, if_list);
! 460: #endif
! 461:
! 462: if_attachsetup(ifp);
! 463: }
! 464:
! 465: /*
! 466: * Detach an interface from everything in the kernel. Also deallocate
! 467: * private resources.
! 468: * XXX So far only the INET protocol family has been looked over
! 469: * wrt resource usage that needs to be decoupled.
! 470: */
! 471: void
! 472: if_detach(struct ifnet *ifp)
! 473: {
! 474: struct ifaddr *ifa;
! 475: struct ifg_list *ifg;
! 476: int s = splnet();
! 477: struct domain *dp;
! 478:
! 479: ifp->if_flags &= ~IFF_OACTIVE;
! 480: ifp->if_start = if_detached_start;
! 481: ifp->if_ioctl = if_detached_ioctl;
! 482: ifp->if_init = if_detached_init;
! 483: ifp->if_watchdog = if_detached_watchdog;
! 484:
! 485: /* Call detach hooks, ie. to remove vlan interfaces */
! 486: dohooks(ifp->if_detachhooks, HOOK_REMOVE | HOOK_FREE);
! 487:
! 488: #if NTRUNK > 0
! 489: if (ifp->if_type == IFT_IEEE8023ADLAG)
! 490: trunk_port_ifdetach(ifp);
! 491: #endif
! 492:
! 493: #if NBRIDGE > 0
! 494: /* Remove the interface from any bridge it is part of. */
! 495: if (ifp->if_bridge)
! 496: bridge_ifdetach(ifp);
! 497: #endif
! 498:
! 499: #if NCARP > 0
! 500: /* Remove the interface from any carp group it is a part of. */
! 501: if (ifp->if_carp && ifp->if_type != IFT_CARP)
! 502: carp_ifdetach(ifp);
! 503: #endif
! 504:
! 505: #if NBPFILTER > 0
! 506: bpfdetach(ifp);
! 507: #endif
! 508: #ifdef ALTQ
! 509: if (ALTQ_IS_ENABLED(&ifp->if_snd))
! 510: altq_disable(&ifp->if_snd);
! 511: if (ALTQ_IS_ATTACHED(&ifp->if_snd))
! 512: altq_detach(&ifp->if_snd);
! 513: #endif
! 514: rt_if_remove(ifp);
! 515: #ifdef INET
! 516: rti_delete(ifp);
! 517: #if NETHER > 0
! 518: myip_ifp = NULL;
! 519: #endif
! 520: #ifdef MROUTING
! 521: vif_delete(ifp);
! 522: #endif
! 523: #endif
! 524: #ifdef INET6
! 525: in6_ifdetach(ifp);
! 526: #endif
! 527:
! 528: #if NPF > 0
! 529: pfi_detach_ifnet(ifp);
! 530: #endif
! 531:
! 532: /*
! 533: * remove packets came from ifp, from software interrupt queues.
! 534: * net/netisr_dispatch.h is not usable, as some of them use
! 535: * strange queue names.
! 536: */
! 537: #define IF_DETACH_QUEUES(x) \
! 538: do { \
! 539: extern struct ifqueue x; \
! 540: if_detach_queues(ifp, & x); \
! 541: } while (0)
! 542: #ifdef INET
! 543: IF_DETACH_QUEUES(arpintrq);
! 544: IF_DETACH_QUEUES(ipintrq);
! 545: #endif
! 546: #ifdef INET6
! 547: IF_DETACH_QUEUES(ip6intrq);
! 548: #endif
! 549: #ifdef NETATALK
! 550: IF_DETACH_QUEUES(atintrq1);
! 551: IF_DETACH_QUEUES(atintrq2);
! 552: #endif
! 553: #ifdef NATM
! 554: IF_DETACH_QUEUES(natmintrq);
! 555: #endif
! 556: #undef IF_DETACH_QUEUES
! 557:
! 558: /*
! 559: * XXX transient ifp refs? inpcb.ip_moptions.imo_multicast_ifp?
! 560: * Other network stacks than INET?
! 561: */
! 562:
! 563: /* Remove the interface from the list of all interfaces. */
! 564: TAILQ_REMOVE(&ifnet, ifp, if_list);
! 565:
! 566: /*
! 567: * Deallocate private resources.
! 568: */
! 569: while ((ifa = TAILQ_FIRST(&ifp->if_addrlist)) != NULL) {
! 570: TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
! 571: #ifdef INET
! 572: if (ifa->ifa_addr->sa_family == AF_INET)
! 573: TAILQ_REMOVE(&in_ifaddr, (struct in_ifaddr *)ifa,
! 574: ia_list);
! 575: #endif
! 576: /* XXX if_free_sadl needs this */
! 577: if (ifa == ifnet_addrs[ifp->if_index])
! 578: continue;
! 579:
! 580: ifa->ifa_ifp = NULL;
! 581: IFAFREE(ifa);
! 582: }
! 583:
! 584: for (ifg = TAILQ_FIRST(&ifp->if_groups); ifg;
! 585: ifg = TAILQ_FIRST(&ifp->if_groups))
! 586: if_delgroup(ifp, ifg->ifgl_group->ifg_group);
! 587:
! 588: if_free_sadl(ifp);
! 589:
! 590: ifnet_addrs[ifp->if_index]->ifa_ifp = NULL;
! 591: IFAFREE(ifnet_addrs[ifp->if_index]);
! 592: ifnet_addrs[ifp->if_index] = NULL;
! 593:
! 594: free(ifp->if_addrhooks, M_TEMP);
! 595: free(ifp->if_linkstatehooks, M_TEMP);
! 596: free(ifp->if_detachhooks, M_TEMP);
! 597:
! 598: for (dp = domains; dp; dp = dp->dom_next) {
! 599: if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
! 600: (*dp->dom_ifdetach)(ifp,
! 601: ifp->if_afdata[dp->dom_family]);
! 602: }
! 603:
! 604: /* Announce that the interface is gone. */
! 605: rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
! 606:
! 607: splx(s);
! 608: }
! 609:
! 610: void
! 611: if_detach_queues(struct ifnet *ifp, struct ifqueue *q)
! 612: {
! 613: struct mbuf *m, *prev, *next;
! 614:
! 615: prev = NULL;
! 616: for (m = q->ifq_head; m; m = next) {
! 617: next = m->m_nextpkt;
! 618: #ifdef DIAGNOSTIC
! 619: if ((m->m_flags & M_PKTHDR) == 0) {
! 620: prev = m;
! 621: continue;
! 622: }
! 623: #endif
! 624: if (m->m_pkthdr.rcvif != ifp) {
! 625: prev = m;
! 626: continue;
! 627: }
! 628:
! 629: if (prev)
! 630: prev->m_nextpkt = m->m_nextpkt;
! 631: else
! 632: q->ifq_head = m->m_nextpkt;
! 633: if (q->ifq_tail == m)
! 634: q->ifq_tail = prev;
! 635: q->ifq_len--;
! 636:
! 637: m->m_nextpkt = NULL;
! 638: m_freem(m);
! 639: IF_DROP(q);
! 640: }
! 641: }
! 642:
! 643: /*
! 644: * Create a clone network interface.
! 645: */
! 646: int
! 647: if_clone_create(const char *name)
! 648: {
! 649: struct if_clone *ifc;
! 650: struct ifnet *ifp;
! 651: int unit, ret;
! 652:
! 653: ifc = if_clone_lookup(name, &unit);
! 654: if (ifc == NULL)
! 655: return (EINVAL);
! 656:
! 657: if (ifunit(name) != NULL)
! 658: return (EEXIST);
! 659:
! 660: if ((ret = (*ifc->ifc_create)(ifc, unit)) == 0 &&
! 661: (ifp = ifunit(name)) != NULL)
! 662: if_addgroup(ifp, ifc->ifc_name);
! 663:
! 664: return (ret);
! 665: }
! 666:
! 667: /*
! 668: * Destroy a clone network interface.
! 669: */
! 670: int
! 671: if_clone_destroy(const char *name)
! 672: {
! 673: struct if_clone *ifc;
! 674: struct ifnet *ifp;
! 675: int s, ret;
! 676:
! 677: ifc = if_clone_lookup(name, NULL);
! 678: if (ifc == NULL)
! 679: return (EINVAL);
! 680:
! 681: ifp = ifunit(name);
! 682: if (ifp == NULL)
! 683: return (ENXIO);
! 684:
! 685: if (ifc->ifc_destroy == NULL)
! 686: return (EOPNOTSUPP);
! 687:
! 688: if (ifp->if_flags & IFF_UP) {
! 689: s = splnet();
! 690: if_down(ifp);
! 691: splx(s);
! 692: }
! 693:
! 694: if_delgroup(ifp, ifc->ifc_name);
! 695:
! 696: if ((ret = (*ifc->ifc_destroy)(ifp)) != 0)
! 697: if_addgroup(ifp, ifc->ifc_name);
! 698:
! 699: return (ret);
! 700: }
! 701:
! 702: /*
! 703: * Look up a network interface cloner.
! 704: */
! 705: struct if_clone *
! 706: if_clone_lookup(const char *name, int *unitp)
! 707: {
! 708: struct if_clone *ifc;
! 709: const char *cp;
! 710: int unit;
! 711:
! 712: /* separate interface name from unit */
! 713: for (cp = name;
! 714: cp - name < IFNAMSIZ && *cp && (*cp < '0' || *cp > '9');
! 715: cp++)
! 716: continue;
! 717:
! 718: if (cp == name || cp - name == IFNAMSIZ || !*cp)
! 719: return (NULL); /* No name or unit number */
! 720:
! 721: if (cp - name < IFNAMSIZ-1 && *cp == '0' && cp[1] != '\0')
! 722: return (NULL); /* unit number 0 padded */
! 723:
! 724: LIST_FOREACH(ifc, &if_cloners, ifc_list) {
! 725: if (strlen(ifc->ifc_name) == cp - name &&
! 726: !strncmp(name, ifc->ifc_name, cp - name))
! 727: break;
! 728: }
! 729:
! 730: if (ifc == NULL)
! 731: return (NULL);
! 732:
! 733: unit = 0;
! 734: while (cp - name < IFNAMSIZ && *cp) {
! 735: if (*cp < '0' || *cp > '9' ||
! 736: unit > (INT_MAX - (*cp - '0')) / 10) {
! 737: /* Bogus unit number. */
! 738: return (NULL);
! 739: }
! 740: unit = (unit * 10) + (*cp++ - '0');
! 741: }
! 742:
! 743: if (unitp != NULL)
! 744: *unitp = unit;
! 745: return (ifc);
! 746: }
! 747:
! 748: /*
! 749: * Register a network interface cloner.
! 750: */
! 751: void
! 752: if_clone_attach(struct if_clone *ifc)
! 753: {
! 754: LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
! 755: if_cloners_count++;
! 756: }
! 757:
! 758: /*
! 759: * Unregister a network interface cloner.
! 760: */
! 761: void
! 762: if_clone_detach(struct if_clone *ifc)
! 763: {
! 764:
! 765: LIST_REMOVE(ifc, ifc_list);
! 766: if_cloners_count--;
! 767: }
! 768:
! 769: /*
! 770: * Provide list of interface cloners to userspace.
! 771: */
! 772: int
! 773: if_clone_list(struct if_clonereq *ifcr)
! 774: {
! 775: char outbuf[IFNAMSIZ], *dst;
! 776: struct if_clone *ifc;
! 777: int count, error = 0;
! 778:
! 779: ifcr->ifcr_total = if_cloners_count;
! 780: if ((dst = ifcr->ifcr_buffer) == NULL) {
! 781: /* Just asking how many there are. */
! 782: return (0);
! 783: }
! 784:
! 785: if (ifcr->ifcr_count < 0)
! 786: return (EINVAL);
! 787:
! 788: count = (if_cloners_count < ifcr->ifcr_count) ?
! 789: if_cloners_count : ifcr->ifcr_count;
! 790:
! 791: for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
! 792: ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
! 793: bzero(outbuf, sizeof outbuf);
! 794: strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ);
! 795: error = copyout(outbuf, dst, IFNAMSIZ);
! 796: if (error)
! 797: break;
! 798: }
! 799:
! 800: return (error);
! 801: }
! 802:
! 803: /*
! 804: * set queue congestion marker and register timeout to clear it
! 805: */
! 806: void
! 807: if_congestion(struct ifqueue *ifq)
! 808: {
! 809: /* Not currently needed, all callers check this */
! 810: if (ifq->ifq_congestion)
! 811: return;
! 812:
! 813: ifq->ifq_congestion = malloc(sizeof(struct timeout), M_TEMP, M_NOWAIT);
! 814: if (ifq->ifq_congestion == NULL)
! 815: return;
! 816: timeout_set(ifq->ifq_congestion, if_congestion_clear, ifq);
! 817: timeout_add(ifq->ifq_congestion, hz / 100);
! 818: }
! 819:
! 820: /*
! 821: * clear the congestion flag
! 822: */
! 823: void
! 824: if_congestion_clear(void *arg)
! 825: {
! 826: struct ifqueue *ifq = arg;
! 827: struct timeout *to = ifq->ifq_congestion;
! 828:
! 829: ifq->ifq_congestion = NULL;
! 830: free(to, M_TEMP);
! 831: }
! 832:
! 833: /*
! 834: * Locate an interface based on a complete address.
! 835: */
! 836: /*ARGSUSED*/
! 837: struct ifaddr *
! 838: ifa_ifwithaddr(struct sockaddr *addr)
! 839: {
! 840: struct ifnet *ifp;
! 841: struct ifaddr *ifa;
! 842:
! 843: #define equal(a1, a2) \
! 844: (bcmp((caddr_t)(a1), (caddr_t)(a2), \
! 845: ((struct sockaddr *)(a1))->sa_len) == 0)
! 846: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 847: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 848: if (ifa->ifa_addr->sa_family != addr->sa_family)
! 849: continue;
! 850: if (equal(addr, ifa->ifa_addr))
! 851: return (ifa);
! 852: if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
! 853: /* IP6 doesn't have broadcast */
! 854: ifa->ifa_broadaddr->sa_len != 0 &&
! 855: equal(ifa->ifa_broadaddr, addr))
! 856: return (ifa);
! 857: }
! 858: }
! 859: return (NULL);
! 860: }
! 861: /*
! 862: * Locate the point to point interface with a given destination address.
! 863: */
! 864: /*ARGSUSED*/
! 865: struct ifaddr *
! 866: ifa_ifwithdstaddr(struct sockaddr *addr)
! 867: {
! 868: struct ifnet *ifp;
! 869: struct ifaddr *ifa;
! 870:
! 871: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 872: if (ifp->if_flags & IFF_POINTOPOINT)
! 873: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 874: if (ifa->ifa_addr->sa_family != addr->sa_family ||
! 875: ifa->ifa_dstaddr == NULL)
! 876: continue;
! 877: if (equal(addr, ifa->ifa_dstaddr))
! 878: return (ifa);
! 879: }
! 880: }
! 881: return (NULL);
! 882: }
! 883:
! 884: /*
! 885: * Find an interface on a specific network. If many, choice
! 886: * is most specific found.
! 887: */
! 888: struct ifaddr *
! 889: ifa_ifwithnet(struct sockaddr *addr)
! 890: {
! 891: struct ifnet *ifp;
! 892: struct ifaddr *ifa;
! 893: struct ifaddr *ifa_maybe = 0;
! 894: u_int af = addr->sa_family;
! 895: char *addr_data = addr->sa_data, *cplim;
! 896:
! 897: if (af == AF_LINK) {
! 898: struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
! 899: if (sdl->sdl_index && sdl->sdl_index < if_indexlim &&
! 900: ifindex2ifnet[sdl->sdl_index])
! 901: return (ifnet_addrs[sdl->sdl_index]);
! 902: }
! 903: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 904: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 905: char *cp, *cp2, *cp3;
! 906:
! 907: if (ifa->ifa_addr->sa_family != af ||
! 908: ifa->ifa_netmask == 0)
! 909: next: continue;
! 910: cp = addr_data;
! 911: cp2 = ifa->ifa_addr->sa_data;
! 912: cp3 = ifa->ifa_netmask->sa_data;
! 913: cplim = (char *)ifa->ifa_netmask +
! 914: ifa->ifa_netmask->sa_len;
! 915: while (cp3 < cplim)
! 916: if ((*cp++ ^ *cp2++) & *cp3++)
! 917: /* want to continue for() loop */
! 918: goto next;
! 919: if (ifa_maybe == 0 ||
! 920: rn_refines((caddr_t)ifa->ifa_netmask,
! 921: (caddr_t)ifa_maybe->ifa_netmask))
! 922: ifa_maybe = ifa;
! 923: }
! 924: }
! 925: return (ifa_maybe);
! 926: }
! 927:
! 928: /*
! 929: * Find an interface using a specific address family
! 930: */
! 931: struct ifaddr *
! 932: ifa_ifwithaf(int af)
! 933: {
! 934: struct ifnet *ifp;
! 935: struct ifaddr *ifa;
! 936:
! 937: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 938: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 939: if (ifa->ifa_addr->sa_family == af)
! 940: return (ifa);
! 941: }
! 942: }
! 943: return (NULL);
! 944: }
! 945:
! 946: /*
! 947: * Find an interface address specific to an interface best matching
! 948: * a given address.
! 949: */
! 950: struct ifaddr *
! 951: ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
! 952: {
! 953: struct ifaddr *ifa;
! 954: char *cp, *cp2, *cp3;
! 955: char *cplim;
! 956: struct ifaddr *ifa_maybe = NULL;
! 957: u_int af = addr->sa_family;
! 958:
! 959: if (af >= AF_MAX)
! 960: return (NULL);
! 961: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 962: if (ifa->ifa_addr->sa_family != af)
! 963: continue;
! 964: if (ifa_maybe == NULL)
! 965: ifa_maybe = ifa;
! 966: if (ifa->ifa_netmask == 0 || ifp->if_flags & IFF_POINTOPOINT) {
! 967: if (equal(addr, ifa->ifa_addr) ||
! 968: (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
! 969: return (ifa);
! 970: continue;
! 971: }
! 972: cp = addr->sa_data;
! 973: cp2 = ifa->ifa_addr->sa_data;
! 974: cp3 = ifa->ifa_netmask->sa_data;
! 975: cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
! 976: for (; cp3 < cplim; cp3++)
! 977: if ((*cp++ ^ *cp2++) & *cp3)
! 978: break;
! 979: if (cp3 == cplim)
! 980: return (ifa);
! 981: }
! 982: return (ifa_maybe);
! 983: }
! 984:
! 985: /*
! 986: * Default action when installing a route with a Link Level gateway.
! 987: * Lookup an appropriate real ifa to point to.
! 988: * This should be moved to /sys/net/link.c eventually.
! 989: */
! 990: void
! 991: link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
! 992: {
! 993: struct ifaddr *ifa;
! 994: struct sockaddr *dst;
! 995: struct ifnet *ifp;
! 996:
! 997: if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
! 998: ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
! 999: return;
! 1000: if ((ifa = ifaof_ifpforaddr(dst, ifp)) != NULL) {
! 1001: ifa->ifa_refcnt++;
! 1002: IFAFREE(rt->rt_ifa);
! 1003: rt->rt_ifa = ifa;
! 1004: if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
! 1005: ifa->ifa_rtrequest(cmd, rt, info);
! 1006: }
! 1007: }
! 1008:
! 1009: /*
! 1010: * Mark an interface down and notify protocols of
! 1011: * the transition.
! 1012: * NOTE: must be called at splsoftnet or equivalent.
! 1013: */
! 1014: void
! 1015: if_down(struct ifnet *ifp)
! 1016: {
! 1017: struct ifaddr *ifa;
! 1018:
! 1019: splassert(IPL_SOFTNET);
! 1020:
! 1021: ifp->if_flags &= ~IFF_UP;
! 1022: microtime(&ifp->if_lastchange);
! 1023: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1024: pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
! 1025: }
! 1026: IFQ_PURGE(&ifp->if_snd);
! 1027: #if NCARP > 0
! 1028: if (ifp->if_carp)
! 1029: carp_carpdev_state(ifp);
! 1030: #endif
! 1031: #if NBRIDGE > 0
! 1032: if (ifp->if_bridge)
! 1033: bstp_ifstate(ifp);
! 1034: #endif
! 1035: rt_ifmsg(ifp);
! 1036: }
! 1037:
! 1038: /*
! 1039: * Mark an interface up and notify protocols of
! 1040: * the transition.
! 1041: * NOTE: must be called at splsoftnet or equivalent.
! 1042: */
! 1043: void
! 1044: if_up(struct ifnet *ifp)
! 1045: {
! 1046: #ifdef notyet
! 1047: struct ifaddr *ifa;
! 1048: #endif
! 1049:
! 1050: splassert(IPL_SOFTNET);
! 1051:
! 1052: ifp->if_flags |= IFF_UP;
! 1053: microtime(&ifp->if_lastchange);
! 1054: #ifdef notyet
! 1055: /* this has no effect on IP, and will kill all ISO connections XXX */
! 1056: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1057: pfctlinput(PRC_IFUP, ifa->ifa_addr);
! 1058: }
! 1059: #endif
! 1060: #if NCARP > 0
! 1061: if (ifp->if_carp)
! 1062: carp_carpdev_state(ifp);
! 1063: #endif
! 1064: #if NBRIDGE > 0
! 1065: if (ifp->if_bridge)
! 1066: bstp_ifstate(ifp);
! 1067: #endif
! 1068: rt_ifmsg(ifp);
! 1069: #ifdef INET6
! 1070: in6_if_up(ifp);
! 1071: #endif
! 1072: }
! 1073:
! 1074: /*
! 1075: * Process a link state change.
! 1076: * NOTE: must be called at splsoftnet or equivalent.
! 1077: */
! 1078: void
! 1079: if_link_state_change(struct ifnet *ifp)
! 1080: {
! 1081: rt_ifmsg(ifp);
! 1082: dohooks(ifp->if_linkstatehooks, 0);
! 1083: }
! 1084:
! 1085: /*
! 1086: * Flush an interface queue.
! 1087: */
! 1088: void
! 1089: if_qflush(struct ifqueue *ifq)
! 1090: {
! 1091: struct mbuf *m, *n;
! 1092:
! 1093: n = ifq->ifq_head;
! 1094: while ((m = n) != NULL) {
! 1095: n = m->m_act;
! 1096: m_freem(m);
! 1097: }
! 1098: ifq->ifq_head = 0;
! 1099: ifq->ifq_tail = 0;
! 1100: ifq->ifq_len = 0;
! 1101: }
! 1102:
! 1103: /*
! 1104: * Handle interface watchdog timer routines. Called
! 1105: * from softclock, we decrement timers (if set) and
! 1106: * call the appropriate interface routine on expiration.
! 1107: */
! 1108: void
! 1109: if_slowtimo(void *arg)
! 1110: {
! 1111: struct timeout *to = (struct timeout *)arg;
! 1112: struct ifnet *ifp;
! 1113: int s = splnet();
! 1114:
! 1115: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 1116: if (ifp->if_timer == 0 || --ifp->if_timer)
! 1117: continue;
! 1118: if (ifp->if_watchdog)
! 1119: (*ifp->if_watchdog)(ifp);
! 1120: }
! 1121: splx(s);
! 1122: timeout_add(to, hz / IFNET_SLOWHZ);
! 1123: }
! 1124:
! 1125: /*
! 1126: * Map interface name to
! 1127: * interface structure pointer.
! 1128: */
! 1129: struct ifnet *
! 1130: ifunit(const char *name)
! 1131: {
! 1132: struct ifnet *ifp;
! 1133:
! 1134: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 1135: if (strcmp(ifp->if_xname, name) == 0)
! 1136: return (ifp);
! 1137: }
! 1138: return (NULL);
! 1139: }
! 1140:
! 1141: /*
! 1142: * Interface ioctls.
! 1143: */
! 1144: int
! 1145: ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
! 1146: {
! 1147: struct ifnet *ifp;
! 1148: struct ifreq *ifr;
! 1149: struct ifaddr *ifa;
! 1150: struct sockaddr_dl *sdl;
! 1151: struct ifgroupreq *ifgr;
! 1152: char ifdescrbuf[IFDESCRSIZE];
! 1153: char ifrtlabelbuf[RTLABEL_LEN];
! 1154: int error = 0;
! 1155: size_t bytesdone;
! 1156: short oif_flags;
! 1157: const char *label;
! 1158:
! 1159: switch (cmd) {
! 1160:
! 1161: case SIOCGIFCONF:
! 1162: case OSIOCGIFCONF:
! 1163: return (ifconf(cmd, data));
! 1164: }
! 1165: ifr = (struct ifreq *)data;
! 1166:
! 1167: switch (cmd) {
! 1168: case SIOCIFCREATE:
! 1169: case SIOCIFDESTROY:
! 1170: if ((error = suser(p, 0)) != 0)
! 1171: return (error);
! 1172: return ((cmd == SIOCIFCREATE) ?
! 1173: if_clone_create(ifr->ifr_name) :
! 1174: if_clone_destroy(ifr->ifr_name));
! 1175: case SIOCIFGCLONERS:
! 1176: return (if_clone_list((struct if_clonereq *)data));
! 1177: case SIOCGIFGMEMB:
! 1178: return (if_getgroupmembers(data));
! 1179: case SIOCGIFGATTR:
! 1180: return (if_getgroupattribs(data));
! 1181: case SIOCSIFGATTR:
! 1182: if ((error = suser(p, 0)) != 0)
! 1183: return (error);
! 1184: return (if_setgroupattribs(data));
! 1185: }
! 1186:
! 1187: ifp = ifunit(ifr->ifr_name);
! 1188: if (ifp == 0)
! 1189: return (ENXIO);
! 1190: oif_flags = ifp->if_flags;
! 1191: switch (cmd) {
! 1192:
! 1193: case SIOCGIFFLAGS:
! 1194: ifr->ifr_flags = ifp->if_flags;
! 1195: break;
! 1196:
! 1197: case SIOCGIFMETRIC:
! 1198: ifr->ifr_metric = ifp->if_metric;
! 1199: break;
! 1200:
! 1201: case SIOCGIFMTU:
! 1202: ifr->ifr_mtu = ifp->if_mtu;
! 1203: break;
! 1204:
! 1205: case SIOCGIFDATA:
! 1206: error = copyout((caddr_t)&ifp->if_data, ifr->ifr_data,
! 1207: sizeof(ifp->if_data));
! 1208: break;
! 1209:
! 1210: case SIOCSIFFLAGS:
! 1211: if ((error = suser(p, 0)) != 0)
! 1212: return (error);
! 1213: if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
! 1214: int s = splnet();
! 1215: if_down(ifp);
! 1216: splx(s);
! 1217: }
! 1218: if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
! 1219: int s = splnet();
! 1220: if_up(ifp);
! 1221: splx(s);
! 1222: }
! 1223: ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
! 1224: (ifr->ifr_flags &~ IFF_CANTCHANGE);
! 1225: if (ifp->if_ioctl)
! 1226: (void) (*ifp->if_ioctl)(ifp, cmd, data);
! 1227: break;
! 1228:
! 1229: case SIOCSIFMETRIC:
! 1230: if ((error = suser(p, 0)) != 0)
! 1231: return (error);
! 1232: ifp->if_metric = ifr->ifr_metric;
! 1233: break;
! 1234:
! 1235: case SIOCSIFMTU:
! 1236: {
! 1237: #ifdef INET6
! 1238: int oldmtu = ifp->if_mtu;
! 1239: #endif
! 1240:
! 1241: if ((error = suser(p, 0)) != 0)
! 1242: return (error);
! 1243: if (ifp->if_ioctl == NULL)
! 1244: return (EOPNOTSUPP);
! 1245: error = (*ifp->if_ioctl)(ifp, cmd, data);
! 1246:
! 1247: /*
! 1248: * If the link MTU changed, do network layer specific procedure.
! 1249: */
! 1250: #ifdef INET6
! 1251: if (ifp->if_mtu != oldmtu)
! 1252: nd6_setmtu(ifp);
! 1253: #endif
! 1254: break;
! 1255: }
! 1256:
! 1257: case SIOCSIFPHYADDR:
! 1258: case SIOCDIFPHYADDR:
! 1259: #ifdef INET6
! 1260: case SIOCSIFPHYADDR_IN6:
! 1261: #endif
! 1262: case SIOCSLIFPHYADDR:
! 1263: case SIOCADDMULTI:
! 1264: case SIOCDELMULTI:
! 1265: case SIOCSIFMEDIA:
! 1266: if ((error = suser(p, 0)) != 0)
! 1267: return (error);
! 1268: /* FALLTHROUGH */
! 1269: case SIOCGIFPSRCADDR:
! 1270: case SIOCGIFPDSTADDR:
! 1271: case SIOCGLIFPHYADDR:
! 1272: case SIOCGIFMEDIA:
! 1273: if (ifp->if_ioctl == 0)
! 1274: return (EOPNOTSUPP);
! 1275: error = (*ifp->if_ioctl)(ifp, cmd, data);
! 1276: break;
! 1277:
! 1278: case SIOCGIFDESCR:
! 1279: strlcpy(ifdescrbuf, ifp->if_description, IFDESCRSIZE);
! 1280: error = copyoutstr(ifdescrbuf, ifr->ifr_data, IFDESCRSIZE,
! 1281: &bytesdone);
! 1282: break;
! 1283:
! 1284: case SIOCSIFDESCR:
! 1285: if ((error = suser(p, 0)) != 0)
! 1286: return (error);
! 1287: error = copyinstr(ifr->ifr_data, ifdescrbuf,
! 1288: IFDESCRSIZE, &bytesdone);
! 1289: if (error == 0) {
! 1290: (void)memset(ifp->if_description, 0, IFDESCRSIZE);
! 1291: strlcpy(ifp->if_description, ifdescrbuf, IFDESCRSIZE);
! 1292: }
! 1293: break;
! 1294:
! 1295: case SIOCGIFRTLABEL:
! 1296: label = rtlabel_id2name(ifp->if_rtlabelid);
! 1297: strlcpy(ifrtlabelbuf, label, RTLABEL_LEN);
! 1298: error = copyoutstr(ifrtlabelbuf, ifr->ifr_data, RTLABEL_LEN,
! 1299: &bytesdone);
! 1300: break;
! 1301:
! 1302: case SIOCSIFRTLABEL:
! 1303: if ((error = suser(p, 0)) != 0)
! 1304: return (error);
! 1305: error = copyinstr(ifr->ifr_data, ifrtlabelbuf,
! 1306: RTLABEL_LEN, &bytesdone);
! 1307: if (error == 0) {
! 1308: rtlabel_unref(ifp->if_rtlabelid);
! 1309: ifp->if_rtlabelid = rtlabel_name2id(ifrtlabelbuf);
! 1310: }
! 1311: break;
! 1312:
! 1313: case SIOCAIFGROUP:
! 1314: if ((error = suser(p, 0)))
! 1315: return (error);
! 1316: (*ifp->if_ioctl)(ifp, cmd, data); /* XXX error check */
! 1317: ifgr = (struct ifgroupreq *)data;
! 1318: if ((error = if_addgroup(ifp, ifgr->ifgr_group)))
! 1319: return (error);
! 1320: break;
! 1321:
! 1322: case SIOCGIFGROUP:
! 1323: if ((error = if_getgroup(data, ifp)))
! 1324: return (error);
! 1325: break;
! 1326:
! 1327: case SIOCDIFGROUP:
! 1328: if ((error = suser(p, 0)))
! 1329: return (error);
! 1330: (*ifp->if_ioctl)(ifp, cmd, data); /* XXX error check */
! 1331: ifgr = (struct ifgroupreq *)data;
! 1332: if ((error = if_delgroup(ifp, ifgr->ifgr_group)))
! 1333: return (error);
! 1334: break;
! 1335:
! 1336: case SIOCSIFLLADDR:
! 1337: if ((error = suser(p, 0)))
! 1338: return (error);
! 1339: ifa = ifnet_addrs[ifp->if_index];
! 1340: if (ifa == NULL)
! 1341: return (EINVAL);
! 1342: sdl = (struct sockaddr_dl *)ifa->ifa_addr;
! 1343: if (sdl == NULL)
! 1344: return (EINVAL);
! 1345: if (ifr->ifr_addr.sa_len != ETHER_ADDR_LEN)
! 1346: return (EINVAL);
! 1347: if (ETHER_IS_MULTICAST(ifr->ifr_addr.sa_data))
! 1348: return (EINVAL);
! 1349: switch (ifp->if_type) {
! 1350: case IFT_ETHER:
! 1351: case IFT_CARP:
! 1352: case IFT_FDDI:
! 1353: case IFT_XETHER:
! 1354: case IFT_ISO88025:
! 1355: case IFT_L2VLAN:
! 1356: bcopy((caddr_t)ifr->ifr_addr.sa_data,
! 1357: (caddr_t)((struct arpcom *)ifp)->ac_enaddr,
! 1358: ETHER_ADDR_LEN);
! 1359: bcopy((caddr_t)ifr->ifr_addr.sa_data,
! 1360: LLADDR(sdl), ETHER_ADDR_LEN);
! 1361: break;
! 1362: default:
! 1363: return (ENODEV);
! 1364: }
! 1365: if (ifp->if_flags & IFF_UP) {
! 1366: struct ifreq ifrq;
! 1367: int s = splnet();
! 1368: ifp->if_flags &= ~IFF_UP;
! 1369: ifrq.ifr_flags = ifp->if_flags;
! 1370: (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
! 1371: ifp->if_flags |= IFF_UP;
! 1372: ifrq.ifr_flags = ifp->if_flags;
! 1373: (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
! 1374: splx(s);
! 1375: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1376: if (ifa->ifa_addr != NULL &&
! 1377: ifa->ifa_addr->sa_family == AF_INET)
! 1378: arp_ifinit((struct arpcom *)ifp, ifa);
! 1379: }
! 1380: }
! 1381: break;
! 1382:
! 1383: default:
! 1384: if (so->so_proto == 0)
! 1385: return (EOPNOTSUPP);
! 1386: #if !defined(COMPAT_43) && !defined(COMPAT_LINUX) && !defined(COMPAT_SVR4)
! 1387: error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
! 1388: (struct mbuf *) cmd, (struct mbuf *) data,
! 1389: (struct mbuf *) ifp));
! 1390: #else
! 1391: {
! 1392: u_long ocmd = cmd;
! 1393:
! 1394: switch (cmd) {
! 1395:
! 1396: case SIOCSIFADDR:
! 1397: case SIOCSIFDSTADDR:
! 1398: case SIOCSIFBRDADDR:
! 1399: case SIOCSIFNETMASK:
! 1400: #if BYTE_ORDER != BIG_ENDIAN
! 1401: if (ifr->ifr_addr.sa_family == 0 &&
! 1402: ifr->ifr_addr.sa_len < 16) {
! 1403: ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
! 1404: ifr->ifr_addr.sa_len = 16;
! 1405: }
! 1406: #else
! 1407: if (ifr->ifr_addr.sa_len == 0)
! 1408: ifr->ifr_addr.sa_len = 16;
! 1409: #endif
! 1410: break;
! 1411:
! 1412: case OSIOCGIFADDR:
! 1413: cmd = SIOCGIFADDR;
! 1414: break;
! 1415:
! 1416: case OSIOCGIFDSTADDR:
! 1417: cmd = SIOCGIFDSTADDR;
! 1418: break;
! 1419:
! 1420: case OSIOCGIFBRDADDR:
! 1421: cmd = SIOCGIFBRDADDR;
! 1422: break;
! 1423:
! 1424: case OSIOCGIFNETMASK:
! 1425: cmd = SIOCGIFNETMASK;
! 1426: }
! 1427: error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
! 1428: (struct mbuf *) cmd, (struct mbuf *) data,
! 1429: (struct mbuf *) ifp));
! 1430: switch (ocmd) {
! 1431:
! 1432: case OSIOCGIFADDR:
! 1433: case OSIOCGIFDSTADDR:
! 1434: case OSIOCGIFBRDADDR:
! 1435: case OSIOCGIFNETMASK:
! 1436: *(u_int16_t *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
! 1437: }
! 1438:
! 1439: }
! 1440: #endif
! 1441: break;
! 1442: }
! 1443:
! 1444: if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) {
! 1445: microtime(&ifp->if_lastchange);
! 1446: #ifdef INET6
! 1447: if ((ifp->if_flags & IFF_UP) != 0) {
! 1448: int s = splnet();
! 1449: in6_if_up(ifp);
! 1450: splx(s);
! 1451: }
! 1452: #endif
! 1453: }
! 1454: return (error);
! 1455: }
! 1456:
! 1457: /*
! 1458: * Return interface configuration
! 1459: * of system. List may be used
! 1460: * in later ioctl's (above) to get
! 1461: * other information.
! 1462: */
! 1463: /*ARGSUSED*/
! 1464: int
! 1465: ifconf(u_long cmd, caddr_t data)
! 1466: {
! 1467: struct ifconf *ifc = (struct ifconf *)data;
! 1468: struct ifnet *ifp;
! 1469: struct ifaddr *ifa;
! 1470: struct ifreq ifr, *ifrp;
! 1471: int space = ifc->ifc_len, error = 0;
! 1472:
! 1473: /* If ifc->ifc_len is 0, fill it in with the needed size and return. */
! 1474: if (space == 0) {
! 1475: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 1476: struct sockaddr *sa;
! 1477:
! 1478: if (TAILQ_EMPTY(&ifp->if_addrlist))
! 1479: space += sizeof (ifr);
! 1480: else
! 1481: TAILQ_FOREACH(ifa,
! 1482: &ifp->if_addrlist, ifa_list) {
! 1483: sa = ifa->ifa_addr;
! 1484: #if defined(COMPAT_43) || defined(COMPAT_LINUX) || defined(COMPAT_SVR4)
! 1485: if (cmd != OSIOCGIFCONF)
! 1486: #endif
! 1487: if (sa->sa_len > sizeof(*sa))
! 1488: space += sa->sa_len -
! 1489: sizeof(*sa);
! 1490: space += sizeof(ifr);
! 1491: }
! 1492: }
! 1493: ifc->ifc_len = space;
! 1494: return (0);
! 1495: }
! 1496:
! 1497: ifrp = ifc->ifc_req;
! 1498: for (ifp = TAILQ_FIRST(&ifnet); space >= sizeof(ifr) &&
! 1499: ifp != TAILQ_END(&ifnet); ifp = TAILQ_NEXT(ifp, if_list)) {
! 1500: bcopy(ifp->if_xname, ifr.ifr_name, IFNAMSIZ);
! 1501: if (TAILQ_EMPTY(&ifp->if_addrlist)) {
! 1502: bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
! 1503: error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
! 1504: sizeof(ifr));
! 1505: if (error)
! 1506: break;
! 1507: space -= sizeof (ifr), ifrp++;
! 1508: } else
! 1509: for (ifa = TAILQ_FIRST(&ifp->if_addrlist);
! 1510: space >= sizeof (ifr) &&
! 1511: ifa != TAILQ_END(&ifp->if_addrlist);
! 1512: ifa = TAILQ_NEXT(ifa, ifa_list)) {
! 1513: struct sockaddr *sa = ifa->ifa_addr;
! 1514: #if defined(COMPAT_43) || defined(COMPAT_LINUX) || defined(COMPAT_SVR4)
! 1515: if (cmd == OSIOCGIFCONF) {
! 1516: struct osockaddr *osa =
! 1517: (struct osockaddr *)&ifr.ifr_addr;
! 1518: ifr.ifr_addr = *sa;
! 1519: osa->sa_family = sa->sa_family;
! 1520: error = copyout((caddr_t)&ifr,
! 1521: (caddr_t)ifrp, sizeof (ifr));
! 1522: ifrp++;
! 1523: } else
! 1524: #endif
! 1525: if (sa->sa_len <= sizeof(*sa)) {
! 1526: ifr.ifr_addr = *sa;
! 1527: error = copyout((caddr_t)&ifr,
! 1528: (caddr_t)ifrp, sizeof (ifr));
! 1529: ifrp++;
! 1530: } else {
! 1531: space -= sa->sa_len - sizeof(*sa);
! 1532: if (space < sizeof (ifr))
! 1533: break;
! 1534: error = copyout((caddr_t)&ifr,
! 1535: (caddr_t)ifrp,
! 1536: sizeof(ifr.ifr_name));
! 1537: if (error == 0)
! 1538: error = copyout((caddr_t)sa,
! 1539: (caddr_t)&ifrp->ifr_addr,
! 1540: sa->sa_len);
! 1541: ifrp = (struct ifreq *)(sa->sa_len +
! 1542: (caddr_t)&ifrp->ifr_addr);
! 1543: }
! 1544: if (error)
! 1545: break;
! 1546: space -= sizeof (ifr);
! 1547: }
! 1548: }
! 1549: ifc->ifc_len -= space;
! 1550: return (error);
! 1551: }
! 1552:
! 1553: /*
! 1554: * Dummy functions replaced in ifnet during detach (if protocols decide to
! 1555: * fiddle with the if during detach.
! 1556: */
! 1557: void
! 1558: if_detached_start(struct ifnet *ifp)
! 1559: {
! 1560: struct mbuf *m;
! 1561:
! 1562: while (1) {
! 1563: IF_DEQUEUE(&ifp->if_snd, m);
! 1564:
! 1565: if (m == NULL)
! 1566: return;
! 1567: m_freem(m);
! 1568: }
! 1569: }
! 1570:
! 1571: int
! 1572: if_detached_ioctl(struct ifnet *ifp, u_long a, caddr_t b)
! 1573: {
! 1574: return ENODEV;
! 1575: }
! 1576:
! 1577: int
! 1578: if_detached_init(struct ifnet *ifp)
! 1579: {
! 1580: return (ENXIO);
! 1581: }
! 1582:
! 1583: void
! 1584: if_detached_watchdog(struct ifnet *ifp)
! 1585: {
! 1586: /* nothing */
! 1587: }
! 1588:
! 1589: /*
! 1590: * Create interface group without members
! 1591: */
! 1592: struct ifg_group *
! 1593: if_creategroup(const char *groupname)
! 1594: {
! 1595: struct ifg_group *ifg = NULL;
! 1596:
! 1597: if ((ifg = (struct ifg_group *)malloc(sizeof(struct ifg_group),
! 1598: M_TEMP, M_NOWAIT)) == NULL)
! 1599: return (NULL);
! 1600:
! 1601: strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
! 1602: ifg->ifg_refcnt = 0;
! 1603: ifg->ifg_carp_demoted = 0;
! 1604: TAILQ_INIT(&ifg->ifg_members);
! 1605: #if NPF > 0
! 1606: pfi_attach_ifgroup(ifg);
! 1607: #endif
! 1608: TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next);
! 1609:
! 1610: return (ifg);
! 1611: }
! 1612:
! 1613: /*
! 1614: * Add a group to an interface
! 1615: */
! 1616: int
! 1617: if_addgroup(struct ifnet *ifp, const char *groupname)
! 1618: {
! 1619: struct ifg_list *ifgl;
! 1620: struct ifg_group *ifg = NULL;
! 1621: struct ifg_member *ifgm;
! 1622:
! 1623: if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
! 1624: groupname[strlen(groupname) - 1] <= '9')
! 1625: return (EINVAL);
! 1626:
! 1627: TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
! 1628: if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
! 1629: return (EEXIST);
! 1630:
! 1631: if ((ifgl = (struct ifg_list *)malloc(sizeof(struct ifg_list), M_TEMP,
! 1632: M_NOWAIT)) == NULL)
! 1633: return (ENOMEM);
! 1634:
! 1635: if ((ifgm = (struct ifg_member *)malloc(sizeof(struct ifg_member),
! 1636: M_TEMP, M_NOWAIT)) == NULL) {
! 1637: free(ifgl, M_TEMP);
! 1638: return (ENOMEM);
! 1639: }
! 1640:
! 1641: TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
! 1642: if (!strcmp(ifg->ifg_group, groupname))
! 1643: break;
! 1644:
! 1645: if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
! 1646: free(ifgl, M_TEMP);
! 1647: free(ifgm, M_TEMP);
! 1648: return (ENOMEM);
! 1649: }
! 1650:
! 1651: ifg->ifg_refcnt++;
! 1652: ifgl->ifgl_group = ifg;
! 1653: ifgm->ifgm_ifp = ifp;
! 1654:
! 1655: TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
! 1656: TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
! 1657:
! 1658: #if NPF > 0
! 1659: pfi_group_change(groupname);
! 1660: #endif
! 1661:
! 1662: return (0);
! 1663: }
! 1664:
! 1665: /*
! 1666: * Remove a group from an interface
! 1667: */
! 1668: int
! 1669: if_delgroup(struct ifnet *ifp, const char *groupname)
! 1670: {
! 1671: struct ifg_list *ifgl;
! 1672: struct ifg_member *ifgm;
! 1673:
! 1674: TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
! 1675: if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
! 1676: break;
! 1677: if (ifgl == NULL)
! 1678: return (ENOENT);
! 1679:
! 1680: TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next);
! 1681:
! 1682: TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
! 1683: if (ifgm->ifgm_ifp == ifp)
! 1684: break;
! 1685:
! 1686: if (ifgm != NULL) {
! 1687: TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next);
! 1688: free(ifgm, M_TEMP);
! 1689: }
! 1690:
! 1691: if (--ifgl->ifgl_group->ifg_refcnt == 0) {
! 1692: TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
! 1693: #if NPF > 0
! 1694: pfi_detach_ifgroup(ifgl->ifgl_group);
! 1695: #endif
! 1696: free(ifgl->ifgl_group, M_TEMP);
! 1697: }
! 1698:
! 1699: free(ifgl, M_TEMP);
! 1700:
! 1701: #if NPF > 0
! 1702: pfi_group_change(groupname);
! 1703: #endif
! 1704:
! 1705: return (0);
! 1706: }
! 1707:
! 1708: /*
! 1709: * Stores all groups from an interface in memory pointed
! 1710: * to by data
! 1711: */
! 1712: int
! 1713: if_getgroup(caddr_t data, struct ifnet *ifp)
! 1714: {
! 1715: int len, error;
! 1716: struct ifg_list *ifgl;
! 1717: struct ifg_req ifgrq, *ifgp;
! 1718: struct ifgroupreq *ifgr = (struct ifgroupreq *)data;
! 1719:
! 1720: if (ifgr->ifgr_len == 0) {
! 1721: TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
! 1722: ifgr->ifgr_len += sizeof(struct ifg_req);
! 1723: return (0);
! 1724: }
! 1725:
! 1726: len = ifgr->ifgr_len;
! 1727: ifgp = ifgr->ifgr_groups;
! 1728: TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
! 1729: if (len < sizeof(ifgrq))
! 1730: return (EINVAL);
! 1731: bzero(&ifgrq, sizeof ifgrq);
! 1732: strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
! 1733: sizeof(ifgrq.ifgrq_group));
! 1734: if ((error = copyout((caddr_t)&ifgrq, (caddr_t)ifgp,
! 1735: sizeof(struct ifg_req))))
! 1736: return (error);
! 1737: len -= sizeof(ifgrq);
! 1738: ifgp++;
! 1739: }
! 1740:
! 1741: return (0);
! 1742: }
! 1743:
! 1744: /*
! 1745: * Stores all members of a group in memory pointed to by data
! 1746: */
! 1747: int
! 1748: if_getgroupmembers(caddr_t data)
! 1749: {
! 1750: struct ifgroupreq *ifgr = (struct ifgroupreq *)data;
! 1751: struct ifg_group *ifg;
! 1752: struct ifg_member *ifgm;
! 1753: struct ifg_req ifgrq, *ifgp;
! 1754: int len, error;
! 1755:
! 1756: TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
! 1757: if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
! 1758: break;
! 1759: if (ifg == NULL)
! 1760: return (ENOENT);
! 1761:
! 1762: if (ifgr->ifgr_len == 0) {
! 1763: TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
! 1764: ifgr->ifgr_len += sizeof(ifgrq);
! 1765: return (0);
! 1766: }
! 1767:
! 1768: len = ifgr->ifgr_len;
! 1769: ifgp = ifgr->ifgr_groups;
! 1770: TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
! 1771: if (len < sizeof(ifgrq))
! 1772: return (EINVAL);
! 1773: bzero(&ifgrq, sizeof ifgrq);
! 1774: strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
! 1775: sizeof(ifgrq.ifgrq_member));
! 1776: if ((error = copyout((caddr_t)&ifgrq, (caddr_t)ifgp,
! 1777: sizeof(struct ifg_req))))
! 1778: return (error);
! 1779: len -= sizeof(ifgrq);
! 1780: ifgp++;
! 1781: }
! 1782:
! 1783: return (0);
! 1784: }
! 1785:
! 1786: int
! 1787: if_getgroupattribs(caddr_t data)
! 1788: {
! 1789: struct ifgroupreq *ifgr = (struct ifgroupreq *)data;
! 1790: struct ifg_group *ifg;
! 1791:
! 1792: TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
! 1793: if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
! 1794: break;
! 1795: if (ifg == NULL)
! 1796: return (ENOENT);
! 1797:
! 1798: ifgr->ifgr_attrib.ifg_carp_demoted = ifg->ifg_carp_demoted;
! 1799:
! 1800: return (0);
! 1801: }
! 1802:
! 1803: int
! 1804: if_setgroupattribs(caddr_t data)
! 1805: {
! 1806: struct ifgroupreq *ifgr = (struct ifgroupreq *)data;
! 1807: struct ifg_group *ifg;
! 1808: struct ifg_member *ifgm;
! 1809: int demote;
! 1810:
! 1811: TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
! 1812: if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
! 1813: break;
! 1814: if (ifg == NULL)
! 1815: return (ENOENT);
! 1816:
! 1817: demote = ifgr->ifgr_attrib.ifg_carp_demoted;
! 1818: if (demote + ifg->ifg_carp_demoted > 0xff ||
! 1819: demote + ifg->ifg_carp_demoted < 0)
! 1820: return (ERANGE);
! 1821:
! 1822: ifg->ifg_carp_demoted += demote;
! 1823:
! 1824: TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
! 1825: if (ifgm->ifgm_ifp->if_ioctl)
! 1826: ifgm->ifgm_ifp->if_ioctl(ifgm->ifgm_ifp,
! 1827: SIOCSIFGATTR, data);
! 1828: return (0);
! 1829: }
! 1830:
! 1831: void
! 1832: if_group_routechange(struct sockaddr *dst, struct sockaddr *mask)
! 1833: {
! 1834: switch (dst->sa_family) {
! 1835: case AF_INET:
! 1836: if (satosin(dst)->sin_addr.s_addr == INADDR_ANY)
! 1837: if_group_egress_build();
! 1838: break;
! 1839: #ifdef INET6
! 1840: case AF_INET6:
! 1841: if (IN6_ARE_ADDR_EQUAL(&(satosin6(dst))->sin6_addr,
! 1842: &in6addr_any) &&
! 1843: mask && IN6_ARE_ADDR_EQUAL(&(satosin6(mask))->sin6_addr,
! 1844: &in6addr_any))
! 1845: if_group_egress_build();
! 1846: break;
! 1847: #endif
! 1848: }
! 1849: }
! 1850:
! 1851: int
! 1852: if_group_egress_build(void)
! 1853: {
! 1854: struct ifg_group *ifg;
! 1855: struct ifg_member *ifgm, *next;
! 1856: struct sockaddr_in sa_in;
! 1857: #ifdef INET6
! 1858: struct sockaddr_in6 sa_in6;
! 1859: #endif
! 1860: struct radix_node *rn;
! 1861: struct rtentry *rt;
! 1862:
! 1863: TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
! 1864: if (!strcmp(ifg->ifg_group, IFG_EGRESS))
! 1865: break;
! 1866:
! 1867: if (ifg != NULL)
! 1868: for (ifgm = TAILQ_FIRST(&ifg->ifg_members); ifgm; ifgm = next) {
! 1869: next = TAILQ_NEXT(ifgm, ifgm_next);
! 1870: if_delgroup(ifgm->ifgm_ifp, IFG_EGRESS);
! 1871: }
! 1872:
! 1873: bzero(&sa_in, sizeof(sa_in));
! 1874: sa_in.sin_len = sizeof(sa_in);
! 1875: sa_in.sin_family = AF_INET;
! 1876: if ((rn = rt_lookup(sintosa(&sa_in), sintosa(&sa_in), 0)) != NULL) {
! 1877: do {
! 1878: rt = (struct rtentry *)rn;
! 1879: if (rt->rt_ifp)
! 1880: if_addgroup(rt->rt_ifp, IFG_EGRESS);
! 1881: #ifndef SMALL_KERNEL
! 1882: rn = rn_mpath_next(rn);
! 1883: #else
! 1884: rn = NULL;
! 1885: #endif
! 1886: } while (rn != NULL);
! 1887: }
! 1888:
! 1889: #ifdef INET6
! 1890: bcopy(&sa6_any, &sa_in6, sizeof(sa_in6));
! 1891: if ((rn = rt_lookup(sin6tosa(&sa_in6), sin6tosa(&sa_in6), 0)) != NULL) {
! 1892: do {
! 1893: rt = (struct rtentry *)rn;
! 1894: if (rt->rt_ifp)
! 1895: if_addgroup(rt->rt_ifp, IFG_EGRESS);
! 1896: #ifndef SMALL_KERNEL
! 1897: rn = rn_mpath_next(rn);
! 1898: #else
! 1899: rn = NULL;
! 1900: #endif
! 1901: } while (rn != NULL);
! 1902: }
! 1903: #endif
! 1904:
! 1905: return (0);
! 1906: }
! 1907:
! 1908: /*
! 1909: * Set/clear promiscuous mode on interface ifp based on the truth value
! 1910: * of pswitch. The calls are reference counted so that only the first
! 1911: * "on" request actually has an effect, as does the final "off" request.
! 1912: * Results are undefined if the "off" and "on" requests are not matched.
! 1913: */
! 1914: int
! 1915: ifpromisc(struct ifnet *ifp, int pswitch)
! 1916: {
! 1917: struct ifreq ifr;
! 1918:
! 1919: if (pswitch) {
! 1920: /*
! 1921: * If the device is not configured up, we cannot put it in
! 1922: * promiscuous mode.
! 1923: */
! 1924: if ((ifp->if_flags & IFF_UP) == 0)
! 1925: return (ENETDOWN);
! 1926: if (ifp->if_pcount++ != 0)
! 1927: return (0);
! 1928: ifp->if_flags |= IFF_PROMISC;
! 1929: } else {
! 1930: if (--ifp->if_pcount > 0)
! 1931: return (0);
! 1932: ifp->if_flags &= ~IFF_PROMISC;
! 1933: /*
! 1934: * If the device is not configured up, we should not need to
! 1935: * turn off promiscuous mode (device should have turned it
! 1936: * off when interface went down; and will look at IFF_PROMISC
! 1937: * again next time interface comes up).
! 1938: */
! 1939: if ((ifp->if_flags & IFF_UP) == 0)
! 1940: return (0);
! 1941: }
! 1942: ifr.ifr_flags = ifp->if_flags;
! 1943: return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
! 1944: }
! 1945:
! 1946: int
! 1947: sysctl_ifq(int *name, u_int namelen, void *oldp, size_t *oldlenp,
! 1948: void *newp, size_t newlen, struct ifqueue *ifq)
! 1949: {
! 1950: /* All sysctl names at this level are terminal. */
! 1951: if (namelen != 1)
! 1952: return (ENOTDIR);
! 1953:
! 1954: switch (name[0]) {
! 1955: case IFQCTL_LEN:
! 1956: return (sysctl_rdint(oldp, oldlenp, newp, ifq->ifq_len));
! 1957: case IFQCTL_MAXLEN:
! 1958: return (sysctl_int(oldp, oldlenp, newp, newlen,
! 1959: &ifq->ifq_maxlen));
! 1960: case IFQCTL_DROPS:
! 1961: return (sysctl_rdint(oldp, oldlenp, newp, ifq->ifq_drops));
! 1962: default:
! 1963: return (EOPNOTSUPP);
! 1964: }
! 1965: /* NOTREACHED */
! 1966: }
! 1967:
! 1968: void
! 1969: netrndintr(void)
! 1970: {
! 1971: add_net_randomness(0);
! 1972: }
CVSweb