ipx.c revision 41514
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 * 3641514Sarchie * $Id: ipx.c,v 1.12 1998/06/07 17:12:18 dfr Exp $ 3711819Sjulian */ 3811819Sjulian 3911819Sjulian#include <sys/param.h> 4011819Sjulian#include <sys/systm.h> 4126965Sjhay#include <sys/malloc.h> 4224204Sbde#include <sys/sockio.h> 4325345Sjhay#include <sys/proc.h> 4411819Sjulian#include <sys/socket.h> 4511819Sjulian 4611819Sjulian#include <net/if.h> 4711819Sjulian#include <net/route.h> 4811819Sjulian 4911819Sjulian#include <netipx/ipx.h> 5011819Sjulian#include <netipx/ipx_if.h> 5125652Sjhay#include <netipx/ipx_var.h> 5211819Sjulian 5311819Sjulianstruct ipx_ifaddr *ipx_ifaddr; 5411819Sjulian 5525652Sjhaystatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 5625652Sjhaystatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 5725652Sjhay struct sockaddr_ipx *sipx, int scrub); 5825652Sjhay 5911819Sjulian/* 6011819Sjulian * Generic internet control operations (ioctl's). 6111819Sjulian */ 6211819Sjulianint 6325345Sjhayipx_control(so, cmd, data, ifp, p) 6411819Sjulian struct socket *so; 6536735Sdfr u_long cmd; 6611819Sjulian caddr_t data; 6711819Sjulian register struct ifnet *ifp; 6825345Sjhay struct proc *p; 6911819Sjulian{ 7011819Sjulian register struct ifreq *ifr = (struct ifreq *)data; 7111819Sjulian register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 7211819Sjulian register struct ipx_ifaddr *ia; 7311819Sjulian struct ifaddr *ifa; 7411819Sjulian struct ipx_ifaddr *oia; 7511819Sjulian int dstIsNew, hostIsNew; 7611819Sjulian int error = 0; 7711819Sjulian 7811819Sjulian /* 7911819Sjulian * Find address for this interface, if it exists. 8011819Sjulian */ 8125652Sjhay if (ifp == NULL) 8211819Sjulian return (EADDRNOTAVAIL); 8325652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 8411819Sjulian if (ia->ia_ifp == ifp) 8511819Sjulian break; 8611819Sjulian 8711819Sjulian switch (cmd) { 8811819Sjulian 8911819Sjulian case SIOCGIFADDR: 9025652Sjhay if (ia == NULL) 9111819Sjulian return (EADDRNOTAVAIL); 9211819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 9311819Sjulian return (0); 9411819Sjulian 9511819Sjulian case SIOCGIFBRDADDR: 9625652Sjhay if (ia == NULL) 9711819Sjulian return (EADDRNOTAVAIL); 9811819Sjulian if ((ifp->if_flags & IFF_BROADCAST) == 0) 9911819Sjulian return (EINVAL); 10011819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 10111819Sjulian return (0); 10211819Sjulian 10311819Sjulian case SIOCGIFDSTADDR: 10425652Sjhay if (ia == NULL) 10511819Sjulian return (EADDRNOTAVAIL); 10611819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 10711819Sjulian return (EINVAL); 10811819Sjulian *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 10911819Sjulian return (0); 11011819Sjulian } 11111819Sjulian 11225345Sjhay if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 11325345Sjhay return (error); 11411819Sjulian 11511819Sjulian switch (cmd) { 11611819Sjulian case SIOCAIFADDR: 11711819Sjulian case SIOCDIFADDR: 11811819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX) 11925652Sjhay for (oia = ia; ia != NULL; ia = ia->ia_next) { 12011819Sjulian if (ia->ia_ifp == ifp && 12111819Sjulian ipx_neteq(ia->ia_addr.sipx_addr, 12211819Sjulian ifra->ifra_addr.sipx_addr)) 12311819Sjulian break; 12411819Sjulian } 12525652Sjhay if (cmd == SIOCDIFADDR && ia == NULL) 12611819Sjulian return (EADDRNOTAVAIL); 12711819Sjulian /* FALLTHROUGH */ 12811819Sjulian 12911819Sjulian case SIOCSIFADDR: 13011819Sjulian case SIOCSIFDSTADDR: 13125652Sjhay if (ia == NULL) { 13211819Sjulian oia = (struct ipx_ifaddr *) 13325652Sjhay malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 13425652Sjhay if (oia == NULL) 13511819Sjulian return (ENOBUFS); 13611819Sjulian bzero((caddr_t)oia, sizeof(*oia)); 13725652Sjhay if ((ia = ipx_ifaddr) != NULL) { 13825652Sjhay for ( ; ia->ia_next != NULL; ia = ia->ia_next) 13911819Sjulian ; 14011819Sjulian ia->ia_next = oia; 14111819Sjulian } else 14211819Sjulian ipx_ifaddr = oia; 14311819Sjulian ia = oia; 14420407Swollman ifa = (struct ifaddr *)ia; 14520407Swollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 14611819Sjulian ia->ia_ifp = ifp; 14720407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 14811819Sjulian 14920407Swollman ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 15011819Sjulian 15120407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 15211819Sjulian if (ifp->if_flags & IFF_BROADCAST) { 15311819Sjulian ia->ia_broadaddr.sipx_family = AF_IPX; 15411819Sjulian ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 15511819Sjulian ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 15611819Sjulian } 15711819Sjulian } 15811819Sjulian } 15911819Sjulian 16011819Sjulian switch (cmd) { 16111819Sjulian 16211819Sjulian case SIOCSIFDSTADDR: 16311819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 16411819Sjulian return (EINVAL); 16511819Sjulian if (ia->ia_flags & IFA_ROUTE) { 16611819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 16711819Sjulian ia->ia_flags &= ~IFA_ROUTE; 16811819Sjulian } 16911819Sjulian if (ifp->if_ioctl) { 17011819Sjulian error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 17111819Sjulian if (error) 17211819Sjulian return (error); 17311819Sjulian } 17411819Sjulian *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 17511819Sjulian return (0); 17611819Sjulian 17711819Sjulian case SIOCSIFADDR: 17811819Sjulian return (ipx_ifinit(ifp, ia, 17911819Sjulian (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 18011819Sjulian 18111819Sjulian case SIOCDIFADDR: 18211819Sjulian ipx_ifscrub(ifp, ia); 18320407Swollman ifa = (struct ifaddr *)ia; 18420407Swollman TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 18511819Sjulian oia = ia; 18611819Sjulian if (oia == (ia = ipx_ifaddr)) { 18711819Sjulian ipx_ifaddr = ia->ia_next; 18811819Sjulian } else { 18911819Sjulian while (ia->ia_next && (ia->ia_next != oia)) { 19011819Sjulian ia = ia->ia_next; 19111819Sjulian } 19211819Sjulian if (ia->ia_next) 19311819Sjulian ia->ia_next = oia->ia_next; 19411819Sjulian else 19511819Sjulian printf("Didn't unlink ipxifadr from list\n"); 19611819Sjulian } 19711819Sjulian IFAFREE((&oia->ia_ifa)); 19811819Sjulian return (0); 19911819Sjulian 20011819Sjulian case SIOCAIFADDR: 20125652Sjhay dstIsNew = 0; 20225652Sjhay hostIsNew = 1; 20311819Sjulian if (ia->ia_addr.sipx_family == AF_IPX) { 20411819Sjulian if (ifra->ifra_addr.sipx_len == 0) { 20511819Sjulian ifra->ifra_addr = ia->ia_addr; 20611819Sjulian hostIsNew = 0; 20711819Sjulian } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 20811819Sjulian ia->ia_addr.sipx_addr)) 20911819Sjulian hostIsNew = 0; 21011819Sjulian } 21111819Sjulian if ((ifp->if_flags & IFF_POINTOPOINT) && 21211819Sjulian (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 21311819Sjulian if (hostIsNew == 0) 21411819Sjulian ipx_ifscrub(ifp, ia); 21511819Sjulian ia->ia_dstaddr = ifra->ifra_dstaddr; 21611819Sjulian dstIsNew = 1; 21711819Sjulian } 21811819Sjulian if (ifra->ifra_addr.sipx_family == AF_IPX && 21911819Sjulian (hostIsNew || dstIsNew)) 22011819Sjulian error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 22111819Sjulian return (error); 22211819Sjulian 22311819Sjulian default: 22425652Sjhay if (ifp->if_ioctl == NULL) 22511819Sjulian return (EOPNOTSUPP); 22611819Sjulian return ((*ifp->if_ioctl)(ifp, cmd, data)); 22711819Sjulian } 22811819Sjulian} 22911819Sjulian 23011819Sjulian/* 23111819Sjulian* Delete any previous route for an old address. 23211819Sjulian*/ 23325652Sjhaystatic void 23411819Sjulianipx_ifscrub(ifp, ia) 23511819Sjulian register struct ifnet *ifp; 23611819Sjulian register struct ipx_ifaddr *ia; 23711819Sjulian{ 23811819Sjulian if (ia->ia_flags & IFA_ROUTE) { 23911819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 24011819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 24111819Sjulian } else 24211819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 24311819Sjulian ia->ia_flags &= ~IFA_ROUTE; 24411819Sjulian } 24511819Sjulian} 24611819Sjulian/* 24711819Sjulian * Initialize an interface's internet address 24811819Sjulian * and routing table entry. 24911819Sjulian */ 25025652Sjhaystatic int 25111819Sjulianipx_ifinit(ifp, ia, sipx, scrub) 25211819Sjulian register struct ifnet *ifp; 25311819Sjulian register struct ipx_ifaddr *ia; 25411819Sjulian register struct sockaddr_ipx *sipx; 25511819Sjulian int scrub; 25611819Sjulian{ 25711819Sjulian struct sockaddr_ipx oldaddr; 25811819Sjulian int s = splimp(), error; 25911819Sjulian 26011819Sjulian /* 26111819Sjulian * Set up new addresses. 26211819Sjulian */ 26311819Sjulian oldaddr = ia->ia_addr; 26411819Sjulian ia->ia_addr = *sipx; 26525652Sjhay 26611819Sjulian /* 26711819Sjulian * The convention we shall adopt for naming is that 26811819Sjulian * a supplied address of zero means that "we don't care". 26925652Sjhay * Use the MAC address of the interface. If it is an 27025652Sjhay * interface without a MAC address, like a serial line, the 27125652Sjhay * address must be supplied. 27211819Sjulian * 27311819Sjulian * Give the interface a chance to initialize 27411819Sjulian * if this is its first address, 27511819Sjulian * and to validate the address if necessary. 27611819Sjulian */ 27725652Sjhay if (ifp->if_ioctl != NULL && 27825652Sjhay (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 27911819Sjulian ia->ia_addr = oldaddr; 28011819Sjulian splx(s); 28125652Sjhay return (error); 28211819Sjulian } 28325652Sjhay splx(s); 28411819Sjulian ia->ia_ifa.ifa_metric = ifp->if_metric; 28511819Sjulian /* 28611819Sjulian * Add route for the network. 28711819Sjulian */ 28811819Sjulian if (scrub) { 28911819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 29011819Sjulian ipx_ifscrub(ifp, ia); 29111819Sjulian ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 29211819Sjulian } 29311819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) 29411819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 29511819Sjulian else { 29611819Sjulian ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 29711819Sjulian rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 29811819Sjulian } 29911819Sjulian ia->ia_flags |= IFA_ROUTE; 30011819Sjulian return (0); 30111819Sjulian} 30211819Sjulian 30311819Sjulian/* 30411819Sjulian * Return address info for specified internet network. 30511819Sjulian */ 30611819Sjulianstruct ipx_ifaddr * 30711819Sjulianipx_iaonnetof(dst) 30811819Sjulian register struct ipx_addr *dst; 30911819Sjulian{ 31011819Sjulian register struct ipx_ifaddr *ia; 31111819Sjulian register struct ipx_addr *compare; 31211819Sjulian register struct ifnet *ifp; 31325652Sjhay struct ipx_ifaddr *ia_maybe = NULL; 31411819Sjulian union ipx_net net = dst->x_net; 31511819Sjulian 31625652Sjhay for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 31725652Sjhay if ((ifp = ia->ia_ifp) != NULL) { 31811819Sjulian if (ifp->if_flags & IFF_POINTOPOINT) { 31911819Sjulian compare = &satoipx_addr(ia->ia_dstaddr); 32011819Sjulian if (ipx_hosteq(*dst, *compare)) 32111819Sjulian return (ia); 32211819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 32311819Sjulian ia_maybe = ia; 32411819Sjulian } else { 32511819Sjulian if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 32611819Sjulian return (ia); 32711819Sjulian } 32811819Sjulian } 32911819Sjulian } 33011819Sjulian return (ia_maybe); 33111819Sjulian} 33226965Sjhay 33326965Sjhay 33426965Sjhayvoid 33526965Sjhayipx_printhost(addr) 33626965Sjhayregister struct ipx_addr *addr; 33726965Sjhay{ 33826965Sjhay u_short port; 33926965Sjhay struct ipx_addr work = *addr; 34026965Sjhay register char *p; register u_char *q; 34126965Sjhay register char *net = "", *host = ""; 34226965Sjhay char cport[10], chost[15], cnet[15]; 34326965Sjhay 34426965Sjhay port = ntohs(work.x_port); 34526965Sjhay 34626965Sjhay if (ipx_nullnet(work) && ipx_nullhost(work)) { 34726965Sjhay 34826965Sjhay if (port) 34926965Sjhay printf("*.%x", port); 35026965Sjhay else 35126965Sjhay printf("*.*"); 35226965Sjhay 35326965Sjhay return; 35426965Sjhay } 35526965Sjhay 35626965Sjhay if (ipx_wildnet(work)) 35726965Sjhay net = "any"; 35826965Sjhay else if (ipx_nullnet(work)) 35926965Sjhay net = "*"; 36026965Sjhay else { 36126965Sjhay q = work.x_net.c_net; 36241514Sarchie snprintf(cnet, sizeof(cnet), "%x%x%x%x", 36326965Sjhay q[0], q[1], q[2], q[3]); 36426965Sjhay for (p = cnet; *p == '0' && p < cnet + 8; p++) 36526965Sjhay continue; 36626965Sjhay net = p; 36726965Sjhay } 36826965Sjhay 36926965Sjhay if (ipx_wildhost(work)) 37026965Sjhay host = "any"; 37126965Sjhay else if (ipx_nullhost(work)) 37226965Sjhay host = "*"; 37326965Sjhay else { 37426965Sjhay q = work.x_host.c_host; 37541514Sarchie snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 37626965Sjhay q[0], q[1], q[2], q[3], q[4], q[5]); 37726965Sjhay for (p = chost; *p == '0' && p < chost + 12; p++) 37826965Sjhay continue; 37926965Sjhay host = p; 38026965Sjhay } 38126965Sjhay 38226965Sjhay if (port) { 38326965Sjhay if (strcmp(host, "*") == 0) { 38426965Sjhay host = ""; 38541514Sarchie snprintf(cport, sizeof(cport), "%x", port); 38626965Sjhay } else 38741514Sarchie snprintf(cport, sizeof(cport), ".%x", port); 38826965Sjhay } else 38926965Sjhay *cport = 0; 39026965Sjhay 39126965Sjhay printf("%s.%s%s", net, host, cport); 39226965Sjhay} 393