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 634844Sbostic * provided that the above copyright notice and this paragraph are 734844Sbostic * duplicated in all such forms and that any documentation, 834844Sbostic * advertising materials, and other materials related to such 934844Sbostic * distribution and use acknowledge that the software was developed 1034844Sbostic * by the University of California, Berkeley. The name of the 1134844Sbostic * University may not be used to endorse or promote products derived 1234844Sbostic * from this software without specific prior written permission. 1334844Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434844Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534844Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633183Sbostic * 17*41545Smckusick * @(#)if.c 7.10 (Berkeley) 05/10/90 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 "user.h" 2717036Sbloom #include "kernel.h" 2817036Sbloom #include "ioctl.h" 2917036Sbloom #include "errno.h" 3010872Ssam 3117036Sbloom #include "if.h" 3217036Sbloom #include "af.h" 3340792Ssklower #include "if_dl.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 7140792Ssklower int if_index = 0; 726333Ssam /* 736333Ssam * Attach an interface to the 746333Ssam * list of "active" interfaces. 756333Ssam */ 765160Swnj if_attach(ifp) 775160Swnj struct ifnet *ifp; 785160Swnj { 795698Swnj register struct ifnet **p = &ifnet; 8040792Ssklower unsigned socksize, ifasize; 8140792Ssklower int namelen, unitlen; 8240792Ssklower char workbuf[16]; 8340792Ssklower register struct sockaddr_dl *sdl; 8440792Ssklower register struct ifaddr *ifa; 855160Swnj 865698Swnj while (*p) 875698Swnj p = &((*p)->if_next); 885698Swnj *p = ifp; 8940792Ssklower ifp->if_index = ++if_index; 9040792Ssklower /* create a link level name for this device */ 9140792Ssklower sprint_d(workbuf, ifp->if_unit); 9240792Ssklower namelen = strlen(ifp->if_name); 9340792Ssklower unitlen = strlen(workbuf); 9440792Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 9540792Ssklower socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) + 9640792Ssklower unitlen + namelen + ifp->if_addrlen; 9740792Ssklower #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 9840792Ssklower socksize = ROUNDUP(socksize); 9940792Ssklower ifasize = sizeof(*ifa) + 2 * socksize; 10040792Ssklower ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); 10140792Ssklower if (ifa == 0) 10240792Ssklower return; 10340792Ssklower bzero((caddr_t)ifa, ifasize); 10440792Ssklower sdl = (struct sockaddr_dl *)(ifa + 1); 10540792Ssklower ifa->ifa_addr = (struct sockaddr *)sdl; 10640792Ssklower ifa->ifa_ifp = ifp; 10740792Ssklower sdl->sdl_len = socksize; 10840792Ssklower sdl->sdl_family = AF_LINK; 10940792Ssklower bcopy(ifp->if_name, sdl->sdl_data, namelen); 11040792Ssklower bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen); 11140792Ssklower sdl->sdl_nlen = (namelen += unitlen); 11240792Ssklower sdl->sdl_index = ifp->if_index; 11340792Ssklower sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 11440792Ssklower ifa->ifa_netmask = (struct sockaddr *)sdl; 11540792Ssklower sdl->sdl_len = socksize - ifp->if_addrlen; 11640792Ssklower while (namelen != 0) 11740792Ssklower sdl->sdl_data[--namelen] = 0xff; 11840792Ssklower ifa->ifa_next = ifp->if_addrlist; 11940792Ssklower ifp->if_addrlist = ifa; 1205160Swnj } 1215160Swnj 1226333Ssam /* 1236333Ssam * Locate an interface based on a complete address. 1246333Ssam */ 1254951Swnj /*ARGSUSED*/ 12618544Skarels struct ifaddr * 12718544Skarels ifa_ifwithaddr(addr) 12837549Smckusick register struct sockaddr *addr; 1294944Swnj { 1304944Swnj register struct ifnet *ifp; 13118544Skarels register struct ifaddr *ifa; 1324944Swnj 1336333Ssam #define equal(a1, a2) \ 13437549Smckusick (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 13518544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 13618544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 13737549Smckusick if (ifa->ifa_addr->sa_family != addr->sa_family) 1386333Ssam continue; 13937549Smckusick if (equal(addr, ifa->ifa_addr)) 14018544Skarels return (ifa); 1416333Ssam if ((ifp->if_flags & IFF_BROADCAST) && 14218544Skarels equal(&ifa->ifa_broadaddr, addr)) 14318544Skarels return (ifa); 1446333Ssam } 14518544Skarels return ((struct ifaddr *)0); 1464944Swnj } 14723933Ssklower /* 14823933Ssklower * Locate the point to point interface with a given destination address. 14923933Ssklower */ 15023933Ssklower /*ARGSUSED*/ 15123933Ssklower struct ifaddr * 15223933Ssklower ifa_ifwithdstaddr(addr) 15337549Smckusick register struct sockaddr *addr; 15423933Ssklower { 15523933Ssklower register struct ifnet *ifp; 15623933Ssklower register struct ifaddr *ifa; 1574944Swnj 15823933Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) 15923933Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 16023933Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 16137549Smckusick if (ifa->ifa_addr->sa_family != addr->sa_family) 16223933Ssklower continue; 16337549Smckusick if (equal(addr, ifa->ifa_dstaddr)) 16423933Ssklower return (ifa); 16523933Ssklower } 16623933Ssklower return ((struct ifaddr *)0); 16723933Ssklower } 16823933Ssklower 1696333Ssam /* 1706333Ssam * Find an interface on a specific network. If many, choice 1716333Ssam * is first found. 1726333Ssam */ 17318544Skarels struct ifaddr * 17418544Skarels ifa_ifwithnet(addr) 17537549Smckusick struct sockaddr *addr; 1764944Swnj { 1774944Swnj register struct ifnet *ifp; 17818544Skarels register struct ifaddr *ifa; 17937549Smckusick register char *cp, *cp2, *cp3; 18037549Smckusick register char *cplim; 18137549Smckusick u_int af = addr->sa_family; 1824944Swnj 1836619Ssam if (af >= AF_MAX) 1846619Ssam return (0); 18518544Skarels for (ifp = ifnet; ifp; ifp = ifp->if_next) 18618544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 18737549Smckusick if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0) 1886333Ssam continue; 18937549Smckusick cp = addr->sa_data; 19037549Smckusick cp2 = ifa->ifa_addr->sa_data; 19137549Smckusick cp3 = ifa->ifa_netmask->sa_data; 19237549Smckusick cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 19337549Smckusick for (; cp3 < cplim; cp3++) 19437549Smckusick if ((*cp++ ^ *cp2++) & *cp3) 19537549Smckusick break; 19637549Smckusick if (cp3 == cplim) 19718544Skarels return (ifa); 19837549Smckusick } 19918544Skarels return ((struct ifaddr *)0); 2006333Ssam } 2016333Ssam 20228942Skarels #ifdef notdef 2036333Ssam /* 2046333Ssam * Find an interface using a specific address family 2056333Ssam */ 20618544Skarels struct ifaddr * 20718544Skarels ifa_ifwithaf(af) 2086333Ssam register int af; 2095083Swnj { 2106333Ssam register struct ifnet *ifp; 21118544Skarels register struct ifaddr *ifa; 2125083Swnj 2136333Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) 21418544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 21537549Smckusick if (ifa->ifa_addr->sa_family == af) 21618544Skarels return (ifa); 21718544Skarels return ((struct ifaddr *)0); 2185083Swnj } 21928942Skarels #endif 2205104Swnj 2216333Ssam /* 2226582Ssam * Mark an interface down and notify protocols of 2236582Ssam * the transition. 2249184Ssam * NOTE: must be called at splnet or eqivalent. 2256582Ssam */ 2266582Ssam if_down(ifp) 2276582Ssam register struct ifnet *ifp; 2286582Ssam { 22918544Skarels register struct ifaddr *ifa; 2308173Sroot 2316582Ssam ifp->if_flags &= ~IFF_UP; 23218544Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 23337549Smckusick pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 23433984Skarels if_qflush(&ifp->if_snd); 2356582Ssam } 2367264Ssam 2377264Ssam /* 23833984Skarels * Flush an interface queue. 23933984Skarels */ 24033984Skarels if_qflush(ifq) 24133984Skarels register struct ifqueue *ifq; 24233984Skarels { 24333984Skarels register struct mbuf *m, *n; 24433984Skarels 24533984Skarels n = ifq->ifq_head; 24633984Skarels while (m = n) { 24733984Skarels n = m->m_act; 24833984Skarels m_freem(m); 24933984Skarels } 25033984Skarels ifq->ifq_head = 0; 25133984Skarels ifq->ifq_tail = 0; 25233984Skarels ifq->ifq_len = 0; 25333984Skarels } 25433984Skarels 25533984Skarels /* 2567264Ssam * Handle interface watchdog timer routines. Called 2577264Ssam * from softclock, we decrement timers (if set) and 2587264Ssam * call the appropriate interface routine on expiration. 2597264Ssam */ 2607264Ssam if_slowtimo() 2617264Ssam { 2627264Ssam register struct ifnet *ifp; 26337549Smckusick int s = splimp(); 2647264Ssam 2659184Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 2669184Ssam if (ifp->if_timer == 0 || --ifp->if_timer) 2679184Ssam continue; 2689184Ssam if (ifp->if_watchdog) 2697264Ssam (*ifp->if_watchdog)(ifp->if_unit); 2709184Ssam } 27137549Smckusick splx(s); 2728692Sroot timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ); 2737264Ssam } 27411576Ssam 27511576Ssam /* 27613049Ssam * Map interface name to 27713049Ssam * interface structure pointer. 27811576Ssam */ 27913049Ssam struct ifnet * 28013049Ssam ifunit(name) 28113049Ssam register char *name; 28211576Ssam { 28313049Ssam register char *cp; 28411576Ssam register struct ifnet *ifp; 28513049Ssam int unit; 28636821Skarels unsigned len; 28736821Skarels char *ep, c; 28811576Ssam 28913049Ssam for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) 29011576Ssam if (*cp >= '0' && *cp <= '9') 29111576Ssam break; 29213049Ssam if (*cp == '\0' || cp == name + IFNAMSIZ) 29313049Ssam return ((struct ifnet *)0); 29436821Skarels /* 29536821Skarels * Save first char of unit, and pointer to it, 29636821Skarels * so we can put a null there to avoid matching 29736821Skarels * initial substrings of interface names. 29836821Skarels */ 29936821Skarels len = cp - name + 1; 30036821Skarels c = *cp; 30136821Skarels ep = cp; 30236821Skarels for (unit = 0; *cp >= '0' && *cp <= '9'; ) 30336821Skarels unit = unit * 10 + *cp++ - '0'; 30436821Skarels *ep = 0; 30511576Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 30636821Skarels if (bcmp(ifp->if_name, name, len)) 30711576Ssam continue; 30811576Ssam if (unit == ifp->if_unit) 30913049Ssam break; 31011576Ssam } 31136821Skarels *ep = c; 31213049Ssam return (ifp); 31313049Ssam } 31411576Ssam 31513049Ssam /* 31613049Ssam * Interface ioctls. 31713049Ssam */ 31818544Skarels ifioctl(so, cmd, data) 31918544Skarels struct socket *so; 32013049Ssam int cmd; 32113049Ssam caddr_t data; 32213049Ssam { 32313049Ssam register struct ifnet *ifp; 32413049Ssam register struct ifreq *ifr; 32537549Smckusick int error; 32613049Ssam 32711576Ssam switch (cmd) { 32811576Ssam 32913049Ssam case SIOCGIFCONF: 33037549Smckusick case OSIOCGIFCONF: 33113049Ssam return (ifconf(cmd, data)); 33213049Ssam 33325647Skarels #if defined(INET) && NETHER > 0 33416220Skarels case SIOCSARP: 33516220Skarels case SIOCDARP: 33637549Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 33737549Smckusick return (error); 33816220Skarels /* FALL THROUGH */ 33916220Skarels case SIOCGARP: 34037549Smckusick case OSIOCGARP: 34116220Skarels return (arpioctl(cmd, data)); 34216220Skarels #endif 34313049Ssam } 34413049Ssam ifr = (struct ifreq *)data; 34513049Ssam ifp = ifunit(ifr->ifr_name); 34613049Ssam if (ifp == 0) 34713049Ssam return (ENXIO); 34813049Ssam switch (cmd) { 34913049Ssam 35011576Ssam case SIOCGIFFLAGS: 35111576Ssam ifr->ifr_flags = ifp->if_flags; 35211576Ssam break; 35311576Ssam 35426091Skarels case SIOCGIFMETRIC: 35526091Skarels ifr->ifr_metric = ifp->if_metric; 35626091Skarels break; 35726091Skarels 35813053Ssam case SIOCSIFFLAGS: 35937549Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 36037549Smckusick return (error); 36113053Ssam if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { 36213053Ssam int s = splimp(); 36313053Ssam if_down(ifp); 36413053Ssam splx(s); 36513053Ssam } 36618544Skarels ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 36718544Skarels (ifr->ifr_flags &~ IFF_CANTCHANGE); 36824773Skarels if (ifp->if_ioctl) 36924773Skarels (void) (*ifp->if_ioctl)(ifp, cmd, data); 37013053Ssam break; 37113053Ssam 37226091Skarels case SIOCSIFMETRIC: 37337549Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 37437549Smckusick return (error); 37526091Skarels ifp->if_metric = ifr->ifr_metric; 37626091Skarels break; 37726091Skarels 37811576Ssam default: 37918544Skarels if (so->so_proto == 0) 38013049Ssam return (EOPNOTSUPP); 38137549Smckusick #ifndef COMPAT_43 38218544Skarels return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 38318544Skarels cmd, data, ifp)); 38437549Smckusick #else 38537549Smckusick { 386*41545Smckusick int ocmd = cmd; 38737549Smckusick 38837549Smckusick switch (cmd) { 38937549Smckusick 39037549Smckusick case SIOCSIFDSTADDR: 39137549Smckusick case SIOCSIFADDR: 39237549Smckusick case SIOCSIFBRDADDR: 39337549Smckusick case SIOCSIFNETMASK: 39437549Smckusick #if BYTE_ORDER != BIG_ENDIAN 39537549Smckusick if (ifr->ifr_addr.sa_family == 0 && 39637549Smckusick ifr->ifr_addr.sa_len < 16) { 39737549Smckusick ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 39837549Smckusick ifr->ifr_addr.sa_len = 16; 39937549Smckusick } 40037549Smckusick #else 40137549Smckusick if (ifr->ifr_addr.sa_len == 0) 40237549Smckusick ifr->ifr_addr.sa_len = 16; 40337549Smckusick #endif 40437549Smckusick break; 40537549Smckusick 40637549Smckusick case OSIOCGIFADDR: 40737549Smckusick cmd = SIOCGIFADDR; 40837549Smckusick break; 40937549Smckusick 41037549Smckusick case OSIOCGIFDSTADDR: 41137549Smckusick cmd = SIOCGIFDSTADDR; 41237549Smckusick break; 41337549Smckusick 41437549Smckusick case OSIOCGIFBRDADDR: 41537549Smckusick cmd = SIOCGIFBRDADDR; 41637549Smckusick break; 41737549Smckusick 41837549Smckusick case OSIOCGIFNETMASK: 41937549Smckusick cmd = SIOCGIFNETMASK; 42037549Smckusick } 42137549Smckusick error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 42237549Smckusick cmd, data, ifp)); 42337549Smckusick switch (ocmd) { 42437549Smckusick 42537549Smckusick case OSIOCGIFADDR: 42637549Smckusick case OSIOCGIFDSTADDR: 42737549Smckusick case OSIOCGIFBRDADDR: 42837549Smckusick case OSIOCGIFNETMASK: 42937549Smckusick *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 43037549Smckusick } 43137549Smckusick return (error); 43237549Smckusick 43337549Smckusick } 43437549Smckusick #endif 43511576Ssam } 43611576Ssam return (0); 43711576Ssam } 43811576Ssam 43911576Ssam /* 44011576Ssam * Return interface configuration 44111576Ssam * of system. List may be used 44211576Ssam * in later ioctl's (above) to get 44311576Ssam * other information. 44411576Ssam */ 44512783Ssam /*ARGSUSED*/ 44611576Ssam ifconf(cmd, data) 44711576Ssam int cmd; 44811576Ssam caddr_t data; 44911576Ssam { 45011576Ssam register struct ifconf *ifc = (struct ifconf *)data; 45111576Ssam register struct ifnet *ifp = ifnet; 45218544Skarels register struct ifaddr *ifa; 45311630Ssam register char *cp, *ep; 45411630Ssam struct ifreq ifr, *ifrp; 45511576Ssam int space = ifc->ifc_len, error = 0; 45611576Ssam 45711630Ssam ifrp = ifc->ifc_req; 45811630Ssam ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2; 45911576Ssam for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { 46011630Ssam bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2); 46111630Ssam for (cp = ifr.ifr_name; cp < ep && *cp; cp++) 46211576Ssam ; 46311630Ssam *cp++ = '0' + ifp->if_unit; *cp = '\0'; 46418544Skarels if ((ifa = ifp->if_addrlist) == 0) { 46518544Skarels bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 46618544Skarels error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr)); 46718544Skarels if (error) 46818544Skarels break; 46918544Skarels space -= sizeof (ifr), ifrp++; 47018544Skarels } else 47118544Skarels for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { 47237549Smckusick register struct sockaddr *sa = ifa->ifa_addr; 47337549Smckusick #ifdef COMPAT_43 47437549Smckusick if (cmd == OSIOCGIFCONF) { 47537549Smckusick struct osockaddr *osa = 47637549Smckusick (struct osockaddr *)&ifr.ifr_addr; 47737549Smckusick ifr.ifr_addr = *sa; 47837549Smckusick osa->sa_family = sa->sa_family; 47937549Smckusick error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 48037549Smckusick sizeof (ifr)); 48137549Smckusick ifrp++; 48237549Smckusick } else 48337549Smckusick #endif 48437549Smckusick if (sa->sa_len <= sizeof(*sa)) { 48537549Smckusick ifr.ifr_addr = *sa; 48637549Smckusick error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 48737549Smckusick sizeof (ifr)); 48837549Smckusick ifrp++; 48937549Smckusick } else { 49037549Smckusick space -= sa->sa_len - sizeof(*sa); 49137549Smckusick if (space < sizeof (ifr)) 49237549Smckusick break; 49337549Smckusick error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 49437549Smckusick sizeof (ifr.ifr_name)); 49537549Smckusick if (error == 0) 49637549Smckusick error = copyout((caddr_t)sa, 49737549Smckusick (caddr_t)&ifrp->ifr_addr, sa->sa_len); 49837549Smckusick ifrp = (struct ifreq *) 49937549Smckusick (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 50037549Smckusick } 50118544Skarels if (error) 50218544Skarels break; 50337549Smckusick space -= sizeof (ifr); 50418544Skarels } 50511576Ssam } 50611576Ssam ifc->ifc_len -= space; 50711576Ssam return (error); 50811576Ssam } 50940792Ssklower 51040792Ssklower static sprint_d(cp, n) 51140792Ssklower register char *cp; 51240792Ssklower u_short n; 51340792Ssklower { 51440792Ssklower register int q, m; 51540792Ssklower do { 51640792Ssklower if (n >= 10000) m = 10000; 51740792Ssklower else if (n >= 1000) m = 1000; 51840792Ssklower else if (n >= 100) m = 100; 51940792Ssklower else if (n >= 10) m = 10; 52040792Ssklower else m = 1; 52140792Ssklower q = n / m; 52240792Ssklower n -= m * q; 52340792Ssklower if (q > 9) q = 10; /* For crays with more than 100K interfaces */ 52440792Ssklower *cp++ = "0123456789Z"[q]; 52540792Ssklower } while (n > 0); 52640792Ssklower *cp++ = 0; 52740792Ssklower } 528