ipx.c revision 25652
138889Sjdp/* 238889Sjdp * Copyright (c) 1995, Mike Mitchell 3130561Sobrien * Copyright (c) 1984, 1985, 1986, 1987, 1993 4218822Sdim * The Regents of the University of California. All rights reserved. 538889Sjdp * 660484Sobrien * Redistribution and use in source and binary forms, with or without 7130561Sobrien * modification, are permitted provided that the following conditions 8130561Sobrien * are met: 9130561Sobrien * 1. Redistributions of source code must retain the above copyright 1038889Sjdp * notice, this list of conditions and the following disclaimer. 1138889Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1238889Sjdp * notice, this list of conditions and the following disclaimer in the 1360484Sobrien * documentation and/or other materials provided with the distribution. 1460484Sobrien * 3. All advertising materials mentioning features or use of this software 1538889Sjdp * must display the following acknowledgement: 16218822Sdim * This product includes software developed by the University of 17218822Sdim * California, Berkeley and its contributors. 18218822Sdim * 4. Neither the name of the University nor the names of its contributors 19218822Sdim * may be used to endorse or promote products derived from this software 2077298Sobrien * without specific prior written permission. 21218822Sdim * 2277298Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2377298Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2460484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2538889Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2638889Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2738889Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2838889Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2938889Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3038889Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3138889Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3238889Sjdp * SUCH DAMAGE. 3338889Sjdp * 3438889Sjdp * @(#)ipx.c 3538889Sjdp * 3638889Sjdp * $Id: ipx.c,v 1.9 1997/05/01 06:21:27 jhay Exp $ 3738889Sjdp */ 38218822Sdim 3938889Sjdp#include <sys/param.h> 4038889Sjdp#include <sys/queue.h> 4138889Sjdp#include <sys/systm.h> 4238889Sjdp#include <sys/mbuf.h> 4338889Sjdp#include <sys/sockio.h> 4438889Sjdp#include <sys/proc.h> 4538889Sjdp#include <sys/protosw.h> 4638889Sjdp#include <sys/errno.h> 4738889Sjdp#include <sys/socket.h> 4838889Sjdp#include <sys/socketvar.h> 4960484Sobrien 50218822Sdim#include <net/if.h> 51218822Sdim#include <net/route.h> 5277298Sobrien 53218822Sdim#include <netipx/ipx.h> 5438889Sjdp#include <netipx/ipx_if.h> 5560484Sobrien#include <netipx/ipx_var.h> 56104834Sobrien 5760484Sobrienstruct ipx_ifaddr *ipx_ifaddr; 58104834Sobrien 5938889Sjdpstatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 6038889Sjdpstatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 6160484Sobrien struct sockaddr_ipx *sipx, int scrub); 6238889Sjdp 6338889Sjdp/* 6438889Sjdp * Generic internet control operations (ioctl's). 65218822Sdim */ 66130561Sobrienint 67218822Sdimipx_control(so, cmd, data, ifp, p) 6838889Sjdp struct socket *so; 6977298Sobrien int cmd; 7038889Sjdp caddr_t data; 71218822Sdim register struct ifnet *ifp; 7260484Sobrien struct proc *p; 73218822Sdim{ 7438889Sjdp register struct ifreq *ifr = (struct ifreq *)data; 7589857Sobrien register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 7638889Sjdp register struct ipx_ifaddr *ia; 7738889Sjdp struct ifaddr *ifa; 78130561Sobrien struct ipx_ifaddr *oia; 79218822Sdim int dstIsNew, hostIsNew; 8038889Sjdp int error = 0; 8189857Sobrien 8291041Sobrien /* 8389857Sobrien * Find address for this interface, if it exists. 8460484Sobrien */ 8538889Sjdp if (ifp == NULL) 8689857Sobrien return (EADDRNOTAVAIL); 87218822Sdim for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 8838889Sjdp if (ia->ia_ifp == ifp) 89104834Sobrien break; 9038889Sjdp 91218822Sdim switch (cmd) { 9238889Sjdp 93130561Sobrien case SIOCGIFADDR: 9477298Sobrien if (ia == NULL) 95218822Sdim return (EADDRNOTAVAIL); 9638889Sjdp *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 97218822Sdim return (0); 9889857Sobrien 99130561Sobrien case SIOCGIFBRDADDR: 100218822Sdim if (ia == NULL) 10138889Sjdp return (EADDRNOTAVAIL); 10238889Sjdp if ((ifp->if_flags & IFF_BROADCAST) == 0) 10338889Sjdp return (EINVAL); 10478828Sobrien *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 10538889Sjdp return (0); 10638889Sjdp 10738889Sjdp case SIOCGIFDSTADDR: 10838889Sjdp if (ia == NULL) 10938889Sjdp return (EADDRNOTAVAIL); 11038889Sjdp if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 111218822Sdim return (EINVAL); 11238889Sjdp *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 11338889Sjdp return (0); 11438889Sjdp } 11538889Sjdp 11638889Sjdp if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 11738889Sjdp return (error); 11838889Sjdp 11938889Sjdp switch (cmd) { 12038889Sjdp case SIOCAIFADDR: 12138889Sjdp case SIOCDIFADDR: 12238889Sjdp if (ifra->ifra_addr.sipx_family == AF_IPX) 123218822Sdim for (oia = ia; ia != NULL; ia = ia->ia_next) { 12438889Sjdp if (ia->ia_ifp == ifp && 12538889Sjdp ipx_neteq(ia->ia_addr.sipx_addr, 126218822Sdim ifra->ifra_addr.sipx_addr)) 12738889Sjdp break; 128218822Sdim } 129218822Sdim if (cmd == SIOCDIFADDR && ia == NULL) 130218822Sdim return (EADDRNOTAVAIL); 13138889Sjdp /* FALLTHROUGH */ 13238889Sjdp 13338889Sjdp case SIOCSIFADDR: 13438889Sjdp case SIOCSIFDSTADDR: 13538889Sjdp if (ia == NULL) { 136218822Sdim oia = (struct ipx_ifaddr *) 137218822Sdim malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 138218822Sdim if (oia == NULL) 139218822Sdim return (ENOBUFS); 14038889Sjdp bzero((caddr_t)oia, sizeof(*oia)); 14138889Sjdp if ((ia = ipx_ifaddr) != NULL) { 14238889Sjdp for ( ; ia->ia_next != NULL; ia = ia->ia_next) 14338889Sjdp ; 14438889Sjdp ia->ia_next = oia; 14538889Sjdp } else 14638889Sjdp ipx_ifaddr = oia; 14738889Sjdp ia = oia; 14838889Sjdp ifa = (struct ifaddr *)ia; 14938889Sjdp TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 15060484Sobrien ia->ia_ifp = ifp; 15138889Sjdp ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 15277298Sobrien 15360484Sobrien ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 15460484Sobrien 15538889Sjdp ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 15660484Sobrien if (ifp->if_flags & IFF_BROADCAST) { 15760484Sobrien ia->ia_broadaddr.sipx_family = AF_IPX; 15860484Sobrien ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 15977298Sobrien ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 16060484Sobrien } 16177298Sobrien } 16277298Sobrien } 16377298Sobrien 16477298Sobrien switch (cmd) { 16560484Sobrien 16660484Sobrien case SIOCSIFDSTADDR: 16760484Sobrien if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 16860484Sobrien return (EINVAL); 16960484Sobrien if (ia->ia_flags & IFA_ROUTE) { 17038889Sjdp rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 17138889Sjdp ia->ia_flags &= ~IFA_ROUTE; 17238889Sjdp } 17338889Sjdp if (ifp->if_ioctl) { 17438889Sjdp error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 17538889Sjdp if (error) 17638889Sjdp return (error); 17738889Sjdp } 17838889Sjdp *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 17938889Sjdp return (0); 18060484Sobrien 181130561Sobrien case SIOCSIFADDR: 18238889Sjdp return (ipx_ifinit(ifp, ia, 18338889Sjdp (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 18438889Sjdp 18538889Sjdp case SIOCDIFADDR: 18638889Sjdp ipx_ifscrub(ifp, ia); 18738889Sjdp ifa = (struct ifaddr *)ia; 18838889Sjdp TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 18938889Sjdp oia = ia; 19038889Sjdp if (oia == (ia = ipx_ifaddr)) { 19138889Sjdp ipx_ifaddr = ia->ia_next; 19238889Sjdp } else { 19338889Sjdp while (ia->ia_next && (ia->ia_next != oia)) { 19438889Sjdp ia = ia->ia_next; 19538889Sjdp } 19638889Sjdp if (ia->ia_next) 19738889Sjdp ia->ia_next = oia->ia_next; 19838889Sjdp else 19938889Sjdp printf("Didn't unlink ipxifadr from list\n"); 20038889Sjdp } 20138889Sjdp IFAFREE((&oia->ia_ifa)); 20238889Sjdp return (0); 20338889Sjdp 204130561Sobrien case SIOCAIFADDR: 20538889Sjdp dstIsNew = 0; 20638889Sjdp hostIsNew = 1; 20738889Sjdp if (ia->ia_addr.sipx_family == AF_IPX) { 20860484Sobrien if (ifra->ifra_addr.sipx_len == 0) { 20938889Sjdp ifra->ifra_addr = ia->ia_addr; 21038889Sjdp hostIsNew = 0; 21160484Sobrien } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 21260484Sobrien ia->ia_addr.sipx_addr)) 213130561Sobrien hostIsNew = 0; 21438889Sjdp } 21538889Sjdp if ((ifp->if_flags & IFF_POINTOPOINT) && 21638889Sjdp (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 21738889Sjdp if (hostIsNew == 0) 21838889Sjdp ipx_ifscrub(ifp, ia); 21938889Sjdp ia->ia_dstaddr = ifra->ifra_dstaddr; 22038889Sjdp dstIsNew = 1; 22138889Sjdp } 222218822Sdim if (ifra->ifra_addr.sipx_family == AF_IPX && 22338889Sjdp (hostIsNew || dstIsNew)) 22438889Sjdp error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 22538889Sjdp return (error); 22638889Sjdp 22738889Sjdp default: 22838889Sjdp if (ifp->if_ioctl == NULL) 22938889Sjdp return (EOPNOTSUPP); 23038889Sjdp return ((*ifp->if_ioctl)(ifp, cmd, data)); 23138889Sjdp } 23238889Sjdp} 23338889Sjdp 23438889Sjdp/* 23538889Sjdp* Delete any previous route for an old address. 23638889Sjdp*/ 23738889Sjdpstatic void 23838889Sjdpipx_ifscrub(ifp, ia) 23938889Sjdp register struct ifnet *ifp; 24038889Sjdp register struct ipx_ifaddr *ia; 24138889Sjdp{ 24260484Sobrien if (ia->ia_flags & IFA_ROUTE) { 243218822Sdim if (ifp->if_flags & IFF_POINTOPOINT) { 244218822Sdim rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 24577298Sobrien } else 246218822Sdim rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 24738889Sjdp ia->ia_flags &= ~IFA_ROUTE; 24860484Sobrien } 249104834Sobrien} 25060484Sobrien/* 251104834Sobrien * Initialize an interface's internet address 25238889Sjdp * and routing table entry. 25338889Sjdp */ 25477298Sobrienstatic int 25560484Sobrienipx_ifinit(ifp, ia, sipx, scrub) 25638889Sjdp register struct ifnet *ifp; 25738889Sjdp register struct ipx_ifaddr *ia; 25838889Sjdp register struct sockaddr_ipx *sipx; 259130561Sobrien int scrub; 260218822Sdim{ 26138889Sjdp struct sockaddr_ipx oldaddr; 26277298Sobrien int s = splimp(), error; 26338889Sjdp 26460484Sobrien /* 265218822Sdim * Set up new addresses. 26638889Sjdp */ 26789857Sobrien oldaddr = ia->ia_addr; 26838889Sjdp ia->ia_addr = *sipx; 26938889Sjdp 270130561Sobrien /* 27138889Sjdp * The convention we shall adopt for naming is that 27289857Sobrien * a supplied address of zero means that "we don't care". 27391041Sobrien * Use the MAC address of the interface. If it is an 27489857Sobrien * interface without a MAC address, like a serial line, the 27560484Sobrien * address must be supplied. 27638889Sjdp * 27789857Sobrien * Give the interface a chance to initialize 278218822Sdim * if this is its first address, 27938889Sjdp * and to validate the address if necessary. 28091041Sobrien */ 28138889Sjdp if (ifp->if_ioctl != NULL && 282218822Sdim (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 28338889Sjdp ia->ia_addr = oldaddr; 28477298Sobrien splx(s); 28538889Sjdp return (error); 28638889Sjdp } 28789857Sobrien splx(s); 288218822Sdim ia->ia_ifa.ifa_metric = ifp->if_metric; 289130561Sobrien /* 290218822Sdim * Add route for the network. 29138889Sjdp */ 29238889Sjdp if (scrub) { 29338889Sjdp ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 29438889Sjdp ipx_ifscrub(ifp, ia); 29538889Sjdp ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 29638889Sjdp } 29760484Sobrien if (ifp->if_flags & IFF_POINTOPOINT) 298218822Sdim rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 299218822Sdim else { 30077298Sobrien ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 301218822Sdim rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 30238889Sjdp } 30360484Sobrien ia->ia_flags |= IFA_ROUTE; 304104834Sobrien return (0); 30560484Sobrien} 306104834Sobrien 30738889Sjdp/* 30838889Sjdp * Return address info for specified internet network. 30977298Sobrien */ 31060484Sobrienstruct ipx_ifaddr * 31138889Sjdpipx_iaonnetof(dst) 31238889Sjdp register struct ipx_addr *dst; 31338889Sjdp{ 314130561Sobrien register struct ipx_ifaddr *ia; 315218822Sdim register struct ipx_addr *compare; 31638889Sjdp register struct ifnet *ifp; 31777298Sobrien struct ipx_ifaddr *ia_maybe = NULL; 31838889Sjdp union ipx_net net = dst->x_net; 31960484Sobrien 320218822Sdim for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 32138889Sjdp if ((ifp = ia->ia_ifp) != NULL) { 32289857Sobrien if (ifp->if_flags & IFF_POINTOPOINT) { 32338889Sjdp compare = &satoipx_addr(ia->ia_dstaddr); 32438889Sjdp if (ipx_hosteq(*dst, *compare)) 325130561Sobrien return (ia); 32638889Sjdp if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 32789857Sobrien ia_maybe = ia; 32891041Sobrien } else { 32989857Sobrien if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 33060484Sobrien return (ia); 33138889Sjdp } 33289857Sobrien } 333218822Sdim } 33438889Sjdp return (ia_maybe); 33591041Sobrien} 33638889Sjdp