1*16220Skarels /* if.c 6.4 84/03/22 */ 24944Swnj 34944Swnj #include "../h/param.h" 44944Swnj #include "../h/systm.h" 56333Ssam #include "../h/socket.h" 66582Ssam #include "../h/protosw.h" 713049Ssam #include "../h/dir.h" 813049Ssam #include "../h/user.h" 910872Ssam #include "../h/kernel.h" 1011576Ssam #include "../h/ioctl.h" 1111576Ssam #include "../h/errno.h" 1210872Ssam 134944Swnj #include "../net/if.h" 146333Ssam #include "../net/af.h" 154944Swnj 16*16220Skarels #include "ether.h" 17*16220Skarels 186207Swnj int ifqmaxlen = IFQ_MAXLEN; 196207Swnj 206333Ssam /* 216333Ssam * Network interface utility routines. 226333Ssam * 236333Ssam * Routines with if_ifwith* names take sockaddr *'s as 246333Ssam * parameters. Other routines take value parameters, 256333Ssam * e.g. if_ifwithnet takes the network number. 266333Ssam */ 276333Ssam 285206Swnj ifinit() 295206Swnj { 305206Swnj register struct ifnet *ifp; 315206Swnj 325206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 336207Swnj if (ifp->if_init) { 346333Ssam (*ifp->if_init)(ifp->if_unit); 356207Swnj if (ifp->if_snd.ifq_maxlen == 0) 366207Swnj ifp->if_snd.ifq_maxlen = ifqmaxlen; 376207Swnj } 388173Sroot if_slowtimo(); 395206Swnj } 405206Swnj 4113049Ssam #ifdef vax 426333Ssam /* 436333Ssam * Call each interface on a Unibus reset. 446333Ssam */ 455206Swnj ifubareset(uban) 465206Swnj int uban; 475206Swnj { 485206Swnj register struct ifnet *ifp; 495206Swnj 505206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 518974Sroot if (ifp->if_reset) 5215116Ssam (*ifp->if_reset)(ifp->if_unit, uban); 535206Swnj } 548393Swnj #endif 555206Swnj 566333Ssam /* 576333Ssam * Attach an interface to the 586333Ssam * list of "active" interfaces. 596333Ssam */ 605160Swnj if_attach(ifp) 615160Swnj struct ifnet *ifp; 625160Swnj { 635698Swnj register struct ifnet **p = &ifnet; 645160Swnj 655698Swnj while (*p) 665698Swnj p = &((*p)->if_next); 675698Swnj *p = ifp; 685160Swnj } 695160Swnj 706333Ssam /* 716333Ssam * Locate an interface based on a complete address. 726333Ssam */ 734951Swnj /*ARGSUSED*/ 744951Swnj struct ifnet * 756333Ssam if_ifwithaddr(addr) 766333Ssam struct sockaddr *addr; 774944Swnj { 784944Swnj register struct ifnet *ifp; 794944Swnj 806333Ssam #define equal(a1, a2) \ 816333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 826333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 836333Ssam if (ifp->if_addr.sa_family != addr->sa_family) 846333Ssam continue; 856333Ssam if (equal(&ifp->if_addr, addr)) 864944Swnj break; 876333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 886333Ssam equal(&ifp->if_broadaddr, addr)) 896333Ssam break; 906333Ssam } 914944Swnj return (ifp); 924944Swnj } 934944Swnj 946333Ssam /* 956333Ssam * Find an interface on a specific network. If many, choice 966333Ssam * is first found. 976333Ssam */ 984951Swnj struct ifnet * 996333Ssam if_ifwithnet(addr) 1006333Ssam register struct sockaddr *addr; 1014944Swnj { 1024944Swnj register struct ifnet *ifp; 1038393Swnj register u_int af = addr->sa_family; 1046619Ssam register int (*netmatch)(); 1054944Swnj 1066619Ssam if (af >= AF_MAX) 1076619Ssam return (0); 1086619Ssam netmatch = afswitch[af].af_netmatch; 1096333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1106333Ssam if (af != ifp->if_addr.sa_family) 1116333Ssam continue; 1126333Ssam if ((*netmatch)(addr, &ifp->if_addr)) 1136333Ssam break; 1146333Ssam } 1156333Ssam return (ifp); 1166333Ssam } 1176333Ssam 1186333Ssam /* 1196333Ssam * As above, but parameter is network number. 1206333Ssam */ 1216333Ssam struct ifnet * 1226333Ssam if_ifonnetof(net) 1236333Ssam register int net; 1246333Ssam { 1256333Ssam register struct ifnet *ifp; 1266333Ssam 1274944Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 1284944Swnj if (ifp->if_net == net) 1294944Swnj break; 1304944Swnj return (ifp); 1314944Swnj } 1324944Swnj 1336333Ssam /* 1346333Ssam * Find an interface using a specific address family 1356333Ssam */ 1365083Swnj struct ifnet * 1376333Ssam if_ifwithaf(af) 1386333Ssam register int af; 1395083Swnj { 1406333Ssam register struct ifnet *ifp; 1415083Swnj 1426333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 1436333Ssam if (ifp->if_addr.sa_family == af) 1446333Ssam break; 1456333Ssam return (ifp); 1465083Swnj } 1475104Swnj 1486333Ssam /* 1496582Ssam * Mark an interface down and notify protocols of 1506582Ssam * the transition. 1519184Ssam * NOTE: must be called at splnet or eqivalent. 1526582Ssam */ 1536582Ssam if_down(ifp) 1546582Ssam register struct ifnet *ifp; 1556582Ssam { 1568173Sroot 1576582Ssam ifp->if_flags &= ~IFF_UP; 1586582Ssam pfctlinput(PRC_IFDOWN, (caddr_t)&ifp->if_addr); 1596582Ssam } 1607264Ssam 1617264Ssam /* 1627264Ssam * Handle interface watchdog timer routines. Called 1637264Ssam * from softclock, we decrement timers (if set) and 1647264Ssam * call the appropriate interface routine on expiration. 1657264Ssam */ 1667264Ssam if_slowtimo() 1677264Ssam { 1687264Ssam register struct ifnet *ifp; 1697264Ssam 1709184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1719184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1729184Ssam continue; 1739184Ssam if (ifp->if_watchdog) 1747264Ssam (*ifp->if_watchdog)(ifp->if_unit); 1759184Ssam } 1768692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 1777264Ssam } 17811576Ssam 17911576Ssam /* 18013049Ssam * Map interface name to 18113049Ssam * interface structure pointer. 18211576Ssam */ 18313049Ssam struct ifnet * 18413049Ssam ifunit(name) 18513049Ssam register char *name; 18611576Ssam { 18713049Ssam register char *cp; 18811576Ssam register struct ifnet *ifp; 18913049Ssam int unit; 19011576Ssam 19113049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 19211576Ssam if (*cp >= '0' && *cp <= '9') 19311576Ssam break; 19413049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 19513049Ssam return ((struct ifnet *)0); 19616135Skarels unit = *cp - '0'; 19711576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 19813049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 19911576Ssam continue; 20011576Ssam if (unit == ifp->if_unit) 20113049Ssam break; 20211576Ssam } 20313049Ssam return (ifp); 20413049Ssam } 20511576Ssam 20613049Ssam /* 20713049Ssam * Interface ioctls. 20813049Ssam */ 20913049Ssam ifioctl(cmd, data) 21013049Ssam int cmd; 21113049Ssam caddr_t data; 21213049Ssam { 21313049Ssam register struct ifnet *ifp; 21413049Ssam register struct ifreq *ifr; 21513049Ssam 21611576Ssam switch (cmd) { 21711576Ssam 21813049Ssam case SIOCGIFCONF: 21913049Ssam return (ifconf(cmd, data)); 22013049Ssam 221*16220Skarels #if defined(INET) && NETHER > 0 222*16220Skarels case SIOCSARP: 223*16220Skarels case SIOCDARP: 224*16220Skarels if (!suser()) 225*16220Skarels return (u.u_error); 226*16220Skarels /* FALL THROUGH */ 227*16220Skarels case SIOCGARP: 228*16220Skarels return (arpioctl(cmd, data)); 229*16220Skarels #endif 230*16220Skarels 23113049Ssam case SIOCSIFADDR: 23213049Ssam case SIOCSIFFLAGS: 23313049Ssam case SIOCSIFDSTADDR: 23413049Ssam if (!suser()) 23513049Ssam return (u.u_error); 23613049Ssam break; 23713049Ssam } 23813049Ssam ifr = (struct ifreq *)data; 23913049Ssam ifp = ifunit(ifr->ifr_name); 24013049Ssam if (ifp == 0) 24113049Ssam return (ENXIO); 24213049Ssam switch (cmd) { 24313049Ssam 24411576Ssam case SIOCGIFADDR: 24511576Ssam ifr->ifr_addr = ifp->if_addr; 24611576Ssam break; 24711576Ssam 24811576Ssam case SIOCGIFDSTADDR: 24911576Ssam if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 25011576Ssam return (EINVAL); 25111576Ssam ifr->ifr_dstaddr = ifp->if_dstaddr; 25211576Ssam break; 25311576Ssam 25411576Ssam case SIOCGIFFLAGS: 25511576Ssam ifr->ifr_flags = ifp->if_flags; 25611576Ssam break; 25711576Ssam 25813053Ssam case SIOCSIFFLAGS: 25913053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 26013053Ssam int s = splimp(); 26113053Ssam if_down(ifp); 26213053Ssam splx(s); 26313053Ssam } 26413053Ssam ifp->if_flags = ifr->ifr_flags; 26513053Ssam break; 26613053Ssam 26711576Ssam default: 26813049Ssam if (ifp->if_ioctl == 0) 26913049Ssam return (EOPNOTSUPP); 27013053Ssam return ((*ifp->if_ioctl)(ifp, cmd, data)); 27111576Ssam } 27211576Ssam return (0); 27311576Ssam } 27411576Ssam 27511576Ssam /* 27611576Ssam * Return interface configuration 27711576Ssam * of system. List may be used 27811576Ssam * in later ioctl's (above) to get 27911576Ssam * other information. 28011576Ssam */ 28112783Ssam /*ARGSUSED*/ 28211576Ssam ifconf(cmd, data) 28311576Ssam int cmd; 28411576Ssam caddr_t data; 28511576Ssam { 28611576Ssam register struct ifconf *ifc = (struct ifconf *)data; 28711576Ssam register struct ifnet *ifp = ifnet; 28811630Ssam register char *cp, *ep; 28911630Ssam struct ifreq ifr, *ifrp; 29011576Ssam int space = ifc->ifc_len, error = 0; 29111576Ssam 29211630Ssam ifrp = ifc->ifc_req; 29311630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 29411576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 29511630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 29611630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 29711576Ssam ; 29811630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 29911576Ssam ifr.ifr_addr = ifp->if_addr; 30011630Ssam error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 30111576Ssam if (error) 30211576Ssam break; 30311630Ssam space -= sizeof (ifr), ifrp++; 30411576Ssam } 30511576Ssam ifc->ifc_len -= space; 30611576Ssam return (error); 30711576Ssam } 308