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 6*34844Sbostic * provided that the above copyright notice and this paragraph are 7*34844Sbostic * duplicated in all such forms and that any documentation, 8*34844Sbostic * advertising materials, and other materials related to such 9*34844Sbostic * distribution and use acknowledge that the software was developed 10*34844Sbostic * by the University of California, Berkeley. The name of the 11*34844Sbostic * University may not be used to endorse or promote products derived 12*34844Sbostic * from this software without specific prior written permission. 13*34844Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34844Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34844Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633183Sbostic * 17*34844Sbostic * @(#)if.c 7.4 (Berkeley) 06/27/88 1823157Smckusick */ 194944Swnj 2017036Sbloom #include "param.h" 2133984Skarels #include "mbuf.h" 2217036Sbloom #include "systm.h" 2317036Sbloom #include "socket.h" 2418544Skarels #include "socketvar.h" 2517036Sbloom #include "protosw.h" 2617036Sbloom #include "dir.h" 2717036Sbloom #include "user.h" 2817036Sbloom #include "kernel.h" 2917036Sbloom #include "ioctl.h" 3017036Sbloom #include "errno.h" 3110872Ssam 3217036Sbloom #include "if.h" 3317036Sbloom #include "af.h" 344944Swnj 3516220Skarels #include "ether.h" 3616220Skarels 376207Swnj int ifqmaxlen = IFQ_MAXLEN; 386207Swnj 396333Ssam /* 406333Ssam * Network interface utility routines. 416333Ssam * 4218544Skarels * Routines with ifa_ifwith* names take sockaddr *'s as 4318544Skarels * parameters. 446333Ssam */ 456333Ssam 465206Swnj ifinit() 475206Swnj { 485206Swnj register struct ifnet *ifp; 495206Swnj 505206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 5124773Skarels if (ifp->if_snd.ifq_maxlen == 0) 5224773Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 538173Sroot if_slowtimo(); 545206Swnj } 555206Swnj 5613049Ssam #ifdef vax 576333Ssam /* 586333Ssam * Call each interface on a Unibus reset. 596333Ssam */ 605206Swnj ifubareset(uban) 615206Swnj int uban; 625206Swnj { 635206Swnj register struct ifnet *ifp; 645206Swnj 655206Swnj for (ifp = ifnet; ifp; ifp = ifp->if_next) 668974Sroot if (ifp->if_reset) 6715116Ssam (*ifp->if_reset)(ifp->if_unit, uban); 685206Swnj } 698393Swnj #endif 705206Swnj 716333Ssam /* 726333Ssam * Attach an interface to the 736333Ssam * list of "active" interfaces. 746333Ssam */ 755160Swnj if_attach(ifp) 765160Swnj struct ifnet *ifp; 775160Swnj { 785698Swnj register struct ifnet **p = &ifnet; 795160Swnj 805698Swnj while (*p) 815698Swnj p = &((*p)->if_next); 825698Swnj *p = ifp; 835160Swnj } 845160Swnj 856333Ssam /* 866333Ssam * Locate an interface based on a complete address. 876333Ssam */ 884951Swnj /*ARGSUSED*/ 8918544Skarels struct ifaddr * 9018544Skarels ifa_ifwithaddr(addr) 916333Ssam struct sockaddr *addr; 924944Swnj { 934944Swnj register struct ifnet *ifp; 9418544Skarels register struct ifaddr *ifa; 954944Swnj 966333Ssam #define equal(a1, a2) \ 976333Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 9818544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 9918544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 10018544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1016333Ssam continue; 10218544Skarels if (equal(&ifa->ifa_addr, addr)) 10318544Skarels return (ifa); 1046333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 10518544Skarels equal(&ifa->ifa_broadaddr, addr)) 10618544Skarels return (ifa); 1076333Ssam } 10818544Skarels return ((struct ifaddr *)0); 1094944Swnj } 11023933Ssklower /* 11123933Ssklower * Locate the point to point interface with a given destination address. 11223933Ssklower */ 11323933Ssklower /*ARGSUSED*/ 11423933Ssklower struct ifaddr * 11523933Ssklower ifa_ifwithdstaddr(addr) 11623933Ssklower struct sockaddr *addr; 11723933Ssklower { 11823933Ssklower register struct ifnet *ifp; 11923933Ssklower register struct ifaddr *ifa; 1204944Swnj 12123933Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) 12223933Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 12323933Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 12423933Ssklower if (ifa->ifa_addr.sa_family != addr->sa_family) 12523933Ssklower continue; 12623933Ssklower if (equal(&ifa->ifa_dstaddr, addr)) 12723933Ssklower return (ifa); 12823933Ssklower } 12923933Ssklower return ((struct ifaddr *)0); 13023933Ssklower } 13123933Ssklower 1326333Ssam /* 1336333Ssam * Find an interface on a specific network. If many, choice 1346333Ssam * is first found. 1356333Ssam */ 13618544Skarels struct ifaddr * 13718544Skarels ifa_ifwithnet(addr) 1386333Ssam register struct sockaddr *addr; 1394944Swnj { 1404944Swnj register struct ifnet *ifp; 14118544Skarels register struct ifaddr *ifa; 1428393Swnj register u_int af = addr->sa_family; 1436619Ssam register int (*netmatch)(); 1444944Swnj 1456619Ssam if (af >= AF_MAX) 1466619Ssam return (0); 1476619Ssam netmatch = afswitch[af].af_netmatch; 14818544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 14918544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 15018544Skarels if (ifa->ifa_addr.sa_family != addr->sa_family) 1516333Ssam continue; 15218544Skarels if ((*netmatch)(&ifa->ifa_addr, addr)) 15318544Skarels return (ifa); 1546333Ssam } 15518544Skarels return ((struct ifaddr *)0); 1566333Ssam } 1576333Ssam 15828942Skarels #ifdef notdef 1596333Ssam /* 1606333Ssam * Find an interface using a specific address family 1616333Ssam */ 16218544Skarels struct ifaddr * 16318544Skarels ifa_ifwithaf(af) 1646333Ssam register int af; 1655083Swnj { 1666333Ssam register struct ifnet *ifp; 16718544Skarels register struct ifaddr *ifa; 1685083Swnj 1696333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 17018544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 17118544Skarels if (ifa->ifa_addr.sa_family == af) 17218544Skarels return (ifa); 17318544Skarels return ((struct ifaddr *)0); 1745083Swnj } 17528942Skarels #endif 1765104Swnj 1776333Ssam /* 1786582Ssam * Mark an interface down and notify protocols of 1796582Ssam * the transition. 1809184Ssam * NOTE: must be called at splnet or eqivalent. 1816582Ssam */ 1826582Ssam if_down(ifp) 1836582Ssam register struct ifnet *ifp; 1846582Ssam { 18518544Skarels register struct ifaddr *ifa; 1868173Sroot 1876582Ssam ifp->if_flags &= ~IFF_UP; 18818544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 18924773Skarels pfctlinput(PRC_IFDOWN, &ifa->ifa_addr); 19033984Skarels if_qflush(&ifp->if_snd); 1916582Ssam } 1927264Ssam 1937264Ssam /* 19433984Skarels * Flush an interface queue. 19533984Skarels */ 19633984Skarels if_qflush(ifq) 19733984Skarels register struct ifqueue *ifq; 19833984Skarels { 19933984Skarels register struct mbuf *m, *n; 20033984Skarels 20133984Skarels n = ifq->ifq_head; 20233984Skarels while (m = n) { 20333984Skarels n = m->m_act; 20433984Skarels m_freem(m); 20533984Skarels } 20633984Skarels ifq->ifq_head = 0; 20733984Skarels ifq->ifq_tail = 0; 20833984Skarels ifq->ifq_len = 0; 20933984Skarels } 21033984Skarels 21133984Skarels /* 2127264Ssam * Handle interface watchdog timer routines. Called 2137264Ssam * from softclock, we decrement timers (if set) and 2147264Ssam * call the appropriate interface routine on expiration. 2157264Ssam */ 2167264Ssam if_slowtimo() 2177264Ssam { 2187264Ssam register struct ifnet *ifp; 2197264Ssam 2209184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 2219184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 2229184Ssam continue; 2239184Ssam if (ifp->if_watchdog) 2247264Ssam (*ifp->if_watchdog)(ifp->if_unit); 2259184Ssam } 2268692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 2277264Ssam } 22811576Ssam 22911576Ssam /* 23013049Ssam * Map interface name to 23113049Ssam * interface structure pointer. 23211576Ssam */ 23313049Ssam struct ifnet * 23413049Ssam ifunit(name) 23513049Ssam register char *name; 23611576Ssam { 23713049Ssam register char *cp; 23811576Ssam register struct ifnet *ifp; 23913049Ssam int unit; 24011576Ssam 24113049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 24211576Ssam if (*cp >= '0' && *cp <= '9') 24311576Ssam break; 24413049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 24513049Ssam return ((struct ifnet *)0); 24616135Skarels unit = *cp - '0'; 24711576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 24813049Ssam if (bcmp(ifp->if_name, name, (unsigned)(cp - name))) 24911576Ssam continue; 25011576Ssam if (unit == ifp->if_unit) 25113049Ssam break; 25211576Ssam } 25313049Ssam return (ifp); 25413049Ssam } 25511576Ssam 25613049Ssam /* 25713049Ssam * Interface ioctls. 25813049Ssam */ 25918544Skarels ifioctl(so, cmd, data) 26018544Skarels struct socket *so; 26113049Ssam int cmd; 26213049Ssam caddr_t data; 26313049Ssam { 26413049Ssam register struct ifnet *ifp; 26513049Ssam register struct ifreq *ifr; 26613049Ssam 26711576Ssam switch (cmd) { 26811576Ssam 26913049Ssam case SIOCGIFCONF: 27013049Ssam return (ifconf(cmd, data)); 27113049Ssam 27225647Skarels #if defined(INET) && NETHER > 0 27316220Skarels case SIOCSARP: 27416220Skarels case SIOCDARP: 27516220Skarels if (!suser()) 27616220Skarels return (u.u_error); 27716220Skarels /* FALL THROUGH */ 27816220Skarels case SIOCGARP: 27916220Skarels return (arpioctl(cmd, data)); 28016220Skarels #endif 28113049Ssam } 28213049Ssam ifr = (struct ifreq *)data; 28313049Ssam ifp = ifunit(ifr->ifr_name); 28413049Ssam if (ifp == 0) 28513049Ssam return (ENXIO); 28613049Ssam switch (cmd) { 28713049Ssam 28811576Ssam case SIOCGIFFLAGS: 28911576Ssam ifr->ifr_flags = ifp->if_flags; 29011576Ssam break; 29111576Ssam 29226091Skarels case SIOCGIFMETRIC: 29326091Skarels ifr->ifr_metric = ifp->if_metric; 29426091Skarels break; 29526091Skarels 29613053Ssam case SIOCSIFFLAGS: 29725565Sbloom if (!suser()) 29825565Sbloom return (u.u_error); 29913053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 30013053Ssam int s = splimp(); 30113053Ssam if_down(ifp); 30213053Ssam splx(s); 30313053Ssam } 30418544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 30518544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 30624773Skarels if (ifp->if_ioctl) 30724773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 30813053Ssam break; 30913053Ssam 31026091Skarels case SIOCSIFMETRIC: 31126091Skarels if (!suser()) 31226091Skarels return (u.u_error); 31326091Skarels ifp->if_metric = ifr->ifr_metric; 31426091Skarels break; 31526091Skarels 31611576Ssam default: 31718544Skarels if (so->so_proto == 0) 31813049Ssam return (EOPNOTSUPP); 31918544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 32018544Skarels cmd, data, ifp)); 32111576Ssam } 32211576Ssam return (0); 32311576Ssam } 32411576Ssam 32511576Ssam /* 32611576Ssam * Return interface configuration 32711576Ssam * of system. List may be used 32811576Ssam * in later ioctl's (above) to get 32911576Ssam * other information. 33011576Ssam */ 33112783Ssam /*ARGSUSED*/ 33211576Ssam ifconf(cmd, data) 33311576Ssam int cmd; 33411576Ssam caddr_t data; 33511576Ssam { 33611576Ssam register struct ifconf *ifc = (struct ifconf *)data; 33711576Ssam register struct ifnet *ifp = ifnet; 33818544Skarels register struct ifaddr *ifa; 33911630Ssam register char *cp, *ep; 34011630Ssam struct ifreq ifr, *ifrp; 34111576Ssam int space = ifc->ifc_len, error = 0; 34211576Ssam 34311630Ssam ifrp = ifc->ifc_req; 34411630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 34511576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 34611630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 34711630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 34811576Ssam ; 34911630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 35018544Skarels if ((ifa = ifp->if_addrlist) == 0) { 35118544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 35218544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 35318544Skarels if (error) 35418544Skarels break; 35518544Skarels space -= sizeof (ifr), ifrp++; 35618544Skarels } else 35718544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 35818544Skarels ifr.ifr_addr = ifa->ifa_addr; 35918544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 36018544Skarels if (error) 36118544Skarels break; 36218544Skarels space -= sizeof (ifr), ifrp++; 36318544Skarels } 36411576Ssam } 36511576Ssam ifc->ifc_len -= space; 36611576Ssam return (error); 36711576Ssam } 368