ipx.c revision 41617
1169689Skan/* 2169689Skan * Copyright (c) 1995, Mike Mitchell 3169689Skan * Copyright (c) 1984, 1985, 1986, 1987, 1993 4169689Skan * The Regents of the University of California. All rights reserved. 5169689Skan * 6169689Skan * Redistribution and use in source and binary forms, with or without 7169689Skan * modification, are permitted provided that the following conditions 8169689Skan * are met: 9169689Skan * 1. Redistributions of source code must retain the above copyright 10169689Skan * notice, this list of conditions and the following disclaimer. 11169689Skan * 2. Redistributions in binary form must reproduce the above copyright 12169689Skan * notice, this list of conditions and the following disclaimer in the 13169689Skan * documentation and/or other materials provided with the distribution. 14169689Skan * 3. All advertising materials mentioning features or use of this software 15169689Skan * must display the following acknowledgement: 16169689Skan * This product includes software developed by the University of 17169689Skan * California, Berkeley and its contributors. 18169689Skan * 4. Neither the name of the University nor the names of its contributors 19169689Skan * may be used to endorse or promote products derived from this software 20169689Skan * without specific prior written permission. 21169689Skan * 22169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32169689Skan * SUCH DAMAGE. 33169689Skan * 34169689Skan * @(#)ipx.c 35169689Skan * 36169689Skan * $Id: ipx.c,v 1.13 1998/12/04 22:54:54 archie Exp $ 37169689Skan */ 38169689Skan 39169689Skan#include <sys/param.h> 40169689Skan#include <sys/systm.h> 41169689Skan#include <sys/malloc.h> 42169689Skan#include <sys/sockio.h> 43169689Skan#include <sys/proc.h> 44169689Skan#include <sys/socket.h> 45169689Skan 46169689Skan#include <net/if.h> 47169689Skan#include <net/route.h> 48169689Skan 49169689Skan#include <netipx/ipx.h> 50169689Skan#include <netipx/ipx_if.h> 51169689Skan#include <netipx/ipx_var.h> 52169689Skan 53169689Skanstruct ipx_ifaddr *ipx_ifaddr; 54169689Skan 55169689Skanstatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 56169689Skanstatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 57169689Skan struct sockaddr_ipx *sipx, int scrub); 58169689Skan 59169689Skan/* 60169689Skan * Generic internet control operations (ioctl's). 61169689Skan */ 62169689Skanint 63169689Skanipx_control(so, cmd, data, ifp, p) 64169689Skan struct socket *so; 65169689Skan u_long cmd; 66169689Skan caddr_t data; 67169689Skan register struct ifnet *ifp; 68169689Skan struct proc *p; 69169689Skan{ 70169689Skan register struct ifreq *ifr = (struct ifreq *)data; 71169689Skan register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 72169689Skan register struct ipx_ifaddr *ia; 73169689Skan struct ifaddr *ifa; 74169689Skan struct ipx_ifaddr *oia; 75169689Skan int dstIsNew, hostIsNew; 76169689Skan int error = 0; 77169689Skan 78169689Skan /* 79169689Skan * Find address for this interface, if it exists. 80169689Skan */ 81169689Skan if (ifp == NULL) 82169689Skan return (EADDRNOTAVAIL); 83169689Skan for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 84169689Skan if (ia->ia_ifp == ifp) 85169689Skan break; 86169689Skan 87169689Skan switch (cmd) { 88169689Skan 89169689Skan case SIOCGIFADDR: 90169689Skan if (ia == NULL) 91169689Skan return (EADDRNOTAVAIL); 92169689Skan *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 93169689Skan return (0); 94169689Skan 95169689Skan case SIOCGIFBRDADDR: 96169689Skan if (ia == NULL) 97169689Skan return (EADDRNOTAVAIL); 98169689Skan if ((ifp->if_flags & IFF_BROADCAST) == 0) 99169689Skan return (EINVAL); 100169689Skan *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 101169689Skan return (0); 102169689Skan 103169689Skan case SIOCGIFDSTADDR: 104169689Skan if (ia == NULL) 105169689Skan return (EADDRNOTAVAIL); 106169689Skan if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 107169689Skan return (EINVAL); 108169689Skan *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 109169689Skan return (0); 110169689Skan } 111169689Skan 112169689Skan if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 113169689Skan return (error); 114169689Skan 115169689Skan switch (cmd) { 116169689Skan case SIOCAIFADDR: 117169689Skan case SIOCDIFADDR: 118169689Skan if (ifra->ifra_addr.sipx_family == AF_IPX) 119169689Skan for (oia = ia; ia != NULL; ia = ia->ia_next) { 120169689Skan if (ia->ia_ifp == ifp && 121169689Skan ipx_neteq(ia->ia_addr.sipx_addr, 122169689Skan ifra->ifra_addr.sipx_addr)) 123169689Skan break; 124169689Skan } 125169689Skan if (cmd == SIOCDIFADDR && ia == NULL) 126169689Skan return (EADDRNOTAVAIL); 127169689Skan /* FALLTHROUGH */ 128169689Skan 129169689Skan case SIOCSIFADDR: 130169689Skan case SIOCSIFDSTADDR: 131169689Skan if (ia == NULL) { 132169689Skan oia = (struct ipx_ifaddr *) 133169689Skan malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 134169689Skan if (oia == NULL) 135169689Skan return (ENOBUFS); 136169689Skan bzero((caddr_t)oia, sizeof(*oia)); 137169689Skan if ((ia = ipx_ifaddr) != NULL) { 138169689Skan for ( ; ia->ia_next != NULL; ia = ia->ia_next) 139169689Skan ; 140169689Skan ia->ia_next = oia; 141169689Skan } else 142169689Skan ipx_ifaddr = oia; 143169689Skan ia = oia; 144169689Skan ifa = (struct ifaddr *)ia; 145169689Skan TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 146169689Skan ia->ia_ifp = ifp; 147169689Skan ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 148169689Skan 149169689Skan ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 150169689Skan 151169689Skan ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 152169689Skan if (ifp->if_flags & IFF_BROADCAST) { 153169689Skan ia->ia_broadaddr.sipx_family = AF_IPX; 154169689Skan ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 155169689Skan ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 156169689Skan } 157169689Skan } 158169689Skan } 159169689Skan 160169689Skan switch (cmd) { 161169689Skan 162169689Skan case SIOCSIFDSTADDR: 163169689Skan if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 164169689Skan return (EINVAL); 165169689Skan if (ia->ia_flags & IFA_ROUTE) { 166169689Skan rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 167169689Skan ia->ia_flags &= ~IFA_ROUTE; 168169689Skan } 169169689Skan if (ifp->if_ioctl) { 170169689Skan error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 171169689Skan if (error) 172169689Skan return (error); 173169689Skan } 174169689Skan *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 175169689Skan return (0); 176169689Skan 177169689Skan case SIOCSIFADDR: 178169689Skan return (ipx_ifinit(ifp, ia, 179169689Skan (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 180169689Skan 181169689Skan case SIOCDIFADDR: 182169689Skan ipx_ifscrub(ifp, ia); 183169689Skan ifa = (struct ifaddr *)ia; 184169689Skan TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 185169689Skan oia = ia; 186169689Skan if (oia == (ia = ipx_ifaddr)) { 187169689Skan ipx_ifaddr = ia->ia_next; 188169689Skan } else { 189169689Skan while (ia->ia_next && (ia->ia_next != oia)) { 190169689Skan ia = ia->ia_next; 191169689Skan } 192169689Skan if (ia->ia_next) 193169689Skan ia->ia_next = oia->ia_next; 194169689Skan else 195169689Skan printf("Didn't unlink ipxifadr from list\n"); 196169689Skan } 197169689Skan IFAFREE((&oia->ia_ifa)); 198169689Skan return (0); 199169689Skan 200169689Skan case SIOCAIFADDR: 201169689Skan dstIsNew = 0; 202169689Skan hostIsNew = 1; 203169689Skan if (ia->ia_addr.sipx_family == AF_IPX) { 204169689Skan if (ifra->ifra_addr.sipx_len == 0) { 205169689Skan ifra->ifra_addr = ia->ia_addr; 206169689Skan hostIsNew = 0; 207169689Skan } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 208169689Skan ia->ia_addr.sipx_addr)) 209169689Skan hostIsNew = 0; 210169689Skan } 211169689Skan if ((ifp->if_flags & IFF_POINTOPOINT) && 212169689Skan (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 213169689Skan if (hostIsNew == 0) 214169689Skan ipx_ifscrub(ifp, ia); 215169689Skan ia->ia_dstaddr = ifra->ifra_dstaddr; 216169689Skan dstIsNew = 1; 217169689Skan } 218169689Skan if (ifra->ifra_addr.sipx_family == AF_IPX && 219169689Skan (hostIsNew || dstIsNew)) 220169689Skan error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 221169689Skan return (error); 222169689Skan 223169689Skan default: 224169689Skan if (ifp->if_ioctl == NULL) 225169689Skan return (EOPNOTSUPP); 226169689Skan return ((*ifp->if_ioctl)(ifp, cmd, data)); 227169689Skan } 228169689Skan} 229169689Skan 230169689Skan/* 231169689Skan* Delete any previous route for an old address. 232169689Skan*/ 233169689Skanstatic void 234169689Skanipx_ifscrub(ifp, ia) 235169689Skan register struct ifnet *ifp; 236169689Skan register struct ipx_ifaddr *ia; 237169689Skan{ 238169689Skan if (ia->ia_flags & IFA_ROUTE) { 239169689Skan if (ifp->if_flags & IFF_POINTOPOINT) { 240169689Skan rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 241169689Skan } else 242169689Skan rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 243169689Skan ia->ia_flags &= ~IFA_ROUTE; 244169689Skan } 245169689Skan} 246169689Skan/* 247169689Skan * Initialize an interface's internet address 248169689Skan * and routing table entry. 249169689Skan */ 250169689Skanstatic int 251169689Skanipx_ifinit(ifp, ia, sipx, scrub) 252169689Skan register struct ifnet *ifp; 253169689Skan register struct ipx_ifaddr *ia; 254169689Skan register struct sockaddr_ipx *sipx; 255169689Skan int scrub; 256169689Skan{ 257169689Skan struct sockaddr_ipx oldaddr; 258169689Skan int s = splimp(), error; 259169689Skan 260169689Skan /* 261169689Skan * Set up new addresses. 262169689Skan */ 263169689Skan oldaddr = ia->ia_addr; 264169689Skan ia->ia_addr = *sipx; 265169689Skan 266169689Skan /* 267169689Skan * The convention we shall adopt for naming is that 268169689Skan * a supplied address of zero means that "we don't care". 269169689Skan * Use the MAC address of the interface. If it is an 270169689Skan * interface without a MAC address, like a serial line, the 271169689Skan * address must be supplied. 272169689Skan * 273169689Skan * Give the interface a chance to initialize 274169689Skan * if this is its first address, 275169689Skan * and to validate the address if necessary. 276169689Skan */ 277169689Skan if (ifp->if_ioctl != NULL && 278169689Skan (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 279169689Skan ia->ia_addr = oldaddr; 280169689Skan splx(s); 281169689Skan return (error); 282169689Skan } 283169689Skan splx(s); 284169689Skan ia->ia_ifa.ifa_metric = ifp->if_metric; 285169689Skan /* 286169689Skan * Add route for the network. 287169689Skan */ 288169689Skan if (scrub) { 289169689Skan ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 290169689Skan ipx_ifscrub(ifp, ia); 291169689Skan ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 292169689Skan } 293169689Skan if (ifp->if_flags & IFF_POINTOPOINT) 294169689Skan rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 295169689Skan else { 296169689Skan ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 297169689Skan rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 298169689Skan } 299169689Skan ia->ia_flags |= IFA_ROUTE; 300169689Skan return (0); 301169689Skan} 302169689Skan 303169689Skan/* 304169689Skan * Return address info for specified internet network. 305169689Skan */ 306169689Skanstruct ipx_ifaddr * 307169689Skanipx_iaonnetof(dst) 308169689Skan register struct ipx_addr *dst; 309169689Skan{ 310169689Skan register struct ipx_ifaddr *ia; 311169689Skan register struct ipx_addr *compare; 312169689Skan register struct ifnet *ifp; 313169689Skan struct ipx_ifaddr *ia_maybe = NULL; 314169689Skan union ipx_net net = dst->x_net; 315169689Skan 316169689Skan for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 317169689Skan if ((ifp = ia->ia_ifp) != NULL) { 318169689Skan if (ifp->if_flags & IFF_POINTOPOINT) { 319169689Skan compare = &satoipx_addr(ia->ia_dstaddr); 320169689Skan if (ipx_hosteq(*dst, *compare)) 321169689Skan return (ia); 322169689Skan if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 323169689Skan ia_maybe = ia; 324169689Skan } else { 325169689Skan if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 326169689Skan return (ia); 327169689Skan } 328169689Skan } 329169689Skan } 330169689Skan return (ia_maybe); 331169689Skan} 332169689Skan 333169689Skan 334169689Skanvoid 335169689Skanipx_printhost(addr) 336169689Skanregister struct ipx_addr *addr; 337169689Skan{ 338169689Skan u_short port; 339169689Skan struct ipx_addr work = *addr; 340169689Skan register char *p; register u_char *q; 341169689Skan register char *net = "", *host = ""; 342169689Skan char cport[10], chost[15], cnet[15]; 343169689Skan 344169689Skan port = ntohs(work.x_port); 345169689Skan 346169689Skan if (ipx_nullnet(work) && ipx_nullhost(work)) { 347169689Skan 348169689Skan if (port) 349169689Skan printf("*.%x", port); 350169689Skan else 351169689Skan printf("*.*"); 352169689Skan 353169689Skan return; 354169689Skan } 355169689Skan 356169689Skan if (ipx_wildnet(work)) 357169689Skan net = "any"; 358169689Skan else if (ipx_nullnet(work)) 359169689Skan net = "*"; 360169689Skan else { 361169689Skan q = work.x_net.c_net; 362169689Skan snprintf(cnet, sizeof(cnet), "%x%x%x%x", 363169689Skan q[0], q[1], q[2], q[3]); 364169689Skan for (p = cnet; *p == '0' && p < cnet + 8; p++) 365169689Skan continue; 366169689Skan net = p; 367169689Skan } 368169689Skan 369169689Skan if (ipx_wildhost(work)) 370169689Skan host = "any"; 371169689Skan else if (ipx_nullhost(work)) 372169689Skan host = "*"; 373169689Skan else { 374169689Skan q = work.x_host.c_host; 375169689Skan snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 376169689Skan q[0], q[1], q[2], q[3], q[4], q[5]); 377169689Skan for (p = chost; *p == '0' && p < chost + 12; p++) 378169689Skan continue; 379169689Skan host = p; 380169689Skan } 381169689Skan 382169689Skan if (port) { 383169689Skan if (strcmp(host, "*") == 0) { 384169689Skan host = ""; 385169689Skan snprintf(cport, sizeof(cport), "%x", port); 386169689Skan } else 387169689Skan snprintf(cport, sizeof(cport), ".%x", port); 388169689Skan } else 389169689Skan *cport = 0; 390169689Skan 391169689Skan printf("%s.%s%s", net, host, cport); 392169689Skan} 393169689Skan