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*28942Skarels * @(#)if.c 6.13 (Berkeley) 06/02/86 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) 3924773Skarels if (ifp->if_snd.ifq_maxlen == 0) 4024773Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 418173Sroot if_slowtimo(); 425206Swnj } 435206Swnj 4413049Ssam #ifdef vax 456333Ssam /* 466333Ssam * Call each interface on a Unibus reset. 476333Ssam */ 485206Swnj ifubareset(uban) 495206Swnj int uban; 505206Swnj { 515206Swnj register struct ifnet *ifp; 525206Swnj 535206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 548974Sroot if (ifp->if_reset) 5515116Ssam (*ifp->if_reset)(ifp->if_unit, uban); 565206Swnj } 578393Swnj #endif 585206Swnj 596333Ssam /* 606333Ssam * Attach an interface to the 616333Ssam * list of "active" interfaces. 626333Ssam */ 635160Swnj if_attach(ifp) 645160Swnj struct ifnet *ifp; 655160Swnj { 665698Swnj register struct ifnet **p = &ifnet; 675160Swnj 685698Swnj while (*p) 695698Swnj p = &((*p)->if_next); 705698Swnj *p = ifp; 715160Swnj } 725160Swnj 736333Ssam /* 746333Ssam * Locate an interface based on a complete address. 756333Ssam */ 764951Swnj /*ARGSUSED*/ 7718544Skarels struct ifaddr * 7818544Skarels ifa_ifwithaddr(addr) 796333Ssam struct sockaddr *addr; 804944Swnj { 814944Swnj register struct ifnet *ifp; 8218544Skarels register struct ifaddr *ifa; 834944Swnj 846333Ssam #define equal(a1, a2) \ 856333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 8618544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 8718544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 8818544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 896333Ssam continue; 9018544Skarels if (equal(&ifa->ifa_addr, addr)) 9118544Skarels return (ifa); 926333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 9318544Skarels equal(&ifa->ifa_broadaddr, addr)) 9418544Skarels return (ifa); 956333Ssam } 9618544Skarels return ((struct ifaddr *)0); 974944Swnj } 9823933Ssklower /* 9923933Ssklower * Locate the point to point interface with a given destination address. 10023933Ssklower */ 10123933Ssklower /*ARGSUSED*/ 10223933Ssklower struct ifaddr * 10323933Ssklower ifa_ifwithdstaddr(addr) 10423933Ssklower struct sockaddr *addr; 10523933Ssklower { 10623933Ssklower register struct ifnet *ifp; 10723933Ssklower register struct ifaddr *ifa; 1084944Swnj 10923933Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) 11023933Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 11123933Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 11223933Ssklower if (ifa->ifa_addr.sa_family != addr->sa_family) 11323933Ssklower continue; 11423933Ssklower if (equal(&ifa->ifa_dstaddr, addr)) 11523933Ssklower return (ifa); 11623933Ssklower } 11723933Ssklower return ((struct ifaddr *)0); 11823933Ssklower } 11923933Ssklower 1206333Ssam /* 1216333Ssam * Find an interface on a specific network. If many, choice 1226333Ssam * is first found. 1236333Ssam */ 12418544Skarels struct ifaddr * 12518544Skarels ifa_ifwithnet(addr) 1266333Ssam register struct sockaddr *addr; 1274944Swnj { 1284944Swnj register struct ifnet *ifp; 12918544Skarels register struct ifaddr *ifa; 1308393Swnj register u_int af = addr->sa_family; 1316619Ssam register int (*netmatch)(); 1324944Swnj 1336619Ssam if (af >= AF_MAX) 1346619Ssam return (0); 1356619Ssam netmatch = afswitch[af].af_netmatch; 13618544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 13718544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 13818544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1396333Ssam continue; 14018544Skarels if ((*netmatch)(&ifa->ifa_addr, addr)) 14118544Skarels return (ifa); 1426333Ssam } 14318544Skarels return ((struct ifaddr *)0); 1446333Ssam } 1456333Ssam 146*28942Skarels #ifdef notdef 1476333Ssam /* 1486333Ssam * Find an interface using a specific address family 1496333Ssam */ 15018544Skarels struct ifaddr * 15118544Skarels ifa_ifwithaf(af) 1526333Ssam register int af; 1535083Swnj { 1546333Ssam register struct ifnet *ifp; 15518544Skarels register struct ifaddr *ifa; 1565083Swnj 1576333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 15818544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 15918544Skarels if (ifa->ifa_addr.sa_family == af) 16018544Skarels return (ifa); 16118544Skarels return ((struct ifaddr *)0); 1625083Swnj } 163*28942Skarels #endif 1645104Swnj 1656333Ssam /* 1666582Ssam * Mark an interface down and notify protocols of 1676582Ssam * the transition. 1689184Ssam * NOTE: must be called at splnet or eqivalent. 1696582Ssam */ 1706582Ssam if_down(ifp) 1716582Ssam register struct ifnet *ifp; 1726582Ssam { 17318544Skarels register struct ifaddr *ifa; 1748173Sroot 1756582Ssam ifp->if_flags &= ~IFF_UP; 17618544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 17724773Skarels pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); 1786582Ssam } 1797264Ssam 1807264Ssam /* 1817264Ssam * Handle interface watchdog timer routines. Called 1827264Ssam * from softclock, we decrement timers (if set) and 1837264Ssam * call the appropriate interface routine on expiration. 1847264Ssam */ 1857264Ssam if_slowtimo() 1867264Ssam { 1877264Ssam register struct ifnet *ifp; 1887264Ssam 1899184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1909184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1919184Ssam continue; 1929184Ssam if (ifp->if_watchdog) 1937264Ssam (*ifp->if_watchdog)(ifp->if_unit); 1949184Ssam } 1958692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 1967264Ssam } 19711576Ssam 19811576Ssam /* 19913049Ssam * Map interface name to 20013049Ssam * interface structure pointer. 20111576Ssam */ 20213049Ssam struct ifnet * 20313049Ssam ifunit(name) 20413049Ssam register char *name; 20511576Ssam { 20613049Ssam register char *cp; 20711576Ssam register struct ifnet *ifp; 20813049Ssam int unit; 20911576Ssam 21013049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 21111576Ssam if (*cp >= '0' && *cp <= '9') 21211576Ssam break; 21313049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 21413049Ssam return ((struct ifnet *)0); 21516135Skarels unit = *cp - '0'; 21611576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 21713049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 21811576Ssam continue; 21911576Ssam if (unit == ifp->if_unit) 22013049Ssam break; 22111576Ssam } 22213049Ssam return (ifp); 22313049Ssam } 22411576Ssam 22513049Ssam /* 22613049Ssam * Interface ioctls. 22713049Ssam */ 22818544Skarels ifioctl(so, cmd, data) 22918544Skarels struct socket *so; 23013049Ssam int cmd; 23113049Ssam caddr_t data; 23213049Ssam { 23313049Ssam register struct ifnet *ifp; 23413049Ssam register struct ifreq *ifr; 23513049Ssam 23611576Ssam switch (cmd) { 23711576Ssam 23813049Ssam case SIOCGIFCONF: 23913049Ssam return (ifconf(cmd, data)); 24013049Ssam 24125647Skarels #if defined(INET) && NETHER > 0 24216220Skarels case SIOCSARP: 24316220Skarels case SIOCDARP: 24416220Skarels if (!suser()) 24516220Skarels return (u.u_error); 24616220Skarels /* FALL THROUGH */ 24716220Skarels case SIOCGARP: 24816220Skarels return (arpioctl(cmd, data)); 24916220Skarels #endif 25013049Ssam } 25113049Ssam ifr = (struct ifreq *)data; 25213049Ssam ifp = ifunit(ifr->ifr_name); 25313049Ssam if (ifp == 0) 25413049Ssam return (ENXIO); 25513049Ssam switch (cmd) { 25613049Ssam 25711576Ssam case SIOCGIFFLAGS: 25811576Ssam ifr->ifr_flags = ifp->if_flags; 25911576Ssam break; 26011576Ssam 26126091Skarels case SIOCGIFMETRIC: 26226091Skarels ifr->ifr_metric = ifp->if_metric; 26326091Skarels break; 26426091Skarels 26513053Ssam case SIOCSIFFLAGS: 26625565Sbloom if (!suser()) 26725565Sbloom return (u.u_error); 26813053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 26913053Ssam int s = splimp(); 27013053Ssam if_down(ifp); 27113053Ssam splx(s); 27213053Ssam } 27318544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 27418544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 27524773Skarels if (ifp->if_ioctl) 27624773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 27713053Ssam break; 27813053Ssam 27926091Skarels case SIOCSIFMETRIC: 28026091Skarels if (!suser()) 28126091Skarels return (u.u_error); 28226091Skarels ifp->if_metric = ifr->ifr_metric; 28326091Skarels break; 28426091Skarels 28511576Ssam default: 28618544Skarels if (so->so_proto == 0) 28713049Ssam return (EOPNOTSUPP); 28818544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 28918544Skarels cmd, data, ifp)); 29011576Ssam } 29111576Ssam return (0); 29211576Ssam } 29311576Ssam 29411576Ssam /* 29511576Ssam * Return interface configuration 29611576Ssam * of system. List may be used 29711576Ssam * in later ioctl's (above) to get 29811576Ssam * other information. 29911576Ssam */ 30012783Ssam /*ARGSUSED*/ 30111576Ssam ifconf(cmd, data) 30211576Ssam int cmd; 30311576Ssam caddr_t data; 30411576Ssam { 30511576Ssam register struct ifconf *ifc = (struct ifconf *)data; 30611576Ssam register struct ifnet *ifp = ifnet; 30718544Skarels register struct ifaddr *ifa; 30811630Ssam register char *cp, *ep; 30911630Ssam struct ifreq ifr, *ifrp; 31011576Ssam int space = ifc->ifc_len, error = 0; 31111576Ssam 31211630Ssam ifrp = ifc->ifc_req; 31311630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 31411576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 31511630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 31611630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 31711576Ssam ; 31811630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 31918544Skarels if ((ifa = ifp->if_addrlist) == 0) { 32018544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 32118544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 32218544Skarels if (error) 32318544Skarels break; 32418544Skarels space -= sizeof (ifr), ifrp++; 32518544Skarels } else 32618544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 32718544Skarels ifr.ifr_addr = ifa->ifa_addr; 32818544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 32918544Skarels if (error) 33018544Skarels break; 33118544Skarels space -= sizeof (ifr), ifrp++; 33218544Skarels } 33311576Ssam } 33411576Ssam ifc->ifc_len -= space; 33511576Ssam return (error); 33611576Ssam } 337