/* if.c 4.18 82/06/23 */ #include "param.h" #include <sys/systm.h> #include <sys/socket.h> #include <sys/protosw.h> #include <sys/ioctl.h> #include <sys/dir.h> #include <sys/user.h> #include <errno.h> #include "../net/in.h" #include "../net/in_systm.h" #include "../net/if.h" #include "../net/af.h" int ifqmaxlen = IFQ_MAXLEN; /* * Network interface utility routines. * * Routines with if_ifwith* names take sockaddr *'s as * parameters. Other routines take value parameters, * e.g. if_ifwithnet takes the network number. */ ifinit() { register struct ifnet *ifp; for (ifp = ifnet; ifp; ifp = ifp->if_next) if (ifp->if_init) { (*ifp->if_init)(ifp->if_unit); if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; } } /* * 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_ubareset) (*ifp->if_ubareset)(uban); } /* * 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_ifwithaddr(addr) struct sockaddr *addr; { register struct ifnet *ifp; #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) { if (ifp->if_addr.sa_family != addr->sa_family) continue; if (equal(&ifp->if_addr, addr)) break; if ((ifp->if_flags & IFF_BROADCAST) && equal(&ifp->if_broadaddr, addr)) break; } return (ifp); } /* * Find an interface on a specific network. If many, choice * is first found. */ struct ifnet * if_ifwithnet(addr) register struct sockaddr *addr; { register struct ifnet *ifp; register 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) { if (af != ifp->if_addr.sa_family) continue; if ((*netmatch)(addr, &ifp->if_addr)) break; } return (ifp); } /* * As above, but parameter is network number. */ struct ifnet * if_ifonnetof(net) register u_long net; { register struct ifnet *ifp; for (ifp = ifnet; ifp; ifp = ifp->if_next) if (ifp->if_net == net) break; return (ifp); } /* * Find an interface using a specific address family */ struct ifnet * if_ifwithaf(af) register int af; { register struct ifnet *ifp; for (ifp = ifnet; ifp; ifp = ifp->if_next) if (ifp->if_addr.sa_family == af) break; return (ifp); } /* * Mark an interface down and notify protocols of * the transition. * NOTE: must be called at splnet or equivalent. */ if_down(ifp) register struct ifnet *ifp; { ifp->if_flags &= ~IFF_UP; pfctlinput(PRC_IFDOWN, (caddr_t)&ifp->if_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); } } /* * 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'; *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); } /* * Interface ioctls. */ ifioctl(cmd, data) int cmd; caddr_t data; { register struct ifnet *ifp; register struct ifreq *ifr; struct ifreq uifr; /* user's ifreq structure */ if (copyin(data, (caddr_t) &uifr, sizeof(uifr))) { return(EFAULT); } switch (cmd) { case SIOCGIFCONF: return (ifconf(cmd, (caddr_t)&uifr)); case SIOCSIFADDR: case SIOCSIFFLAGS: case SIOCSIFDSTADDR: if (!suser()) return (u.u_error); break; } ifr = (struct ifreq *)&uifr; ifp = ifunit(ifr->ifr_name); if (ifp == (struct ifnet *)0) return (ENXIO); switch (cmd) { case SIOCGIFADDR: ifr->ifr_addr = ifp->if_addr; break; case SIOCGIFDSTADDR: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) return (EINVAL); ifr->ifr_dstaddr = ifp->if_dstaddr; break; case SIOCGIFFLAGS: ifr->ifr_flags = ifp->if_flags; break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { int s = splimp(); if_down(ifp); splx(s); } ifp->if_flags = ifr->ifr_flags; break; default: if (ifp->if_ioctl == 0) return (EOPNOTSUPP); return ((*ifp->if_ioctl)(ifp, cmd, (caddr_t)&uifr)); } if (copyout((caddr_t)&uifr, data, sizeof(uifr))) { return(EFAULT); } return (0); } /* * 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; { register struct ifconf *ifc = (struct ifconf *)data; register struct ifnet *ifp = ifnet; register char *cp, *ep; struct ifreq ifr, *ifrp; int space = ifc->ifc_len, error = 0; 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'; ifr.ifr_addr = ifp->if_addr; error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); if (error) break; space -= sizeof (ifr), ifrp++; } ifc->ifc_len -= space; return (error); }