X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/45e7fd7235544cf7420a38cbfe425dca6c89e83b..67336957bf4ba9077e903c3d9fe3d098cac1602b:/usr/src/sys/net/if.c diff --git a/usr/src/sys/net/if.c b/usr/src/sys/net/if.c index a265280d30..2ead25f07d 100644 --- a/usr/src/sys/net/if.c +++ b/usr/src/sys/net/if.c @@ -2,19 +2,9 @@ * Copyright (c) 1980, 1986 Regents of the University of California. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * %sccs.include.redist.c% * - * @(#)if.c 7.6.1.1 (Berkeley) %G% + * @(#)if.c 7.13 (Berkeley) %G% */ #include "param.h" @@ -23,7 +13,6 @@ #include "socket.h" #include "socketvar.h" #include "protosw.h" -#include "dir.h" #include "user.h" #include "kernel.h" #include "ioctl.h" @@ -31,6 +20,8 @@ #include "if.h" #include "af.h" +#include "if_dl.h" +#include "if_types.h" #include "ether.h" @@ -68,6 +59,8 @@ ifubareset(uban) } #endif +int if_index = 0; +struct ifaddr **ifnet_addrs; /* * Attach an interface to the * list of "active" interfaces. @@ -75,13 +68,72 @@ ifubareset(uban) if_attach(ifp) struct ifnet *ifp; { + unsigned socksize, ifasize; + int namelen, unitlen; + char workbuf[16]; register struct ifnet **p = &ifnet; + register struct sockaddr_dl *sdl; + register struct ifaddr *ifa; + static int if_indexlim = 8; + extern link_rtrequest(), ether_output(); 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); + if (ifnet_addrs) { + bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); + free((caddr_t)ifnet_addrs, M_IFADDR); + } + ifnet_addrs = q; + } + /* XXX -- Temporary fix before changing 10 ethernet drivers */ + if (ifp->if_output == ether_output) { + ifp->if_type = IFT_ETHER; + ifp->if_addrlen = 6; + ifp->if_hdrlen = 14; + } + /* + * create a Link Level name for this device + */ + sprint_d(workbuf, ifp->if_unit); + namelen = strlen(ifp->if_name); + unitlen = strlen(workbuf); +#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) + socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) + + unitlen + namelen + 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 == 0) + return; + ifnet_addrs[if_index - 1] = ifa; + bzero((caddr_t)ifa, ifasize); + sdl = (struct sockaddr_dl *)(ifa + 1); + ifa->ifa_addr = (struct sockaddr *)sdl; + ifa->ifa_ifp = ifp; + sdl->sdl_len = socksize; + sdl->sdl_family = AF_LINK; + bcopy(ifp->if_name, sdl->sdl_data, namelen); + bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen); + sdl->sdl_nlen = (namelen += unitlen); + sdl->sdl_index = ifp->if_index; + sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); + ifa->ifa_netmask = (struct sockaddr *)sdl; + sdl->sdl_len = socksize - ifp->if_addrlen; + while (namelen != 0) + sdl->sdl_data[--namelen] = 0xff; + ifa->ifa_next = ifp->if_addrlist; + ifa->ifa_rtrequest = link_rtrequest; + ifp->if_addrlist = ifa; } - /* * Locate an interface based on a complete address. */ @@ -101,8 +153,8 @@ ifa_ifwithaddr(addr) continue; if (equal(addr, ifa->ifa_addr)) return (ifa); - if ((ifp->if_flags & IFF_BROADCAST) && - equal(&ifa->ifa_broadaddr, addr)) + if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && + equal(ifa->ifa_broadaddr, addr)) return (ifa); } return ((struct ifaddr *)0); @@ -139,14 +191,19 @@ ifa_ifwithnet(addr) { register struct ifnet *ifp; register struct ifaddr *ifa; - register char *cp, *cp2, *cp3; - register char *cplim; u_int af = addr->sa_family; if (af >= AF_MAX) return (0); + 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; + register char *cplim; if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0) continue; cp = addr->sa_data; @@ -162,7 +219,6 @@ ifa_ifwithnet(addr) return ((struct ifaddr *)0); } -#ifdef notdef /* * Find an interface using a specific address family */ @@ -179,7 +235,69 @@ ifa_ifwithaf(af) return (ifa); return ((struct ifaddr *)0); } -#endif + +/* + * 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; + } + 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 "route.h" +/* + * 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. + */ +link_rtrequest(cmd, rt, sa) +register struct rtentry *rt; +struct sockaddr *sa; +{ + register struct ifaddr *ifa; + struct sockaddr *dst; + struct ifnet *ifp, *oldifnet = ifnet; + + if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || + ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) + return; + if (ifa = ifaof_ifpforaddr(dst, ifp)) { + rt->rt_ifa = ifa; + if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) + ifa->ifa_rtrequest(cmd, rt, sa); + } +} /* * Mark an interface down and notify protocols of @@ -285,6 +403,7 @@ ifioctl(so, cmd, data) { register struct ifnet *ifp; register struct ifreq *ifr; + int error; switch (cmd) { @@ -295,8 +414,8 @@ ifioctl(so, cmd, data) #if defined(INET) && NETHER > 0 case SIOCSARP: case SIOCDARP: - if (!suser()) - return (u.u_error); + if (error = suser(u.u_cred, &u.u_acflag)) + return (error); /* FALL THROUGH */ case SIOCGARP: case OSIOCGARP: @@ -318,8 +437,8 @@ ifioctl(so, cmd, data) break; case SIOCSIFFLAGS: - if (!suser()) - return (u.u_error); + if (error = suser(u.u_cred, &u.u_acflag)) + return (error); if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { int s = splimp(); if_down(ifp); @@ -332,8 +451,8 @@ ifioctl(so, cmd, data) break; case SIOCSIFMETRIC: - if (!suser()) - return (u.u_error); + if (error = suser(u.u_cred, &u.u_acflag)) + return (error); ifp->if_metric = ifr->ifr_metric; break; @@ -345,7 +464,7 @@ ifioctl(so, cmd, data) cmd, data, ifp)); #else { - int error, ocmd = cmd; + int ocmd = cmd; switch (cmd) { @@ -468,3 +587,22 @@ ifconf(cmd, data) ifc->ifc_len -= space; return (error); } + +static sprint_d(cp, n) +register char *cp; +u_short n; +{ + register int q, m; + do { + if (n >= 10000) m = 10000; + else if (n >= 1000) m = 1000; + else if (n >= 100) m = 100; + else if (n >= 10) m = 10; + else m = 1; + q = n / m; + n -= m * q; + if (q > 9) q = 10; /* For crays with more than 100K interfaces */ + *cp++ = "0123456789Z"[q]; + } while (n > 0); + *cp++ = 0; +}