123204Smckusick /* 233371Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 333371Ssklower * All rights reserved. 423204Smckusick * 533371Ssklower * Redistribution and use in source and binary forms are permitted 6*34856Sbostic * provided that the above copyright notice and this paragraph are 7*34856Sbostic * duplicated in all such forms and that any documentation, 8*34856Sbostic * advertising materials, and other materials related to such 9*34856Sbostic * distribution and use acknowledge that the software was developed 10*34856Sbostic * by the University of California, Berkeley. The name of the 11*34856Sbostic * University may not be used to endorse or promote products derived 12*34856Sbostic * from this software without specific prior written permission. 13*34856Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34856Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34856Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633371Ssklower * 17*34856Sbostic * @(#)ns.c 7.3 (Berkeley) 06/29/88 1823204Smckusick */ 1921481Ssklower 2021481Ssklower #include "param.h" 2121481Ssklower #include "mbuf.h" 2221481Ssklower #include "ioctl.h" 2321481Ssklower #include "protosw.h" 2421481Ssklower #include "socket.h" 2521481Ssklower #include "socketvar.h" 2621481Ssklower #include "uio.h" 2721481Ssklower #include "dir.h" 2821481Ssklower #include "user.h" 2921481Ssklower 3021481Ssklower 3121481Ssklower #include "../net/if.h" 3221481Ssklower #include "../net/route.h" 3321481Ssklower #include "../net/af.h" 3421481Ssklower 3521481Ssklower #include "ns.h" 3621481Ssklower #include "ns_if.h" 3721481Ssklower 3821481Ssklower #ifdef NS 3921481Ssklower 4021481Ssklower struct ns_ifaddr *ns_ifaddr; 4121481Ssklower 4221481Ssklower ns_hash(sns, hp) 4321481Ssklower register struct sockaddr_ns *sns; 4421481Ssklower struct afhash *hp; 4521481Ssklower { 4621481Ssklower register long hash = 0; 4721481Ssklower register u_short *s = sns->sns_addr.x_host.s_host; 4826055Ssklower union { 4926055Ssklower union ns_net net_e; 5026055Ssklower long long_e; 5126055Ssklower } net; 5221481Ssklower 5326055Ssklower net.net_e = sns->sns_addr.x_net; 5426055Ssklower hp->afh_nethash = net.long_e; 5521481Ssklower hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s; 5621481Ssklower hp->afh_hosthash = hash; 5721481Ssklower } 5821481Ssklower 5921481Ssklower 6021481Ssklower ns_netmatch(sns1, sns2) 6121481Ssklower struct sockaddr_ns *sns1, *sns2; 6221481Ssklower { 6321481Ssklower 6426055Ssklower return (ns_neteq(sns1->sns_addr, sns2->sns_addr)); 6521481Ssklower } 6621481Ssklower 6721481Ssklower /* 6821481Ssklower * Generic internet control operations (ioctl's). 6921481Ssklower */ 7024226Ssklower /* ARGSUSED */ 7121481Ssklower ns_control(so, cmd, data, ifp) 7221481Ssklower struct socket *so; 7321481Ssklower int cmd; 7421481Ssklower caddr_t data; 7521481Ssklower register struct ifnet *ifp; 7621481Ssklower { 7721481Ssklower register struct ifreq *ifr = (struct ifreq *)data; 7821481Ssklower register struct ns_ifaddr *ia; 7921481Ssklower struct ifaddr *ifa; 8021481Ssklower struct mbuf *m; 8121481Ssklower 8221481Ssklower /* 8321481Ssklower * Find address for this interface, if it exists. 8421481Ssklower */ 8525453Ssklower if (ifp == 0) 8624109Ssklower return (EADDRNOTAVAIL); 8721481Ssklower for (ia = ns_ifaddr; ia; ia = ia->ia_next) 8821481Ssklower if (ia->ia_ifp == ifp) 8921481Ssklower break; 9021481Ssklower 9121481Ssklower switch (cmd) { 9221481Ssklower 9321481Ssklower case SIOCGIFADDR: 9424109Ssklower if (ia == (struct ns_ifaddr *)0) 9524109Ssklower return (EADDRNOTAVAIL); 9624109Ssklower ifr->ifr_addr = ia->ia_addr; 9724109Ssklower return (0); 9824109Ssklower 9924109Ssklower 10021481Ssklower case SIOCGIFBRDADDR: 10124109Ssklower if (ia == (struct ns_ifaddr *)0) 10224109Ssklower return (EADDRNOTAVAIL); 10324109Ssklower if ((ifp->if_flags & IFF_BROADCAST) == 0) 10424109Ssklower return (EINVAL); 10524109Ssklower ifr->ifr_dstaddr = ia->ia_broadaddr; 10624109Ssklower return (0); 10724109Ssklower 10821481Ssklower case SIOCGIFDSTADDR: 10921481Ssklower if (ia == (struct ns_ifaddr *)0) 11021481Ssklower return (EADDRNOTAVAIL); 11124109Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 11224109Ssklower return (EINVAL); 11324109Ssklower ifr->ifr_dstaddr = ia->ia_dstaddr; 11424109Ssklower return (0); 11524109Ssklower } 11621481Ssklower 11724109Ssklower if (!suser()) 11824109Ssklower return (u.u_error); 11924109Ssklower 12024109Ssklower switch (cmd) { 12124109Ssklower 12225453Ssklower case SIOCSIFADDR: 12321481Ssklower case SIOCSIFDSTADDR: 12421481Ssklower if (ia == (struct ns_ifaddr *)0) { 12521481Ssklower m = m_getclr(M_WAIT, MT_IFADDR); 12621481Ssklower if (m == (struct mbuf *)NULL) 12721481Ssklower return (ENOBUFS); 12821481Ssklower if (ia = ns_ifaddr) { 12921481Ssklower for ( ; ia->ia_next; ia = ia->ia_next) 13021481Ssklower ; 13121481Ssklower ia->ia_next = mtod(m, struct ns_ifaddr *); 13221481Ssklower } else 13321481Ssklower ns_ifaddr = mtod(m, struct ns_ifaddr *); 13421481Ssklower ia = mtod(m, struct ns_ifaddr *); 13521481Ssklower if (ifa = ifp->if_addrlist) { 13621481Ssklower for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 13721481Ssklower ; 13821481Ssklower ifa->ifa_next = (struct ifaddr *) ia; 13921481Ssklower } else 14021481Ssklower ifp->if_addrlist = (struct ifaddr *) ia; 14121481Ssklower ia->ia_ifp = ifp; 14221481Ssklower IA_SNS(ia)->sns_family = AF_NS; 14321481Ssklower } 14425453Ssklower } 14525453Ssklower 14625453Ssklower switch (cmd) { 14725453Ssklower 14825453Ssklower case SIOCSIFDSTADDR: 14925453Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 15025453Ssklower return (EINVAL); 15125453Ssklower if (ia->ia_flags & IFA_ROUTE) { 15225453Ssklower rtinit(&ia->ia_dstaddr, &ia->ia_addr, 15325453Ssklower (int)SIOCDELRT, RTF_HOST); 15425453Ssklower ia->ia_flags &= ~IFA_ROUTE; 15525453Ssklower } 15625453Ssklower if (ifp->if_ioctl) { 15725453Ssklower int error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia); 15825453Ssklower if (error) 15925453Ssklower return (error); 16025453Ssklower } 16125453Ssklower ia->ia_dstaddr = ifr->ifr_dstaddr; 16225453Ssklower return (0); 16325453Ssklower 16425453Ssklower case SIOCSIFADDR: 16521481Ssklower return 16621481Ssklower (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr)); 16721481Ssklower 16821481Ssklower default: 16921481Ssklower if (ifp->if_ioctl == 0) 17021481Ssklower return (EOPNOTSUPP); 17121481Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 17221481Ssklower } 17321481Ssklower } 17421481Ssklower 17521481Ssklower /* 17621481Ssklower * Initialize an interface's internet address 17721481Ssklower * and routing table entry. 17821481Ssklower */ 17921481Ssklower ns_ifinit(ifp, ia, sns) 18021481Ssklower register struct ifnet *ifp; 18121481Ssklower register struct ns_ifaddr *ia; 18221481Ssklower struct sockaddr_ns *sns; 18321481Ssklower { 18421481Ssklower struct sockaddr_ns netaddr; 18521481Ssklower register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host); 18621481Ssklower int s = splimp(), error; 18721481Ssklower 18821481Ssklower /* 18921481Ssklower * The convention we shall adopt for naming is that 19021481Ssklower * a supplied address of zero means that "we don't care". 19121481Ssklower * if there is a single interface, use the address of that 19221481Ssklower * interface as our 6 byte host address. 19321481Ssklower * if there are multiple interfaces, use any address already 19421481Ssklower * used. 19521481Ssklower * 19621481Ssklower * If we have gotten into trouble and want to reset back to 19721481Ssklower * virginity, we recognize a request of the broadcast address. 19821481Ssklower */ 19921481Ssklower if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) { 20021481Ssklower ns_thishost = ns_zerohost; 20121481Ssklower splx(s); 20225453Ssklower return (0); 20321481Ssklower } 20421481Ssklower 20521481Ssklower /* 20621481Ssklower * Delete any previous route for an old address. 20721481Ssklower */ 20821481Ssklower bzero((caddr_t)&netaddr, sizeof (netaddr)); 20921481Ssklower netaddr.sns_family = AF_NS; 21021481Ssklower netaddr.sns_addr.x_host = ns_broadhost; 21121481Ssklower netaddr.sns_addr.x_net = ia->ia_net; 21221481Ssklower if (ia->ia_flags & IFA_ROUTE) { 21321481Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 21425453Ssklower rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 21525453Ssklower (int)SIOCDELRT, 0); 21621481Ssklower } else 21725453Ssklower rtinit(&ia->ia_dstaddr, &ia->ia_addr, 21825453Ssklower (int)SIOCDELRT, RTF_HOST); 21921481Ssklower } 22021481Ssklower 22121481Ssklower /* 22221481Ssklower * Set up new addresses. 22321481Ssklower */ 22421481Ssklower ia->ia_addr = *(struct sockaddr *)sns; 22521481Ssklower ia->ia_net = sns->sns_addr.x_net; 22621481Ssklower netaddr.sns_addr.x_net = ia->ia_net; 22721481Ssklower if (ifp->if_flags & IFF_BROADCAST) { 22821481Ssklower ia->ia_broadaddr = * (struct sockaddr *) &netaddr; 22921481Ssklower } 23025453Ssklower 23121481Ssklower /* 23221481Ssklower * Give the interface a chance to initialize 23321481Ssklower * if this is its first address, 23421481Ssklower * and to validate the address if necessary. 23521481Ssklower */ 23621481Ssklower if (ns_hosteqnh(ns_thishost, ns_zerohost)) { 23721481Ssklower if (ifp->if_ioctl && 23821481Ssklower (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 23921481Ssklower splx(s); 24021481Ssklower return (error); 24121481Ssklower } 24221481Ssklower ns_thishost = *h; 24321481Ssklower } else if (ns_hosteqnh(sns->sns_addr.x_host, ns_zerohost) 24421481Ssklower || ns_hosteqnh(sns->sns_addr.x_host, ns_thishost)) { 24521481Ssklower *h = ns_thishost; 24621481Ssklower if (ifp->if_ioctl && 24721481Ssklower (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 24821481Ssklower splx(s); 24921481Ssklower return (error); 25021481Ssklower } 25125453Ssklower if (!ns_hosteqnh(ns_thishost,*h)) { 25221481Ssklower splx(s); 25321481Ssklower return (EINVAL); 25421481Ssklower } 25521481Ssklower } else { 25621481Ssklower splx(s); 25725453Ssklower return (EINVAL); 25821481Ssklower } 25925453Ssklower 26021481Ssklower /* 26121481Ssklower * Add route for the network. 26221481Ssklower */ 26325453Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 26425453Ssklower rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 26521481Ssklower RTF_HOST|RTF_UP); 26625453Ssklower else 26725453Ssklower rtinit(&ia->ia_broadaddr, &ia->ia_addr, (int)SIOCADDRT, 26825453Ssklower RTF_UP); 26921481Ssklower ia->ia_flags |= IFA_ROUTE; 27025453Ssklower return (0); 27121481Ssklower } 27221481Ssklower 27321481Ssklower /* 27421481Ssklower * Return address info for specified internet network. 27521481Ssklower */ 27621481Ssklower struct ns_ifaddr * 27725045Ssklower ns_iaonnetof(dst) 27825045Ssklower register struct ns_addr *dst; 27921481Ssklower { 28021481Ssklower register struct ns_ifaddr *ia; 28125045Ssklower register struct ns_addr *compare; 28225453Ssklower register struct ifnet *ifp; 28325453Ssklower struct ns_ifaddr *ia_maybe = 0; 28426055Ssklower union ns_net net = dst->x_net; 28521481Ssklower 28625045Ssklower for (ia = ns_ifaddr; ia; ia = ia->ia_next) { 28725453Ssklower if (ifp = ia->ia_ifp) { 28825453Ssklower if (ifp->if_flags & IFF_POINTOPOINT) { 28925453Ssklower compare = &satons_addr(ia->ia_dstaddr); 29025453Ssklower if (ns_hosteq(*dst, *compare)) 29125045Ssklower return (ia); 29226055Ssklower if (ns_neteqnn(net, ia->ia_net)) 29325453Ssklower ia_maybe = ia; 29425453Ssklower } else { 29526055Ssklower if (ns_neteqnn(net, ia->ia_net)) 29625453Ssklower return (ia); 29725045Ssklower } 29825045Ssklower } 29925045Ssklower } 30025045Ssklower return (ia_maybe); 30121481Ssklower } 30221481Ssklower #endif 303