ipx.c revision 24204
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 * 3412057Sjulian * @(#)ipx.c 3512057Sjulian * 3624204Sbde * $Id: ipx.c,v 1.7 1997/02/22 09:41:51 peter Exp $ 3711819Sjulian */ 3811819Sjulian 3911819Sjulian#include <sys/param.h> 4014546Sdg#include <sys/queue.h> 4111819Sjulian#include <sys/systm.h> 4211819Sjulian#include <sys/mbuf.h> 4324204Sbde#include <sys/sockio.h> 4411819Sjulian#include <sys/protosw.h> 4511819Sjulian#include <sys/errno.h> 4611819Sjulian#include <sys/socket.h> 4711819Sjulian#include <sys/socketvar.h> 4811819Sjulian 4911819Sjulian#include <net/if.h> 5011819Sjulian#include <net/route.h> 5111819Sjulian 5211819Sjulian#include <netipx/ipx.h> 5311819Sjulian#include <netipx/ipx_if.h> 5411819Sjulian 5511819Sjulian#ifdef IPX 5611819Sjulian 5711819Sjulianstruct ipx_ifaddr *ipx_ifaddr; 5811819Sjulianint ipx_interfaces; 5911819Sjulian 6011819Sjulian/* 6111819Sjulian * Generic internet control operations (ioctl's). 6211819Sjulian */ 6311819Sjulian/* ARGSUSED */ 6411819Sjulianint 6511819Sjulianipx_control(so, cmd, data, ifp) 6611819Sjulian struct socket *so; 6711819Sjulian int cmd; 6811819Sjulian caddr_t data; 6911819Sjulian register struct ifnet *ifp; 7011819Sjulian{ 7111819Sjulian register struct ifreq *ifr = (struct ifreq *)data; 7211819Sjulian register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 7311819Sjulian register struct ipx_ifaddr *ia; 7411819Sjulian struct ifaddr *ifa; 7511819Sjulian struct ipx_ifaddr *oia; 7611819Sjulian int dstIsNew, hostIsNew; 7711819Sjulian int error = 0; 7811819Sjulian 7911819Sjulian /* 8011819Sjulian * Find address for this interface, if it exists. 8111819Sjulian */ 8211819Sjulian if (ifp == 0) 8311819Sjulian return (EADDRNOTAVAIL); 8411819Sjulian for (ia = ipx_ifaddr; ia; ia = ia->ia_next) 8511819Sjulian if (ia->ia_ifp == ifp) 8611819Sjulian break; 8711819Sjulian 8811819Sjulian switch (cmd) { 8911819Sjulian 9011819Sjulian case SIOCGIFADDR: 9111819Sjulian if (ia == (struct ipx_ifaddr *)0) 9211819Sjulian return (EADDRNOTAVAIL); 9311819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 9411819Sjulian return (0); 9511819Sjulian 9611819Sjulian case SIOCGIFBRDADDR: 9711819Sjulian if (ia == (struct ipx_ifaddr *)0) 9811819Sjulian return (EADDRNOTAVAIL); 9911819Sjulian if ((ifp->if_flags & IFF_BROADCAST) == 0) 10011819Sjulian return (EINVAL); 10111819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 10211819Sjulian return (0); 10311819Sjulian 10411819Sjulian case SIOCGIFDSTADDR: 10511819Sjulian if (ia == (struct ipx_ifaddr *)0) 10611819Sjulian return (EADDRNOTAVAIL); 10711819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 10811819Sjulian return (EINVAL); 10911819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 11011819Sjulian return (0); 11111819Sjulian } 11211819Sjulian 11311819Sjulian if ((so->so_state & SS_PRIV) == 0) 11411819Sjulian return (EPERM); 11511819Sjulian 11611819Sjulian switch (cmd) { 11711819Sjulian case SIOCAIFADDR: 11811819Sjulian case SIOCDIFADDR: 11911819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX) 12011819Sjulian for (oia = ia; ia; ia = ia->ia_next) { 12111819Sjulian if (ia->ia_ifp == ifp && 12211819Sjulian ipx_neteq(ia->ia_addr.sipx_addr, 12311819Sjulian ifra->ifra_addr.sipx_addr)) 12411819Sjulian break; 12511819Sjulian } 12611819Sjulian if (cmd == SIOCDIFADDR && ia == 0) 12711819Sjulian return (EADDRNOTAVAIL); 12811819Sjulian /* FALLTHROUGH */ 12911819Sjulian 13011819Sjulian case SIOCSIFADDR: 13111819Sjulian case SIOCSIFDSTADDR: 13211819Sjulian if (ia == (struct ipx_ifaddr *)0) { 13311819Sjulian oia = (struct ipx_ifaddr *) 13411819Sjulian malloc(sizeof *ia, M_IFADDR, M_WAITOK); 13511819Sjulian if (oia == (struct ipx_ifaddr *)NULL) 13611819Sjulian return (ENOBUFS); 13711819Sjulian bzero((caddr_t)oia, sizeof(*oia)); 13811819Sjulian if ((ia = ipx_ifaddr)) { 13911819Sjulian for ( ; ia->ia_next; ia = ia->ia_next) 14011819Sjulian ; 14111819Sjulian ia->ia_next = oia; 14211819Sjulian } else 14311819Sjulian ipx_ifaddr = oia; 14411819Sjulian ia = oia; 14520407Swollman ifa = (struct ifaddr *)ia; 14620407Swollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 14711819Sjulian ia->ia_ifp = ifp; 14820407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 14911819Sjulian 15020407Swollman ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 15111819Sjulian 15220407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 15311819Sjulian if (ifp->if_flags & IFF_BROADCAST) { 15411819Sjulian ia->ia_broadaddr.sipx_family = AF_IPX; 15511819Sjulian ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 15611819Sjulian ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 15711819Sjulian } 15811819Sjulian ipx_interfaces++; 15911819Sjulian } 16011819Sjulian } 16111819Sjulian 16211819Sjulian switch (cmd) { 16311819Sjulian 16411819Sjulian case SIOCSIFDSTADDR: 16511819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 16611819Sjulian return (EINVAL); 16711819Sjulian if (ia->ia_flags & IFA_ROUTE) { 16811819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 16911819Sjulian ia->ia_flags &= ~IFA_ROUTE; 17011819Sjulian } 17111819Sjulian if (ifp->if_ioctl) { 17211819Sjulian error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 17311819Sjulian if (error) 17411819Sjulian return (error); 17511819Sjulian } 17611819Sjulian *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 17711819Sjulian return (0); 17811819Sjulian 17911819Sjulian case SIOCSIFADDR: 18011819Sjulian return (ipx_ifinit(ifp, ia, 18111819Sjulian (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 18211819Sjulian 18311819Sjulian case SIOCDIFADDR: 18411819Sjulian ipx_ifscrub(ifp, ia); 18520407Swollman ifa = (struct ifaddr *)ia; 18620407Swollman TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 18711819Sjulian oia = ia; 18811819Sjulian if (oia == (ia = ipx_ifaddr)) { 18911819Sjulian ipx_ifaddr = ia->ia_next; 19011819Sjulian } else { 19111819Sjulian while (ia->ia_next && (ia->ia_next != oia)) { 19211819Sjulian ia = ia->ia_next; 19311819Sjulian } 19411819Sjulian if (ia->ia_next) 19511819Sjulian ia->ia_next = oia->ia_next; 19611819Sjulian else 19711819Sjulian printf("Didn't unlink ipxifadr from list\n"); 19811819Sjulian } 19911819Sjulian IFAFREE((&oia->ia_ifa)); 20011819Sjulian if (0 == --ipx_interfaces) { 20111819Sjulian /* 20211819Sjulian * We reset to virginity and start all over again 20311819Sjulian */ 20411819Sjulian ipx_thishost = ipx_zerohost; 20511819Sjulian } 20611819Sjulian return (0); 20711819Sjulian 20811819Sjulian case SIOCAIFADDR: 20911819Sjulian dstIsNew = 0; hostIsNew = 1; 21011819Sjulian if (ia->ia_addr.sipx_family == AF_IPX) { 21111819Sjulian if (ifra->ifra_addr.sipx_len == 0) { 21211819Sjulian ifra->ifra_addr = ia->ia_addr; 21311819Sjulian hostIsNew = 0; 21411819Sjulian } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 21511819Sjulian ia->ia_addr.sipx_addr)) 21611819Sjulian hostIsNew = 0; 21711819Sjulian } 21811819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) && 21911819Sjulian (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 22011819Sjulian if (hostIsNew == 0) 22111819Sjulian ipx_ifscrub(ifp, ia); 22211819Sjulian ia->ia_dstaddr = ifra->ifra_dstaddr; 22311819Sjulian dstIsNew = 1; 22411819Sjulian } 22511819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX && 22611819Sjulian (hostIsNew || dstIsNew)) 22711819Sjulian error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 22811819Sjulian return (error); 22911819Sjulian 23011819Sjulian default: 23111819Sjulian if (ifp->if_ioctl == 0) 23211819Sjulian return (EOPNOTSUPP); 23311819Sjulian return ((*ifp->if_ioctl)(ifp, cmd, data)); 23411819Sjulian } 23511819Sjulian} 23611819Sjulian 23711819Sjulian/* 23811819Sjulian* Delete any previous route for an old address. 23911819Sjulian*/ 24011819Sjulianvoid 24111819Sjulianipx_ifscrub(ifp, ia) 24211819Sjulian register struct ifnet *ifp; 24311819Sjulian register struct ipx_ifaddr *ia; 24411819Sjulian{ 24511819Sjulian if (ia->ia_flags & IFA_ROUTE) { 24611819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 24711819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 24811819Sjulian } else 24911819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 25011819Sjulian ia->ia_flags &= ~IFA_ROUTE; 25111819Sjulian } 25211819Sjulian} 25311819Sjulian/* 25411819Sjulian * Initialize an interface's internet address 25511819Sjulian * and routing table entry. 25611819Sjulian */ 25711819Sjulianint 25811819Sjulianipx_ifinit(ifp, ia, sipx, scrub) 25911819Sjulian register struct ifnet *ifp; 26011819Sjulian register struct ipx_ifaddr *ia; 26111819Sjulian register struct sockaddr_ipx *sipx; 26211819Sjulian int scrub; 26311819Sjulian{ 26411819Sjulian struct sockaddr_ipx oldaddr; 26511819Sjulian register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host; 26611819Sjulian int s = splimp(), error; 26711819Sjulian 26811819Sjulian /* 26911819Sjulian * Set up new addresses. 27011819Sjulian */ 27111819Sjulian oldaddr = ia->ia_addr; 27211819Sjulian ia->ia_addr = *sipx; 27311819Sjulian /* 27411819Sjulian * The convention we shall adopt for naming is that 27511819Sjulian * a supplied address of zero means that "we don't care". 27611819Sjulian * if there is a single interface, use the address of that 27711819Sjulian * interface as our 6 byte host address. 27811819Sjulian * if there are multiple interfaces, use any address already 27911819Sjulian * used. 28011819Sjulian * 28111819Sjulian * Give the interface a chance to initialize 28211819Sjulian * if this is its first address, 28311819Sjulian * and to validate the address if necessary. 28411819Sjulian */ 28511819Sjulian if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) { 28611819Sjulian if (ifp->if_ioctl && 28711819Sjulian (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 28811819Sjulian ia->ia_addr = oldaddr; 28911819Sjulian splx(s); 29011819Sjulian return (error); 29111819Sjulian } 29211819Sjulian ipx_thishost = *h; 29311819Sjulian } else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost) 29411819Sjulian || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) { 29511819Sjulian *h = ipx_thishost; 29611819Sjulian if (ifp->if_ioctl && 29711819Sjulian (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 29811819Sjulian ia->ia_addr = oldaddr; 29911819Sjulian splx(s); 30011819Sjulian return (error); 30111819Sjulian } 30211819Sjulian if (!ipx_hosteqnh(ipx_thishost,*h)) { 30311819Sjulian ia->ia_addr = oldaddr; 30411819Sjulian splx(s); 30511819Sjulian return (EINVAL); 30611819Sjulian } 30711819Sjulian } else { 30811819Sjulian ia->ia_addr = oldaddr; 30911819Sjulian splx(s); 31011819Sjulian return (EINVAL); 31111819Sjulian } 31211819Sjulian ia->ia_ifa.ifa_metric = ifp->if_metric; 31311819Sjulian /* 31411819Sjulian * Add route for the network. 31511819Sjulian */ 31611819Sjulian if (scrub) { 31711819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 31811819Sjulian ipx_ifscrub(ifp, ia); 31911819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 32011819Sjulian } 32111819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) 32211819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 32311819Sjulian else { 32411819Sjulian ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 32511819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 32611819Sjulian } 32711819Sjulian ia->ia_flags |= IFA_ROUTE; 32811819Sjulian return (0); 32911819Sjulian} 33011819Sjulian 33111819Sjulian/* 33211819Sjulian * Return address info for specified internet network. 33311819Sjulian */ 33411819Sjulianstruct ipx_ifaddr * 33511819Sjulianipx_iaonnetof(dst) 33611819Sjulian register struct ipx_addr *dst; 33711819Sjulian{ 33811819Sjulian register struct ipx_ifaddr *ia; 33911819Sjulian register struct ipx_addr *compare; 34011819Sjulian register struct ifnet *ifp; 34111819Sjulian struct ipx_ifaddr *ia_maybe = 0; 34211819Sjulian union ipx_net net = dst->x_net; 34311819Sjulian 34411819Sjulian for (ia = ipx_ifaddr; ia; ia = ia->ia_next) { 34511819Sjulian if ((ifp = ia->ia_ifp)) { 34611819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 34711819Sjulian compare = &satoipx_addr(ia->ia_dstaddr); 34811819Sjulian if (ipx_hosteq(*dst, *compare)) 34911819Sjulian return (ia); 35011819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 35111819Sjulian ia_maybe = ia; 35211819Sjulian } else { 35311819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 35411819Sjulian return (ia); 35511819Sjulian } 35611819Sjulian } 35711819Sjulian } 35811819Sjulian return (ia_maybe); 35911819Sjulian} 36011819Sjulian#endif 361