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*25565Sbloom * @(#)if.c 6.10 (Berkeley) 12/06/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) 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 1466333Ssam /* 1476333Ssam * Find an interface using a specific address family 1486333Ssam */ 14918544Skarels struct ifaddr * 15018544Skarels ifa_ifwithaf(af) 1516333Ssam register int af; 1525083Swnj { 1536333Ssam register struct ifnet *ifp; 15418544Skarels register struct ifaddr *ifa; 1555083Swnj 1566333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 15718544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 15818544Skarels if (ifa->ifa_addr.sa_family == af) 15918544Skarels return (ifa); 16018544Skarels return ((struct ifaddr *)0); 1615083Swnj } 1625104Swnj 1636333Ssam /* 1646582Ssam * Mark an interface down and notify protocols of 1656582Ssam * the transition. 1669184Ssam * NOTE: must be called at splnet or eqivalent. 1676582Ssam */ 1686582Ssam if_down(ifp) 1696582Ssam register struct ifnet *ifp; 1706582Ssam { 17118544Skarels register struct ifaddr *ifa; 1728173Sroot 1736582Ssam ifp->if_flags &= ~IFF_UP; 17418544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 17524773Skarels pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); 1766582Ssam } 1777264Ssam 1787264Ssam /* 1797264Ssam * Handle interface watchdog timer routines. Called 1807264Ssam * from softclock, we decrement timers (if set) and 1817264Ssam * call the appropriate interface routine on expiration. 1827264Ssam */ 1837264Ssam if_slowtimo() 1847264Ssam { 1857264Ssam register struct ifnet *ifp; 1867264Ssam 1879184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1889184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1899184Ssam continue; 1909184Ssam if (ifp->if_watchdog) 1917264Ssam (*ifp->if_watchdog)(ifp->if_unit); 1929184Ssam } 1938692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 1947264Ssam } 19511576Ssam 19611576Ssam /* 19713049Ssam * Map interface name to 19813049Ssam * interface structure pointer. 19911576Ssam */ 20013049Ssam struct ifnet * 20113049Ssam ifunit(name) 20213049Ssam register char *name; 20311576Ssam { 20413049Ssam register char *cp; 20511576Ssam register struct ifnet *ifp; 20613049Ssam int unit; 20711576Ssam 20813049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 20911576Ssam if (*cp >= '0' && *cp <= '9') 21011576Ssam break; 21113049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 21213049Ssam return ((struct ifnet *)0); 21316135Skarels unit = *cp - '0'; 21411576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 21513049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 21611576Ssam continue; 21711576Ssam if (unit == ifp->if_unit) 21813049Ssam break; 21911576Ssam } 22013049Ssam return (ifp); 22113049Ssam } 22211576Ssam 22313049Ssam /* 22413049Ssam * Interface ioctls. 22513049Ssam */ 22618544Skarels ifioctl(so, cmd, data) 22718544Skarels struct socket *so; 22813049Ssam int cmd; 22913049Ssam caddr_t data; 23013049Ssam { 23113049Ssam register struct ifnet *ifp; 23213049Ssam register struct ifreq *ifr; 23313049Ssam 23411576Ssam switch (cmd) { 23511576Ssam 23613049Ssam case SIOCGIFCONF: 23713049Ssam return (ifconf(cmd, data)); 23813049Ssam 23924773Skarels #if (defined(INET) || defined(BBNNET)) && NETHER > 0 24016220Skarels case SIOCSARP: 24116220Skarels case SIOCDARP: 24216220Skarels if (!suser()) 24316220Skarels return (u.u_error); 24416220Skarels /* FALL THROUGH */ 24516220Skarels case SIOCGARP: 24616220Skarels return (arpioctl(cmd, data)); 24716220Skarels #endif 24813049Ssam } 24913049Ssam ifr = (struct ifreq *)data; 25013049Ssam ifp = ifunit(ifr->ifr_name); 25113049Ssam if (ifp == 0) 25213049Ssam return (ENXIO); 25313049Ssam switch (cmd) { 25413049Ssam 25511576Ssam case SIOCGIFFLAGS: 25611576Ssam ifr->ifr_flags = ifp->if_flags; 25711576Ssam break; 25811576Ssam 25913053Ssam case SIOCSIFFLAGS: 260*25565Sbloom if (!suser()) 261*25565Sbloom return (u.u_error); 26213053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 26313053Ssam int s = splimp(); 26413053Ssam if_down(ifp); 26513053Ssam splx(s); 26613053Ssam } 26718544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 26818544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 26924773Skarels if (ifp->if_ioctl) 27024773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 27113053Ssam break; 27213053Ssam 27311576Ssam default: 27418544Skarels if (so->so_proto == 0) 27513049Ssam return (EOPNOTSUPP); 27618544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 27718544Skarels cmd, data, ifp)); 27811576Ssam } 27911576Ssam return (0); 28011576Ssam } 28111576Ssam 28211576Ssam /* 28311576Ssam * Return interface configuration 28411576Ssam * of system. List may be used 28511576Ssam * in later ioctl's (above) to get 28611576Ssam * other information. 28711576Ssam */ 28812783Ssam /*ARGSUSED*/ 28911576Ssam ifconf(cmd, data) 29011576Ssam int cmd; 29111576Ssam caddr_t data; 29211576Ssam { 29311576Ssam register struct ifconf *ifc = (struct ifconf *)data; 29411576Ssam register struct ifnet *ifp = ifnet; 29518544Skarels register struct ifaddr *ifa; 29611630Ssam register char *cp, *ep; 29711630Ssam struct ifreq ifr, *ifrp; 29811576Ssam int space = ifc->ifc_len, error = 0; 29911576Ssam 30011630Ssam ifrp = ifc->ifc_req; 30111630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 30211576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 30311630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 30411630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 30511576Ssam ; 30611630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 30718544Skarels if ((ifa = ifp->if_addrlist) == 0) { 30818544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 30918544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 31018544Skarels if (error) 31118544Skarels break; 31218544Skarels space -= sizeof (ifr), ifrp++; 31318544Skarels } else 31418544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 31518544Skarels ifr.ifr_addr = ifa->ifa_addr; 31618544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 31718544Skarels if (error) 31818544Skarels break; 31918544Skarels space -= sizeof (ifr), ifrp++; 32018544Skarels } 32111576Ssam } 32211576Ssam ifc->ifc_len -= space; 32311576Ssam return (error); 32411576Ssam } 325