1*23157Smckusick /* 2*23157Smckusick * Copyright (c) 1980 Regents of the University of California. 3*23157Smckusick * All rights reserved. The Berkeley software License Agreement 4*23157Smckusick * specifies the terms and conditions for redistribution. 5*23157Smckusick * 6*23157Smckusick * @(#)if.c 6.7 (Berkeley) 06/08/85 7*23157Smckusick */ 84944Swnj 917036Sbloom #include "param.h" 1017036Sbloom #include "systm.h" 1117036Sbloom #include "socket.h" 1218544Skarels #include "socketvar.h" 1317036Sbloom #include "protosw.h" 1417036Sbloom #include "dir.h" 1517036Sbloom #include "user.h" 1617036Sbloom #include "kernel.h" 1717036Sbloom #include "ioctl.h" 1817036Sbloom #include "errno.h" 1910872Ssam 2017036Sbloom #include "if.h" 2117036Sbloom #include "af.h" 224944Swnj 2316220Skarels #include "ether.h" 2416220Skarels 256207Swnj int ifqmaxlen = IFQ_MAXLEN; 266207Swnj 276333Ssam /* 286333Ssam * Network interface utility routines. 296333Ssam * 3018544Skarels * Routines with ifa_ifwith* names take sockaddr *'s as 3118544Skarels * parameters. 326333Ssam */ 336333Ssam 345206Swnj ifinit() 355206Swnj { 365206Swnj register struct ifnet *ifp; 375206Swnj 385206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 396207Swnj if (ifp->if_init) { 406333Ssam (*ifp->if_init)(ifp->if_unit); 416207Swnj if (ifp->if_snd.ifq_maxlen == 0) 426207Swnj ifp->if_snd.ifq_maxlen = ifqmaxlen; 436207Swnj } 448173Sroot if_slowtimo(); 455206Swnj } 465206Swnj 4713049Ssam #ifdef vax 486333Ssam /* 496333Ssam * Call each interface on a Unibus reset. 506333Ssam */ 515206Swnj ifubareset(uban) 525206Swnj int uban; 535206Swnj { 545206Swnj register struct ifnet *ifp; 555206Swnj 565206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 578974Sroot if (ifp->if_reset) 5815116Ssam (*ifp->if_reset)(ifp->if_unit, uban); 595206Swnj } 608393Swnj #endif 615206Swnj 626333Ssam /* 636333Ssam * Attach an interface to the 646333Ssam * list of "active" interfaces. 656333Ssam */ 665160Swnj if_attach(ifp) 675160Swnj struct ifnet *ifp; 685160Swnj { 695698Swnj register struct ifnet **p = &ifnet; 705160Swnj 715698Swnj while (*p) 725698Swnj p = &((*p)->if_next); 735698Swnj *p = ifp; 745160Swnj } 755160Swnj 766333Ssam /* 776333Ssam * Locate an interface based on a complete address. 786333Ssam */ 794951Swnj /*ARGSUSED*/ 8018544Skarels struct ifaddr * 8118544Skarels ifa_ifwithaddr(addr) 826333Ssam struct sockaddr *addr; 834944Swnj { 844944Swnj register struct ifnet *ifp; 8518544Skarels register struct ifaddr *ifa; 864944Swnj 876333Ssam #define equal(a1, a2) \ 886333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 8918544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 9018544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 9118544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 926333Ssam continue; 9318544Skarels if (equal(&ifa->ifa_addr, addr)) 9418544Skarels return (ifa); 956333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 9618544Skarels equal(&ifa->ifa_broadaddr, addr)) 9718544Skarels return (ifa); 986333Ssam } 9918544Skarels return ((struct ifaddr *)0); 1004944Swnj } 1014944Swnj 1026333Ssam /* 1036333Ssam * Find an interface on a specific network. If many, choice 1046333Ssam * is first found. 1056333Ssam */ 10618544Skarels struct ifaddr * 10718544Skarels ifa_ifwithnet(addr) 1086333Ssam register struct sockaddr *addr; 1094944Swnj { 1104944Swnj register struct ifnet *ifp; 11118544Skarels register struct ifaddr *ifa; 1128393Swnj register u_int af = addr->sa_family; 1136619Ssam register int (*netmatch)(); 1144944Swnj 1156619Ssam if (af >= AF_MAX) 1166619Ssam return (0); 1176619Ssam netmatch = afswitch[af].af_netmatch; 11818544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 11918544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 12018544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1216333Ssam continue; 12218544Skarels if ((*netmatch)(&ifa->ifa_addr, addr)) 12318544Skarels return (ifa); 1246333Ssam } 12518544Skarels return ((struct ifaddr *)0); 1266333Ssam } 1276333Ssam 1286333Ssam /* 1296333Ssam * Find an interface using a specific address family 1306333Ssam */ 13118544Skarels struct ifaddr * 13218544Skarels ifa_ifwithaf(af) 1336333Ssam register int af; 1345083Swnj { 1356333Ssam register struct ifnet *ifp; 13618544Skarels register struct ifaddr *ifa; 1375083Swnj 1386333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 13918544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 14018544Skarels if (ifa->ifa_addr.sa_family == af) 14118544Skarels return (ifa); 14218544Skarels return ((struct ifaddr *)0); 1435083Swnj } 1445104Swnj 1456333Ssam /* 1466582Ssam * Mark an interface down and notify protocols of 1476582Ssam * the transition. 1489184Ssam * NOTE: must be called at splnet or eqivalent. 1496582Ssam */ 1506582Ssam if_down(ifp) 1516582Ssam register struct ifnet *ifp; 1526582Ssam { 15318544Skarels register struct ifaddr *ifa; 1548173Sroot 1556582Ssam ifp->if_flags &= ~IFF_UP; 15618544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 15718544Skarels pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr); 1586582Ssam } 1597264Ssam 1607264Ssam /* 1617264Ssam * Handle interface watchdog timer routines. Called 1627264Ssam * from softclock, we decrement timers (if set) and 1637264Ssam * call the appropriate interface routine on expiration. 1647264Ssam */ 1657264Ssam if_slowtimo() 1667264Ssam { 1677264Ssam register struct ifnet *ifp; 1687264Ssam 1699184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1709184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1719184Ssam continue; 1729184Ssam if (ifp->if_watchdog) 1737264Ssam (*ifp->if_watchdog)(ifp->if_unit); 1749184Ssam } 1758692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 1767264Ssam } 17711576Ssam 17811576Ssam /* 17913049Ssam * Map interface name to 18013049Ssam * interface structure pointer. 18111576Ssam */ 18213049Ssam struct ifnet * 18313049Ssam ifunit(name) 18413049Ssam register char *name; 18511576Ssam { 18613049Ssam register char *cp; 18711576Ssam register struct ifnet *ifp; 18813049Ssam int unit; 18911576Ssam 19013049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 19111576Ssam if (*cp >= '0' && *cp <= '9') 19211576Ssam break; 19313049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 19413049Ssam return ((struct ifnet *)0); 19516135Skarels unit = *cp - '0'; 19611576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 19713049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 19811576Ssam continue; 19911576Ssam if (unit == ifp->if_unit) 20013049Ssam break; 20111576Ssam } 20213049Ssam return (ifp); 20313049Ssam } 20411576Ssam 20513049Ssam /* 20613049Ssam * Interface ioctls. 20713049Ssam */ 20818544Skarels ifioctl(so, cmd, data) 20918544Skarels struct socket *so; 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 22116220Skarels #if defined(INET) && NETHER > 0 22216220Skarels case SIOCSARP: 22316220Skarels case SIOCDARP: 22416220Skarels if (!suser()) 22516220Skarels return (u.u_error); 22616220Skarels /* FALL THROUGH */ 22716220Skarels case SIOCGARP: 22816220Skarels return (arpioctl(cmd, data)); 22916220Skarels #endif 23013049Ssam } 23113049Ssam ifr = (struct ifreq *)data; 23213049Ssam ifp = ifunit(ifr->ifr_name); 23313049Ssam if (ifp == 0) 23413049Ssam return (ENXIO); 23513049Ssam switch (cmd) { 23613049Ssam 23711576Ssam case SIOCGIFFLAGS: 23811576Ssam ifr->ifr_flags = ifp->if_flags; 23911576Ssam break; 24011576Ssam 24113053Ssam case SIOCSIFFLAGS: 24213053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 24313053Ssam int s = splimp(); 24413053Ssam if_down(ifp); 24513053Ssam splx(s); 24613053Ssam } 24718544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 24818544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 24913053Ssam break; 25013053Ssam 25111576Ssam default: 25218544Skarels if (so->so_proto == 0) 25313049Ssam return (EOPNOTSUPP); 25418544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 25518544Skarels cmd, data, ifp)); 25611576Ssam } 25711576Ssam return (0); 25811576Ssam } 25911576Ssam 26011576Ssam /* 26111576Ssam * Return interface configuration 26211576Ssam * of system. List may be used 26311576Ssam * in later ioctl's (above) to get 26411576Ssam * other information. 26511576Ssam */ 26612783Ssam /*ARGSUSED*/ 26711576Ssam ifconf(cmd, data) 26811576Ssam int cmd; 26911576Ssam caddr_t data; 27011576Ssam { 27111576Ssam register struct ifconf *ifc = (struct ifconf *)data; 27211576Ssam register struct ifnet *ifp = ifnet; 27318544Skarels register struct ifaddr *ifa; 27411630Ssam register char *cp, *ep; 27511630Ssam struct ifreq ifr, *ifrp; 27611576Ssam int space = ifc->ifc_len, error = 0; 27711576Ssam 27811630Ssam ifrp = ifc->ifc_req; 27911630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 28011576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 28111630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 28211630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 28311576Ssam ; 28411630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 28518544Skarels if ((ifa = ifp->if_addrlist) == 0) { 28618544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 28718544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 28818544Skarels if (error) 28918544Skarels break; 29018544Skarels space -= sizeof (ifr), ifrp++; 29118544Skarels } else 29218544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 29318544Skarels ifr.ifr_addr = ifa->ifa_addr; 29418544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 29518544Skarels if (error) 29618544Skarels break; 29718544Skarels space -= sizeof (ifr), ifrp++; 29818544Skarels } 29911576Ssam } 30011576Ssam ifc->ifc_len -= space; 30111576Ssam return (error); 30211576Ssam } 303