123204Smckusick /* 2*33371Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3*33371Ssklower * All rights reserved. 423204Smckusick * 5*33371Ssklower * Redistribution and use in source and binary forms are permitted 6*33371Ssklower * provided that this notice is preserved and that due credit is given 7*33371Ssklower * to the University of California at Berkeley. The name of the University 8*33371Ssklower * may not be used to endorse or promote products derived from this 9*33371Ssklower * software without specific prior written permission. This software 10*33371Ssklower * is provided ``as is'' without express or implied warranty. 11*33371Ssklower * 12*33371Ssklower * @(#)ns.c 7.2 (Berkeley) 01/20/88 1323204Smckusick */ 1421481Ssklower 1521481Ssklower #include "param.h" 1621481Ssklower #include "mbuf.h" 1721481Ssklower #include "ioctl.h" 1821481Ssklower #include "protosw.h" 1921481Ssklower #include "socket.h" 2021481Ssklower #include "socketvar.h" 2121481Ssklower #include "uio.h" 2221481Ssklower #include "dir.h" 2321481Ssklower #include "user.h" 2421481Ssklower 2521481Ssklower 2621481Ssklower #include "../net/if.h" 2721481Ssklower #include "../net/route.h" 2821481Ssklower #include "../net/af.h" 2921481Ssklower 3021481Ssklower #include "ns.h" 3121481Ssklower #include "ns_if.h" 3221481Ssklower 3321481Ssklower #ifdef NS 3421481Ssklower 3521481Ssklower struct ns_ifaddr *ns_ifaddr; 3621481Ssklower 3721481Ssklower ns_hash(sns, hp) 3821481Ssklower register struct sockaddr_ns *sns; 3921481Ssklower struct afhash *hp; 4021481Ssklower { 4121481Ssklower register long hash = 0; 4221481Ssklower register u_short *s = sns->sns_addr.x_host.s_host; 4326055Ssklower union { 4426055Ssklower union ns_net net_e; 4526055Ssklower long long_e; 4626055Ssklower } net; 4721481Ssklower 4826055Ssklower net.net_e = sns->sns_addr.x_net; 4926055Ssklower hp->afh_nethash = net.long_e; 5021481Ssklower hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s; 5121481Ssklower hp->afh_hosthash = hash; 5221481Ssklower } 5321481Ssklower 5421481Ssklower 5521481Ssklower ns_netmatch(sns1, sns2) 5621481Ssklower struct sockaddr_ns *sns1, *sns2; 5721481Ssklower { 5821481Ssklower 5926055Ssklower return (ns_neteq(sns1->sns_addr, sns2->sns_addr)); 6021481Ssklower } 6121481Ssklower 6221481Ssklower /* 6321481Ssklower * Generic internet control operations (ioctl's). 6421481Ssklower */ 6524226Ssklower /* ARGSUSED */ 6621481Ssklower ns_control(so, cmd, data, ifp) 6721481Ssklower struct socket *so; 6821481Ssklower int cmd; 6921481Ssklower caddr_t data; 7021481Ssklower register struct ifnet *ifp; 7121481Ssklower { 7221481Ssklower register struct ifreq *ifr = (struct ifreq *)data; 7321481Ssklower register struct ns_ifaddr *ia; 7421481Ssklower struct ifaddr *ifa; 7521481Ssklower struct mbuf *m; 7621481Ssklower 7721481Ssklower /* 7821481Ssklower * Find address for this interface, if it exists. 7921481Ssklower */ 8025453Ssklower if (ifp == 0) 8124109Ssklower return (EADDRNOTAVAIL); 8221481Ssklower for (ia = ns_ifaddr; ia; ia = ia->ia_next) 8321481Ssklower if (ia->ia_ifp == ifp) 8421481Ssklower break; 8521481Ssklower 8621481Ssklower switch (cmd) { 8721481Ssklower 8821481Ssklower case SIOCGIFADDR: 8924109Ssklower if (ia == (struct ns_ifaddr *)0) 9024109Ssklower return (EADDRNOTAVAIL); 9124109Ssklower ifr->ifr_addr = ia->ia_addr; 9224109Ssklower return (0); 9324109Ssklower 9424109Ssklower 9521481Ssklower case SIOCGIFBRDADDR: 9624109Ssklower if (ia == (struct ns_ifaddr *)0) 9724109Ssklower return (EADDRNOTAVAIL); 9824109Ssklower if ((ifp->if_flags & IFF_BROADCAST) == 0) 9924109Ssklower return (EINVAL); 10024109Ssklower ifr->ifr_dstaddr = ia->ia_broadaddr; 10124109Ssklower return (0); 10224109Ssklower 10321481Ssklower case SIOCGIFDSTADDR: 10421481Ssklower if (ia == (struct ns_ifaddr *)0) 10521481Ssklower return (EADDRNOTAVAIL); 10624109Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 10724109Ssklower return (EINVAL); 10824109Ssklower ifr->ifr_dstaddr = ia->ia_dstaddr; 10924109Ssklower return (0); 11024109Ssklower } 11121481Ssklower 11224109Ssklower if (!suser()) 11324109Ssklower return (u.u_error); 11424109Ssklower 11524109Ssklower switch (cmd) { 11624109Ssklower 11725453Ssklower case SIOCSIFADDR: 11821481Ssklower case SIOCSIFDSTADDR: 11921481Ssklower if (ia == (struct ns_ifaddr *)0) { 12021481Ssklower m = m_getclr(M_WAIT, MT_IFADDR); 12121481Ssklower if (m == (struct mbuf *)NULL) 12221481Ssklower return (ENOBUFS); 12321481Ssklower if (ia = ns_ifaddr) { 12421481Ssklower for ( ; ia->ia_next; ia = ia->ia_next) 12521481Ssklower ; 12621481Ssklower ia->ia_next = mtod(m, struct ns_ifaddr *); 12721481Ssklower } else 12821481Ssklower ns_ifaddr = mtod(m, struct ns_ifaddr *); 12921481Ssklower ia = mtod(m, struct ns_ifaddr *); 13021481Ssklower if (ifa = ifp->if_addrlist) { 13121481Ssklower for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 13221481Ssklower ; 13321481Ssklower ifa->ifa_next = (struct ifaddr *) ia; 13421481Ssklower } else 13521481Ssklower ifp->if_addrlist = (struct ifaddr *) ia; 13621481Ssklower ia->ia_ifp = ifp; 13721481Ssklower IA_SNS(ia)->sns_family = AF_NS; 13821481Ssklower } 13925453Ssklower } 14025453Ssklower 14125453Ssklower switch (cmd) { 14225453Ssklower 14325453Ssklower case SIOCSIFDSTADDR: 14425453Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 14525453Ssklower return (EINVAL); 14625453Ssklower if (ia->ia_flags & IFA_ROUTE) { 14725453Ssklower rtinit(&ia->ia_dstaddr, &ia->ia_addr, 14825453Ssklower (int)SIOCDELRT, RTF_HOST); 14925453Ssklower ia->ia_flags &= ~IFA_ROUTE; 15025453Ssklower } 15125453Ssklower if (ifp->if_ioctl) { 15225453Ssklower int error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); 15325453Ssklower if (error) 15425453Ssklower return (error); 15525453Ssklower } 15625453Ssklower ia->ia_dstaddr = ifr->ifr_dstaddr; 15725453Ssklower return (0); 15825453Ssklower 15925453Ssklower case SIOCSIFADDR: 16021481Ssklower return 16121481Ssklower (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr)); 16221481Ssklower 16321481Ssklower default: 16421481Ssklower if (ifp->if_ioctl == 0) 16521481Ssklower return (EOPNOTSUPP); 16621481Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 16721481Ssklower } 16821481Ssklower } 16921481Ssklower 17021481Ssklower /* 17121481Ssklower * Initialize an interface's internet address 17221481Ssklower * and routing table entry. 17321481Ssklower */ 17421481Ssklower ns_ifinit(ifp, ia, sns) 17521481Ssklower register struct ifnet *ifp; 17621481Ssklower register struct ns_ifaddr *ia; 17721481Ssklower struct sockaddr_ns *sns; 17821481Ssklower { 17921481Ssklower struct sockaddr_ns netaddr; 18021481Ssklower register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host); 18121481Ssklower int s = splimp(), error; 18221481Ssklower 18321481Ssklower /* 18421481Ssklower * The convention we shall adopt for naming is that 18521481Ssklower * a supplied address of zero means that "we don't care". 18621481Ssklower * if there is a single interface, use the address of that 18721481Ssklower * interface as our 6 byte host address. 18821481Ssklower * if there are multiple interfaces, use any address already 18921481Ssklower * used. 19021481Ssklower * 19121481Ssklower * If we have gotten into trouble and want to reset back to 19221481Ssklower * virginity, we recognize a request of the broadcast address. 19321481Ssklower */ 19421481Ssklower if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) { 19521481Ssklower ns_thishost = ns_zerohost; 19621481Ssklower splx(s); 19725453Ssklower return (0); 19821481Ssklower } 19921481Ssklower 20021481Ssklower /* 20121481Ssklower * Delete any previous route for an old address. 20221481Ssklower */ 20321481Ssklower bzero((caddr_t)&netaddr, sizeof (netaddr)); 20421481Ssklower netaddr.sns_family = AF_NS; 20521481Ssklower netaddr.sns_addr.x_host = ns_broadhost; 20621481Ssklower netaddr.sns_addr.x_net = ia->ia_net; 20721481Ssklower if (ia->ia_flags & IFA_ROUTE) { 20821481Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 20925453Ssklower rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 21025453Ssklower (int)SIOCDELRT, 0); 21121481Ssklower } else 21225453Ssklower rtinit(&ia->ia_dstaddr, &ia->ia_addr, 21325453Ssklower (int)SIOCDELRT, RTF_HOST); 21421481Ssklower } 21521481Ssklower 21621481Ssklower /* 21721481Ssklower * Set up new addresses. 21821481Ssklower */ 21921481Ssklower ia->ia_addr = *(struct sockaddr *)sns; 22021481Ssklower ia->ia_net = sns->sns_addr.x_net; 22121481Ssklower netaddr.sns_addr.x_net = ia->ia_net; 22221481Ssklower if (ifp->if_flags & IFF_BROADCAST) { 22321481Ssklower ia->ia_broadaddr = * (struct sockaddr *) &netaddr; 22421481Ssklower } 22525453Ssklower 22621481Ssklower /* 22721481Ssklower * Give the interface a chance to initialize 22821481Ssklower * if this is its first address, 22921481Ssklower * and to validate the address if necessary. 23021481Ssklower */ 23121481Ssklower if (ns_hosteqnh(ns_thishost, ns_zerohost)) { 23221481Ssklower if (ifp->if_ioctl && 23321481Ssklower (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 23421481Ssklower splx(s); 23521481Ssklower return (error); 23621481Ssklower } 23721481Ssklower ns_thishost = *h; 23821481Ssklower } else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost) 23921481Ssklower || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) { 24021481Ssklower *h = ns_thishost; 24121481Ssklower if (ifp->if_ioctl && 24221481Ssklower (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 24321481Ssklower splx(s); 24421481Ssklower return (error); 24521481Ssklower } 24625453Ssklower if (!ns_hosteqnh(ns_thishost,*h)) { 24721481Ssklower splx(s); 24821481Ssklower return (EINVAL); 24921481Ssklower } 25021481Ssklower } else { 25121481Ssklower splx(s); 25225453Ssklower return (EINVAL); 25321481Ssklower } 25425453Ssklower 25521481Ssklower /* 25621481Ssklower * Add route for the network. 25721481Ssklower */ 25825453Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 25925453Ssklower rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 26021481Ssklower RTF_HOST|RTF_UP); 26125453Ssklower else 26225453Ssklower rtinit(&ia->ia_broadaddr, &ia->ia_addr, (int)SIOCADDRT, 26325453Ssklower RTF_UP); 26421481Ssklower ia->ia_flags |= IFA_ROUTE; 26525453Ssklower return (0); 26621481Ssklower } 26721481Ssklower 26821481Ssklower /* 26921481Ssklower * Return address info for specified internet network. 27021481Ssklower */ 27121481Ssklower struct ns_ifaddr * 27225045Ssklower ns_iaonnetof(dst) 27325045Ssklower register struct ns_addr *dst; 27421481Ssklower { 27521481Ssklower register struct ns_ifaddr *ia; 27625045Ssklower register struct ns_addr *compare; 27725453Ssklower register struct ifnet *ifp; 27825453Ssklower struct ns_ifaddr *ia_maybe = 0; 27926055Ssklower union ns_net net = dst->x_net; 28021481Ssklower 28125045Ssklower for (ia = ns_ifaddr; ia; ia = ia->ia_next) { 28225453Ssklower if (ifp = ia->ia_ifp) { 28325453Ssklower if (ifp->if_flags & IFF_POINTOPOINT) { 28425453Ssklower compare = &satons_addr(ia->ia_dstaddr); 28525453Ssklower if (ns_hosteq(*dst, *compare)) 28625045Ssklower return (ia); 28726055Ssklower if (ns_neteqnn(net, ia->ia_net)) 28825453Ssklower ia_maybe = ia; 28925453Ssklower } else { 29026055Ssklower if (ns_neteqnn(net, ia->ia_net)) 29125453Ssklower return (ia); 29225045Ssklower } 29325045Ssklower } 29425045Ssklower } 29525045Ssklower return (ia_maybe); 29621481Ssklower } 29721481Ssklower #endif 298