123157Smckusick /* 229061Smckusick * Copyright (c) 1980, 1986 Regents of the University of California. 333183Sbostic * All rights reserved. 423157Smckusick * 533183Sbostic * Redistribution and use in source and binary forms are permitted 633183Sbostic * provided that this notice is preserved and that due credit is given 733183Sbostic * to the University of California at Berkeley. The name of the University 833183Sbostic * may not be used to endorse or promote products derived from this 933183Sbostic * software without specific prior written permission. This software 1033183Sbostic * is provided ``as is'' without express or implied warranty. 1133183Sbostic * 12*33984Skarels * @(#)if.c 7.3 (Berkeley) 04/07/88 1323157Smckusick */ 144944Swnj 1517036Sbloom #include "param.h" 16*33984Skarels #include "mbuf.h" 1717036Sbloom #include "systm.h" 1817036Sbloom #include "socket.h" 1918544Skarels #include "socketvar.h" 2017036Sbloom #include "protosw.h" 2117036Sbloom #include "dir.h" 2217036Sbloom #include "user.h" 2317036Sbloom #include "kernel.h" 2417036Sbloom #include "ioctl.h" 2517036Sbloom #include "errno.h" 2610872Ssam 2717036Sbloom #include "if.h" 2817036Sbloom #include "af.h" 294944Swnj 3016220Skarels #include "ether.h" 3116220Skarels 326207Swnj int ifqmaxlen = IFQ_MAXLEN; 336207Swnj 346333Ssam /* 356333Ssam * Network interface utility routines. 366333Ssam * 3718544Skarels * Routines with ifa_ifwith* names take sockaddr *'s as 3818544Skarels * parameters. 396333Ssam */ 406333Ssam 415206Swnj ifinit() 425206Swnj { 435206Swnj register struct ifnet *ifp; 445206Swnj 455206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 4624773Skarels if (ifp->if_snd.ifq_maxlen == 0) 4724773Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 488173Sroot if_slowtimo(); 495206Swnj } 505206Swnj 5113049Ssam #ifdef vax 526333Ssam /* 536333Ssam * Call each interface on a Unibus reset. 546333Ssam */ 555206Swnj ifubareset(uban) 565206Swnj int uban; 575206Swnj { 585206Swnj register struct ifnet *ifp; 595206Swnj 605206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 618974Sroot if (ifp->if_reset) 6215116Ssam (*ifp->if_reset)(ifp->if_unit, uban); 635206Swnj } 648393Swnj #endif 655206Swnj 666333Ssam /* 676333Ssam * Attach an interface to the 686333Ssam * list of "active" interfaces. 696333Ssam */ 705160Swnj if_attach(ifp) 715160Swnj struct ifnet *ifp; 725160Swnj { 735698Swnj register struct ifnet **p = &ifnet; 745160Swnj 755698Swnj while (*p) 765698Swnj p = &((*p)->if_next); 775698Swnj *p = ifp; 785160Swnj } 795160Swnj 806333Ssam /* 816333Ssam * Locate an interface based on a complete address. 826333Ssam */ 834951Swnj /*ARGSUSED*/ 8418544Skarels struct ifaddr * 8518544Skarels ifa_ifwithaddr(addr) 866333Ssam struct sockaddr *addr; 874944Swnj { 884944Swnj register struct ifnet *ifp; 8918544Skarels register struct ifaddr *ifa; 904944Swnj 916333Ssam #define equal(a1, a2) \ 926333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 9318544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 9418544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 9518544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 966333Ssam continue; 9718544Skarels if (equal(&ifa->ifa_addr, addr)) 9818544Skarels return (ifa); 996333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 10018544Skarels equal(&ifa->ifa_broadaddr, addr)) 10118544Skarels return (ifa); 1026333Ssam } 10318544Skarels return ((struct ifaddr *)0); 1044944Swnj } 10523933Ssklower /* 10623933Ssklower * Locate the point to point interface with a given destination address. 10723933Ssklower */ 10823933Ssklower /*ARGSUSED*/ 10923933Ssklower struct ifaddr * 11023933Ssklower ifa_ifwithdstaddr(addr) 11123933Ssklower struct sockaddr *addr; 11223933Ssklower { 11323933Ssklower register struct ifnet *ifp; 11423933Ssklower register struct ifaddr *ifa; 1154944Swnj 11623933Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) 11723933Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 11823933Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 11923933Ssklower if (ifa->ifa_addr.sa_family != addr->sa_family) 12023933Ssklower continue; 12123933Ssklower if (equal(&ifa->ifa_dstaddr, addr)) 12223933Ssklower return (ifa); 12323933Ssklower } 12423933Ssklower return ((struct ifaddr *)0); 12523933Ssklower } 12623933Ssklower 1276333Ssam /* 1286333Ssam * Find an interface on a specific network. If many, choice 1296333Ssam * is first found. 1306333Ssam */ 13118544Skarels struct ifaddr * 13218544Skarels ifa_ifwithnet(addr) 1336333Ssam register struct sockaddr *addr; 1344944Swnj { 1354944Swnj register struct ifnet *ifp; 13618544Skarels register struct ifaddr *ifa; 1378393Swnj register u_int af = addr->sa_family; 1386619Ssam register int (*netmatch)(); 1394944Swnj 1406619Ssam if (af >= AF_MAX) 1416619Ssam return (0); 1426619Ssam netmatch = afswitch[af].af_netmatch; 14318544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 14418544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 14518544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1466333Ssam continue; 14718544Skarels if ((*netmatch)(&ifa->ifa_addr, addr)) 14818544Skarels return (ifa); 1496333Ssam } 15018544Skarels return ((struct ifaddr *)0); 1516333Ssam } 1526333Ssam 15328942Skarels #ifdef notdef 1546333Ssam /* 1556333Ssam * Find an interface using a specific address family 1566333Ssam */ 15718544Skarels struct ifaddr * 15818544Skarels ifa_ifwithaf(af) 1596333Ssam register int af; 1605083Swnj { 1616333Ssam register struct ifnet *ifp; 16218544Skarels register struct ifaddr *ifa; 1635083Swnj 1646333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 16518544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 16618544Skarels if (ifa->ifa_addr.sa_family == af) 16718544Skarels return (ifa); 16818544Skarels return ((struct ifaddr *)0); 1695083Swnj } 17028942Skarels #endif 1715104Swnj 1726333Ssam /* 1736582Ssam * Mark an interface down and notify protocols of 1746582Ssam * the transition. 1759184Ssam * NOTE: must be called at splnet or eqivalent. 1766582Ssam */ 1776582Ssam if_down(ifp) 1786582Ssam register struct ifnet *ifp; 1796582Ssam { 18018544Skarels register struct ifaddr *ifa; 1818173Sroot 1826582Ssam ifp->if_flags &= ~IFF_UP; 18318544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 18424773Skarels pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); 185*33984Skarels if_qflush(&ifp->if_snd); 1866582Ssam } 1877264Ssam 1887264Ssam /* 189*33984Skarels * Flush an interface queue. 190*33984Skarels */ 191*33984Skarels if_qflush(ifq) 192*33984Skarels register struct ifqueue *ifq; 193*33984Skarels { 194*33984Skarels register struct mbuf *m, *n; 195*33984Skarels 196*33984Skarels n = ifq->ifq_head; 197*33984Skarels while (m = n) { 198*33984Skarels n = m->m_act; 199*33984Skarels m_freem(m); 200*33984Skarels } 201*33984Skarels ifq->ifq_head = 0; 202*33984Skarels ifq->ifq_tail = 0; 203*33984Skarels ifq->ifq_len = 0; 204*33984Skarels } 205*33984Skarels 206*33984Skarels /* 2077264Ssam * Handle interface watchdog timer routines. Called 2087264Ssam * from softclock, we decrement timers (if set) and 2097264Ssam * call the appropriate interface routine on expiration. 2107264Ssam */ 2117264Ssam if_slowtimo() 2127264Ssam { 2137264Ssam register struct ifnet *ifp; 2147264Ssam 2159184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 2169184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 2179184Ssam continue; 2189184Ssam if (ifp->if_watchdog) 2197264Ssam (*ifp->if_watchdog)(ifp->if_unit); 2209184Ssam } 2218692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 2227264Ssam } 22311576Ssam 22411576Ssam /* 22513049Ssam * Map interface name to 22613049Ssam * interface structure pointer. 22711576Ssam */ 22813049Ssam struct ifnet * 22913049Ssam ifunit(name) 23013049Ssam register char *name; 23111576Ssam { 23213049Ssam register char *cp; 23311576Ssam register struct ifnet *ifp; 23413049Ssam int unit; 23511576Ssam 23613049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 23711576Ssam if (*cp >= '0' && *cp <= '9') 23811576Ssam break; 23913049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 24013049Ssam return ((struct ifnet *)0); 24116135Skarels unit = *cp - '0'; 24211576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 24313049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 24411576Ssam continue; 24511576Ssam if (unit == ifp->if_unit) 24613049Ssam break; 24711576Ssam } 24813049Ssam return (ifp); 24913049Ssam } 25011576Ssam 25113049Ssam /* 25213049Ssam * Interface ioctls. 25313049Ssam */ 25418544Skarels ifioctl(so, cmd, data) 25518544Skarels struct socket *so; 25613049Ssam int cmd; 25713049Ssam caddr_t data; 25813049Ssam { 25913049Ssam register struct ifnet *ifp; 26013049Ssam register struct ifreq *ifr; 26113049Ssam 26211576Ssam switch (cmd) { 26311576Ssam 26413049Ssam case SIOCGIFCONF: 26513049Ssam return (ifconf(cmd, data)); 26613049Ssam 26725647Skarels #if defined(INET) && NETHER > 0 26816220Skarels case SIOCSARP: 26916220Skarels case SIOCDARP: 27016220Skarels if (!suser()) 27116220Skarels return (u.u_error); 27216220Skarels /* FALL THROUGH */ 27316220Skarels case SIOCGARP: 27416220Skarels return (arpioctl(cmd, data)); 27516220Skarels #endif 27613049Ssam } 27713049Ssam ifr = (struct ifreq *)data; 27813049Ssam ifp = ifunit(ifr->ifr_name); 27913049Ssam if (ifp == 0) 28013049Ssam return (ENXIO); 28113049Ssam switch (cmd) { 28213049Ssam 28311576Ssam case SIOCGIFFLAGS: 28411576Ssam ifr->ifr_flags = ifp->if_flags; 28511576Ssam break; 28611576Ssam 28726091Skarels case SIOCGIFMETRIC: 28826091Skarels ifr->ifr_metric = ifp->if_metric; 28926091Skarels break; 29026091Skarels 29113053Ssam case SIOCSIFFLAGS: 29225565Sbloom if (!suser()) 29325565Sbloom return (u.u_error); 29413053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 29513053Ssam int s = splimp(); 29613053Ssam if_down(ifp); 29713053Ssam splx(s); 29813053Ssam } 29918544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 30018544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 30124773Skarels if (ifp->if_ioctl) 30224773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 30313053Ssam break; 30413053Ssam 30526091Skarels case SIOCSIFMETRIC: 30626091Skarels if (!suser()) 30726091Skarels return (u.u_error); 30826091Skarels ifp->if_metric = ifr->ifr_metric; 30926091Skarels break; 31026091Skarels 31111576Ssam default: 31218544Skarels if (so->so_proto == 0) 31313049Ssam return (EOPNOTSUPP); 31418544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 31518544Skarels cmd, data, ifp)); 31611576Ssam } 31711576Ssam return (0); 31811576Ssam } 31911576Ssam 32011576Ssam /* 32111576Ssam * Return interface configuration 32211576Ssam * of system. List may be used 32311576Ssam * in later ioctl's (above) to get 32411576Ssam * other information. 32511576Ssam */ 32612783Ssam /*ARGSUSED*/ 32711576Ssam ifconf(cmd, data) 32811576Ssam int cmd; 32911576Ssam caddr_t data; 33011576Ssam { 33111576Ssam register struct ifconf *ifc = (struct ifconf *)data; 33211576Ssam register struct ifnet *ifp = ifnet; 33318544Skarels register struct ifaddr *ifa; 33411630Ssam register char *cp, *ep; 33511630Ssam struct ifreq ifr, *ifrp; 33611576Ssam int space = ifc->ifc_len, error = 0; 33711576Ssam 33811630Ssam ifrp = ifc->ifc_req; 33911630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 34011576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 34111630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 34211630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 34311576Ssam ; 34411630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 34518544Skarels if ((ifa = ifp->if_addrlist) == 0) { 34618544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 34718544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 34818544Skarels if (error) 34918544Skarels break; 35018544Skarels space -= sizeof (ifr), ifrp++; 35118544Skarels } else 35218544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 35318544Skarels ifr.ifr_addr = ifa->ifa_addr; 35418544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 35518544Skarels if (error) 35618544Skarels break; 35718544Skarels space -= sizeof (ifr), ifrp++; 35818544Skarels } 35911576Ssam } 36011576Ssam ifc->ifc_len -= space; 36111576Ssam return (error); 36211576Ssam } 363