123157Smckusick /* 223157Smckusick * Copyright (c) 1980 Regents of the University of California. 323157Smckusick * All rights reserved. The Berkeley software License Agreement 423157Smckusick * specifies the terms and conditions for redistribution. 523157Smckusick * 6*23933Ssklower * @(#)if.c 6.8 (Berkeley) 07/18/85 723157Smckusick */ 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 } 101*23933Ssklower /* 102*23933Ssklower * Locate the point to point interface with a given destination address. 103*23933Ssklower */ 104*23933Ssklower /*ARGSUSED*/ 105*23933Ssklower struct ifaddr * 106*23933Ssklower ifa_ifwithdstaddr(addr) 107*23933Ssklower struct sockaddr *addr; 108*23933Ssklower { 109*23933Ssklower register struct ifnet *ifp; 110*23933Ssklower register struct ifaddr *ifa; 1114944Swnj 112*23933Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) 113*23933Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 114*23933Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 115*23933Ssklower if (ifa->ifa_addr.sa_family != addr->sa_family) 116*23933Ssklower continue; 117*23933Ssklower if (equal(&ifa->ifa_dstaddr, addr)) 118*23933Ssklower return (ifa); 119*23933Ssklower } 120*23933Ssklower return ((struct ifaddr *)0); 121*23933Ssklower } 122*23933Ssklower 1236333Ssam /* 1246333Ssam * Find an interface on a specific network. If many, choice 1256333Ssam * is first found. 1266333Ssam */ 12718544Skarels struct ifaddr * 12818544Skarels ifa_ifwithnet(addr) 1296333Ssam register struct sockaddr *addr; 1304944Swnj { 1314944Swnj register struct ifnet *ifp; 13218544Skarels register struct ifaddr *ifa; 1338393Swnj register u_int af = addr->sa_family; 1346619Ssam register int (*netmatch)(); 1354944Swnj 1366619Ssam if (af >= AF_MAX) 1376619Ssam return (0); 1386619Ssam netmatch = afswitch[af].af_netmatch; 13918544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 14018544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 14118544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1426333Ssam continue; 14318544Skarels if ((*netmatch)(&ifa->ifa_addr, addr)) 14418544Skarels return (ifa); 1456333Ssam } 14618544Skarels return ((struct ifaddr *)0); 1476333Ssam } 1486333Ssam 1496333Ssam /* 1506333Ssam * Find an interface using a specific address family 1516333Ssam */ 15218544Skarels struct ifaddr * 15318544Skarels ifa_ifwithaf(af) 1546333Ssam register int af; 1555083Swnj { 1566333Ssam register struct ifnet *ifp; 15718544Skarels register struct ifaddr *ifa; 1585083Swnj 1596333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 16018544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 16118544Skarels if (ifa->ifa_addr.sa_family == af) 16218544Skarels return (ifa); 16318544Skarels return ((struct ifaddr *)0); 1645083Swnj } 1655104Swnj 1666333Ssam /* 1676582Ssam * Mark an interface down and notify protocols of 1686582Ssam * the transition. 1699184Ssam * NOTE: must be called at splnet or eqivalent. 1706582Ssam */ 1716582Ssam if_down(ifp) 1726582Ssam register struct ifnet *ifp; 1736582Ssam { 17418544Skarels register struct ifaddr *ifa; 1758173Sroot 1766582Ssam ifp->if_flags &= ~IFF_UP; 17718544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 17818544Skarels pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr); 1796582Ssam } 1807264Ssam 1817264Ssam /* 1827264Ssam * Handle interface watchdog timer routines. Called 1837264Ssam * from softclock, we decrement timers (if set) and 1847264Ssam * call the appropriate interface routine on expiration. 1857264Ssam */ 1867264Ssam if_slowtimo() 1877264Ssam { 1887264Ssam register struct ifnet *ifp; 1897264Ssam 1909184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1919184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1929184Ssam continue; 1939184Ssam if (ifp->if_watchdog) 1947264Ssam (*ifp->if_watchdog)(ifp->if_unit); 1959184Ssam } 1968692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 1977264Ssam } 19811576Ssam 19911576Ssam /* 20013049Ssam * Map interface name to 20113049Ssam * interface structure pointer. 20211576Ssam */ 20313049Ssam struct ifnet * 20413049Ssam ifunit(name) 20513049Ssam register char *name; 20611576Ssam { 20713049Ssam register char *cp; 20811576Ssam register struct ifnet *ifp; 20913049Ssam int unit; 21011576Ssam 21113049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 21211576Ssam if (*cp >= '0' && *cp <= '9') 21311576Ssam break; 21413049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 21513049Ssam return ((struct ifnet *)0); 21616135Skarels unit = *cp - '0'; 21711576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 21813049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 21911576Ssam continue; 22011576Ssam if (unit == ifp->if_unit) 22113049Ssam break; 22211576Ssam } 22313049Ssam return (ifp); 22413049Ssam } 22511576Ssam 22613049Ssam /* 22713049Ssam * Interface ioctls. 22813049Ssam */ 22918544Skarels ifioctl(so, cmd, data) 23018544Skarels struct socket *so; 23113049Ssam int cmd; 23213049Ssam caddr_t data; 23313049Ssam { 23413049Ssam register struct ifnet *ifp; 23513049Ssam register struct ifreq *ifr; 23613049Ssam 23711576Ssam switch (cmd) { 23811576Ssam 23913049Ssam case SIOCGIFCONF: 24013049Ssam return (ifconf(cmd, data)); 24113049Ssam 24216220Skarels #if defined(INET) && NETHER > 0 24316220Skarels case SIOCSARP: 24416220Skarels case SIOCDARP: 24516220Skarels if (!suser()) 24616220Skarels return (u.u_error); 24716220Skarels /* FALL THROUGH */ 24816220Skarels case SIOCGARP: 24916220Skarels return (arpioctl(cmd, data)); 25016220Skarels #endif 25113049Ssam } 25213049Ssam ifr = (struct ifreq *)data; 25313049Ssam ifp = ifunit(ifr->ifr_name); 25413049Ssam if (ifp == 0) 25513049Ssam return (ENXIO); 25613049Ssam switch (cmd) { 25713049Ssam 25811576Ssam case SIOCGIFFLAGS: 25911576Ssam ifr->ifr_flags = ifp->if_flags; 26011576Ssam break; 26111576Ssam 26213053Ssam case SIOCSIFFLAGS: 26313053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 26413053Ssam int s = splimp(); 26513053Ssam if_down(ifp); 26613053Ssam splx(s); 26713053Ssam } 26818544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 26918544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 27013053Ssam break; 27113053Ssam 27211576Ssam default: 27318544Skarels if (so->so_proto == 0) 27413049Ssam return (EOPNOTSUPP); 27518544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 27618544Skarels cmd, data, ifp)); 27711576Ssam } 27811576Ssam return (0); 27911576Ssam } 28011576Ssam 28111576Ssam /* 28211576Ssam * Return interface configuration 28311576Ssam * of system. List may be used 28411576Ssam * in later ioctl's (above) to get 28511576Ssam * other information. 28611576Ssam */ 28712783Ssam /*ARGSUSED*/ 28811576Ssam ifconf(cmd, data) 28911576Ssam int cmd; 29011576Ssam caddr_t data; 29111576Ssam { 29211576Ssam register struct ifconf *ifc = (struct ifconf *)data; 29311576Ssam register struct ifnet *ifp = ifnet; 29418544Skarels register struct ifaddr *ifa; 29511630Ssam register char *cp, *ep; 29611630Ssam struct ifreq ifr, *ifrp; 29711576Ssam int space = ifc->ifc_len, error = 0; 29811576Ssam 29911630Ssam ifrp = ifc->ifc_req; 30011630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 30111576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 30211630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 30311630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 30411576Ssam ; 30511630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 30618544Skarels if ((ifa = ifp->if_addrlist) == 0) { 30718544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 30818544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 30918544Skarels if (error) 31018544Skarels break; 31118544Skarels space -= sizeof (ifr), ifrp++; 31218544Skarels } else 31318544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 31418544Skarels ifr.ifr_addr = ifa->ifa_addr; 31518544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 31618544Skarels if (error) 31718544Skarels break; 31818544Skarels space -= sizeof (ifr), ifrp++; 31918544Skarels } 32011576Ssam } 32111576Ssam ifc->ifc_len -= space; 32211576Ssam return (error); 32311576Ssam } 324