ipx.c revision 183113
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 183113 2008-09-17 15:49:44Z attilio $"); 64116189Sobrien 6511819Sjulian#include <sys/param.h> 66134445Srwatson#include <sys/kernel.h> 6711819Sjulian#include <sys/systm.h> 6826965Sjhay#include <sys/malloc.h> 69170689Srwatson#include <sys/priv.h> 7024204Sbde#include <sys/sockio.h> 7111819Sjulian#include <sys/socket.h> 7211819Sjulian 7311819Sjulian#include <net/if.h> 7411819Sjulian#include <net/route.h> 7511819Sjulian 7611819Sjulian#include <netipx/ipx.h> 7711819Sjulian#include <netipx/ipx_if.h> 7825652Sjhay#include <netipx/ipx_var.h> 7911819Sjulian 80134445Srwatson/* 81134445Srwatson * XXXRW: Requires synchronization. 82134445Srwatson */ 8311819Sjulianstruct ipx_ifaddr *ipx_ifaddr; 8411819Sjulian 8525652Sjhaystatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 8625652Sjhaystatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 8725652Sjhay struct sockaddr_ipx *sipx, int scrub); 8825652Sjhay 8911819Sjulian/* 9011819Sjulian * Generic internet control operations (ioctl's). 9111819Sjulian */ 9211819Sjulianint 93169463Srwatsonipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, 94169463Srwatson struct thread *td) 9511819Sjulian{ 96169463Srwatson struct ifreq *ifr = (struct ifreq *)data; 97169463Srwatson struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 98169463Srwatson struct ipx_ifaddr *ia; 9911819Sjulian struct ifaddr *ifa; 10011819Sjulian struct ipx_ifaddr *oia; 10111819Sjulian int dstIsNew, hostIsNew; 102183113Sattilio int error = 0, priv; 10311819Sjulian 10411819Sjulian /* 10511819Sjulian * Find address for this interface, if it exists. 10611819Sjulian */ 10725652Sjhay if (ifp == NULL) 10811819Sjulian return (EADDRNOTAVAIL); 10925652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 11011819Sjulian if (ia->ia_ifp == ifp) 11111819Sjulian break; 11211819Sjulian 11311819Sjulian switch (cmd) { 11411819Sjulian 11511819Sjulian case SIOCGIFADDR: 11625652Sjhay if (ia == NULL) 11711819Sjulian return (EADDRNOTAVAIL); 11811819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 11911819Sjulian return (0); 12011819Sjulian 12111819Sjulian case SIOCGIFBRDADDR: 12225652Sjhay if (ia == NULL) 12311819Sjulian return (EADDRNOTAVAIL); 12411819Sjulian if ((ifp->if_flags & IFF_BROADCAST) == 0) 12511819Sjulian return (EINVAL); 12611819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 12711819Sjulian return (0); 12811819Sjulian 12911819Sjulian case SIOCGIFDSTADDR: 13025652Sjhay if (ia == NULL) 13111819Sjulian return (EADDRNOTAVAIL); 13211819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 13311819Sjulian return (EINVAL); 13411819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 13511819Sjulian return (0); 13611819Sjulian } 13711819Sjulian 13811819Sjulian switch (cmd) { 13911819Sjulian case SIOCAIFADDR: 14011819Sjulian case SIOCDIFADDR: 141183113Sattilio priv = (cmd == SIOCAIFADDR) ? PRIV_NET_ADDIFADDR : 142183113Sattilio PRIV_NET_DELIFADDR; 143183113Sattilio if (td && (error = priv_check(td, priv)) != 0) 144183113Sattilio return (error); 14511819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX) 14625652Sjhay for (oia = ia; ia != NULL; ia = ia->ia_next) { 14711819Sjulian if (ia->ia_ifp == ifp && 14811819Sjulian ipx_neteq(ia->ia_addr.sipx_addr, 14911819Sjulian ifra->ifra_addr.sipx_addr)) 15011819Sjulian break; 15111819Sjulian } 15241617Seivind if (cmd == SIOCDIFADDR && ia == NULL) 15311819Sjulian return (EADDRNOTAVAIL); 15411819Sjulian /* FALLTHROUGH */ 15511819Sjulian 15611819Sjulian case SIOCSIFADDR: 15711819Sjulian case SIOCSIFDSTADDR: 158183113Sattilio if (td && (error = priv_check(td, PRIV_NET_SETLLADDR)) != 0) 159183113Sattilio return (error); 16025652Sjhay if (ia == NULL) { 16111819Sjulian oia = (struct ipx_ifaddr *) 16269781Sdwmalone malloc(sizeof(*ia), M_IFADDR, 163111119Simp M_WAITOK | M_ZERO); 16425652Sjhay if (oia == NULL) 16511819Sjulian return (ENOBUFS); 16625652Sjhay if ((ia = ipx_ifaddr) != NULL) { 16725652Sjhay for ( ; ia->ia_next != NULL; ia = ia->ia_next) 16811819Sjulian ; 16911819Sjulian ia->ia_next = oia; 17011819Sjulian } else 17111819Sjulian ipx_ifaddr = oia; 17211819Sjulian ia = oia; 17320407Swollman ifa = (struct ifaddr *)ia; 174109765Sfjoe IFA_LOCK_INIT(ifa); 175111487Stjr ifa->ifa_refcnt = 1; 17620407Swollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 17711819Sjulian ia->ia_ifp = ifp; 17820407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 17911819Sjulian 18020407Swollman ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 18111819Sjulian 18220407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 18311819Sjulian if (ifp->if_flags & IFF_BROADCAST) { 18411819Sjulian ia->ia_broadaddr.sipx_family = AF_IPX; 18511819Sjulian ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 18611819Sjulian ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 18711819Sjulian } 18811819Sjulian } 189183113Sattilio break; 190183113Sattilio default: 191183113Sattilio if (td && (error = priv_check(td, PRIV_NET_HWIOCTL)) != 0) 192183113Sattilio return (error); 19311819Sjulian } 19411819Sjulian 19511819Sjulian switch (cmd) { 19611819Sjulian 19711819Sjulian case SIOCSIFDSTADDR: 19811819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 19911819Sjulian return (EINVAL); 20011819Sjulian if (ia->ia_flags & IFA_ROUTE) { 20111819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 20211819Sjulian ia->ia_flags &= ~IFA_ROUTE; 20311819Sjulian } 20411819Sjulian if (ifp->if_ioctl) { 20511819Sjulian error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 20611819Sjulian if (error) 20711819Sjulian return (error); 20811819Sjulian } 20911819Sjulian *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 21011819Sjulian return (0); 21111819Sjulian 21211819Sjulian case SIOCSIFADDR: 21311819Sjulian return (ipx_ifinit(ifp, ia, 21411819Sjulian (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 21511819Sjulian 21611819Sjulian case SIOCDIFADDR: 21711819Sjulian ipx_ifscrub(ifp, ia); 21820407Swollman ifa = (struct ifaddr *)ia; 21920407Swollman TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 22011819Sjulian oia = ia; 22111819Sjulian if (oia == (ia = ipx_ifaddr)) { 22211819Sjulian ipx_ifaddr = ia->ia_next; 22311819Sjulian } else { 22411819Sjulian while (ia->ia_next && (ia->ia_next != oia)) { 22511819Sjulian ia = ia->ia_next; 22611819Sjulian } 22711819Sjulian if (ia->ia_next) 22811819Sjulian ia->ia_next = oia->ia_next; 22911819Sjulian else 23011819Sjulian printf("Didn't unlink ipxifadr from list\n"); 23111819Sjulian } 23211819Sjulian IFAFREE((&oia->ia_ifa)); 23311819Sjulian return (0); 234139584Srwatson 23511819Sjulian case SIOCAIFADDR: 23625652Sjhay dstIsNew = 0; 23725652Sjhay hostIsNew = 1; 23811819Sjulian if (ia->ia_addr.sipx_family == AF_IPX) { 23911819Sjulian if (ifra->ifra_addr.sipx_len == 0) { 24011819Sjulian ifra->ifra_addr = ia->ia_addr; 24111819Sjulian hostIsNew = 0; 24211819Sjulian } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 24311819Sjulian ia->ia_addr.sipx_addr)) 24411819Sjulian hostIsNew = 0; 24511819Sjulian } 24611819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) && 24711819Sjulian (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 24811819Sjulian if (hostIsNew == 0) 24911819Sjulian ipx_ifscrub(ifp, ia); 25011819Sjulian ia->ia_dstaddr = ifra->ifra_dstaddr; 25111819Sjulian dstIsNew = 1; 25211819Sjulian } 25311819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX && 25411819Sjulian (hostIsNew || dstIsNew)) 25511819Sjulian error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 25611819Sjulian return (error); 25711819Sjulian 25811819Sjulian default: 25925652Sjhay if (ifp->if_ioctl == NULL) 26011819Sjulian return (EOPNOTSUPP); 26111819Sjulian return ((*ifp->if_ioctl)(ifp, cmd, data)); 26211819Sjulian } 26311819Sjulian} 26411819Sjulian 26511819Sjulian/* 26611819Sjulian* Delete any previous route for an old address. 26711819Sjulian*/ 26825652Sjhaystatic void 269169463Srwatsonipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia) 27011819Sjulian{ 271169463Srwatson 27211819Sjulian if (ia->ia_flags & IFA_ROUTE) { 27311819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 27411819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 27511819Sjulian } else 27611819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 27711819Sjulian ia->ia_flags &= ~IFA_ROUTE; 27811819Sjulian } 27911819Sjulian} 28011819Sjulian/* 28111819Sjulian * Initialize an interface's internet address 28211819Sjulian * and routing table entry. 28311819Sjulian */ 28425652Sjhaystatic int 285169463Srwatsonipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 286169463Srwatson struct sockaddr_ipx *sipx, int scrub) 28711819Sjulian{ 28811819Sjulian struct sockaddr_ipx oldaddr; 28911819Sjulian int s = splimp(), error; 29011819Sjulian 29111819Sjulian /* 29211819Sjulian * Set up new addresses. 29311819Sjulian */ 29411819Sjulian oldaddr = ia->ia_addr; 29511819Sjulian ia->ia_addr = *sipx; 29625652Sjhay 29711819Sjulian /* 29811819Sjulian * The convention we shall adopt for naming is that 29911819Sjulian * a supplied address of zero means that "we don't care". 30025652Sjhay * Use the MAC address of the interface. If it is an 30125652Sjhay * interface without a MAC address, like a serial line, the 30225652Sjhay * address must be supplied. 30311819Sjulian * 30411819Sjulian * Give the interface a chance to initialize 30511819Sjulian * if this is its first address, 30611819Sjulian * and to validate the address if necessary. 30711819Sjulian */ 30825652Sjhay if (ifp->if_ioctl != NULL && 30925652Sjhay (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 31011819Sjulian ia->ia_addr = oldaddr; 31111819Sjulian splx(s); 31225652Sjhay return (error); 31311819Sjulian } 31425652Sjhay splx(s); 31511819Sjulian ia->ia_ifa.ifa_metric = ifp->if_metric; 31611819Sjulian /* 31711819Sjulian * Add route for the network. 31811819Sjulian */ 31911819Sjulian if (scrub) { 32011819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 32111819Sjulian ipx_ifscrub(ifp, ia); 32211819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 32311819Sjulian } 32411819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) 32511819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 32611819Sjulian else { 32711819Sjulian ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 32811819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 32911819Sjulian } 33011819Sjulian ia->ia_flags |= IFA_ROUTE; 33111819Sjulian return (0); 33211819Sjulian} 33311819Sjulian 33411819Sjulian/* 33511819Sjulian * Return address info for specified internet network. 33611819Sjulian */ 33711819Sjulianstruct ipx_ifaddr * 338169463Srwatsonipx_iaonnetof(struct ipx_addr *dst) 33911819Sjulian{ 340169463Srwatson struct ipx_ifaddr *ia; 341169463Srwatson struct ipx_addr *compare; 342169463Srwatson struct ifnet *ifp; 34325652Sjhay struct ipx_ifaddr *ia_maybe = NULL; 34411819Sjulian union ipx_net net = dst->x_net; 34511819Sjulian 34625652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 34725652Sjhay if ((ifp = ia->ia_ifp) != NULL) { 34811819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 34911819Sjulian compare = &satoipx_addr(ia->ia_dstaddr); 35011819Sjulian if (ipx_hosteq(*dst, *compare)) 35111819Sjulian return (ia); 35211819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 35311819Sjulian ia_maybe = ia; 35411819Sjulian } else { 35511819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 35611819Sjulian return (ia); 35711819Sjulian } 35811819Sjulian } 35911819Sjulian } 36011819Sjulian return (ia_maybe); 36111819Sjulian} 36226965Sjhay 36326965Sjhay 36426965Sjhayvoid 365169463Srwatsonipx_printhost(struct ipx_addr *addr) 36626965Sjhay{ 36726965Sjhay u_short port; 36826965Sjhay struct ipx_addr work = *addr; 369169463Srwatson char *p; u_char *q; 370169463Srwatson char *net = "", *host = ""; 37126965Sjhay char cport[10], chost[15], cnet[15]; 37226965Sjhay 37326965Sjhay port = ntohs(work.x_port); 37426965Sjhay 37526965Sjhay if (ipx_nullnet(work) && ipx_nullhost(work)) { 37626965Sjhay 37726965Sjhay if (port) 37826965Sjhay printf("*.%x", port); 37926965Sjhay else 38026965Sjhay printf("*.*"); 38126965Sjhay 38226965Sjhay return; 38326965Sjhay } 38426965Sjhay 38526965Sjhay if (ipx_wildnet(work)) 38626965Sjhay net = "any"; 38726965Sjhay else if (ipx_nullnet(work)) 38826965Sjhay net = "*"; 38926965Sjhay else { 39026965Sjhay q = work.x_net.c_net; 39141514Sarchie snprintf(cnet, sizeof(cnet), "%x%x%x%x", 39226965Sjhay q[0], q[1], q[2], q[3]); 39326965Sjhay for (p = cnet; *p == '0' && p < cnet + 8; p++) 39426965Sjhay continue; 39526965Sjhay net = p; 39626965Sjhay } 39726965Sjhay 39826965Sjhay if (ipx_wildhost(work)) 39926965Sjhay host = "any"; 40026965Sjhay else if (ipx_nullhost(work)) 40126965Sjhay host = "*"; 40226965Sjhay else { 40326965Sjhay q = work.x_host.c_host; 40441514Sarchie snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 40526965Sjhay q[0], q[1], q[2], q[3], q[4], q[5]); 40626965Sjhay for (p = chost; *p == '0' && p < chost + 12; p++) 40726965Sjhay continue; 40826965Sjhay host = p; 40926965Sjhay } 41026965Sjhay 41126965Sjhay if (port) { 41226965Sjhay if (strcmp(host, "*") == 0) { 41326965Sjhay host = ""; 41441514Sarchie snprintf(cport, sizeof(cport), "%x", port); 41526965Sjhay } else 41641514Sarchie snprintf(cport, sizeof(cport), ".%x", port); 41726965Sjhay } else 41826965Sjhay *cport = 0; 41926965Sjhay 42026965Sjhay printf("%s.%s%s", net, host, cport); 42126965Sjhay} 422