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*26091Skarels * @(#)if.c 6.12 (Berkeley) 02/06/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 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 23925647Skarels #if defined(INET) && 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 259*26091Skarels case SIOCGIFMETRIC: 260*26091Skarels ifr->ifr_metric = ifp->if_metric; 261*26091Skarels break; 262*26091Skarels 26313053Ssam case SIOCSIFFLAGS: 26425565Sbloom if (!suser()) 26525565Sbloom return (u.u_error); 26613053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 26713053Ssam int s = splimp(); 26813053Ssam if_down(ifp); 26913053Ssam splx(s); 27013053Ssam } 27118544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 27218544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 27324773Skarels if (ifp->if_ioctl) 27424773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 27513053Ssam break; 27613053Ssam 277*26091Skarels case SIOCSIFMETRIC: 278*26091Skarels if (!suser()) 279*26091Skarels return (u.u_error); 280*26091Skarels ifp->if_metric = ifr->ifr_metric; 281*26091Skarels break; 282*26091Skarels 28311576Ssam default: 28418544Skarels if (so->so_proto == 0) 28513049Ssam return (EOPNOTSUPP); 28618544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 28718544Skarels cmd, data, ifp)); 28811576Ssam } 28911576Ssam return (0); 29011576Ssam } 29111576Ssam 29211576Ssam /* 29311576Ssam * Return interface configuration 29411576Ssam * of system. List may be used 29511576Ssam * in later ioctl's (above) to get 29611576Ssam * other information. 29711576Ssam */ 29812783Ssam /*ARGSUSED*/ 29911576Ssam ifconf(cmd, data) 30011576Ssam int cmd; 30111576Ssam caddr_t data; 30211576Ssam { 30311576Ssam register struct ifconf *ifc = (struct ifconf *)data; 30411576Ssam register struct ifnet *ifp = ifnet; 30518544Skarels register struct ifaddr *ifa; 30611630Ssam register char *cp, *ep; 30711630Ssam struct ifreq ifr, *ifrp; 30811576Ssam int space = ifc->ifc_len, error = 0; 30911576Ssam 31011630Ssam ifrp = ifc->ifc_req; 31111630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 31211576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 31311630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 31411630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 31511576Ssam ; 31611630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 31718544Skarels if ((ifa = ifp->if_addrlist) == 0) { 31818544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 31918544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 32018544Skarels if (error) 32118544Skarels break; 32218544Skarels space -= sizeof (ifr), ifrp++; 32318544Skarels } else 32418544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 32518544Skarels ifr.ifr_addr = ifa->ifa_addr; 32618544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 32718544Skarels if (error) 32818544Skarels break; 32918544Skarels space -= sizeof (ifr), ifrp++; 33018544Skarels } 33111576Ssam } 33211576Ssam ifc->ifc_len -= space; 33311576Ssam return (error); 33411576Ssam } 335