Index: head/sys/net/if.c =================================================================== --- head/sys/net/if.c (revision 12705) +++ head/sys/net/if.c (revision 12706) @@ -1,769 +1,758 @@ /* * Copyright (c) 1980, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if.c 8.3 (Berkeley) 1/4/94 - * $Id: if.c,v 1.22 1995/11/18 13:01:19 bde Exp $ + * $Id: if.c,v 1.23 1995/12/05 02:01:36 davidg Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * System initialization */ +static int ifconf __P((int, caddr_t)); static void ifinit __P((void *)); +static void if_qflush __P((struct ifqueue *)); +static void if_slowtimo __P((void *)); +static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *)); +static char *sprint_d __P((u_int, char *, int)); + SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) int ifqmaxlen = IFQ_MAXLEN; struct ifnet *ifnet; /* * Network interface utility routines. * * Routines with ifa_ifwith* names take sockaddr *'s as * parameters. * * This routine assumes that it will be called at splimp() or higher. */ /* ARGSUSED*/ void ifinit(dummy) void *dummy; { register struct ifnet *ifp; for (ifp = ifnet; ifp; ifp = ifp->if_next) if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; if_slowtimo(0); } -int if_index = 0; -struct ifaddr **ifnet_addrs; -static char *sprint_d __P((u_int, char *, int)); +static int if_index = 0; +static struct ifaddr **ifnet_addrs; + /* * Attach an interface to the * list of "active" interfaces. */ void if_attach(ifp) struct ifnet *ifp; { unsigned socksize, ifasize; int namelen, unitlen, masklen; char workbuf[12], *unitname; register struct ifnet **p = &ifnet; register struct sockaddr_dl *sdl; register struct ifaddr *ifa; static int if_indexlim = 8; while (*p) p = &((*p)->if_next); *p = ifp; ifp->if_index = ++if_index; if (ifnet_addrs == 0 || if_index >= if_indexlim) { unsigned n = (if_indexlim <<= 1) * sizeof(ifa); struct ifaddr **q = (struct ifaddr **) malloc(n, M_IFADDR, M_WAITOK); bzero((caddr_t)q, n); if (ifnet_addrs) { bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); free((caddr_t)ifnet_addrs, M_IFADDR); } ifnet_addrs = q; } /* * create a Link Level name for this device */ unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf)); namelen = strlen(ifp->if_name); unitlen = strlen(unitname); #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + unitlen + namelen; socksize = masklen + ifp->if_addrlen; #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) socksize = ROUNDUP(socksize); if (socksize < sizeof(*sdl)) socksize = sizeof(*sdl); ifasize = sizeof(*ifa) + 2 * socksize; ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); if (ifa) { bzero((caddr_t)ifa, ifasize); sdl = (struct sockaddr_dl *)(ifa + 1); sdl->sdl_len = socksize; sdl->sdl_family = AF_LINK; bcopy(ifp->if_name, sdl->sdl_data, namelen); bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen); sdl->sdl_nlen = (namelen += unitlen); sdl->sdl_index = ifp->if_index; sdl->sdl_type = ifp->if_type; ifnet_addrs[if_index - 1] = ifa; ifa->ifa_ifp = ifp; ifa->ifa_next = ifp->if_addrlist; ifa->ifa_rtrequest = link_rtrequest; ifp->if_addrlist = ifa; ifa->ifa_addr = (struct sockaddr *)sdl; sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); ifa->ifa_netmask = (struct sockaddr *)sdl; sdl->sdl_len = masklen; while (namelen != 0) sdl->sdl_data[--namelen] = 0xff; } /* XXX -- Temporary fix before changing 10 ethernet drivers */ #if NETHER > 0 if (ifp->if_output == ether_output) ether_ifattach(ifp); #endif } /* * Locate an interface based on a complete address. */ /*ARGSUSED*/ struct ifaddr * ifa_ifwithaddr(addr) register struct sockaddr *addr; { register struct ifnet *ifp; register struct ifaddr *ifa; #define equal(a1, a2) \ (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) for (ifp = ifnet; ifp; ifp = ifp->if_next) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (equal(addr, ifa->ifa_addr)) return (ifa); if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && equal(ifa->ifa_broadaddr, addr)) return (ifa); } return ((struct ifaddr *)0); } /* * Locate the point to point interface with a given destination address. */ /*ARGSUSED*/ struct ifaddr * ifa_ifwithdstaddr(addr) register struct sockaddr *addr; { register struct ifnet *ifp; register struct ifaddr *ifa; for (ifp = ifnet; ifp; ifp = ifp->if_next) if (ifp->if_flags & IFF_POINTOPOINT) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) return (ifa); } return ((struct ifaddr *)0); } /* * Find an interface on a specific network. If many, choice * is most specific found. */ struct ifaddr * ifa_ifwithnet(addr) struct sockaddr *addr; { register struct ifnet *ifp; register struct ifaddr *ifa; struct ifaddr *ifa_maybe = (struct ifaddr *) 0; u_int af = addr->sa_family; char *addr_data = addr->sa_data, *cplim; if (af == AF_LINK) { register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; if (sdl->sdl_index && sdl->sdl_index <= if_index) return (ifnet_addrs[sdl->sdl_index - 1]); } for (ifp = ifnet; ifp; ifp = ifp->if_next) { for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { register char *cp, *cp2, *cp3; if (ifa->ifa_addr->sa_family != af) next: continue; if (ifp->if_flags & IFF_POINTOPOINT) { if (equal(addr, ifa->ifa_dstaddr)) return (ifa); } else { if (ifa->ifa_netmask == 0) continue; cp = addr_data; cp2 = ifa->ifa_addr->sa_data; cp3 = ifa->ifa_netmask->sa_data; cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; while (cp3 < cplim) if ((*cp++ ^ *cp2++) & *cp3++) goto next; if (ifa_maybe == 0 || rn_refines((caddr_t)ifa->ifa_netmask, (caddr_t)ifa_maybe->ifa_netmask)) ifa_maybe = ifa; } } } return (ifa_maybe); } /* - * Find an interface using a specific address family - */ -struct ifaddr * -ifa_ifwithaf(af) - register int af; -{ - register struct ifnet *ifp; - register struct ifaddr *ifa; - - for (ifp = ifnet; ifp; ifp = ifp->if_next) - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) - if (ifa->ifa_addr->sa_family == af) - return (ifa); - return ((struct ifaddr *)0); -} - -/* * Find an interface address specific to an interface best matching * a given address. */ struct ifaddr * ifaof_ifpforaddr(addr, ifp) struct sockaddr *addr; register struct ifnet *ifp; { register struct ifaddr *ifa; register char *cp, *cp2, *cp3; register char *cplim; struct ifaddr *ifa_maybe = 0; u_int af = addr->sa_family; if (af >= AF_MAX) return (0); for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != af) continue; ifa_maybe = ifa; if (ifa->ifa_netmask == 0) { if (equal(addr, ifa->ifa_addr) || (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) return (ifa); continue; } if (ifp->if_flags & IFF_POINTOPOINT) { if (equal(addr, ifa->ifa_dstaddr)) return (ifa); } else { cp = addr->sa_data; cp2 = ifa->ifa_addr->sa_data; cp3 = ifa->ifa_netmask->sa_data; cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; for (; cp3 < cplim; cp3++) if ((*cp++ ^ *cp2++) & *cp3) break; if (cp3 == cplim) return (ifa); } } return (ifa_maybe); } #include /* * Default action when installing a route with a Link Level gateway. * Lookup an appropriate real ifa to point to. * This should be moved to /sys/net/link.c eventually. */ -void +static void link_rtrequest(cmd, rt, sa) int cmd; register struct rtentry *rt; struct sockaddr *sa; { register struct ifaddr *ifa; struct sockaddr *dst; struct ifnet *ifp; if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) return; ifa = ifaof_ifpforaddr(dst, ifp); if (ifa) { IFAFREE(rt->rt_ifa); rt->rt_ifa = ifa; ifa->ifa_refcnt++; if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) ifa->ifa_rtrequest(cmd, rt, sa); } } /* * Mark an interface down and notify protocols of * the transition. * NOTE: must be called at splnet or eqivalent. */ void if_down(ifp) register struct ifnet *ifp; { register struct ifaddr *ifa; ifp->if_flags &= ~IFF_UP; for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) pfctlinput(PRC_IFDOWN, ifa->ifa_addr); if_qflush(&ifp->if_snd); rt_ifmsg(ifp); } /* * Mark an interface up and notify protocols of * the transition. * NOTE: must be called at splnet or eqivalent. */ void if_up(ifp) register struct ifnet *ifp; { ifp->if_flags |= IFF_UP; #ifdef notyet register struct ifaddr *ifa; /* this has no effect on IP, and will kill all iso connections XXX */ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) pfctlinput(PRC_IFUP, ifa->ifa_addr); #endif rt_ifmsg(ifp); } /* * Flush an interface queue. */ -void +static void if_qflush(ifq) register struct ifqueue *ifq; { register struct mbuf *m, *n; n = ifq->ifq_head; while ((m = n) != 0) { n = m->m_act; m_freem(m); } ifq->ifq_head = 0; ifq->ifq_tail = 0; ifq->ifq_len = 0; } /* * Handle interface watchdog timer routines. Called * from softclock, we decrement timers (if set) and * call the appropriate interface routine on expiration. */ -void +static void if_slowtimo(arg) void *arg; { register struct ifnet *ifp; int s = splimp(); for (ifp = ifnet; ifp; ifp = ifp->if_next) { if (ifp->if_timer == 0 || --ifp->if_timer) continue; if (ifp->if_watchdog) (*ifp->if_watchdog)(ifp); } splx(s); timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); } /* * Map interface name to * interface structure pointer. */ struct ifnet * ifunit(name) register char *name; { register char *cp; register struct ifnet *ifp; int unit; unsigned len; char *ep, c; for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) if (*cp >= '0' && *cp <= '9') break; if (*cp == '\0' || cp == name + IFNAMSIZ) return ((struct ifnet *)0); /* * Save first char of unit, and pointer to it, * so we can put a null there to avoid matching * initial substrings of interface names. */ len = cp - name + 1; c = *cp; ep = cp; for (unit = 0; *cp >= '0' && *cp <= '9'; ) unit = unit * 10 + *cp++ - '0'; *ep = 0; for (ifp = ifnet; ifp; ifp = ifp->if_next) { if (bcmp(ifp->if_name, name, len)) continue; if (unit == ifp->if_unit) break; } *ep = c; return (ifp); } /* * Interface ioctls. */ int ifioctl(so, cmd, data, p) struct socket *so; int cmd; caddr_t data; struct proc *p; { register struct ifnet *ifp; register struct ifreq *ifr; int error; switch (cmd) { case SIOCGIFCONF: case OSIOCGIFCONF: return (ifconf(cmd, data)); } ifr = (struct ifreq *)data; ifp = ifunit(ifr->ifr_name); if (ifp == 0) return (ENXIO); switch (cmd) { case SIOCGIFFLAGS: ifr->ifr_flags = ifp->if_flags; break; case SIOCGIFMETRIC: ifr->ifr_metric = ifp->if_metric; break; case SIOCGIFMTU: ifr->ifr_mtu = ifp->if_mtu; break; case SIOCGIFPHYS: ifr->ifr_phys = ifp->if_physical; break; case SIOCSIFFLAGS: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { int s = splimp(); if_down(ifp); splx(s); } if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { int s = splimp(); if_up(ifp); splx(s); } ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | (ifr->ifr_flags &~ IFF_CANTCHANGE); if (ifp->if_ioctl) (void) (*ifp->if_ioctl)(ifp, cmd, data); break; case SIOCSIFMETRIC: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); ifp->if_metric = ifr->ifr_metric; break; case SIOCSIFPHYS: error = suser(p->p_ucred, &p->p_acflag); if (error) return error; if (!ifp->if_ioctl) return EOPNOTSUPP; return ifp->if_ioctl(ifp, cmd, data); case SIOCSIFMTU: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); /* * 72 was chosen below because it is the size of a TCP/IP * header (40) + the minimum mss (32). */ if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535) return (EINVAL); return ((*ifp->if_ioctl)(ifp, cmd, data)); case SIOCADDMULTI: case SIOCDELMULTI: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); return ((*ifp->if_ioctl)(ifp, cmd, data)); default: if (so->so_proto == 0) return (EOPNOTSUPP); #ifndef COMPAT_43 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)ifp)); #else { int ocmd = cmd; switch (cmd) { case SIOCSIFDSTADDR: case SIOCSIFADDR: case SIOCSIFBRDADDR: case SIOCSIFNETMASK: #if BYTE_ORDER != BIG_ENDIAN if (ifr->ifr_addr.sa_family == 0 && ifr->ifr_addr.sa_len < 16) { ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; ifr->ifr_addr.sa_len = 16; } #else if (ifr->ifr_addr.sa_len == 0) ifr->ifr_addr.sa_len = 16; #endif break; case OSIOCGIFADDR: cmd = SIOCGIFADDR; break; case OSIOCGIFDSTADDR: cmd = SIOCGIFDSTADDR; break; case OSIOCGIFBRDADDR: cmd = SIOCGIFBRDADDR; break; case OSIOCGIFNETMASK: cmd = SIOCGIFNETMASK; } error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, /* * XXX callees reverse the following bogus casts, * but it would be easier to use a separate * interface that is guaranteed to work. */ (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)ifp)); switch (ocmd) { case OSIOCGIFADDR: case OSIOCGIFDSTADDR: case OSIOCGIFBRDADDR: case OSIOCGIFNETMASK: *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; } return (error); } #endif } return (0); } /* * Set/clear promiscuous mode on interface ifp based on the truth value * of pswitch. The calls are reference counted so that only the first * "on" request actually has an effect, as does the final "off" request. * Results are undefined if the "off" and "on" requests are not matched. */ int ifpromisc(ifp, pswitch) struct ifnet *ifp; int pswitch; { struct ifreq ifr; if (pswitch) { /* * If the device is not configured up, we cannot put it in * promiscuous mode. */ if ((ifp->if_flags & IFF_UP) == 0) return (ENETDOWN); if (ifp->if_pcount++ != 0) return (0); ifp->if_flags |= IFF_PROMISC; log(LOG_INFO, "%s%d: promiscuous mode enabled\n", ifp->if_name, ifp->if_unit); } else { if (--ifp->if_pcount > 0) return (0); ifp->if_flags &= ~IFF_PROMISC; } ifr.ifr_flags = ifp->if_flags; return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); } /* * Return interface configuration * of system. List may be used * in later ioctl's (above) to get * other information. */ /*ARGSUSED*/ -int +static int ifconf(cmd, data) int cmd; caddr_t data; { register struct ifconf *ifc = (struct ifconf *)data; register struct ifnet *ifp = ifnet; register struct ifaddr *ifa; struct ifreq ifr, *ifrp; int space = ifc->ifc_len, error = 0; ifrp = ifc->ifc_req; for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { char workbuf[12], *unitname; int unitlen, ifnlen; unitname = sprint_d(ifp->if_unit, workbuf, sizeof workbuf); unitlen = strlen(unitname); ifnlen = strlen(ifp->if_name); if(unitlen + ifnlen + 1 > sizeof ifr.ifr_name) { error = ENAMETOOLONG; } else { strcpy(ifr.ifr_name, ifp->if_name); strcpy(&ifr.ifr_name[ifnlen], unitname); } if ((ifa = ifp->if_addrlist) == 0) { bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); if (error) break; space -= sizeof (ifr), ifrp++; } else for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { register struct sockaddr *sa = ifa->ifa_addr; #ifdef COMPAT_43 if (cmd == OSIOCGIFCONF) { struct osockaddr *osa = (struct osockaddr *)&ifr.ifr_addr; ifr.ifr_addr = *sa; osa->sa_family = sa->sa_family; error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); ifrp++; } else #endif if (sa->sa_len <= sizeof(*sa)) { ifr.ifr_addr = *sa; error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); ifrp++; } else { space -= sa->sa_len - sizeof(*sa); if (space < sizeof (ifr)) break; error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr.ifr_name)); if (error == 0) error = copyout((caddr_t)sa, (caddr_t)&ifrp->ifr_addr, sa->sa_len); ifrp = (struct ifreq *) (sa->sa_len + (caddr_t)&ifrp->ifr_addr); } if (error) break; space -= sizeof (ifr); } } ifc->ifc_len -= space; return (error); } static char * sprint_d(n, buf, buflen) u_int n; char *buf; int buflen; { register char *cp = buf + buflen - 1; *cp = 0; do { cp--; *cp = "0123456789"[n % 10]; n /= 10; } while (n != 0); return (cp); } Index: head/sys/net/if.h =================================================================== --- head/sys/net/if.h (revision 12705) +++ head/sys/net/if.h (revision 12706) @@ -1,396 +1,389 @@ /* * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if.h 8.1 (Berkeley) 6/10/93 - * $Id: if.h,v 1.23 1995/10/13 19:48:00 wollman Exp $ + * $Id: if.h,v 1.24 1995/12/05 02:01:37 davidg Exp $ */ #ifndef _NET_IF_H_ #define _NET_IF_H_ /* * Structures defining a network interface, providing a packet * transport mechanism (ala level 0 of the PUP protocols). * * Each interface accepts output datagrams of a specified maximum * length, and provides higher level routines with input datagrams * received from its medium. * * Output occurs when the routine if_output is called, with three parameters: * (*ifp->if_output)(ifp, m, dst, rt) * Here m is the mbuf chain to be sent and dst is the destination address. * The output routine encapsulates the supplied datagram if necessary, * and then transmits it on its medium. * * On input, each interface unwraps the data received by it, and either * places it on the input queue of a internetwork datagram routine * and posts the associated software interrupt, or passes the datagram to a raw * packet input routine. * * Routines exist for locating interfaces by their addresses * or for locating a interface on a certain network, as well as more general * routing and gateway routines maintaining information used to locate * interfaces. These routines live in the files if.c and route.c */ #include /* for struct sockaddr */ #ifndef _TIME_ /* XXX fast fix for SNMP, going away soon */ #include #endif #ifdef __STDC__ /* * Forward structure declarations for function prototypes [sic]. */ struct mbuf; struct proc; struct rtentry; struct socket; struct ether_header; #endif struct if_data { /* generic interface information */ u_char ifi_type; /* ethernet, tokenring, etc */ u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ u_char ifi_addrlen; /* media address length */ u_char ifi_hdrlen; /* media header length */ u_long ifi_mtu; /* maximum transmission unit */ u_long ifi_metric; /* routing metric (external only) */ u_long ifi_baudrate; /* linespeed */ /* volatile statistics */ u_long ifi_ipackets; /* packets received on interface */ u_long ifi_ierrors; /* input errors on interface */ u_long ifi_opackets; /* packets sent on interface */ u_long ifi_oerrors; /* output errors on interface */ u_long ifi_collisions; /* collisions on csma interfaces */ u_long ifi_ibytes; /* total number of octets received */ u_long ifi_obytes; /* total number of octets sent */ u_long ifi_imcasts; /* packets received via multicast */ u_long ifi_omcasts; /* packets sent via multicast */ u_long ifi_iqdrops; /* dropped on input, this interface */ u_long ifi_noproto; /* destined for unsupported protocol */ struct timeval ifi_lastchange; /* last updated */ }; /* * Structure defining a queue for a network interface. * * (Would like to call this struct ``if'', but C isn't PL/1.) */ struct ifqueue { struct mbuf *ifq_head; struct mbuf *ifq_tail; int ifq_len; int ifq_maxlen; int ifq_drops; }; #define IF_NPRIVATE 4 /* * Structure describing information about an interface * which may be of interest to management entities. */ struct ifnet { char *if_name; /* name, e.g. ``en'' or ``lo'' */ struct ifnet *if_next; /* all struct ifnets are chained */ struct ifaddr *if_addrlist; /* linked list of addresses per if */ int if_pcount; /* number of promiscuous listeners */ caddr_t if_bpf; /* packet filter structure */ u_short if_index; /* numeric abbreviation for this if */ short if_unit; /* sub-unit for lower level driver */ short if_timer; /* time 'til if_watchdog called */ short if_flags; /* up/down, broadcast, etc. */ struct if_data if_data; /* procedure handles */ int (*if_output) /* output routine (enqueue) */ __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); void (*if_start) /* initiate output routine */ __P((struct ifnet *)); int (*if_done) /* output complete routine */ __P((struct ifnet *)); /* (XXX not used; fake prototype) */ int (*if_ioctl) /* ioctl routine */ __P((struct ifnet *, int, caddr_t)); void (*if_watchdog) /* timer routine */ __P((struct ifnet *)); struct ifqueue if_snd; /* output queue */ void *if_private[IF_NPRIVATE]; /* opaque data for various clients */ }; #define if_mtu if_data.ifi_mtu #define if_type if_data.ifi_type #define if_physical if_data.ifi_physical #define if_addrlen if_data.ifi_addrlen #define if_hdrlen if_data.ifi_hdrlen #define if_metric if_data.ifi_metric #define if_baudrate if_data.ifi_baudrate #define if_ipackets if_data.ifi_ipackets #define if_ierrors if_data.ifi_ierrors #define if_opackets if_data.ifi_opackets #define if_oerrors if_data.ifi_oerrors #define if_collisions if_data.ifi_collisions #define if_ibytes if_data.ifi_ibytes #define if_obytes if_data.ifi_obytes #define if_imcasts if_data.ifi_imcasts #define if_omcasts if_data.ifi_omcasts #define if_iqdrops if_data.ifi_iqdrops #define if_noproto if_data.ifi_noproto #define if_lastchange if_data.ifi_lastchange #define if_rawoutput(if, m, sa) if_output(if, m, sa, (struct rtentry *)0) #define IFF_UP 0x1 /* interface is up */ #define IFF_BROADCAST 0x2 /* broadcast address valid */ #define IFF_DEBUG 0x4 /* turn on debugging */ #define IFF_LOOPBACK 0x8 /* is a loopback net */ #define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */ /*#define IFF_NOTRAILERS 0x20 * obsolete: avoid use of trailers */ #define IFF_RUNNING 0x40 /* resources allocated */ #define IFF_NOARP 0x80 /* no address resolution protocol */ #define IFF_PROMISC 0x100 /* receive all packets */ #define IFF_ALLMULTI 0x200 /* receive all multicast packets */ #define IFF_OACTIVE 0x400 /* transmission in progress */ #define IFF_SIMPLEX 0x800 /* can't hear own transmissions */ #define IFF_LINK0 0x1000 /* per link layer defined bit */ #define IFF_LINK1 0x2000 /* per link layer defined bit */ #define IFF_LINK2 0x4000 /* per link layer defined bit */ #define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ #define IFF_MULTICAST 0x8000 /* supports multicast */ /* flags set internally only: */ #define IFF_CANTCHANGE \ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI) /* * These really don't belong here, but there's no other obviously appropriate * location. */ #define IFP_AUI 0 #define IFP_10BASE2 1 #define IFP_10BASET 2 /* etc. */ /* * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1) * input routines have queues of messages stored on ifqueue structures * (defined above). Entries are added to and deleted from these structures * by these macros, which should be called with ipl raised to splimp(). */ #define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen) #define IF_DROP(ifq) ((ifq)->ifq_drops++) #define IF_ENQUEUE(ifq, m) { \ (m)->m_nextpkt = 0; \ if ((ifq)->ifq_tail == 0) \ (ifq)->ifq_head = m; \ else \ (ifq)->ifq_tail->m_nextpkt = m; \ (ifq)->ifq_tail = m; \ (ifq)->ifq_len++; \ } #define IF_PREPEND(ifq, m) { \ (m)->m_nextpkt = (ifq)->ifq_head; \ if ((ifq)->ifq_tail == 0) \ (ifq)->ifq_tail = (m); \ (ifq)->ifq_head = (m); \ (ifq)->ifq_len++; \ } #define IF_DEQUEUE(ifq, m) { \ (m) = (ifq)->ifq_head; \ if (m) { \ if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \ (ifq)->ifq_tail = 0; \ (m)->m_nextpkt = 0; \ (ifq)->ifq_len--; \ } \ } #define IFQ_MAXLEN 50 #define IFNET_SLOWHZ 1 /* granularity is 1 second */ /* * The ifaddr structure contains information about one address * of an interface. They are maintained by the different address families, * are allocated and attached when an address is set, and are linked * together so all addresses for an interface can be located. */ struct ifaddr { struct sockaddr *ifa_addr; /* address of interface */ struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */ #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ struct sockaddr *ifa_netmask; /* used to determine subnet */ struct ifnet *ifa_ifp; /* back-pointer to interface */ struct ifaddr *ifa_next; /* next address for interface */ void (*ifa_rtrequest) /* check or clean routes (+ or -)'d */ __P((int, struct rtentry *, struct sockaddr *)); u_short ifa_flags; /* mostly rt_flags for cloning */ short ifa_refcnt; /* extra to malloc for link info */ int ifa_metric; /* cost of going out this interface */ #ifdef notdef struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */ #endif }; #define IFA_ROUTE RTF_UP /* route installed */ /* * Message format for use in obtaining information about interfaces * from getkerninfo and the routing socket */ struct if_msghdr { u_short ifm_msglen; /* to skip over non-understood messages */ u_char ifm_version; /* future binary compatability */ u_char ifm_type; /* message type */ int ifm_addrs; /* like rtm_addrs */ int ifm_flags; /* value of if_flags */ u_short ifm_index; /* index for associated ifp */ struct if_data ifm_data;/* statistics and other data about if */ }; /* * Message format for use in obtaining information about interface addresses * from getkerninfo and the routing socket */ struct ifa_msghdr { u_short ifam_msglen; /* to skip over non-understood messages */ u_char ifam_version; /* future binary compatability */ u_char ifam_type; /* message type */ int ifam_addrs; /* like rtm_addrs */ int ifam_flags; /* value of ifa_flags */ u_short ifam_index; /* index for associated ifp */ int ifam_metric; /* value of ifa_metric */ }; /* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The * remainder may be interface specific. */ struct ifreq { #define IFNAMSIZ 16 char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; short ifru_flags; int ifru_metric; int ifru_mtu; int ifru_phys; caddr_t ifru_data; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define ifr_phys ifr_ifru.ifru_phys /* physical wire */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ }; struct ifaliasreq { char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ struct sockaddr ifra_addr; struct sockaddr ifra_broadaddr; struct sockaddr ifra_mask; }; /* * Structure used in SIOCGIFCONF request. * Used to retrieve interface configuration * for machine (useful for programs which * must know all networks accessible). */ struct ifconf { int ifc_len; /* size of associated buffer */ union { caddr_t ifcu_buf; struct ifreq *ifcu_req; } ifc_ifcu; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ }; #include #ifdef KERNEL #define IFAFREE(ifa) \ if ((ifa)->ifa_refcnt <= 0) \ ifafree(ifa); \ else \ (ifa)->ifa_refcnt--; extern struct ifnet *ifnet; extern int ifqmaxlen; extern struct ifnet loif[]; void ether_ifattach __P((struct ifnet *)); void ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *)); int ether_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); char *ether_sprintf __P((u_char *)); void if_attach __P((struct ifnet *)); void if_down __P((struct ifnet *)); -void if_qflush __P((struct ifqueue *)); -void if_slowtimo __P((void *)); void if_up __P((struct ifnet *)); #ifdef vax void ifubareset __P((int)); #endif -int ifconf __P((int, caddr_t)); /*void ifinit __P((void));*/ /* declared in systm.h for main() */ int ifioctl __P((struct socket *, int, caddr_t, struct proc *)); int ifpromisc __P((struct ifnet *, int)); struct ifnet *ifunit __P((char *)); struct ifaddr *ifa_ifwithaddr __P((struct sockaddr *)); -struct ifaddr *ifa_ifwithaf __P((int)); struct ifaddr *ifa_ifwithdstaddr __P((struct sockaddr *)); struct ifaddr *ifa_ifwithnet __P((struct sockaddr *)); struct ifaddr *ifa_ifwithroute __P((int, struct sockaddr *, struct sockaddr *)); struct ifaddr *ifaof_ifpforaddr __P((struct sockaddr *, struct ifnet *)); void ifafree __P((struct ifaddr *)); -void link_rtrequest __P((int, struct rtentry *, struct sockaddr *)); -int loioctl __P((struct ifnet *, int, caddr_t)); int looutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); -void lortrequest __P((int, struct rtentry *, struct sockaddr *)); #endif /* KERNEL */ #endif /* !_NET_IF_H_ */ Index: head/sys/net/if_ethersubr.c =================================================================== --- head/sys/net/if_ethersubr.c (revision 12705) +++ head/sys/net/if_ethersubr.c (revision 12706) @@ -1,710 +1,714 @@ /* * Copyright (c) 1982, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 - * $Id: if_ethersubr.c,v 1.10 1995/10/26 20:30:09 julian Exp $ + * $Id: if_ethersubr.c,v 1.11 1995/10/29 15:32:03 phk Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #endif #include #ifdef IPX #include #include #endif #ifdef NS #include #include #endif #ifdef ISO #include #include #include #include #endif #ifdef LLC #include #include #endif #if defined(LLC) && defined(CCITT) extern struct ifqueue pkintrq; #endif u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define senderr(e) { error = (e); goto bad;} /* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. * Assumes that ifp is actually pointer to arpcom structure. */ int ether_output(ifp, m0, dst, rt0) register struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; struct rtentry *rt0; { short type; int s, error = 0; u_char edst[6]; register struct mbuf *m = m0; register struct rtentry *rt; struct mbuf *mcopy = (struct mbuf *)0; register struct ether_header *eh; int off, len = m->m_pkthdr.len; struct arpcom *ac = (struct arpcom *)ifp; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); ifp->if_lastchange = time; - if (rt = rt0) { + rt = rt0; + if (rt) { if ((rt->rt_flags & RTF_UP) == 0) { - if (rt0 = rt = rtalloc1(dst, 1, 0UL)) + rt0 = rt = rtalloc1(dst, 1, 0UL); + if (rt0) rt->rt_refcnt--; else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); } } if (rt->rt_flags & RTF_REJECT) if (rt->rt_rmx.rmx_expire == 0 || time.tv_sec < rt->rt_rmx.rmx_expire) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } switch (dst->sa_family) { #ifdef INET case AF_INET: if (!arpresolve(ac, rt, m, dst, edst, rt0)) return (0); /* if not yet resolved */ /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m, 0, (int)M_COPYALL); off = m->m_pkthdr.len - m->m_len; type = ETHERTYPE_IP; break; #endif #ifdef IPX case AF_IPX: type = ETHERTYPE_IPX; bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), (caddr_t)edst, sizeof (edst)); if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst))) return (looutput(ifp, m, dst, rt)); /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m, 0, (int)M_COPYALL); break; #endif #ifdef NS case AF_NS: type = ETHERTYPE_NS; bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), (caddr_t)edst, sizeof (edst)); if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) return (looutput(ifp, m, dst, rt)); /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m, 0, (int)M_COPYALL); break; #endif #ifdef ISO case AF_ISO: { int snpalen; struct llc *l; register struct sockaddr_dl *sdl; if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); } else if (error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst, (char *)edst, &snpalen)) goto bad; /* Not Resolved */ /* If broadcasting on a simplex interface, loopback a copy */ if (*edst & 1) m->m_flags |= (M_BCAST|M_MCAST); if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && (mcopy = m_copy(m, 0, (int)M_COPYALL))) { M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); if (mcopy) { eh = mtod(mcopy, struct ether_header *); bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, sizeof (edst)); } } M_PREPEND(m, 3, M_DONTWAIT); if (m == NULL) return (0); type = m->m_pkthdr.len; l = mtod(m, struct llc *); l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; l->llc_control = LLC_UI; len += 3; IFDEBUG(D_ETHER) int i; printf("unoutput: sending pkt to: "); for (i=0; i<6; i++) printf("%x ", edst[i] & 0xff); printf("\n"); ENDDEBUG } break; #endif /* ISO */ #ifdef LLC /* case AF_NSAP: */ case AF_CCITT: { register struct sockaddr_dl *sdl = (struct sockaddr_dl *) rt -> rt_gateway; if (sdl && sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { bcopy(LLADDR(sdl), (char *)edst, sizeof(edst)); } else goto bad; /* Not a link interface ? Funny ... */ if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && (mcopy = m_copy(m, 0, (int)M_COPYALL))) { M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); if (mcopy) { eh = mtod(mcopy, struct ether_header *); bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, sizeof (edst)); } } type = m->m_pkthdr.len; #ifdef LLC_DEBUG { int i; register struct llc *l = mtod(m, struct llc *); printf("ether_output: sending LLC2 pkt to: "); for (i=0; i<6; i++) printf("%x ", edst[i] & 0xff); printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, l->llc_control & 0xff); } #endif /* LLC_DEBUG */ } break; #endif /* LLC */ case AF_UNSPEC: eh = (struct ether_header *)dst->sa_data; (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); type = eh->ether_type; break; default: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, dst->sa_family); senderr(EAFNOSUPPORT); } if (mcopy) (void) looutput(ifp, mcopy, dst, rt); /* * Add local net header. If no space in first mbuf, * allocate another. */ M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); if (m == 0) senderr(ENOBUFS); eh = mtod(m, struct ether_header *); type = htons((u_short)type); (void)memcpy(&eh->ether_type, &type, sizeof(eh->ether_type)); (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); (void)memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost)); s = splimp(); /* * Queue message on interface, and start output if interface * not yet active. */ if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); splx(s); senderr(ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); if ((ifp->if_flags & IFF_OACTIVE) == 0) (*ifp->if_start)(ifp); splx(s); ifp->if_obytes += len + sizeof (struct ether_header); if (m->m_flags & M_MCAST) ifp->if_omcasts++; return (error); bad: if (m) m_freem(m); return (error); } /* * Process a received Ethernet packet; * the packet is in the mbuf chain m without * the ether header, which is provided separately. */ void ether_input(ifp, eh, m) struct ifnet *ifp; register struct ether_header *eh; struct mbuf *m; { register struct ifqueue *inq; register struct llc *l; u_short ether_type; int s; if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); return; } ifp->if_lastchange = time; ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, sizeof(etherbroadcastaddr)) == 0) m->m_flags |= M_BCAST; else if (eh->ether_dhost[0] & 1) m->m_flags |= M_MCAST; if (m->m_flags & (M_BCAST|M_MCAST)) ifp->if_imcasts++; ether_type = ntohs(eh->ether_type); switch (ether_type) { #ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: schednetisr(NETISR_ARP); inq = &arpintrq; break; #endif #ifdef IPX case ETHERTYPE_IPX: schednetisr(NETISR_IPX); inq = &ipxintrq; break; #endif #ifdef NS case ETHERTYPE_NS: schednetisr(NETISR_NS); inq = &nsintrq; break; #endif default: #if defined (ISO) || defined (LLC) if (ether_type > ETHERMTU) goto dropanyway; l = mtod(m, struct llc *); switch (l->llc_dsap) { #ifdef ISO case LLC_ISO_LSAP: switch (l->llc_control) { case LLC_UI: /* LLC_UI_P forbidden in class 1 service */ if ((l->llc_dsap == LLC_ISO_LSAP) && (l->llc_ssap == LLC_ISO_LSAP)) { /* LSAP for ISO */ if (m->m_pkthdr.len > ether_type) m_adj(m, ether_type - m->m_pkthdr.len); m->m_data += 3; /* XXX */ m->m_len -= 3; /* XXX */ m->m_pkthdr.len -= 3; /* XXX */ M_PREPEND(m, sizeof *eh, M_DONTWAIT); if (m == 0) return; *mtod(m, struct ether_header *) = *eh; IFDEBUG(D_ETHER) printf("clnp packet"); ENDDEBUG schednetisr(NETISR_ISO); inq = &clnlintrq; break; } goto dropanyway; case LLC_XID: case LLC_XID_P: if(m->m_len < 6) goto dropanyway; l->llc_window = 0; l->llc_fid = 9; l->llc_class = 1; l->llc_dsap = l->llc_ssap = 0; /* Fall through to */ case LLC_TEST: case LLC_TEST_P: { struct sockaddr sa; register struct ether_header *eh2; int i; u_char c = l->llc_dsap; l->llc_dsap = l->llc_ssap; l->llc_ssap = c; if (m->m_flags & (M_BCAST | M_MCAST)) bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_dhost, 6); sa.sa_family = AF_UNSPEC; sa.sa_len = sizeof(sa); eh2 = (struct ether_header *)sa.sa_data; for (i = 0; i < 6; i++) { eh2->ether_shost[i] = c = eh->ether_dhost[i]; eh2->ether_dhost[i] = eh->ether_dhost[i] = eh->ether_shost[i]; eh->ether_shost[i] = c; } ifp->if_output(ifp, m, &sa, NULL); return; } default: m_freem(m); return; } break; #endif /* ISO */ #ifdef LLC case LLC_X25_LSAP: { if (m->m_pkthdr.len > ether_type) m_adj(m, ether_type - m->m_pkthdr.len); M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); if (m == 0) return; if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, eh->ether_dhost, LLC_X25_LSAP, 6, mtod(m, struct sdl_hdr *))) panic("ETHER cons addr failure"); mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type; #ifdef LLC_DEBUG printf("llc packet\n"); #endif /* LLC_DEBUG */ schednetisr(NETISR_CCITT); inq = &llcintrq; break; } #endif /* LLC */ dropanyway: default: m_freem(m); return; } #else /* ISO || LLC */ m_freem(m); return; #endif /* ISO || LLC */ } s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUE(inq, m); splx(s); } /* * Convert Ethernet address to printable (loggable) representation. */ static char digits[] = "0123456789abcdef"; char * ether_sprintf(ap) register u_char *ap; { register i; static char etherbuf[18]; register char *cp = etherbuf; for (i = 0; i < 6; i++) { *cp++ = digits[*ap >> 4]; *cp++ = digits[*ap++ & 0xf]; *cp++ = ':'; } *--cp = 0; return (etherbuf); } /* * Perform common duties while attaching to interface list */ void ether_ifattach(ifp) register struct ifnet *ifp; { register struct ifaddr *ifa; register struct sockaddr_dl *sdl; ifp->if_type = IFT_ETHER; ifp->if_addrlen = 6; ifp->if_hdrlen = 14; ifp->if_mtu = ETHERMTU; for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && sdl->sdl_family == AF_LINK) { sdl->sdl_type = IFT_ETHER; sdl->sdl_alen = ifp->if_addrlen; bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); break; } } -u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; -u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; +static u_char ether_ipmulticast_min[6] = + { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; +static u_char ether_ipmulticast_max[6] = + { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; /* * Add an Ethernet multicast address or range of addresses to the list for a * given interface. */ int ether_addmulti(ifr, ac) struct ifreq *ifr; register struct arpcom *ac; { register struct ether_multi *enm; struct sockaddr_in *sin; u_char addrlo[6]; u_char addrhi[6]; int set_allmulti = 0; int s = splimp(); switch (ifr->ifr_addr.sa_family) { case AF_UNSPEC: bcopy(ifr->ifr_addr.sa_data, addrlo, 6); bcopy(addrlo, addrhi, 6); break; #ifdef INET case AF_INET: sin = (struct sockaddr_in *)&(ifr->ifr_addr); if (sin->sin_addr.s_addr == INADDR_ANY) { /* * An IP address of INADDR_ANY means listen to all * of the Ethernet multicast addresses used for IP. * (This is for the sake of IP multicast routers.) */ bcopy(ether_ipmulticast_min, addrlo, 6); bcopy(ether_ipmulticast_max, addrhi, 6); set_allmulti = 1; } else { ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); bcopy(addrlo, addrhi, 6); } break; #endif default: splx(s); return (EAFNOSUPPORT); } /* * Verify that we have valid Ethernet multicast addresses. */ if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { splx(s); return (EINVAL); } /* * See if the address range is already in the list. */ ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); if (enm != NULL) { /* * Found it; just increment the reference count. */ ++enm->enm_refcount; splx(s); return (0); } /* * New address or range; malloc a new multicast record * and link it into the interface's multicast list. */ enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); if (enm == NULL) { splx(s); return (ENOBUFS); } bcopy(addrlo, enm->enm_addrlo, 6); bcopy(addrhi, enm->enm_addrhi, 6); enm->enm_ac = ac; enm->enm_refcount = 1; enm->enm_next = ac->ac_multiaddrs; ac->ac_multiaddrs = enm; ac->ac_multicnt++; splx(s); if (set_allmulti) ac->ac_if.if_flags |= IFF_ALLMULTI; /* * Return ENETRESET to inform the driver that the list has changed * and its reception filter should be adjusted accordingly. */ return (ENETRESET); } /* * Delete a multicast address record. */ int ether_delmulti(ifr, ac) struct ifreq *ifr; register struct arpcom *ac; { register struct ether_multi *enm; register struct ether_multi **p; struct sockaddr_in *sin; u_char addrlo[6]; u_char addrhi[6]; int unset_allmulti = 0; int s = splimp(); switch (ifr->ifr_addr.sa_family) { case AF_UNSPEC: bcopy(ifr->ifr_addr.sa_data, addrlo, 6); bcopy(addrlo, addrhi, 6); break; #ifdef INET case AF_INET: sin = (struct sockaddr_in *)&(ifr->ifr_addr); if (sin->sin_addr.s_addr == INADDR_ANY) { /* * An IP address of INADDR_ANY means stop listening * to the range of Ethernet multicast addresses used * for IP. */ bcopy(ether_ipmulticast_min, addrlo, 6); bcopy(ether_ipmulticast_max, addrhi, 6); unset_allmulti = 1; } else { ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); bcopy(addrlo, addrhi, 6); } break; #endif default: splx(s); return (EAFNOSUPPORT); } /* * Look up the address in our list. */ ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); if (enm == NULL) { splx(s); return (ENXIO); } if (--enm->enm_refcount != 0) { /* * Still some claims to this record. */ splx(s); return (0); } /* * No remaining claims to this record; unlink and free it. */ for (p = &enm->enm_ac->ac_multiaddrs; *p != enm; p = &(*p)->enm_next) continue; *p = (*p)->enm_next; free(enm, M_IFMADDR); ac->ac_multicnt--; splx(s); if (unset_allmulti) ac->ac_if.if_flags &= ~IFF_ALLMULTI; /* * Return ENETRESET to inform the driver that the list has changed * and its reception filter should be adjusted accordingly. */ return (ENETRESET); } Index: head/sys/net/if_loop.c =================================================================== --- head/sys/net/if_loop.c (revision 12705) +++ head/sys/net/if_loop.c (revision 12706) @@ -1,282 +1,285 @@ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 - * $Id: if_loop.c,v 1.14 1995/10/26 20:30:13 julian Exp $ + * $Id: if_loop.c,v 1.15 1995/12/02 17:11:11 bde Exp $ */ /* * Loopback interface driver for protocol testing and timing. */ #include "loop.h" #if NLOOP > 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #include #include #endif #ifdef IPX #include #include #endif #ifdef NS #include #include #endif #ifdef ISO #include #include #endif #include "bpfilter.h" +static int loioctl __P((struct ifnet *, int, caddr_t)); +static void lortrequest __P((int, struct rtentry *, struct sockaddr *)); + static void loopattach __P((void *)); PSEUDO_SET(loopattach, if_loop); #ifdef TINY_LOMTU #define LOMTU (1024+512) #else #define LOMTU 16384 #endif struct ifnet loif[NLOOP]; /* ARGSUSED */ static void loopattach(dummy) void *dummy; { register struct ifnet *ifp; register int i = 0; for (ifp = loif; i < NLOOP; ifp++) { ifp->if_name = "lo"; ifp->if_next = NULL; ifp->if_unit = i++; ifp->if_mtu = LOMTU; ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; ifp->if_ioctl = loioctl; ifp->if_output = looutput; ifp->if_type = IFT_LOOP; ifp->if_hdrlen = 0; ifp->if_addrlen = 0; if_attach(ifp); #if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); #endif } } int looutput(ifp, m, dst, rt) struct ifnet *ifp; register struct mbuf *m; struct sockaddr *dst; register struct rtentry *rt; { int s, isr; register struct ifqueue *ifq = 0; if ((m->m_flags & M_PKTHDR) == 0) panic("looutput no HDR"); ifp->if_lastchange = time; #if NBPFILTER > 0 /* BPF write needs to be handled specially */ if (dst->sa_family == AF_UNSPEC) { dst->sa_family = *(mtod(m, int *)); m->m_len -= sizeof(int); m->m_pkthdr.len -= sizeof(int); m->m_data += sizeof(int); } if (ifp->if_bpf) { /* * We need to prepend the address family as * a four byte field. Cons up a dummy header * to pacify bpf. This is safe because bpf * will only read from the mbuf (i.e., it won't * try to free it or keep a pointer a to it). */ struct mbuf m0; u_int af = dst->sa_family; m0.m_next = m; m0.m_len = 4; m0.m_data = (char *)⁡ bpf_mtap(ifp->if_bpf, &m0); } #endif m->m_pkthdr.rcvif = ifp; if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { m_freem(m); return (rt->rt_flags & RTF_BLACKHOLE ? 0 : rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; switch (dst->sa_family) { #ifdef INET case AF_INET: ifq = &ipintrq; isr = NETISR_IP; break; #endif #ifdef IPX case AF_IPX: ifq = &ipxintrq; isr = NETISR_IPX; break; #endif #ifdef NS case AF_NS: ifq = &nsintrq; isr = NETISR_NS; break; #endif #ifdef ISO case AF_ISO: ifq = &clnlintrq; isr = NETISR_ISO; break; #endif default: printf("lo%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); m_freem(m); return (EAFNOSUPPORT); } s = splimp(); if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(isr); ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; splx(s); return (0); } /* ARGSUSED */ -void +static void lortrequest(cmd, rt, sa) int cmd; struct rtentry *rt; struct sockaddr *sa; { if (rt) rt->rt_rmx.rmx_mtu = LOMTU; } /* * Process an ioctl request. */ /* ARGSUSED */ -int +static int loioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data; { register struct ifaddr *ifa; register struct ifreq *ifr = (struct ifreq *)data; register int error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ifa = (struct ifaddr *)data; if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) ifa->ifa_rtrequest = lortrequest; /* * Everything else is done at a higher level. */ break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == 0) { error = EAFNOSUPPORT; /* XXX */ break; } switch (ifr->ifr_addr.sa_family) { #ifdef INET case AF_INET: break; #endif default: error = EAFNOSUPPORT; break; } break; case SIOCSIFMTU: ifp->if_mtu = ifr->ifr_mtu; break; default: error = EINVAL; } return (error); } #endif /* NLOOP > 0 */ Index: head/sys/net/if_tun.c =================================================================== --- head/sys/net/if_tun.c (revision 12705) +++ head/sys/net/if_tun.c (revision 12706) @@ -1,625 +1,625 @@ /* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */ /* * Copyright (c) 1988, Julian Onions * Nottingham University 1987. * * This source may be freely distributed, however I would be interested * in any changes that are made. * * This driver takes packets off the IP i/f and hands them up to a * user process to have it's wicked way with. This driver has it's * roots in a similar driver written by Phil Cockcroft (formerly) at * UCL. This driver is based much more on read/write/select mode of * operation though. */ #include "tun.h" #if NTUN > 0 #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifdef __FreeBSD__ #include -#endif +#include #ifdef DEVFS #include #endif /*DEVFS*/ #include #include #include #include #include #ifdef INET #include #include #include #include #include #endif #ifdef NS #include #include #endif #include "bpfilter.h" #if NBPFILTER > 0 #include #include #endif #include #ifdef __FreeBSD__ static void tunattach __P((void *)); PSEUDO_SET(tunattach, if_tun); #endif #define TUNDEBUG if (tundebug) printf -int tundebug = 0; +static int tundebug = 0; +SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RD, &tundebug, 0, ""); -struct tun_softc tunctl[NTUN]; +static struct tun_softc tunctl[NTUN]; -int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, +static int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *rt)); -int tunifioctl __P((struct ifnet *, int, caddr_t)); +static int tunifioctl __P((struct ifnet *, int, caddr_t)); static int tuninit __P((int)); static d_open_t tunopen; static d_close_t tunclose; static d_read_t tunread; static d_write_t tunwrite; static d_ioctl_t tunioctl; static d_select_t tunselect; #define CDEV_MAJOR 52 static struct cdevsw tun_cdevsw = { tunopen, tunclose, tunread, tunwrite, tunioctl, nullstop, noreset, nodevtotty, tunselect, nommap, nostrategy, "tun", NULL, -1 }; static tun_devsw_installed = 0; #ifdef DEVFS static void *tun_devfs_token[NTUN]; #endif static void tunattach(dummy) void *dummy; { register int i; struct ifnet *ifp; dev_t dev; - char name[32]; if( tun_devsw_installed ) return; dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev,&tun_cdevsw, NULL); tun_devsw_installed = 1; for ( i = 0; i < NTUN; i++ ) { #ifdef DEVFS sprintf(name, "tun%d", i ); tun_devfs_token[i] = devfs_add_devsw( "/", name, &tun_cdevsw , i, DV_CHR, 0, 0, 0600); #endif tunctl[i].tun_flags = TUN_INITED; ifp = &tunctl[i].tun_if; ifp->if_unit = i; ifp->if_name = "tun"; ifp->if_mtu = TUNMTU; ifp->if_ioctl = tunifioctl; ifp->if_output = tunoutput; ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_collisions = 0; ifp->if_ierrors = 0; ifp->if_oerrors = 0; ifp->if_ipackets = 0; ifp->if_opackets = 0; if_attach(ifp); #if NBPFILTER > 0 bpfattach(&tunctl[i].tun_bpf, ifp, DLT_NULL, sizeof(u_int)); #endif } } /* * tunnel open - must be superuser & the device must be * configured in */ static int tunopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p; { struct ifnet *ifp; struct tun_softc *tp; register int unit, error; - if (error = suser(p->p_ucred, &p->p_acflag)) + error = suser(p->p_ucred, &p->p_acflag); + if (error) return (error); if ((unit = minor(dev)) >= NTUN) return (ENXIO); tp = &tunctl[unit]; if (tp->tun_flags & TUN_OPEN) return ENXIO; ifp = &tp->tun_if; tp->tun_flags |= TUN_OPEN; TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit); return (0); } /* * tunclose - close the device - mark i/f down & delete * routing info */ static int tunclose(dev_t dev, int foo, int bar, struct proc *p) { register int unit = minor(dev), s; struct tun_softc *tp = &tunctl[unit]; struct ifnet *ifp = &tp->tun_if; struct mbuf *m; tp->tun_flags &= ~TUN_OPEN; /* * junk all pending output */ do { s = splimp(); IF_DEQUEUE(&ifp->if_snd, m); splx(s); if (m) m_freem(m); } while (m); if (ifp->if_flags & IFF_UP) { s = splimp(); if_down(ifp); if (ifp->if_flags & IFF_RUNNING) { /* find internet addresses and delete routes */ register struct ifaddr *ifa; for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family == AF_INET) { rtinit(ifa, (int)RTM_DELETE, tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0); } } } splx(s); } tp->tun_pgrp = 0; selwakeup(&tp->tun_rsel); TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit); return (0); } static int tuninit(unit) int unit; { struct tun_softc *tp = &tunctl[unit]; struct ifnet *ifp = &tp->tun_if; register struct ifaddr *ifa; TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit); ifp->if_flags |= IFF_UP | IFF_RUNNING; for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *si; si = (struct sockaddr_in *)ifa->ifa_addr; if (si && si->sin_addr.s_addr) tp->tun_flags |= TUN_IASET; si = (struct sockaddr_in *)ifa->ifa_dstaddr; if (si && si->sin_addr.s_addr) tp->tun_flags |= TUN_DSTADDR; } return 0; } /* * Process an ioctl request. */ int tunifioctl(ifp, cmd, data) struct ifnet *ifp; int cmd; caddr_t data; { register struct ifreq *ifr = (struct ifreq *)data; int error = 0, s; s = splimp(); switch(cmd) { case SIOCSIFADDR: tuninit(ifp->if_unit); TUNDEBUG("%s%d: address set\n", ifp->if_name, ifp->if_unit); break; case SIOCSIFDSTADDR: tuninit(ifp->if_unit); TUNDEBUG("%s%d: destination address set\n", ifp->if_name, ifp->if_unit); break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == 0) { error = EAFNOSUPPORT; /* XXX */ break; } switch (ifr->ifr_addr.sa_family) { #ifdef INET case AF_INET: break; #endif default: error = EAFNOSUPPORT; break; } break; default: error = EINVAL; } splx(s); return (error); } /* * tunoutput - queue packets from higher level ready to put out. */ int tunoutput(ifp, m0, dst, rt) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; struct rtentry *rt; { struct tun_softc *tp = &tunctl[ifp->if_unit]; struct proc *p; int s; TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); if ((tp->tun_flags & TUN_READY) != TUN_READY) { TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, ifp->if_unit, tp->tun_flags); m_freem (m0); return EHOSTDOWN; } #if NBPFILTER > 0 /* BPF write needs to be handled specially */ if (dst->sa_family == AF_UNSPEC) { dst->sa_family = *(mtod(m0, int *)); m0->m_len -= sizeof(int); m0->m_pkthdr.len -= sizeof(int); m0->m_data += sizeof(int); } if (tp->tun_bpf) { /* * We need to prepend the address family as * a four byte field. Cons up a dummy header * to pacify bpf. This is safe because bpf * will only read from the mbuf (i.e., it won't * try to free it or keep a pointer to it). */ struct mbuf m; u_int af = dst->sa_family; m.m_next = m0; m.m_len = 4; m.m_data = (char *)⁡ bpf_mtap(tp->tun_bpf, &m); } #endif switch(dst->sa_family) { #ifdef INET case AF_INET: s = splimp(); if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); m_freem(m0); splx(s); ifp->if_collisions++; return (ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m0); splx(s); ifp->if_opackets++; break; #endif default: m_freem(m0); return EAFNOSUPPORT; } if (tp->tun_flags & TUN_RWAIT) { tp->tun_flags &= ~TUN_RWAIT; wakeup((caddr_t)tp); } if (tp->tun_flags & TUN_ASYNC && tp->tun_pgrp) { if (tp->tun_pgrp > 0) gsignal(tp->tun_pgrp, SIGIO); - else if (p = pfind(-tp->tun_pgrp)) + else if ((p = pfind(-tp->tun_pgrp)) != 0) psignal(p, SIGIO); } selwakeup(&tp->tun_rsel); return 0; } /* * the cdevsw interface is now pretty minimal. */ static int tunioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p; { int unit = minor(dev), s; struct tun_softc *tp = &tunctl[unit]; struct tuninfo *tunp; switch (cmd) { case TUNSIFINFO: tunp = (struct tuninfo *)data; tp->tun_if.if_mtu = tunp->mtu; tp->tun_if.if_type = tunp->type; tp->tun_if.if_baudrate = tunp->baudrate; break; case TUNGIFINFO: tunp = (struct tuninfo *)data; tunp->mtu = tp->tun_if.if_mtu; tunp->type = tp->tun_if.if_type; tunp->baudrate = tp->tun_if.if_baudrate; break; case TUNSDEBUG: tundebug = *(int *)data; break; case TUNGDEBUG: *(int *)data = tundebug; break; case FIONBIO: if (*(int *)data) tp->tun_flags |= TUN_NBIO; else tp->tun_flags &= ~TUN_NBIO; break; case FIOASYNC: if (*(int *)data) tp->tun_flags |= TUN_ASYNC; else tp->tun_flags &= ~TUN_ASYNC; break; case FIONREAD: s = splimp(); if (tp->tun_if.if_snd.ifq_head) *(int *)data = tp->tun_if.if_snd.ifq_head->m_len; else *(int *)data = 0; splx(s); break; case TIOCSPGRP: tp->tun_pgrp = *(int *)data; break; case TIOCGPGRP: *(int *)data = tp->tun_pgrp; break; default: return (ENOTTY); } return (0); } /* * The cdevsw read interface - reads a packet at a time, or at * least as much of a packet as can be read. */ static int tunread(dev_t dev, struct uio *uio, int flag) { int unit = minor(dev); struct tun_softc *tp = &tunctl[unit]; struct ifnet *ifp = &tp->tun_if; struct mbuf *m, *m0; int error=0, len, s; TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit); if ((tp->tun_flags & TUN_READY) != TUN_READY) { TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, ifp->if_unit, tp->tun_flags); return EHOSTDOWN; } tp->tun_flags &= ~TUN_RWAIT; s = splimp(); do { IF_DEQUEUE(&ifp->if_snd, m0); if (m0 == 0) { if (tp->tun_flags & TUN_NBIO) { splx(s); return EWOULDBLOCK; } tp->tun_flags |= TUN_RWAIT; tsleep((caddr_t)tp, PZERO + 1, "tunread", 0); } } while (m0 == 0); splx(s); while (m0 && uio->uio_resid > 0 && error == 0) { len = min(uio->uio_resid, m0->m_len); if (len == 0) break; error = uiomove(mtod(m0, caddr_t), len, uio); MFREE(m0, m); m0 = m; } if (m0) { TUNDEBUG("Dropping mbuf\n"); m_freem(m0); } return error; } /* * the cdevsw write interface - an atomic write is a packet - or else! */ static int tunwrite(dev_t dev, struct uio *uio, int flag) { int unit = minor (dev); struct ifnet *ifp = &tunctl[unit].tun_if; struct mbuf *top, **mp, *m; int error=0, s, tlen, mlen; TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit); if (uio->uio_resid < 0 || uio->uio_resid > TUNMTU) { TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit, uio->uio_resid); return EIO; } tlen = uio->uio_resid; /* get a header mbuf */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return ENOBUFS; mlen = MHLEN; top = 0; mp = ⊤ while (error == 0 && uio->uio_resid > 0) { m->m_len = min(mlen, uio->uio_resid); error = uiomove(mtod (m, caddr_t), m->m_len, uio); *mp = m; mp = &m->m_next; if (uio->uio_resid > 0) { MGET (m, M_DONTWAIT, MT_DATA); if (m == 0) { error = ENOBUFS; break; } mlen = MLEN; } } if (error) { if (top) m_freem (top); return error; } top->m_pkthdr.len = tlen; top->m_pkthdr.rcvif = ifp; #if NBPFILTER > 0 if (tunctl[unit].tun_bpf) { /* * We need to prepend the address family as * a four byte field. Cons up a dummy header * to pacify bpf. This is safe because bpf * will only read from the mbuf (i.e., it won't * try to free it or keep a pointer to it). */ struct mbuf m; u_int af = AF_INET; m.m_next = top; m.m_len = 4; m.m_data = (char *)⁡ bpf_mtap(tunctl[unit].tun_bpf, &m); } #endif s = splimp(); if (IF_QFULL (&ipintrq)) { IF_DROP(&ipintrq); splx(s); ifp->if_collisions++; m_freem(top); return ENOBUFS; } IF_ENQUEUE(&ipintrq, top); splx(s); ifp->if_ipackets++; schednetisr(NETISR_IP); return error; } /* * tunselect - the select interface, this is only useful on reads * really. The write detect always returns true, write never blocks * anyway, it either accepts the packet or drops it. */ static int tunselect(dev_t dev, int rw, struct proc *p) { int unit = minor(dev), s; struct tun_softc *tp = &tunctl[unit]; struct ifnet *ifp = &tp->tun_if; s = splimp(); TUNDEBUG("%s%d: tunselect\n", ifp->if_name, ifp->if_unit); switch (rw) { case FREAD: if (ifp->if_snd.ifq_len > 0) { splx(s); TUNDEBUG("%s%d: tunselect q=%d\n", ifp->if_name, ifp->if_unit, ifp->if_snd.ifq_len); return 1; } selrecord(p, &tp->tun_rsel); break; case FWRITE: splx(s); return 1; } splx(s); TUNDEBUG("%s%d: tunselect waiting\n", ifp->if_name, ifp->if_unit); return 0; } #endif /* NTUN */