123157Smckusick /* 229061Smckusick * Copyright (c) 1980, 1986 Regents of the University of California. 3*33183Sbostic * All rights reserved. 423157Smckusick * 5*33183Sbostic * Redistribution and use in source and binary forms are permitted 6*33183Sbostic * provided that this notice is preserved and that due credit is given 7*33183Sbostic * to the University of California at Berkeley. The name of the University 8*33183Sbostic * may not be used to endorse or promote products derived from this 9*33183Sbostic * software without specific prior written permission. This software 10*33183Sbostic * is provided ``as is'' without express or implied warranty. 11*33183Sbostic * 12*33183Sbostic * @(#)if.c 7.2 (Berkeley) 12/30/87 1323157Smckusick */ 144944Swnj 1517036Sbloom #include "param.h" 1617036Sbloom #include "systm.h" 1717036Sbloom #include "socket.h" 1818544Skarels #include "socketvar.h" 1917036Sbloom #include "protosw.h" 2017036Sbloom #include "dir.h" 2117036Sbloom #include "user.h" 2217036Sbloom #include "kernel.h" 2317036Sbloom #include "ioctl.h" 2417036Sbloom #include "errno.h" 2510872Ssam 2617036Sbloom #include "if.h" 2717036Sbloom #include "af.h" 284944Swnj 2916220Skarels #include "ether.h" 3016220Skarels 316207Swnj int ifqmaxlen = IFQ_MAXLEN; 326207Swnj 336333Ssam /* 346333Ssam * Network interface utility routines. 356333Ssam * 3618544Skarels * Routines with ifa_ifwith* names take sockaddr *'s as 3718544Skarels * parameters. 386333Ssam */ 396333Ssam 405206Swnj ifinit() 415206Swnj { 425206Swnj register struct ifnet *ifp; 435206Swnj 445206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 4524773Skarels if (ifp->if_snd.ifq_maxlen == 0) 4624773Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 478173Sroot if_slowtimo(); 485206Swnj } 495206Swnj 5013049Ssam #ifdef vax 516333Ssam /* 526333Ssam * Call each interface on a Unibus reset. 536333Ssam */ 545206Swnj ifubareset(uban) 555206Swnj int uban; 565206Swnj { 575206Swnj register struct ifnet *ifp; 585206Swnj 595206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 608974Sroot if (ifp->if_reset) 6115116Ssam (*ifp->if_reset)(ifp->if_unit, uban); 625206Swnj } 638393Swnj #endif 645206Swnj 656333Ssam /* 666333Ssam * Attach an interface to the 676333Ssam * list of "active" interfaces. 686333Ssam */ 695160Swnj if_attach(ifp) 705160Swnj struct ifnet *ifp; 715160Swnj { 725698Swnj register struct ifnet **p = &ifnet; 735160Swnj 745698Swnj while (*p) 755698Swnj p = &((*p)->if_next); 765698Swnj *p = ifp; 775160Swnj } 785160Swnj 796333Ssam /* 806333Ssam * Locate an interface based on a complete address. 816333Ssam */ 824951Swnj /*ARGSUSED*/ 8318544Skarels struct ifaddr * 8418544Skarels ifa_ifwithaddr(addr) 856333Ssam struct sockaddr *addr; 864944Swnj { 874944Swnj register struct ifnet *ifp; 8818544Skarels register struct ifaddr *ifa; 894944Swnj 906333Ssam #define equal(a1, a2) \ 916333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 9218544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 9318544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 9418544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 956333Ssam continue; 9618544Skarels if (equal(&ifa->ifa_addr, addr)) 9718544Skarels return (ifa); 986333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 9918544Skarels equal(&ifa->ifa_broadaddr, addr)) 10018544Skarels return (ifa); 1016333Ssam } 10218544Skarels return ((struct ifaddr *)0); 1034944Swnj } 10423933Ssklower /* 10523933Ssklower * Locate the point to point interface with a given destination address. 10623933Ssklower */ 10723933Ssklower /*ARGSUSED*/ 10823933Ssklower struct ifaddr * 10923933Ssklower ifa_ifwithdstaddr(addr) 11023933Ssklower struct sockaddr *addr; 11123933Ssklower { 11223933Ssklower register struct ifnet *ifp; 11323933Ssklower register struct ifaddr *ifa; 1144944Swnj 11523933Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) 11623933Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 11723933Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 11823933Ssklower if (ifa->ifa_addr.sa_family != addr->sa_family) 11923933Ssklower continue; 12023933Ssklower if (equal(&ifa->ifa_dstaddr, addr)) 12123933Ssklower return (ifa); 12223933Ssklower } 12323933Ssklower return ((struct ifaddr *)0); 12423933Ssklower } 12523933Ssklower 1266333Ssam /* 1276333Ssam * Find an interface on a specific network. If many, choice 1286333Ssam * is first found. 1296333Ssam */ 13018544Skarels struct ifaddr * 13118544Skarels ifa_ifwithnet(addr) 1326333Ssam register struct sockaddr *addr; 1334944Swnj { 1344944Swnj register struct ifnet *ifp; 13518544Skarels register struct ifaddr *ifa; 1368393Swnj register u_int af = addr->sa_family; 1376619Ssam register int (*netmatch)(); 1384944Swnj 1396619Ssam if (af >= AF_MAX) 1406619Ssam return (0); 1416619Ssam netmatch = afswitch[af].af_netmatch; 14218544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 14318544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 14418544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1456333Ssam continue; 14618544Skarels if ((*netmatch)(&ifa->ifa_addr, addr)) 14718544Skarels return (ifa); 1486333Ssam } 14918544Skarels return ((struct ifaddr *)0); 1506333Ssam } 1516333Ssam 15228942Skarels #ifdef notdef 1536333Ssam /* 1546333Ssam * Find an interface using a specific address family 1556333Ssam */ 15618544Skarels struct ifaddr * 15718544Skarels ifa_ifwithaf(af) 1586333Ssam register int af; 1595083Swnj { 1606333Ssam register struct ifnet *ifp; 16118544Skarels register struct ifaddr *ifa; 1625083Swnj 1636333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 16418544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 16518544Skarels if (ifa->ifa_addr.sa_family == af) 16618544Skarels return (ifa); 16718544Skarels return ((struct ifaddr *)0); 1685083Swnj } 16928942Skarels #endif 1705104Swnj 1716333Ssam /* 1726582Ssam * Mark an interface down and notify protocols of 1736582Ssam * the transition. 1749184Ssam * NOTE: must be called at splnet or eqivalent. 1756582Ssam */ 1766582Ssam if_down(ifp) 1776582Ssam register struct ifnet *ifp; 1786582Ssam { 17918544Skarels register struct ifaddr *ifa; 1808173Sroot 1816582Ssam ifp->if_flags &= ~IFF_UP; 18218544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 18324773Skarels pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); 1846582Ssam } 1857264Ssam 1867264Ssam /* 1877264Ssam * Handle interface watchdog timer routines. Called 1887264Ssam * from softclock, we decrement timers (if set) and 1897264Ssam * call the appropriate interface routine on expiration. 1907264Ssam */ 1917264Ssam if_slowtimo() 1927264Ssam { 1937264Ssam register struct ifnet *ifp; 1947264Ssam 1959184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1969184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 1979184Ssam continue; 1989184Ssam if (ifp->if_watchdog) 1997264Ssam (*ifp->if_watchdog)(ifp->if_unit); 2009184Ssam } 2018692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 2027264Ssam } 20311576Ssam 20411576Ssam /* 20513049Ssam * Map interface name to 20613049Ssam * interface structure pointer. 20711576Ssam */ 20813049Ssam struct ifnet * 20913049Ssam ifunit(name) 21013049Ssam register char *name; 21111576Ssam { 21213049Ssam register char *cp; 21311576Ssam register struct ifnet *ifp; 21413049Ssam int unit; 21511576Ssam 21613049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 21711576Ssam if (*cp >= '0' && *cp <= '9') 21811576Ssam break; 21913049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 22013049Ssam return ((struct ifnet *)0); 22116135Skarels unit = *cp - '0'; 22211576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 22313049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 22411576Ssam continue; 22511576Ssam if (unit == ifp->if_unit) 22613049Ssam break; 22711576Ssam } 22813049Ssam return (ifp); 22913049Ssam } 23011576Ssam 23113049Ssam /* 23213049Ssam * Interface ioctls. 23313049Ssam */ 23418544Skarels ifioctl(so, cmd, data) 23518544Skarels struct socket *so; 23613049Ssam int cmd; 23713049Ssam caddr_t data; 23813049Ssam { 23913049Ssam register struct ifnet *ifp; 24013049Ssam register struct ifreq *ifr; 24113049Ssam 24211576Ssam switch (cmd) { 24311576Ssam 24413049Ssam case SIOCGIFCONF: 24513049Ssam return (ifconf(cmd, data)); 24613049Ssam 24725647Skarels #if defined(INET) && NETHER > 0 24816220Skarels case SIOCSARP: 24916220Skarels case SIOCDARP: 25016220Skarels if (!suser()) 25116220Skarels return (u.u_error); 25216220Skarels /* FALL THROUGH */ 25316220Skarels case SIOCGARP: 25416220Skarels return (arpioctl(cmd, data)); 25516220Skarels #endif 25613049Ssam } 25713049Ssam ifr = (struct ifreq *)data; 25813049Ssam ifp = ifunit(ifr->ifr_name); 25913049Ssam if (ifp == 0) 26013049Ssam return (ENXIO); 26113049Ssam switch (cmd) { 26213049Ssam 26311576Ssam case SIOCGIFFLAGS: 26411576Ssam ifr->ifr_flags = ifp->if_flags; 26511576Ssam break; 26611576Ssam 26726091Skarels case SIOCGIFMETRIC: 26826091Skarels ifr->ifr_metric = ifp->if_metric; 26926091Skarels break; 27026091Skarels 27113053Ssam case SIOCSIFFLAGS: 27225565Sbloom if (!suser()) 27325565Sbloom return (u.u_error); 27413053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 27513053Ssam int s = splimp(); 27613053Ssam if_down(ifp); 27713053Ssam splx(s); 27813053Ssam } 27918544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 28018544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 28124773Skarels if (ifp->if_ioctl) 28224773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 28313053Ssam break; 28413053Ssam 28526091Skarels case SIOCSIFMETRIC: 28626091Skarels if (!suser()) 28726091Skarels return (u.u_error); 28826091Skarels ifp->if_metric = ifr->ifr_metric; 28926091Skarels break; 29026091Skarels 29111576Ssam default: 29218544Skarels if (so->so_proto == 0) 29313049Ssam return (EOPNOTSUPP); 29418544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 29518544Skarels cmd, data, ifp)); 29611576Ssam } 29711576Ssam return (0); 29811576Ssam } 29911576Ssam 30011576Ssam /* 30111576Ssam * Return interface configuration 30211576Ssam * of system. List may be used 30311576Ssam * in later ioctl's (above) to get 30411576Ssam * other information. 30511576Ssam */ 30612783Ssam /*ARGSUSED*/ 30711576Ssam ifconf(cmd, data) 30811576Ssam int cmd; 30911576Ssam caddr_t data; 31011576Ssam { 31111576Ssam register struct ifconf *ifc = (struct ifconf *)data; 31211576Ssam register struct ifnet *ifp = ifnet; 31318544Skarels register struct ifaddr *ifa; 31411630Ssam register char *cp, *ep; 31511630Ssam struct ifreq ifr, *ifrp; 31611576Ssam int space = ifc->ifc_len, error = 0; 31711576Ssam 31811630Ssam ifrp = ifc->ifc_req; 31911630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 32011576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 32111630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 32211630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 32311576Ssam ; 32411630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 32518544Skarels if ((ifa = ifp->if_addrlist) == 0) { 32618544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 32718544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 32818544Skarels if (error) 32918544Skarels break; 33018544Skarels space -= sizeof (ifr), ifrp++; 33118544Skarels } else 33218544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 33318544Skarels ifr.ifr_addr = ifa->ifa_addr; 33418544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 33518544Skarels if (error) 33618544Skarels break; 33718544Skarels space -= sizeof (ifr), ifrp++; 33818544Skarels } 33911576Ssam } 34011576Ssam ifc->ifc_len -= space; 34111576Ssam return (error); 34211576Ssam } 343