ipx.c revision 67893
1251876Speter/* 2251876Speter * Copyright (c) 1995, Mike Mitchell 3251876Speter * Copyright (c) 1984, 1985, 1986, 1987, 1993 4251876Speter * The Regents of the University of California. All rights reserved. 5251876Speter * 6251876Speter * Redistribution and use in source and binary forms, with or without 7251876Speter * modification, are permitted provided that the following conditions 8251876Speter * are met: 9251876Speter * 1. Redistributions of source code must retain the above copyright 10251876Speter * notice, this list of conditions and the following disclaimer. 11251876Speter * 2. Redistributions in binary form must reproduce the above copyright 12251876Speter * notice, this list of conditions and the following disclaimer in the 13251876Speter * documentation and/or other materials provided with the distribution. 14251876Speter * 3. All advertising materials mentioning features or use of this software 15251876Speter * must display the following acknowledgement: 16251876Speter * This product includes software developed by the University of 17251876Speter * California, Berkeley and its contributors. 18251876Speter * 4. Neither the name of the University nor the names of its contributors 19251876Speter * may be used to endorse or promote products derived from this software 20251876Speter * without specific prior written permission. 21251876Speter * 22251876Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23251876Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24251876Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25251876Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26251876Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27251876Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28251876Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29251876Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30251876Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31251876Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32251876Speter * SUCH DAMAGE. 33251876Speter * 34251876Speter * @(#)ipx.c 35251876Speter * 36251876Speter * $FreeBSD: head/sys/netipx/ipx.c 67893 2000-10-29 16:06:56Z phk $ 37251876Speter */ 38251876Speter 39251876Speter#include <sys/param.h> 40251876Speter#include <sys/systm.h> 41251876Speter#include <sys/malloc.h> 42251876Speter#include <sys/sockio.h> 43251876Speter#include <sys/socket.h> 44251876Speter 45251876Speter#include <net/if.h> 46251876Speter#include <net/route.h> 47251876Speter 48251876Speter#include <netipx/ipx.h> 49251876Speter#include <netipx/ipx_if.h> 50251876Speter#include <netipx/ipx_var.h> 51251876Speter 52251876Speterstruct ipx_ifaddr *ipx_ifaddr; 53251876Speter 54251876Speterstatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 55251876Speterstatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 56251876Speter struct sockaddr_ipx *sipx, int scrub); 57251876Speter 58251876Speter/* 59251876Speter * Generic internet control operations (ioctl's). 60251876Speter */ 61251876Speterint 62251876Speteripx_control(so, cmd, data, ifp, p) 63251876Speter struct socket *so; 64251876Speter u_long cmd; 65251876Speter caddr_t data; 66251876Speter register struct ifnet *ifp; 67251876Speter struct proc *p; 68251876Speter{ 69251876Speter register struct ifreq *ifr = (struct ifreq *)data; 70251876Speter register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 71251876Speter register struct ipx_ifaddr *ia; 72251876Speter struct ifaddr *ifa; 73251876Speter struct ipx_ifaddr *oia; 74251876Speter int dstIsNew, hostIsNew; 75251876Speter int error = 0; 76251876Speter 77251876Speter /* 78251876Speter * Find address for this interface, if it exists. 79251876Speter */ 80251876Speter if (ifp == NULL) 81251876Speter return (EADDRNOTAVAIL); 82251876Speter for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 83251876Speter if (ia->ia_ifp == ifp) 84251876Speter break; 85251876Speter 86251876Speter switch (cmd) { 87251876Speter 88251876Speter case SIOCGIFADDR: 89251876Speter if (ia == NULL) 90251876Speter return (EADDRNOTAVAIL); 91251876Speter *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 92251876Speter return (0); 93251876Speter 94251876Speter case SIOCGIFBRDADDR: 95251876Speter if (ia == NULL) 96251876Speter return (EADDRNOTAVAIL); 97251876Speter if ((ifp->if_flags & IFF_BROADCAST) == 0) 98251876Speter return (EINVAL); 99251876Speter *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 100251876Speter return (0); 101251876Speter 102251876Speter case SIOCGIFDSTADDR: 103251876Speter if (ia == NULL) 104251876Speter return (EADDRNOTAVAIL); 105251876Speter if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 106251876Speter return (EINVAL); 107251876Speter *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 108251876Speter return (0); 109251876Speter } 110251876Speter 111251876Speter if (p && (error = suser(p)) != 0) 112251876Speter return (error); 113251876Speter 114251876Speter switch (cmd) { 115251876Speter case SIOCAIFADDR: 116251876Speter case SIOCDIFADDR: 117251876Speter if (ifra->ifra_addr.sipx_family == AF_IPX) 118251876Speter for (oia = ia; ia != NULL; ia = ia->ia_next) { 119251876Speter if (ia->ia_ifp == ifp && 120251876Speter ipx_neteq(ia->ia_addr.sipx_addr, 121251876Speter ifra->ifra_addr.sipx_addr)) 122251876Speter break; 123251876Speter } 124251876Speter if (cmd == SIOCDIFADDR && ia == NULL) 125251876Speter return (EADDRNOTAVAIL); 126251876Speter /* FALLTHROUGH */ 127251876Speter 128251876Speter case SIOCSIFADDR: 129251876Speter case SIOCSIFDSTADDR: 130251876Speter if (ia == NULL) { 131251876Speter oia = (struct ipx_ifaddr *) 132251876Speter malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 133251876Speter if (oia == NULL) 134251876Speter return (ENOBUFS); 135251876Speter bzero((caddr_t)oia, sizeof(*oia)); 136251876Speter if ((ia = ipx_ifaddr) != NULL) { 137251876Speter for ( ; ia->ia_next != NULL; ia = ia->ia_next) 138251876Speter ; 139251876Speter ia->ia_next = oia; 140251876Speter } else 141251876Speter ipx_ifaddr = oia; 142251876Speter ia = oia; 143251876Speter ifa = (struct ifaddr *)ia; 144251876Speter TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 145251876Speter ia->ia_ifp = ifp; 146251876Speter ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 147251876Speter 148251876Speter ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 149251876Speter 150251876Speter ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 151251876Speter if (ifp->if_flags & IFF_BROADCAST) { 152251876Speter ia->ia_broadaddr.sipx_family = AF_IPX; 153251876Speter ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 154251876Speter ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 155251876Speter } 156251876Speter } 157251876Speter } 158251876Speter 159251876Speter switch (cmd) { 160251876Speter 161251876Speter case SIOCSIFDSTADDR: 162251876Speter if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 163251876Speter return (EINVAL); 164251876Speter if (ia->ia_flags & IFA_ROUTE) { 165251876Speter rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 166251876Speter ia->ia_flags &= ~IFA_ROUTE; 167251876Speter } 168251876Speter if (ifp->if_ioctl) { 169251876Speter error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 170251876Speter if (error) 171251876Speter return (error); 172251876Speter } 173251876Speter *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 174251876Speter return (0); 175251876Speter 176251876Speter case SIOCSIFADDR: 177251876Speter return (ipx_ifinit(ifp, ia, 178251876Speter (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 179251876Speter 180251876Speter case SIOCDIFADDR: 181251876Speter ipx_ifscrub(ifp, ia); 182251876Speter ifa = (struct ifaddr *)ia; 183251876Speter TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 184251876Speter oia = ia; 185251876Speter if (oia == (ia = ipx_ifaddr)) { 186251876Speter ipx_ifaddr = ia->ia_next; 187251876Speter } else { 188251876Speter while (ia->ia_next && (ia->ia_next != oia)) { 189251876Speter ia = ia->ia_next; 190251876Speter } 191251876Speter if (ia->ia_next) 192251876Speter ia->ia_next = oia->ia_next; 193251876Speter else 194251876Speter printf("Didn't unlink ipxifadr from list\n"); 195251876Speter } 196251876Speter IFAFREE((&oia->ia_ifa)); 197251876Speter return (0); 198251876Speter 199251876Speter case SIOCAIFADDR: 200251876Speter dstIsNew = 0; 201251876Speter hostIsNew = 1; 202251876Speter if (ia->ia_addr.sipx_family == AF_IPX) { 203251876Speter if (ifra->ifra_addr.sipx_len == 0) { 204251876Speter ifra->ifra_addr = ia->ia_addr; 205251876Speter hostIsNew = 0; 206251876Speter } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 207251876Speter ia->ia_addr.sipx_addr)) 208251876Speter hostIsNew = 0; 209251876Speter } 210251876Speter if ((ifp->if_flags & IFF_POINTOPOINT) && 211251876Speter (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 212251876Speter if (hostIsNew == 0) 213251876Speter ipx_ifscrub(ifp, ia); 214251876Speter ia->ia_dstaddr = ifra->ifra_dstaddr; 215251876Speter dstIsNew = 1; 216251876Speter } 217251876Speter if (ifra->ifra_addr.sipx_family == AF_IPX && 218251876Speter (hostIsNew || dstIsNew)) 219251876Speter error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 220251876Speter return (error); 221251876Speter 222251876Speter default: 223251876Speter if (ifp->if_ioctl == NULL) 224251876Speter return (EOPNOTSUPP); 225251876Speter return ((*ifp->if_ioctl)(ifp, cmd, data)); 226251876Speter } 227251876Speter} 228251876Speter 229251876Speter/* 230251876Speter* Delete any previous route for an old address. 231251876Speter*/ 232251876Speterstatic void 233251876Speteripx_ifscrub(ifp, ia) 234251876Speter register struct ifnet *ifp; 235251876Speter register struct ipx_ifaddr *ia; 236251876Speter{ 237251876Speter if (ia->ia_flags & IFA_ROUTE) { 238251876Speter if (ifp->if_flags & IFF_POINTOPOINT) { 239251876Speter rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 240251876Speter } else 241251876Speter rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 242251876Speter ia->ia_flags &= ~IFA_ROUTE; 243251876Speter } 244251876Speter} 245251876Speter/* 246251876Speter * Initialize an interface's internet address 247251876Speter * and routing table entry. 248251876Speter */ 249251876Speterstatic int 250251876Speteripx_ifinit(ifp, ia, sipx, scrub) 251251876Speter register struct ifnet *ifp; 252251876Speter register struct ipx_ifaddr *ia; 253251876Speter register struct sockaddr_ipx *sipx; 254251876Speter int scrub; 255251876Speter{ 256251876Speter struct sockaddr_ipx oldaddr; 257251876Speter int s = splimp(), error; 258251876Speter 259251876Speter /* 260251876Speter * Set up new addresses. 261251876Speter */ 262251876Speter oldaddr = ia->ia_addr; 263251876Speter ia->ia_addr = *sipx; 264251876Speter 265251876Speter /* 266251876Speter * The convention we shall adopt for naming is that 267251876Speter * a supplied address of zero means that "we don't care". 268251876Speter * Use the MAC address of the interface. If it is an 269251876Speter * interface without a MAC address, like a serial line, the 270251876Speter * address must be supplied. 271251876Speter * 272251876Speter * Give the interface a chance to initialize 273251876Speter * if this is its first address, 274251876Speter * and to validate the address if necessary. 275251876Speter */ 276251876Speter if (ifp->if_ioctl != NULL && 277251876Speter (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 278251876Speter ia->ia_addr = oldaddr; 279251876Speter splx(s); 280251876Speter return (error); 281251876Speter } 282251876Speter splx(s); 283251876Speter ia->ia_ifa.ifa_metric = ifp->if_metric; 284251876Speter /* 285251876Speter * Add route for the network. 286251876Speter */ 287251876Speter if (scrub) { 288251876Speter ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 289251876Speter ipx_ifscrub(ifp, ia); 290251876Speter ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 291251876Speter } 292251876Speter if (ifp->if_flags & IFF_POINTOPOINT) 293251876Speter rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 294251876Speter else { 295251876Speter ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 296251876Speter rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 297251876Speter } 298251876Speter ia->ia_flags |= IFA_ROUTE; 299251876Speter return (0); 300251876Speter} 301251876Speter 302251876Speter/* 303251876Speter * Return address info for specified internet network. 304251876Speter */ 305251876Speterstruct ipx_ifaddr * 306251876Speteripx_iaonnetof(dst) 307251876Speter register struct ipx_addr *dst; 308251876Speter{ 309251876Speter register struct ipx_ifaddr *ia; 310251876Speter register struct ipx_addr *compare; 311251876Speter register struct ifnet *ifp; 312251876Speter struct ipx_ifaddr *ia_maybe = NULL; 313251876Speter union ipx_net net = dst->x_net; 314251876Speter 315251876Speter for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 316251876Speter if ((ifp = ia->ia_ifp) != NULL) { 317251876Speter if (ifp->if_flags & IFF_POINTOPOINT) { 318251876Speter compare = &satoipx_addr(ia->ia_dstaddr); 319251876Speter if (ipx_hosteq(*dst, *compare)) 320251876Speter return (ia); 321251876Speter if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 322251876Speter ia_maybe = ia; 323251876Speter } else { 324251876Speter if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 325251876Speter return (ia); 326251876Speter } 327251876Speter } 328251876Speter } 329251876Speter return (ia_maybe); 330251876Speter} 331251876Speter 332251876Speter 333251876Spetervoid 334251876Speteripx_printhost(addr) 335251876Speterregister struct ipx_addr *addr; 336251876Speter{ 337251876Speter u_short port; 338251876Speter struct ipx_addr work = *addr; 339251876Speter register char *p; register u_char *q; 340251876Speter register char *net = "", *host = ""; 341251876Speter char cport[10], chost[15], cnet[15]; 342251876Speter 343251876Speter port = ntohs(work.x_port); 344251876Speter 345251876Speter if (ipx_nullnet(work) && ipx_nullhost(work)) { 346251876Speter 347251876Speter if (port) 348251876Speter printf("*.%x", port); 349251876Speter else 350251876Speter printf("*.*"); 351251876Speter 352251876Speter return; 353251876Speter } 354251876Speter 355251876Speter if (ipx_wildnet(work)) 356251876Speter net = "any"; 357251876Speter else if (ipx_nullnet(work)) 358251876Speter net = "*"; 359251876Speter else { 360251876Speter q = work.x_net.c_net; 361251876Speter snprintf(cnet, sizeof(cnet), "%x%x%x%x", 362251876Speter q[0], q[1], q[2], q[3]); 363251876Speter for (p = cnet; *p == '0' && p < cnet + 8; p++) 364251876Speter continue; 365251876Speter net = p; 366253734Speter } 367251876Speter 368251876Speter if (ipx_wildhost(work)) 369251876Speter host = "any"; 370251876Speter else if (ipx_nullhost(work)) 371251876Speter host = "*"; 372251876Speter else { 373251876Speter q = work.x_host.c_host; 374251876Speter snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 375251876Speter q[0], q[1], q[2], q[3], q[4], q[5]); 376251876Speter for (p = chost; *p == '0' && p < chost + 12; p++) 377251876Speter continue; 378251876Speter host = p; 379251876Speter } 380251876Speter 381251876Speter if (port) { 382251876Speter if (strcmp(host, "*") == 0) { 383251876Speter host = ""; 384251876Speter snprintf(cport, sizeof(cport), "%x", port); 385251876Speter } else 386251876Speter snprintf(cport, sizeof(cport), ".%x", port); 387251876Speter } else 388251876Speter *cport = 0; 389251876Speter 390251876Speter printf("%s.%s%s", net, host, cport); 391251876Speter} 392251876Speter