ipx.c revision 165899
1/*- 2 * Copyright (c) 1984, 1985, 1986, 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * Copyright (c) 1995, Mike Mitchell 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 3. All advertising materials mentioning features or use of this software 40 * must display the following acknowledgement: 41 * This product includes software developed by the University of 42 * California, Berkeley and its contributors. 43 * 4. Neither the name of the University nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * 59 * @(#)ipx.c 60 */ 61 62#include <sys/cdefs.h> 63__FBSDID("$FreeBSD: head/sys/netipx/ipx.c 165899 2007-01-08 22:14:00Z rwatson $"); 64 65#include <sys/param.h> 66#include <sys/kernel.h> 67#include <sys/systm.h> 68#include <sys/malloc.h> 69#include <sys/sockio.h> 70#include <sys/socket.h> 71 72#include <net/if.h> 73#include <net/route.h> 74 75#include <netipx/ipx.h> 76#include <netipx/ipx_if.h> 77#include <netipx/ipx_var.h> 78 79/* 80 * XXXRW: Requires synchronization. 81 */ 82struct ipx_ifaddr *ipx_ifaddr; 83 84static void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 85static int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 86 struct sockaddr_ipx *sipx, int scrub); 87 88/* 89 * Generic internet control operations (ioctl's). 90 */ 91int 92ipx_control(so, cmd, data, ifp, td) 93 struct socket *so; 94 u_long cmd; 95 caddr_t data; 96 register struct ifnet *ifp; 97 struct thread *td; 98{ 99 register struct ifreq *ifr = (struct ifreq *)data; 100 register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 101 register struct ipx_ifaddr *ia; 102 struct ifaddr *ifa; 103 struct ipx_ifaddr *oia; 104 int dstIsNew, hostIsNew; 105 int error = 0; 106 107 /* 108 * Find address for this interface, if it exists. 109 */ 110 if (ifp == NULL) 111 return (EADDRNOTAVAIL); 112 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 113 if (ia->ia_ifp == ifp) 114 break; 115 116 switch (cmd) { 117 118 case SIOCGIFADDR: 119 if (ia == NULL) 120 return (EADDRNOTAVAIL); 121 *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 122 return (0); 123 124 case SIOCGIFBRDADDR: 125 if (ia == NULL) 126 return (EADDRNOTAVAIL); 127 if ((ifp->if_flags & IFF_BROADCAST) == 0) 128 return (EINVAL); 129 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 130 return (0); 131 132 case SIOCGIFDSTADDR: 133 if (ia == NULL) 134 return (EADDRNOTAVAIL); 135 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 136 return (EINVAL); 137 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 138 return (0); 139 } 140 141 if (td && (error = suser(td)) != 0) 142 return (error); 143 144 switch (cmd) { 145 case SIOCAIFADDR: 146 case SIOCDIFADDR: 147 if (ifra->ifra_addr.sipx_family == AF_IPX) 148 for (oia = ia; ia != NULL; ia = ia->ia_next) { 149 if (ia->ia_ifp == ifp && 150 ipx_neteq(ia->ia_addr.sipx_addr, 151 ifra->ifra_addr.sipx_addr)) 152 break; 153 } 154 if (cmd == SIOCDIFADDR && ia == NULL) 155 return (EADDRNOTAVAIL); 156 /* FALLTHROUGH */ 157 158 case SIOCSIFADDR: 159 case SIOCSIFDSTADDR: 160 if (ia == NULL) { 161 oia = (struct ipx_ifaddr *) 162 malloc(sizeof(*ia), M_IFADDR, 163 M_WAITOK | M_ZERO); 164 if (oia == NULL) 165 return (ENOBUFS); 166 if ((ia = ipx_ifaddr) != NULL) { 167 for ( ; ia->ia_next != NULL; ia = ia->ia_next) 168 ; 169 ia->ia_next = oia; 170 } else 171 ipx_ifaddr = oia; 172 ia = oia; 173 ifa = (struct ifaddr *)ia; 174 IFA_LOCK_INIT(ifa); 175 ifa->ifa_refcnt = 1; 176 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 177 ia->ia_ifp = ifp; 178 ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 179 180 ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 181 182 ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 183 if (ifp->if_flags & IFF_BROADCAST) { 184 ia->ia_broadaddr.sipx_family = AF_IPX; 185 ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 186 ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 187 } 188 } 189 } 190 191 switch (cmd) { 192 193 case SIOCSIFDSTADDR: 194 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 195 return (EINVAL); 196 if (ia->ia_flags & IFA_ROUTE) { 197 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 198 ia->ia_flags &= ~IFA_ROUTE; 199 } 200 if (ifp->if_ioctl) { 201 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 202 if (error) 203 return (error); 204 } 205 *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 206 return (0); 207 208 case SIOCSIFADDR: 209 return (ipx_ifinit(ifp, ia, 210 (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 211 212 case SIOCDIFADDR: 213 ipx_ifscrub(ifp, ia); 214 ifa = (struct ifaddr *)ia; 215 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 216 oia = ia; 217 if (oia == (ia = ipx_ifaddr)) { 218 ipx_ifaddr = ia->ia_next; 219 } else { 220 while (ia->ia_next && (ia->ia_next != oia)) { 221 ia = ia->ia_next; 222 } 223 if (ia->ia_next) 224 ia->ia_next = oia->ia_next; 225 else 226 printf("Didn't unlink ipxifadr from list\n"); 227 } 228 IFAFREE((&oia->ia_ifa)); 229 return (0); 230 231 case SIOCAIFADDR: 232 dstIsNew = 0; 233 hostIsNew = 1; 234 if (ia->ia_addr.sipx_family == AF_IPX) { 235 if (ifra->ifra_addr.sipx_len == 0) { 236 ifra->ifra_addr = ia->ia_addr; 237 hostIsNew = 0; 238 } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 239 ia->ia_addr.sipx_addr)) 240 hostIsNew = 0; 241 } 242 if ((ifp->if_flags & IFF_POINTOPOINT) && 243 (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 244 if (hostIsNew == 0) 245 ipx_ifscrub(ifp, ia); 246 ia->ia_dstaddr = ifra->ifra_dstaddr; 247 dstIsNew = 1; 248 } 249 if (ifra->ifra_addr.sipx_family == AF_IPX && 250 (hostIsNew || dstIsNew)) 251 error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 252 return (error); 253 254 default: 255 if (ifp->if_ioctl == NULL) 256 return (EOPNOTSUPP); 257 return ((*ifp->if_ioctl)(ifp, cmd, data)); 258 } 259} 260 261/* 262* Delete any previous route for an old address. 263*/ 264static void 265ipx_ifscrub(ifp, ia) 266 register struct ifnet *ifp; 267 register struct ipx_ifaddr *ia; 268{ 269 if (ia->ia_flags & IFA_ROUTE) { 270 if (ifp->if_flags & IFF_POINTOPOINT) { 271 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 272 } else 273 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 274 ia->ia_flags &= ~IFA_ROUTE; 275 } 276} 277/* 278 * Initialize an interface's internet address 279 * and routing table entry. 280 */ 281static int 282ipx_ifinit(ifp, ia, sipx, scrub) 283 register struct ifnet *ifp; 284 register struct ipx_ifaddr *ia; 285 register struct sockaddr_ipx *sipx; 286 int scrub; 287{ 288 struct sockaddr_ipx oldaddr; 289 int s = splimp(), error; 290 291 /* 292 * Set up new addresses. 293 */ 294 oldaddr = ia->ia_addr; 295 ia->ia_addr = *sipx; 296 297 /* 298 * The convention we shall adopt for naming is that 299 * a supplied address of zero means that "we don't care". 300 * Use the MAC address of the interface. If it is an 301 * interface without a MAC address, like a serial line, the 302 * address must be supplied. 303 * 304 * Give the interface a chance to initialize 305 * if this is its first address, 306 * and to validate the address if necessary. 307 */ 308 if (ifp->if_ioctl != NULL && 309 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 310 ia->ia_addr = oldaddr; 311 splx(s); 312 return (error); 313 } 314 splx(s); 315 ia->ia_ifa.ifa_metric = ifp->if_metric; 316 /* 317 * Add route for the network. 318 */ 319 if (scrub) { 320 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 321 ipx_ifscrub(ifp, ia); 322 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 323 } 324 if (ifp->if_flags & IFF_POINTOPOINT) 325 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 326 else { 327 ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 328 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 329 } 330 ia->ia_flags |= IFA_ROUTE; 331 return (0); 332} 333 334/* 335 * Return address info for specified internet network. 336 */ 337struct ipx_ifaddr * 338ipx_iaonnetof(dst) 339 register struct ipx_addr *dst; 340{ 341 register struct ipx_ifaddr *ia; 342 register struct ipx_addr *compare; 343 register struct ifnet *ifp; 344 struct ipx_ifaddr *ia_maybe = NULL; 345 union ipx_net net = dst->x_net; 346 347 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 348 if ((ifp = ia->ia_ifp) != NULL) { 349 if (ifp->if_flags & IFF_POINTOPOINT) { 350 compare = &satoipx_addr(ia->ia_dstaddr); 351 if (ipx_hosteq(*dst, *compare)) 352 return (ia); 353 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 354 ia_maybe = ia; 355 } else { 356 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 357 return (ia); 358 } 359 } 360 } 361 return (ia_maybe); 362} 363 364 365void 366ipx_printhost(addr) 367register struct ipx_addr *addr; 368{ 369 u_short port; 370 struct ipx_addr work = *addr; 371 register char *p; register u_char *q; 372 register char *net = "", *host = ""; 373 char cport[10], chost[15], cnet[15]; 374 375 port = ntohs(work.x_port); 376 377 if (ipx_nullnet(work) && ipx_nullhost(work)) { 378 379 if (port) 380 printf("*.%x", port); 381 else 382 printf("*.*"); 383 384 return; 385 } 386 387 if (ipx_wildnet(work)) 388 net = "any"; 389 else if (ipx_nullnet(work)) 390 net = "*"; 391 else { 392 q = work.x_net.c_net; 393 snprintf(cnet, sizeof(cnet), "%x%x%x%x", 394 q[0], q[1], q[2], q[3]); 395 for (p = cnet; *p == '0' && p < cnet + 8; p++) 396 continue; 397 net = p; 398 } 399 400 if (ipx_wildhost(work)) 401 host = "any"; 402 else if (ipx_nullhost(work)) 403 host = "*"; 404 else { 405 q = work.x_host.c_host; 406 snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 407 q[0], q[1], q[2], q[3], q[4], q[5]); 408 for (p = chost; *p == '0' && p < chost + 12; p++) 409 continue; 410 host = p; 411 } 412 413 if (port) { 414 if (strcmp(host, "*") == 0) { 415 host = ""; 416 snprintf(cport, sizeof(cport), "%x", port); 417 } else 418 snprintf(cport, sizeof(cport), ".%x", port); 419 } else 420 *cport = 0; 421 422 printf("%s.%s%s", net, host, cport); 423} 424