ipx.c revision 169463
1139823Simp/*- 211819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 311819Sjulian * The Regents of the University of California. All rights reserved. 411819Sjulian * 511819Sjulian * Redistribution and use in source and binary forms, with or without 611819Sjulian * modification, are permitted provided that the following conditions 711819Sjulian * are met: 811819Sjulian * 1. Redistributions of source code must retain the above copyright 911819Sjulian * notice, this list of conditions and the following disclaimer. 1011819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1111819Sjulian * notice, this list of conditions and the following disclaimer in the 1211819Sjulian * documentation and/or other materials provided with the distribution. 13165899Srwatson * 4. Neither the name of the University nor the names of its contributors 14165899Srwatson * may be used to endorse or promote products derived from this software 15165899Srwatson * without specific prior written permission. 16165899Srwatson * 17165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20165899Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27165899Srwatson * SUCH DAMAGE. 28165899Srwatson * 29165899Srwatson * Copyright (c) 1995, Mike Mitchell 30165899Srwatson * 31165899Srwatson * Redistribution and use in source and binary forms, with or without 32165899Srwatson * modification, are permitted provided that the following conditions 33165899Srwatson * are met: 34165899Srwatson * 1. Redistributions of source code must retain the above copyright 35165899Srwatson * notice, this list of conditions and the following disclaimer. 36165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright 37165899Srwatson * notice, this list of conditions and the following disclaimer in the 38165899Srwatson * documentation and/or other materials provided with the distribution. 3911819Sjulian * 3. All advertising materials mentioning features or use of this software 4011819Sjulian * must display the following acknowledgement: 4111819Sjulian * This product includes software developed by the University of 4211819Sjulian * California, Berkeley and its contributors. 4311819Sjulian * 4. Neither the name of the University nor the names of its contributors 4411819Sjulian * may be used to endorse or promote products derived from this software 4511819Sjulian * without specific prior written permission. 4611819Sjulian * 4711819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4811819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4911819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5011819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5111819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5211819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5311819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5411819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5511819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5611819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5711819Sjulian * SUCH DAMAGE. 58139584Srwatson * 5912057Sjulian * @(#)ipx.c 6011819Sjulian */ 6111819Sjulian 62116189Sobrien#include <sys/cdefs.h> 63116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx.c 169463 2007-05-11 10:38:34Z rwatson $"); 64116189Sobrien 6511819Sjulian#include <sys/param.h> 66134445Srwatson#include <sys/kernel.h> 6711819Sjulian#include <sys/systm.h> 6826965Sjhay#include <sys/malloc.h> 6924204Sbde#include <sys/sockio.h> 7011819Sjulian#include <sys/socket.h> 7111819Sjulian 7211819Sjulian#include <net/if.h> 7311819Sjulian#include <net/route.h> 7411819Sjulian 7511819Sjulian#include <netipx/ipx.h> 7611819Sjulian#include <netipx/ipx_if.h> 7725652Sjhay#include <netipx/ipx_var.h> 7811819Sjulian 79134445Srwatson/* 80134445Srwatson * XXXRW: Requires synchronization. 81134445Srwatson */ 8211819Sjulianstruct ipx_ifaddr *ipx_ifaddr; 8311819Sjulian 8425652Sjhaystatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 8525652Sjhaystatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 8625652Sjhay struct sockaddr_ipx *sipx, int scrub); 8725652Sjhay 8811819Sjulian/* 8911819Sjulian * Generic internet control operations (ioctl's). 9011819Sjulian */ 9111819Sjulianint 92169463Srwatsonipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, 93169463Srwatson struct thread *td) 9411819Sjulian{ 95169463Srwatson struct ifreq *ifr = (struct ifreq *)data; 96169463Srwatson struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 97169463Srwatson struct ipx_ifaddr *ia; 9811819Sjulian struct ifaddr *ifa; 9911819Sjulian struct ipx_ifaddr *oia; 10011819Sjulian int dstIsNew, hostIsNew; 10111819Sjulian int error = 0; 10211819Sjulian 10311819Sjulian /* 10411819Sjulian * Find address for this interface, if it exists. 10511819Sjulian */ 10625652Sjhay if (ifp == NULL) 10711819Sjulian return (EADDRNOTAVAIL); 10825652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 10911819Sjulian if (ia->ia_ifp == ifp) 11011819Sjulian break; 11111819Sjulian 11211819Sjulian switch (cmd) { 11311819Sjulian 11411819Sjulian case SIOCGIFADDR: 11525652Sjhay if (ia == NULL) 11611819Sjulian return (EADDRNOTAVAIL); 11711819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 11811819Sjulian return (0); 11911819Sjulian 12011819Sjulian case SIOCGIFBRDADDR: 12125652Sjhay if (ia == NULL) 12211819Sjulian return (EADDRNOTAVAIL); 12311819Sjulian if ((ifp->if_flags & IFF_BROADCAST) == 0) 12411819Sjulian return (EINVAL); 12511819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 12611819Sjulian return (0); 12711819Sjulian 12811819Sjulian case SIOCGIFDSTADDR: 12925652Sjhay if (ia == NULL) 13011819Sjulian return (EADDRNOTAVAIL); 13111819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 13211819Sjulian return (EINVAL); 13311819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 13411819Sjulian return (0); 13511819Sjulian } 13611819Sjulian 13793593Sjhb if (td && (error = suser(td)) != 0) 13825345Sjhay return (error); 13911819Sjulian 14011819Sjulian switch (cmd) { 14111819Sjulian case SIOCAIFADDR: 14211819Sjulian case SIOCDIFADDR: 14311819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX) 14425652Sjhay for (oia = ia; ia != NULL; ia = ia->ia_next) { 14511819Sjulian if (ia->ia_ifp == ifp && 14611819Sjulian ipx_neteq(ia->ia_addr.sipx_addr, 14711819Sjulian ifra->ifra_addr.sipx_addr)) 14811819Sjulian break; 14911819Sjulian } 15041617Seivind if (cmd == SIOCDIFADDR && ia == NULL) 15111819Sjulian return (EADDRNOTAVAIL); 15211819Sjulian /* FALLTHROUGH */ 15311819Sjulian 15411819Sjulian case SIOCSIFADDR: 15511819Sjulian case SIOCSIFDSTADDR: 15625652Sjhay if (ia == NULL) { 15711819Sjulian oia = (struct ipx_ifaddr *) 15869781Sdwmalone malloc(sizeof(*ia), M_IFADDR, 159111119Simp M_WAITOK | M_ZERO); 16025652Sjhay if (oia == NULL) 16111819Sjulian return (ENOBUFS); 16225652Sjhay if ((ia = ipx_ifaddr) != NULL) { 16325652Sjhay for ( ; ia->ia_next != NULL; ia = ia->ia_next) 16411819Sjulian ; 16511819Sjulian ia->ia_next = oia; 16611819Sjulian } else 16711819Sjulian ipx_ifaddr = oia; 16811819Sjulian ia = oia; 16920407Swollman ifa = (struct ifaddr *)ia; 170109765Sfjoe IFA_LOCK_INIT(ifa); 171111487Stjr ifa->ifa_refcnt = 1; 17220407Swollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 17311819Sjulian ia->ia_ifp = ifp; 17420407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 17511819Sjulian 17620407Swollman ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 17711819Sjulian 17820407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 17911819Sjulian if (ifp->if_flags & IFF_BROADCAST) { 18011819Sjulian ia->ia_broadaddr.sipx_family = AF_IPX; 18111819Sjulian ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 18211819Sjulian ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 18311819Sjulian } 18411819Sjulian } 18511819Sjulian } 18611819Sjulian 18711819Sjulian switch (cmd) { 18811819Sjulian 18911819Sjulian case SIOCSIFDSTADDR: 19011819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 19111819Sjulian return (EINVAL); 19211819Sjulian if (ia->ia_flags & IFA_ROUTE) { 19311819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 19411819Sjulian ia->ia_flags &= ~IFA_ROUTE; 19511819Sjulian } 19611819Sjulian if (ifp->if_ioctl) { 19711819Sjulian error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 19811819Sjulian if (error) 19911819Sjulian return (error); 20011819Sjulian } 20111819Sjulian *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 20211819Sjulian return (0); 20311819Sjulian 20411819Sjulian case SIOCSIFADDR: 20511819Sjulian return (ipx_ifinit(ifp, ia, 20611819Sjulian (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 20711819Sjulian 20811819Sjulian case SIOCDIFADDR: 20911819Sjulian ipx_ifscrub(ifp, ia); 21020407Swollman ifa = (struct ifaddr *)ia; 21120407Swollman TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 21211819Sjulian oia = ia; 21311819Sjulian if (oia == (ia = ipx_ifaddr)) { 21411819Sjulian ipx_ifaddr = ia->ia_next; 21511819Sjulian } else { 21611819Sjulian while (ia->ia_next && (ia->ia_next != oia)) { 21711819Sjulian ia = ia->ia_next; 21811819Sjulian } 21911819Sjulian if (ia->ia_next) 22011819Sjulian ia->ia_next = oia->ia_next; 22111819Sjulian else 22211819Sjulian printf("Didn't unlink ipxifadr from list\n"); 22311819Sjulian } 22411819Sjulian IFAFREE((&oia->ia_ifa)); 22511819Sjulian return (0); 226139584Srwatson 22711819Sjulian case SIOCAIFADDR: 22825652Sjhay dstIsNew = 0; 22925652Sjhay hostIsNew = 1; 23011819Sjulian if (ia->ia_addr.sipx_family == AF_IPX) { 23111819Sjulian if (ifra->ifra_addr.sipx_len == 0) { 23211819Sjulian ifra->ifra_addr = ia->ia_addr; 23311819Sjulian hostIsNew = 0; 23411819Sjulian } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 23511819Sjulian ia->ia_addr.sipx_addr)) 23611819Sjulian hostIsNew = 0; 23711819Sjulian } 23811819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) && 23911819Sjulian (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 24011819Sjulian if (hostIsNew == 0) 24111819Sjulian ipx_ifscrub(ifp, ia); 24211819Sjulian ia->ia_dstaddr = ifra->ifra_dstaddr; 24311819Sjulian dstIsNew = 1; 24411819Sjulian } 24511819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX && 24611819Sjulian (hostIsNew || dstIsNew)) 24711819Sjulian error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 24811819Sjulian return (error); 24911819Sjulian 25011819Sjulian default: 25125652Sjhay if (ifp->if_ioctl == NULL) 25211819Sjulian return (EOPNOTSUPP); 25311819Sjulian return ((*ifp->if_ioctl)(ifp, cmd, data)); 25411819Sjulian } 25511819Sjulian} 25611819Sjulian 25711819Sjulian/* 25811819Sjulian* Delete any previous route for an old address. 25911819Sjulian*/ 26025652Sjhaystatic void 261169463Srwatsonipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia) 26211819Sjulian{ 263169463Srwatson 26411819Sjulian if (ia->ia_flags & IFA_ROUTE) { 26511819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 26611819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 26711819Sjulian } else 26811819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 26911819Sjulian ia->ia_flags &= ~IFA_ROUTE; 27011819Sjulian } 27111819Sjulian} 27211819Sjulian/* 27311819Sjulian * Initialize an interface's internet address 27411819Sjulian * and routing table entry. 27511819Sjulian */ 27625652Sjhaystatic int 277169463Srwatsonipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 278169463Srwatson struct sockaddr_ipx *sipx, int scrub) 27911819Sjulian{ 28011819Sjulian struct sockaddr_ipx oldaddr; 28111819Sjulian int s = splimp(), error; 28211819Sjulian 28311819Sjulian /* 28411819Sjulian * Set up new addresses. 28511819Sjulian */ 28611819Sjulian oldaddr = ia->ia_addr; 28711819Sjulian ia->ia_addr = *sipx; 28825652Sjhay 28911819Sjulian /* 29011819Sjulian * The convention we shall adopt for naming is that 29111819Sjulian * a supplied address of zero means that "we don't care". 29225652Sjhay * Use the MAC address of the interface. If it is an 29325652Sjhay * interface without a MAC address, like a serial line, the 29425652Sjhay * address must be supplied. 29511819Sjulian * 29611819Sjulian * Give the interface a chance to initialize 29711819Sjulian * if this is its first address, 29811819Sjulian * and to validate the address if necessary. 29911819Sjulian */ 30025652Sjhay if (ifp->if_ioctl != NULL && 30125652Sjhay (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 30211819Sjulian ia->ia_addr = oldaddr; 30311819Sjulian splx(s); 30425652Sjhay return (error); 30511819Sjulian } 30625652Sjhay splx(s); 30711819Sjulian ia->ia_ifa.ifa_metric = ifp->if_metric; 30811819Sjulian /* 30911819Sjulian * Add route for the network. 31011819Sjulian */ 31111819Sjulian if (scrub) { 31211819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 31311819Sjulian ipx_ifscrub(ifp, ia); 31411819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 31511819Sjulian } 31611819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) 31711819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 31811819Sjulian else { 31911819Sjulian ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 32011819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 32111819Sjulian } 32211819Sjulian ia->ia_flags |= IFA_ROUTE; 32311819Sjulian return (0); 32411819Sjulian} 32511819Sjulian 32611819Sjulian/* 32711819Sjulian * Return address info for specified internet network. 32811819Sjulian */ 32911819Sjulianstruct ipx_ifaddr * 330169463Srwatsonipx_iaonnetof(struct ipx_addr *dst) 33111819Sjulian{ 332169463Srwatson struct ipx_ifaddr *ia; 333169463Srwatson struct ipx_addr *compare; 334169463Srwatson struct ifnet *ifp; 33525652Sjhay struct ipx_ifaddr *ia_maybe = NULL; 33611819Sjulian union ipx_net net = dst->x_net; 33711819Sjulian 33825652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 33925652Sjhay if ((ifp = ia->ia_ifp) != NULL) { 34011819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 34111819Sjulian compare = &satoipx_addr(ia->ia_dstaddr); 34211819Sjulian if (ipx_hosteq(*dst, *compare)) 34311819Sjulian return (ia); 34411819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 34511819Sjulian ia_maybe = ia; 34611819Sjulian } else { 34711819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 34811819Sjulian return (ia); 34911819Sjulian } 35011819Sjulian } 35111819Sjulian } 35211819Sjulian return (ia_maybe); 35311819Sjulian} 35426965Sjhay 35526965Sjhay 35626965Sjhayvoid 357169463Srwatsonipx_printhost(struct ipx_addr *addr) 35826965Sjhay{ 35926965Sjhay u_short port; 36026965Sjhay struct ipx_addr work = *addr; 361169463Srwatson char *p; u_char *q; 362169463Srwatson char *net = "", *host = ""; 36326965Sjhay char cport[10], chost[15], cnet[15]; 36426965Sjhay 36526965Sjhay port = ntohs(work.x_port); 36626965Sjhay 36726965Sjhay if (ipx_nullnet(work) && ipx_nullhost(work)) { 36826965Sjhay 36926965Sjhay if (port) 37026965Sjhay printf("*.%x", port); 37126965Sjhay else 37226965Sjhay printf("*.*"); 37326965Sjhay 37426965Sjhay return; 37526965Sjhay } 37626965Sjhay 37726965Sjhay if (ipx_wildnet(work)) 37826965Sjhay net = "any"; 37926965Sjhay else if (ipx_nullnet(work)) 38026965Sjhay net = "*"; 38126965Sjhay else { 38226965Sjhay q = work.x_net.c_net; 38341514Sarchie snprintf(cnet, sizeof(cnet), "%x%x%x%x", 38426965Sjhay q[0], q[1], q[2], q[3]); 38526965Sjhay for (p = cnet; *p == '0' && p < cnet + 8; p++) 38626965Sjhay continue; 38726965Sjhay net = p; 38826965Sjhay } 38926965Sjhay 39026965Sjhay if (ipx_wildhost(work)) 39126965Sjhay host = "any"; 39226965Sjhay else if (ipx_nullhost(work)) 39326965Sjhay host = "*"; 39426965Sjhay else { 39526965Sjhay q = work.x_host.c_host; 39641514Sarchie snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 39726965Sjhay q[0], q[1], q[2], q[3], q[4], q[5]); 39826965Sjhay for (p = chost; *p == '0' && p < chost + 12; p++) 39926965Sjhay continue; 40026965Sjhay host = p; 40126965Sjhay } 40226965Sjhay 40326965Sjhay if (port) { 40426965Sjhay if (strcmp(host, "*") == 0) { 40526965Sjhay host = ""; 40641514Sarchie snprintf(cport, sizeof(cport), "%x", port); 40726965Sjhay } else 40841514Sarchie snprintf(cport, sizeof(cport), ".%x", port); 40926965Sjhay } else 41026965Sjhay *cport = 0; 41126965Sjhay 41226965Sjhay printf("%s.%s%s", net, host, cport); 41326965Sjhay} 414