1*13053Ssam /* if.c 4.30 83/06/12 */ 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 166207Swnj int ifqmaxlen = IFQ_MAXLEN; 176207Swnj 186333Ssam /* 196333Ssam * Network interface utility routines. 206333Ssam * 216333Ssam * Routines with if_ifwith* names take sockaddr *'s as 226333Ssam * parameters. Other routines take value parameters, 236333Ssam * e.g. if_ifwithnet takes the network number. 246333Ssam */ 256333Ssam 265206Swnj ifinit() 275206Swnj { 285206Swnj register struct ifnet *ifp; 295206Swnj 305206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 316207Swnj if (ifp->if_init) { 326333Ssam (*ifp->if_init)(ifp->if_unit); 336207Swnj if (ifp->if_snd.ifq_maxlen == 0) 346207Swnj ifp->if_snd.ifq_maxlen = ifqmaxlen; 356207Swnj } 368173Sroot if_slowtimo(); 375206Swnj } 385206Swnj 3913049Ssam #ifdef vax 406333Ssam /* 416333Ssam * Call each interface on a Unibus reset. 426333Ssam */ 435206Swnj ifubareset(uban) 445206Swnj int uban; 455206Swnj { 465206Swnj register struct ifnet *ifp; 475206Swnj 485206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 498974Sroot if (ifp->if_reset) 508974Sroot (*ifp->if_reset)(uban); 515206Swnj } 528393Swnj #endif 535206Swnj 546333Ssam /* 556333Ssam * Attach an interface to the 566333Ssam * list of "active" interfaces. 576333Ssam */ 585160Swnj if_attach(ifp) 595160Swnj struct ifnet *ifp; 605160Swnj { 615698Swnj register struct ifnet **p = &ifnet; 625160Swnj 635698Swnj while (*p) 645698Swnj p = &((*p)->if_next); 655698Swnj *p = ifp; 665160Swnj } 675160Swnj 686333Ssam /* 696333Ssam * Locate an interface based on a complete address. 706333Ssam */ 714951Swnj /*ARGSUSED*/ 724951Swnj struct ifnet * 736333Ssam if_ifwithaddr(addr) 746333Ssam struct sockaddr *addr; 754944Swnj { 764944Swnj register struct ifnet *ifp; 774944Swnj 786333Ssam #define equal(a1, a2) \ 796333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 806333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 816333Ssam if (ifp->if_addr.sa_family != addr->sa_family) 826333Ssam continue; 836333Ssam if (equal(&ifp->if_addr, addr)) 844944Swnj break; 856333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 866333Ssam equal(&ifp->if_broadaddr, addr)) 876333Ssam break; 886333Ssam } 894944Swnj return (ifp); 904944Swnj } 914944Swnj 926333Ssam /* 936333Ssam * Find an interface on a specific network. If many, choice 946333Ssam * is first found. 956333Ssam */ 964951Swnj struct ifnet * 976333Ssam if_ifwithnet(addr) 986333Ssam register struct sockaddr *addr; 994944Swnj { 1004944Swnj register struct ifnet *ifp; 1018393Swnj register u_int af = addr->sa_family; 1026619Ssam register int (*netmatch)(); 1034944Swnj 1046619Ssam if (af >= AF_MAX) 1056619Ssam return (0); 1066619Ssam netmatch = afswitch[af].af_netmatch; 1076333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1086333Ssam if (af != ifp->if_addr.sa_family) 1096333Ssam continue; 1106333Ssam if ((*netmatch)(addr, &ifp->if_addr)) 1116333Ssam break; 1126333Ssam } 1136333Ssam return (ifp); 1146333Ssam } 1156333Ssam 1166333Ssam /* 1176333Ssam * As above, but parameter is network number. 1186333Ssam */ 1196333Ssam struct ifnet * 1206333Ssam if_ifonnetof(net) 1216333Ssam register int net; 1226333Ssam { 1236333Ssam register struct ifnet *ifp; 1246333Ssam 1254944Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 1264944Swnj if (ifp->if_net == net) 1274944Swnj break; 1284944Swnj return (ifp); 1294944Swnj } 1304944Swnj 1316333Ssam /* 1326333Ssam * Find an interface using a specific address family 1336333Ssam */ 1345083Swnj struct ifnet * 1356333Ssam if_ifwithaf(af) 1366333Ssam register int af; 1375083Swnj { 1386333Ssam register struct ifnet *ifp; 1395083Swnj 1406333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 1416333Ssam if (ifp->if_addr.sa_family == af) 1426333Ssam break; 1436333Ssam return (ifp); 1445083Swnj } 1455104Swnj 1466333Ssam /* 1476582Ssam * Mark an interface down and notify protocols of 1486582Ssam * the transition. 1499184Ssam * NOTE: must be called at splnet or eqivalent. 1506582Ssam */ 1516582Ssam if_down(ifp) 1526582Ssam register struct ifnet *ifp; 1536582Ssam { 1548173Sroot 1556582Ssam ifp->if_flags &= ~IFF_UP; 1566582Ssam pfctlinput(PRC_IFDOWN, (caddr_t)&ifp->if_addr); 1576582Ssam } 1587264Ssam 1597264Ssam /* 1607264Ssam * Handle interface watchdog timer routines. Called 1617264Ssam * from softclock, we decrement timers (if set) and 1627264Ssam * call the appropriate interface routine on expiration. 1637264Ssam */ 1647264Ssam if_slowtimo() 1657264Ssam { 1667264Ssam register struct ifnet *ifp; 1677264Ssam 1689184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1699184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1709184Ssam continue; 1719184Ssam if (ifp->if_watchdog) 1727264Ssam (*ifp->if_watchdog)(ifp->if_unit); 1739184Ssam } 1748692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 1757264Ssam } 17611576Ssam 17711576Ssam /* 17813049Ssam * Map interface name to 17913049Ssam * interface structure pointer. 18011576Ssam */ 18113049Ssam struct ifnet * 18213049Ssam ifunit(name) 18313049Ssam register char *name; 18411576Ssam { 18513049Ssam register char *cp; 18611576Ssam register struct ifnet *ifp; 18713049Ssam int unit; 18811576Ssam 18913049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 19011576Ssam if (*cp >= '0' && *cp <= '9') 19111576Ssam break; 19213049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 19313049Ssam return ((struct ifnet *)0); 19411576Ssam unit = *cp - '0', *cp = 0; 19511576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 19613049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 19711576Ssam continue; 19811576Ssam if (unit == ifp->if_unit) 19913049Ssam break; 20011576Ssam } 20113049Ssam return (ifp); 20213049Ssam } 20311576Ssam 20413049Ssam /* 20513049Ssam * Interface ioctls. 20613049Ssam */ 20713049Ssam ifioctl(cmd, data) 20813049Ssam int cmd; 20913049Ssam caddr_t data; 21013049Ssam { 21113049Ssam register struct ifnet *ifp; 21213049Ssam register struct ifreq *ifr; 21313049Ssam 21411576Ssam switch (cmd) { 21511576Ssam 21613049Ssam case SIOCGIFCONF: 21713049Ssam return (ifconf(cmd, data)); 21813049Ssam 21913049Ssam case SIOCSIFADDR: 22013049Ssam case SIOCSIFFLAGS: 22113049Ssam case SIOCSIFDSTADDR: 22213049Ssam if (!suser()) 22313049Ssam return (u.u_error); 22413049Ssam break; 22513049Ssam } 22613049Ssam ifr = (struct ifreq *)data; 22713049Ssam ifp = ifunit(ifr->ifr_name); 22813049Ssam if (ifp == 0) 22913049Ssam return (ENXIO); 23013049Ssam switch (cmd) { 23113049Ssam 23211576Ssam case SIOCGIFADDR: 23311576Ssam ifr->ifr_addr = ifp->if_addr; 23411576Ssam break; 23511576Ssam 23611576Ssam case SIOCGIFDSTADDR: 23711576Ssam if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 23811576Ssam return (EINVAL); 23911576Ssam ifr->ifr_dstaddr = ifp->if_dstaddr; 24011576Ssam break; 24111576Ssam 24211576Ssam case SIOCGIFFLAGS: 24311576Ssam ifr->ifr_flags = ifp->if_flags; 24411576Ssam break; 24511576Ssam 246*13053Ssam case SIOCSIFFLAGS: 247*13053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 248*13053Ssam int s = splimp(); 249*13053Ssam if_down(ifp); 250*13053Ssam splx(s); 251*13053Ssam } 252*13053Ssam ifp->if_flags = ifr->ifr_flags; 253*13053Ssam break; 254*13053Ssam 25511576Ssam default: 25613049Ssam if (ifp->if_ioctl == 0) 25713049Ssam return (EOPNOTSUPP); 258*13053Ssam return ((*ifp->if_ioctl)(ifp, cmd, data)); 25911576Ssam } 26011576Ssam return (0); 26111576Ssam } 26211576Ssam 26311576Ssam /* 26411576Ssam * Return interface configuration 26511576Ssam * of system. List may be used 26611576Ssam * in later ioctl's (above) to get 26711576Ssam * other information. 26811576Ssam */ 26912783Ssam /*ARGSUSED*/ 27011576Ssam ifconf(cmd, data) 27111576Ssam int cmd; 27211576Ssam caddr_t data; 27311576Ssam { 27411576Ssam register struct ifconf *ifc = (struct ifconf *)data; 27511576Ssam register struct ifnet *ifp = ifnet; 27611630Ssam register char *cp, *ep; 27711630Ssam struct ifreq ifr, *ifrp; 27811576Ssam int space = ifc->ifc_len, error = 0; 27911576Ssam 28011630Ssam ifrp = ifc->ifc_req; 28111630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 28211576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 28311630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 28411630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 28511576Ssam ; 28611630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 28711576Ssam ifr.ifr_addr = ifp->if_addr; 28811630Ssam error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 28911576Ssam if (error) 29011576Ssam break; 29111630Ssam space -= sizeof (ifr), ifrp++; 29211576Ssam } 29311576Ssam ifc->ifc_len -= space; 29411576Ssam return (error); 29511576Ssam } 296