X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/f1b2fa5b8a62e80603e6c83b87eaf0b06db3818e..5658e54ccedc665bd9eedaacab8aa1d857374c7b:/usr/src/sys/net/if.c diff --git a/usr/src/sys/net/if.c b/usr/src/sys/net/if.c index 1cd6adb347..c04bff6445 100644 --- a/usr/src/sys/net/if.c +++ b/usr/src/sys/net/if.c @@ -1,63 +1,342 @@ -/* if.c 4.4 81/11/29 */ +/* + * 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 this notice is preserved and that due credit is given + * to the University of California at 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'' without express or implied warranty. + * + * @(#)if.c 7.2 (Berkeley) %G% + */ -#include "../h/param.h" -#include "../h/systm.h" -#include "../net/in.h" -#include "../net/in_systm.h" -#include "../net/if.h" +#include "param.h" +#include "systm.h" +#include "socket.h" +#include "socketvar.h" +#include "protosw.h" +#include "dir.h" +#include "user.h" +#include "kernel.h" +#include "ioctl.h" +#include "errno.h" -/*ARGSUSED*/ -struct ifnet * -if_ifwithaddr(in) - struct in_addr in; +#include "if.h" +#include "af.h" + +#include "ether.h" + +int ifqmaxlen = IFQ_MAXLEN; + +/* + * Network interface utility routines. + * + * Routines with ifa_ifwith* names take sockaddr *'s as + * parameters. + */ + +ifinit() { register struct ifnet *ifp; -COUNT(IF_IFWITHADDR); for (ifp = ifnet; ifp; ifp = ifp->if_next) - if (ifp->if_addr.s_addr == in.s_addr) - break; - return (ifp); + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + if_slowtimo(); +} + +#ifdef vax +/* + * Call each interface on a Unibus reset. + */ +ifubareset(uban) + int uban; +{ + register struct ifnet *ifp; + + for (ifp = ifnet; ifp; ifp = ifp->if_next) + if (ifp->if_reset) + (*ifp->if_reset)(ifp->if_unit, uban); +} +#endif + +/* + * Attach an interface to the + * list of "active" interfaces. + */ +if_attach(ifp) + struct ifnet *ifp; +{ + register struct ifnet **p = &ifnet; + + while (*p) + p = &((*p)->if_next); + *p = ifp; } +/* + * Locate an interface based on a complete address. + */ /*ARGSUSED*/ -struct ifnet * -if_ifonnetof(in) - struct in_addr in; +struct ifaddr * +ifa_ifwithaddr(addr) + struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + +#define equal(a1, a2) \ + (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 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(&ifa->ifa_addr, addr)) + return (ifa); + if ((ifp->if_flags & IFF_BROADCAST) && + 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) + 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 (equal(&ifa->ifa_dstaddr, addr)) + return (ifa); + } + return ((struct ifaddr *)0); +} + +/* + * Find an interface on a specific network. If many, choice + * is first found. + */ +struct ifaddr * +ifa_ifwithnet(addr) + register struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + register u_int af = addr->sa_family; + register int (*netmatch)(); + + if (af >= AF_MAX) + return (0); + netmatch = afswitch[af].af_netmatch; + 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 ((*netmatch)(&ifa->ifa_addr, addr)) + return (ifa); + } + return ((struct ifaddr *)0); +} + +#ifdef notdef +/* + * Find an interface using a specific address family + */ +struct ifaddr * +ifa_ifwithaf(af) + register int af; { register struct ifnet *ifp; - int net; + register struct ifaddr *ifa; -COUNT(IF_IFONNETOF); - net = in.s_net; /* XXX */ for (ifp = ifnet; ifp; ifp = ifp->if_next) - if (ifp->if_net == net) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr.sa_family == af) + return (ifa); + return ((struct ifaddr *)0); +} +#endif + +/* + * Mark an interface down and notify protocols of + * the transition. + * NOTE: must be called at splnet or eqivalent. + */ +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); +} + +/* + * Handle interface watchdog timer routines. Called + * from softclock, we decrement timers (if set) and + * call the appropriate interface routine on expiration. + */ +if_slowtimo() +{ + register struct ifnet *ifp; + + 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->if_unit); + } + timeout(if_slowtimo, (caddr_t)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; + + for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) + if (*cp >= '0' && *cp <= '9') break; + if (*cp == '\0' || cp == name + IFNAMSIZ) + return ((struct ifnet *)0); + unit = *cp - '0'; + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) + continue; + if (unit == ifp->if_unit) + break; + } return (ifp); } -/*ARGSUSED*/ -struct ifnet * -if_gatewayfor(addr) - struct in_addr addr; +/* + * Interface ioctls. + */ +ifioctl(so, cmd, data) + struct socket *so; + int cmd; + caddr_t data; { + register struct ifnet *ifp; + register struct ifreq *ifr; -COUNT(IF_GATEWAYFOR); + switch (cmd) { + + case SIOCGIFCONF: + return (ifconf(cmd, data)); + +#if defined(INET) && NETHER > 0 + case SIOCSARP: + case SIOCDARP: + if (!suser()) + return (u.u_error); + /* FALL THROUGH */ + case SIOCGARP: + return (arpioctl(cmd, data)); +#endif + } + 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 SIOCSIFFLAGS: + if (!suser()) + return (u.u_error); + if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { + int s = splimp(); + if_down(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: + if (!suser()) + return (u.u_error); + ifp->if_metric = ifr->ifr_metric; + break; + + default: + if (so->so_proto == 0) + return (EOPNOTSUPP); + return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, + cmd, data, ifp)); + } return (0); } -struct in_addr -if_makeaddr(net, host) - int net, host; +/* + * Return interface configuration + * of system. List may be used + * in later ioctl's (above) to get + * other information. + */ +/*ARGSUSED*/ +ifconf(cmd, data) + int cmd; + caddr_t data; { - u_long addr; + register struct ifconf *ifc = (struct ifconf *)data; + register struct ifnet *ifp = ifnet; + register struct ifaddr *ifa; + register char *cp, *ep; + struct ifreq ifr, *ifrp; + int space = ifc->ifc_len, error = 0; - if (net < 128) - addr = (host << 8) | net; - else if (net < 65536) - addr = (host << 16) | net; - else - addr = (host << 24) | net; - addr = htonl(addr); - return (*(struct in_addr *)&addr); + ifrp = ifc->ifc_req; + ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; + for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { + bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); + for (cp = ifr.ifr_name; cp < ep && *cp; cp++) + ; + *cp++ = '0' + ifp->if_unit; *cp = '\0'; + 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) { + ifr.ifr_addr = ifa->ifa_addr; + error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); + if (error) + break; + space -= sizeof (ifr), ifrp++; + } + } + ifc->ifc_len -= space; + return (error); }