ipx.c revision 194602
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 194602 2009-06-21 19:30:33Z 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/priv.h> 70#include <sys/sockio.h> 71#include <sys/socket.h> 72 73#include <net/if.h> 74#include <net/route.h> 75 76#include <netipx/ipx.h> 77#include <netipx/ipx_if.h> 78#include <netipx/ipx_var.h> 79 80/* 81 * XXXRW: Requires synchronization. 82 */ 83struct ipx_ifaddr *ipx_ifaddr; 84 85static void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 86static int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 87 struct sockaddr_ipx *sipx, int scrub); 88 89/* 90 * Generic internet control operations (ioctl's). 91 */ 92int 93ipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, 94 struct thread *td) 95{ 96 struct ifreq *ifr = (struct ifreq *)data; 97 struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 98 struct ipx_ifaddr *ia; 99 struct ifaddr *ifa; 100 struct ipx_ifaddr *oia; 101 int dstIsNew, hostIsNew; 102 int error = 0, priv; 103 104 /* 105 * Find address for this interface, if it exists. 106 */ 107 if (ifp == NULL) 108 return (EADDRNOTAVAIL); 109 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 110 if (ia->ia_ifp == ifp) 111 break; 112 113 switch (cmd) { 114 case SIOCGIFADDR: 115 if (ia == NULL) 116 return (EADDRNOTAVAIL); 117 *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 118 return (0); 119 120 case SIOCGIFBRDADDR: 121 if (ia == NULL) 122 return (EADDRNOTAVAIL); 123 if ((ifp->if_flags & IFF_BROADCAST) == 0) 124 return (EINVAL); 125 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 126 return (0); 127 128 case SIOCGIFDSTADDR: 129 if (ia == NULL) 130 return (EADDRNOTAVAIL); 131 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 132 return (EINVAL); 133 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 134 return (0); 135 } 136 137 switch (cmd) { 138 case SIOCAIFADDR: 139 case SIOCDIFADDR: 140 priv = (cmd == SIOCAIFADDR) ? PRIV_NET_ADDIFADDR : 141 PRIV_NET_DELIFADDR; 142 if (td && (error = priv_check(td, priv)) != 0) 143 return (error); 144 if (ifra->ifra_addr.sipx_family == AF_IPX) 145 for (oia = ia; ia != NULL; ia = ia->ia_next) { 146 if (ia->ia_ifp == ifp && 147 ipx_neteq(ia->ia_addr.sipx_addr, 148 ifra->ifra_addr.sipx_addr)) 149 break; 150 } 151 if (cmd == SIOCDIFADDR && ia == NULL) 152 return (EADDRNOTAVAIL); 153 /* FALLTHROUGH */ 154 155 case SIOCSIFADDR: 156 case SIOCSIFDSTADDR: 157 if (td && (error = priv_check(td, PRIV_NET_SETLLADDR)) != 0) 158 return (error); 159 if (ia == NULL) { 160 oia = (struct ipx_ifaddr *) 161 malloc(sizeof(*ia), M_IFADDR, 162 M_WAITOK | M_ZERO); 163 if (oia == NULL) 164 return (ENOBUFS); 165 if ((ia = ipx_ifaddr) != NULL) { 166 for ( ; ia->ia_next != NULL; ia = ia->ia_next) 167 ; 168 ia->ia_next = oia; 169 } else 170 ipx_ifaddr = oia; 171 ia = oia; 172 ifa = (struct ifaddr *)ia; 173 ifa_init(ifa); 174 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 175 ia->ia_ifp = ifp; 176 ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 177 178 ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 179 180 ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 181 if (ifp->if_flags & IFF_BROADCAST) { 182 ia->ia_broadaddr.sipx_family = AF_IPX; 183 ia->ia_broadaddr.sipx_len = 184 sizeof(ia->ia_addr); 185 ia->ia_broadaddr.sipx_addr.x_host = 186 ipx_broadhost; 187 } 188 } 189 break; 190 191 default: 192 if (td && (error = priv_check(td, PRIV_NET_HWIOCTL)) != 0) 193 return (error); 194 } 195 196 switch (cmd) { 197 case SIOCSIFDSTADDR: 198 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 199 return (EINVAL); 200 if (ia->ia_flags & IFA_ROUTE) { 201 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 202 ia->ia_flags &= ~IFA_ROUTE; 203 } 204 if (ifp->if_ioctl) { 205 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, 206 (void *)ia); 207 if (error) 208 return (error); 209 } 210 *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 211 return (0); 212 213 case SIOCSIFADDR: 214 return (ipx_ifinit(ifp, ia, 215 (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 216 217 case SIOCDIFADDR: 218 ipx_ifscrub(ifp, ia); 219 ifa = (struct ifaddr *)ia; 220 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 221 oia = ia; 222 if (oia == (ia = ipx_ifaddr)) { 223 ipx_ifaddr = ia->ia_next; 224 } else { 225 while (ia->ia_next && (ia->ia_next != oia)) { 226 ia = ia->ia_next; 227 } 228 if (ia->ia_next) 229 ia->ia_next = oia->ia_next; 230 else 231 printf("Didn't unlink ipxifadr from list\n"); 232 } 233 ifa_free(&oia->ia_ifa); 234 return (0); 235 236 case SIOCAIFADDR: 237 dstIsNew = 0; 238 hostIsNew = 1; 239 if (ia->ia_addr.sipx_family == AF_IPX) { 240 if (ifra->ifra_addr.sipx_len == 0) { 241 ifra->ifra_addr = ia->ia_addr; 242 hostIsNew = 0; 243 } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 244 ia->ia_addr.sipx_addr)) 245 hostIsNew = 0; 246 } 247 if ((ifp->if_flags & IFF_POINTOPOINT) && 248 (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 249 if (hostIsNew == 0) 250 ipx_ifscrub(ifp, ia); 251 ia->ia_dstaddr = ifra->ifra_dstaddr; 252 dstIsNew = 1; 253 } 254 if (ifra->ifra_addr.sipx_family == AF_IPX && 255 (hostIsNew || dstIsNew)) 256 error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 257 return (error); 258 259 default: 260 if (ifp->if_ioctl == NULL) 261 return (EOPNOTSUPP); 262 return ((*ifp->if_ioctl)(ifp, cmd, data)); 263 } 264} 265 266/* 267 * Delete any previous route for an old address. 268 */ 269static void 270ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia) 271{ 272 273 if (ia->ia_flags & IFA_ROUTE) { 274 if (ifp->if_flags & IFF_POINTOPOINT) { 275 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 276 } else 277 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 278 ia->ia_flags &= ~IFA_ROUTE; 279 } 280} 281 282/* 283 * Initialize an interface's internet address and routing table entry. 284 */ 285static int 286ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 287 struct sockaddr_ipx *sipx, int scrub) 288{ 289 struct sockaddr_ipx oldaddr; 290 int s = splimp(), error; 291 292 /* 293 * Set up new addresses. 294 */ 295 oldaddr = ia->ia_addr; 296 ia->ia_addr = *sipx; 297 298 /* 299 * The convention we shall adopt for naming is that a supplied 300 * address of zero means that "we don't care". Use the MAC address 301 * of the interface. If it is an interface without a MAC address, 302 * like a serial line, the address must be supplied. 303 * 304 * Give the interface a chance to initialize if this is its first 305 * address, and to validate the address if necessary. 306 */ 307 if (ifp->if_ioctl != NULL && 308 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 309 ia->ia_addr = oldaddr; 310 splx(s); 311 return (error); 312 } 313 splx(s); 314 ia->ia_ifa.ifa_metric = ifp->if_metric; 315 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(struct ipx_addr *dst) 339{ 340 struct ipx_ifaddr *ia; 341 struct ipx_addr *compare; 342 struct ifnet *ifp; 343 struct ipx_ifaddr *ia_maybe = NULL; 344 union ipx_net net = dst->x_net; 345 346 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 347 if ((ifp = ia->ia_ifp) != NULL) { 348 if (ifp->if_flags & IFF_POINTOPOINT) { 349 compare = &satoipx_addr(ia->ia_dstaddr); 350 if (ipx_hosteq(*dst, *compare)) 351 return (ia); 352 if (ipx_neteqnn(net, 353 ia->ia_addr.sipx_addr.x_net)) 354 ia_maybe = ia; 355 } else { 356 if (ipx_neteqnn(net, 357 ia->ia_addr.sipx_addr.x_net)) 358 return (ia); 359 } 360 } 361 } 362 return (ia_maybe); 363} 364 365void 366ipx_printhost(struct ipx_addr *addr) 367{ 368 u_short port; 369 struct ipx_addr work = *addr; 370 char *p; u_char *q; 371 char *net = "", *host = ""; 372 char cport[10], chost[15], cnet[15]; 373 374 port = ntohs(work.x_port); 375 376 if (ipx_nullnet(work) && ipx_nullhost(work)) { 377 if (port) 378 printf("*.%x", port); 379 else 380 printf("*.*"); 381 382 return; 383 } 384 385 if (ipx_wildnet(work)) 386 net = "any"; 387 else if (ipx_nullnet(work)) 388 net = "*"; 389 else { 390 q = work.x_net.c_net; 391 snprintf(cnet, sizeof(cnet), "%x%x%x%x", 392 q[0], q[1], q[2], q[3]); 393 for (p = cnet; *p == '0' && p < cnet + 8; p++) 394 continue; 395 net = p; 396 } 397 398 if (ipx_wildhost(work)) 399 host = "any"; 400 else if (ipx_nullhost(work)) 401 host = "*"; 402 else { 403 q = work.x_host.c_host; 404 snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 405 q[0], q[1], q[2], q[3], q[4], q[5]); 406 for (p = chost; *p == '0' && p < chost + 12; p++) 407 continue; 408 host = p; 409 } 410 411 if (port) { 412 if (strcmp(host, "*") == 0) { 413 host = ""; 414 snprintf(cport, sizeof(cport), "%x", port); 415 } else 416 snprintf(cport, sizeof(cport), ".%x", port); 417 } else 418 *cport = 0; 419 420 printf("%s.%s%s", net, host, cport); 421} 422