ipx.c revision 11819
111819Sjulian/* 211819Sjulian * Copyright (c) 1995, Mike Mitchell 311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 411819Sjulian * The Regents of the University of California. All rights reserved. 511819Sjulian * 611819Sjulian * Redistribution and use in source and binary forms, with or without 711819Sjulian * modification, are permitted provided that the following conditions 811819Sjulian * are met: 911819Sjulian * 1. Redistributions of source code must retain the above copyright 1011819Sjulian * notice, this list of conditions and the following disclaimer. 1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1211819Sjulian * notice, this list of conditions and the following disclaimer in the 1311819Sjulian * documentation and/or other materials provided with the distribution. 1411819Sjulian * 3. All advertising materials mentioning features or use of this software 1511819Sjulian * must display the following acknowledgement: 1611819Sjulian * This product includes software developed by the University of 1711819Sjulian * California, Berkeley and its contributors. 1811819Sjulian * 4. Neither the name of the University nor the names of its contributors 1911819Sjulian * may be used to endorse or promote products derived from this software 2011819Sjulian * without specific prior written permission. 2111819Sjulian * 2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2511819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3211819Sjulian * SUCH DAMAGE. 3311819Sjulian * 3411819Sjulian * @(#)ipx.c 3511819Sjulian */ 3611819Sjulian 3711819Sjulian#include <sys/param.h> 3811819Sjulian#include <sys/systm.h> 3911819Sjulian#include <sys/mbuf.h> 4011819Sjulian#include <sys/ioctl.h> 4111819Sjulian#include <sys/protosw.h> 4211819Sjulian#include <sys/errno.h> 4311819Sjulian#include <sys/socket.h> 4411819Sjulian#include <sys/socketvar.h> 4511819Sjulian 4611819Sjulian#include <net/if.h> 4711819Sjulian#include <net/route.h> 4811819Sjulian 4911819Sjulian#include <netipx/ipx.h> 5011819Sjulian#include <netipx/ipx_if.h> 5111819Sjulian 5211819Sjulian#ifdef IPX 5311819Sjulian 5411819Sjulianstruct ipx_ifaddr *ipx_ifaddr; 5511819Sjulianint ipx_interfaces; 5611819Sjulian 5711819Sjulian/* 5811819Sjulian * Generic internet control operations (ioctl's). 5911819Sjulian */ 6011819Sjulian/* ARGSUSED */ 6111819Sjulianint 6211819Sjulianipx_control(so, cmd, data, ifp) 6311819Sjulian struct socket *so; 6411819Sjulian int cmd; 6511819Sjulian caddr_t data; 6611819Sjulian register struct ifnet *ifp; 6711819Sjulian{ 6811819Sjulian register struct ifreq *ifr = (struct ifreq *)data; 6911819Sjulian register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 7011819Sjulian register struct ipx_ifaddr *ia; 7111819Sjulian struct ifaddr *ifa; 7211819Sjulian struct ipx_ifaddr *oia; 7311819Sjulian int dstIsNew, hostIsNew; 7411819Sjulian int error = 0; 7511819Sjulian 7611819Sjulian /* 7711819Sjulian * Find address for this interface, if it exists. 7811819Sjulian */ 7911819Sjulian if (ifp == 0) 8011819Sjulian return (EADDRNOTAVAIL); 8111819Sjulian for (ia = ipx_ifaddr; ia; ia = ia->ia_next) 8211819Sjulian if (ia->ia_ifp == ifp) 8311819Sjulian break; 8411819Sjulian 8511819Sjulian switch (cmd) { 8611819Sjulian 8711819Sjulian case SIOCGIFADDR: 8811819Sjulian if (ia == (struct ipx_ifaddr *)0) 8911819Sjulian return (EADDRNOTAVAIL); 9011819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 9111819Sjulian return (0); 9211819Sjulian 9311819Sjulian case SIOCGIFBRDADDR: 9411819Sjulian if (ia == (struct ipx_ifaddr *)0) 9511819Sjulian return (EADDRNOTAVAIL); 9611819Sjulian if ((ifp->if_flags & IFF_BROADCAST) == 0) 9711819Sjulian return (EINVAL); 9811819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 9911819Sjulian return (0); 10011819Sjulian 10111819Sjulian case SIOCGIFDSTADDR: 10211819Sjulian if (ia == (struct ipx_ifaddr *)0) 10311819Sjulian return (EADDRNOTAVAIL); 10411819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 10511819Sjulian return (EINVAL); 10611819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 10711819Sjulian return (0); 10811819Sjulian } 10911819Sjulian 11011819Sjulian if ((so->so_state & SS_PRIV) == 0) 11111819Sjulian return (EPERM); 11211819Sjulian 11311819Sjulian switch (cmd) { 11411819Sjulian case SIOCAIFADDR: 11511819Sjulian case SIOCDIFADDR: 11611819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX) 11711819Sjulian for (oia = ia; ia; ia = ia->ia_next) { 11811819Sjulian if (ia->ia_ifp == ifp && 11911819Sjulian ipx_neteq(ia->ia_addr.sipx_addr, 12011819Sjulian ifra->ifra_addr.sipx_addr)) 12111819Sjulian break; 12211819Sjulian } 12311819Sjulian if (cmd == SIOCDIFADDR && ia == 0) 12411819Sjulian return (EADDRNOTAVAIL); 12511819Sjulian /* FALLTHROUGH */ 12611819Sjulian 12711819Sjulian case SIOCSIFADDR: 12811819Sjulian case SIOCSIFDSTADDR: 12911819Sjulian if (ia == (struct ipx_ifaddr *)0) { 13011819Sjulian oia = (struct ipx_ifaddr *) 13111819Sjulian malloc(sizeof *ia, M_IFADDR, M_WAITOK); 13211819Sjulian if (oia == (struct ipx_ifaddr *)NULL) 13311819Sjulian return (ENOBUFS); 13411819Sjulian bzero((caddr_t)oia, sizeof(*oia)); 13511819Sjulian if ((ia = ipx_ifaddr)) { 13611819Sjulian for ( ; ia->ia_next; ia = ia->ia_next) 13711819Sjulian ; 13811819Sjulian ia->ia_next = oia; 13911819Sjulian } else 14011819Sjulian ipx_ifaddr = oia; 14111819Sjulian ia = oia; 14211819Sjulian if ((ifa = ifp->if_addrlist)) { 14311819Sjulian for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 14411819Sjulian ; 14511819Sjulian ifa->ifa_next = (struct ifaddr *) ia; 14611819Sjulian } else 14711819Sjulian ifp->if_addrlist = (struct ifaddr *) ia; 14811819Sjulian ia->ia_ifp = ifp; 14911819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 15011819Sjulian 15111819Sjulian ia->ia_ifa.ifa_netmask = 15211819Sjulian (struct sockaddr *)&ipx_netmask; 15311819Sjulian 15411819Sjulian ia->ia_ifa.ifa_dstaddr = 15511819Sjulian (struct sockaddr *)&ia->ia_dstaddr; 15611819Sjulian if (ifp->if_flags & IFF_BROADCAST) { 15711819Sjulian ia->ia_broadaddr.sipx_family = AF_IPX; 15811819Sjulian ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 15911819Sjulian ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 16011819Sjulian } 16111819Sjulian ipx_interfaces++; 16211819Sjulian } 16311819Sjulian } 16411819Sjulian 16511819Sjulian switch (cmd) { 16611819Sjulian 16711819Sjulian case SIOCSIFDSTADDR: 16811819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 16911819Sjulian return (EINVAL); 17011819Sjulian if (ia->ia_flags & IFA_ROUTE) { 17111819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 17211819Sjulian ia->ia_flags &= ~IFA_ROUTE; 17311819Sjulian } 17411819Sjulian if (ifp->if_ioctl) { 17511819Sjulian error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 17611819Sjulian if (error) 17711819Sjulian return (error); 17811819Sjulian } 17911819Sjulian *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 18011819Sjulian return (0); 18111819Sjulian 18211819Sjulian case SIOCSIFADDR: 18311819Sjulian return (ipx_ifinit(ifp, ia, 18411819Sjulian (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 18511819Sjulian 18611819Sjulian case SIOCDIFADDR: 18711819Sjulian ipx_ifscrub(ifp, ia); 18811819Sjulian if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) 18911819Sjulian ifp->if_addrlist = ifa->ifa_next; 19011819Sjulian else { 19111819Sjulian while (ifa->ifa_next && 19211819Sjulian (ifa->ifa_next != (struct ifaddr *)ia)) 19311819Sjulian ifa = ifa->ifa_next; 19411819Sjulian if (ifa->ifa_next) 19511819Sjulian ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; 19611819Sjulian else 19711819Sjulian printf("Couldn't unlink ipxifaddr from ifp\n"); 19811819Sjulian } 19911819Sjulian oia = ia; 20011819Sjulian if (oia == (ia = ipx_ifaddr)) { 20111819Sjulian ipx_ifaddr = ia->ia_next; 20211819Sjulian } else { 20311819Sjulian while (ia->ia_next && (ia->ia_next != oia)) { 20411819Sjulian ia = ia->ia_next; 20511819Sjulian } 20611819Sjulian if (ia->ia_next) 20711819Sjulian ia->ia_next = oia->ia_next; 20811819Sjulian else 20911819Sjulian printf("Didn't unlink ipxifadr from list\n"); 21011819Sjulian } 21111819Sjulian IFAFREE((&oia->ia_ifa)); 21211819Sjulian if (0 == --ipx_interfaces) { 21311819Sjulian /* 21411819Sjulian * We reset to virginity and start all over again 21511819Sjulian */ 21611819Sjulian ipx_thishost = ipx_zerohost; 21711819Sjulian } 21811819Sjulian return (0); 21911819Sjulian 22011819Sjulian case SIOCAIFADDR: 22111819Sjulian dstIsNew = 0; hostIsNew = 1; 22211819Sjulian if (ia->ia_addr.sipx_family == AF_IPX) { 22311819Sjulian if (ifra->ifra_addr.sipx_len == 0) { 22411819Sjulian ifra->ifra_addr = ia->ia_addr; 22511819Sjulian hostIsNew = 0; 22611819Sjulian } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 22711819Sjulian ia->ia_addr.sipx_addr)) 22811819Sjulian hostIsNew = 0; 22911819Sjulian } 23011819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) && 23111819Sjulian (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 23211819Sjulian if (hostIsNew == 0) 23311819Sjulian ipx_ifscrub(ifp, ia); 23411819Sjulian ia->ia_dstaddr = ifra->ifra_dstaddr; 23511819Sjulian dstIsNew = 1; 23611819Sjulian } 23711819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX && 23811819Sjulian (hostIsNew || dstIsNew)) 23911819Sjulian error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 24011819Sjulian return (error); 24111819Sjulian 24211819Sjulian default: 24311819Sjulian if (ifp->if_ioctl == 0) 24411819Sjulian return (EOPNOTSUPP); 24511819Sjulian return ((*ifp->if_ioctl)(ifp, cmd, data)); 24611819Sjulian } 24711819Sjulian} 24811819Sjulian 24911819Sjulian/* 25011819Sjulian* Delete any previous route for an old address. 25111819Sjulian*/ 25211819Sjulianvoid 25311819Sjulianipx_ifscrub(ifp, ia) 25411819Sjulian register struct ifnet *ifp; 25511819Sjulian register struct ipx_ifaddr *ia; 25611819Sjulian{ 25711819Sjulian if (ia->ia_flags & IFA_ROUTE) { 25811819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 25911819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 26011819Sjulian } else 26111819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 26211819Sjulian ia->ia_flags &= ~IFA_ROUTE; 26311819Sjulian } 26411819Sjulian} 26511819Sjulian/* 26611819Sjulian * Initialize an interface's internet address 26711819Sjulian * and routing table entry. 26811819Sjulian */ 26911819Sjulianint 27011819Sjulianipx_ifinit(ifp, ia, sipx, scrub) 27111819Sjulian register struct ifnet *ifp; 27211819Sjulian register struct ipx_ifaddr *ia; 27311819Sjulian register struct sockaddr_ipx *sipx; 27411819Sjulian int scrub; 27511819Sjulian{ 27611819Sjulian struct sockaddr_ipx oldaddr; 27711819Sjulian register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host; 27811819Sjulian int s = splimp(), error; 27911819Sjulian 28011819Sjulian /* 28111819Sjulian * Set up new addresses. 28211819Sjulian */ 28311819Sjulian oldaddr = ia->ia_addr; 28411819Sjulian ia->ia_addr = *sipx; 28511819Sjulian /* 28611819Sjulian * The convention we shall adopt for naming is that 28711819Sjulian * a supplied address of zero means that "we don't care". 28811819Sjulian * if there is a single interface, use the address of that 28911819Sjulian * interface as our 6 byte host address. 29011819Sjulian * if there are multiple interfaces, use any address already 29111819Sjulian * used. 29211819Sjulian * 29311819Sjulian * Give the interface a chance to initialize 29411819Sjulian * if this is its first address, 29511819Sjulian * and to validate the address if necessary. 29611819Sjulian */ 29711819Sjulian if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) { 29811819Sjulian if (ifp->if_ioctl && 29911819Sjulian (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 30011819Sjulian ia->ia_addr = oldaddr; 30111819Sjulian splx(s); 30211819Sjulian return (error); 30311819Sjulian } 30411819Sjulian ipx_thishost = *h; 30511819Sjulian } else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost) 30611819Sjulian || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) { 30711819Sjulian *h = ipx_thishost; 30811819Sjulian if (ifp->if_ioctl && 30911819Sjulian (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 31011819Sjulian ia->ia_addr = oldaddr; 31111819Sjulian splx(s); 31211819Sjulian return (error); 31311819Sjulian } 31411819Sjulian if (!ipx_hosteqnh(ipx_thishost,*h)) { 31511819Sjulian ia->ia_addr = oldaddr; 31611819Sjulian splx(s); 31711819Sjulian return (EINVAL); 31811819Sjulian } 31911819Sjulian } else { 32011819Sjulian ia->ia_addr = oldaddr; 32111819Sjulian splx(s); 32211819Sjulian return (EINVAL); 32311819Sjulian } 32411819Sjulian ia->ia_ifa.ifa_metric = ifp->if_metric; 32511819Sjulian /* 32611819Sjulian * Add route for the network. 32711819Sjulian */ 32811819Sjulian if (scrub) { 32911819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 33011819Sjulian ipx_ifscrub(ifp, ia); 33111819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 33211819Sjulian } 33311819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) 33411819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 33511819Sjulian else { 33611819Sjulian ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 33711819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 33811819Sjulian } 33911819Sjulian ia->ia_flags |= IFA_ROUTE; 34011819Sjulian return (0); 34111819Sjulian} 34211819Sjulian 34311819Sjulian/* 34411819Sjulian * Return address info for specified internet network. 34511819Sjulian */ 34611819Sjulianstruct ipx_ifaddr * 34711819Sjulianipx_iaonnetof(dst) 34811819Sjulian register struct ipx_addr *dst; 34911819Sjulian{ 35011819Sjulian register struct ipx_ifaddr *ia; 35111819Sjulian register struct ipx_addr *compare; 35211819Sjulian register struct ifnet *ifp; 35311819Sjulian struct ipx_ifaddr *ia_maybe = 0; 35411819Sjulian union ipx_net net = dst->x_net; 35511819Sjulian 35611819Sjulian for (ia = ipx_ifaddr; ia; ia = ia->ia_next) { 35711819Sjulian if ((ifp = ia->ia_ifp)) { 35811819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 35911819Sjulian compare = &satoipx_addr(ia->ia_dstaddr); 36011819Sjulian if (ipx_hosteq(*dst, *compare)) 36111819Sjulian return (ia); 36211819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 36311819Sjulian ia_maybe = ia; 36411819Sjulian } else { 36511819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 36611819Sjulian return (ia); 36711819Sjulian } 36811819Sjulian } 36911819Sjulian } 37011819Sjulian return (ia_maybe); 37111819Sjulian} 37211819Sjulian#endif 373