ipx.c revision 170689
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 170689 2007-06-13 22:42:43Z 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; 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 115 case SIOCGIFADDR: 116 if (ia == NULL) 117 return (EADDRNOTAVAIL); 118 *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 119 return (0); 120 121 case SIOCGIFBRDADDR: 122 if (ia == NULL) 123 return (EADDRNOTAVAIL); 124 if ((ifp->if_flags & IFF_BROADCAST) == 0) 125 return (EINVAL); 126 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 127 return (0); 128 129 case SIOCGIFDSTADDR: 130 if (ia == NULL) 131 return (EADDRNOTAVAIL); 132 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 133 return (EINVAL); 134 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 135 return (0); 136 } 137 138 if (td && (error = suser(td)) != 0) 139 return (error); 140 141 switch (cmd) { 142 case SIOCAIFADDR: 143 case SIOCDIFADDR: 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 (ia == NULL) { 158 oia = (struct ipx_ifaddr *) 159 malloc(sizeof(*ia), M_IFADDR, 160 M_WAITOK | M_ZERO); 161 if (oia == NULL) 162 return (ENOBUFS); 163 if ((ia = ipx_ifaddr) != NULL) { 164 for ( ; ia->ia_next != NULL; ia = ia->ia_next) 165 ; 166 ia->ia_next = oia; 167 } else 168 ipx_ifaddr = oia; 169 ia = oia; 170 ifa = (struct ifaddr *)ia; 171 IFA_LOCK_INIT(ifa); 172 ifa->ifa_refcnt = 1; 173 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 174 ia->ia_ifp = ifp; 175 ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 176 177 ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask; 178 179 ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 180 if (ifp->if_flags & IFF_BROADCAST) { 181 ia->ia_broadaddr.sipx_family = AF_IPX; 182 ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 183 ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 184 } 185 } 186 } 187 188 switch (cmd) { 189 190 case SIOCSIFDSTADDR: 191 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 192 return (EINVAL); 193 if (ia->ia_flags & IFA_ROUTE) { 194 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 195 ia->ia_flags &= ~IFA_ROUTE; 196 } 197 if (ifp->if_ioctl) { 198 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia); 199 if (error) 200 return (error); 201 } 202 *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr; 203 return (0); 204 205 case SIOCSIFADDR: 206 return (ipx_ifinit(ifp, ia, 207 (struct sockaddr_ipx *)&ifr->ifr_addr, 1)); 208 209 case SIOCDIFADDR: 210 ipx_ifscrub(ifp, ia); 211 ifa = (struct ifaddr *)ia; 212 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 213 oia = ia; 214 if (oia == (ia = ipx_ifaddr)) { 215 ipx_ifaddr = ia->ia_next; 216 } else { 217 while (ia->ia_next && (ia->ia_next != oia)) { 218 ia = ia->ia_next; 219 } 220 if (ia->ia_next) 221 ia->ia_next = oia->ia_next; 222 else 223 printf("Didn't unlink ipxifadr from list\n"); 224 } 225 IFAFREE((&oia->ia_ifa)); 226 return (0); 227 228 case SIOCAIFADDR: 229 dstIsNew = 0; 230 hostIsNew = 1; 231 if (ia->ia_addr.sipx_family == AF_IPX) { 232 if (ifra->ifra_addr.sipx_len == 0) { 233 ifra->ifra_addr = ia->ia_addr; 234 hostIsNew = 0; 235 } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 236 ia->ia_addr.sipx_addr)) 237 hostIsNew = 0; 238 } 239 if ((ifp->if_flags & IFF_POINTOPOINT) && 240 (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 241 if (hostIsNew == 0) 242 ipx_ifscrub(ifp, ia); 243 ia->ia_dstaddr = ifra->ifra_dstaddr; 244 dstIsNew = 1; 245 } 246 if (ifra->ifra_addr.sipx_family == AF_IPX && 247 (hostIsNew || dstIsNew)) 248 error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 249 return (error); 250 251 default: 252 if (ifp->if_ioctl == NULL) 253 return (EOPNOTSUPP); 254 return ((*ifp->if_ioctl)(ifp, cmd, data)); 255 } 256} 257 258/* 259* Delete any previous route for an old address. 260*/ 261static void 262ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia) 263{ 264 265 if (ia->ia_flags & IFA_ROUTE) { 266 if (ifp->if_flags & IFF_POINTOPOINT) { 267 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 268 } else 269 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 270 ia->ia_flags &= ~IFA_ROUTE; 271 } 272} 273/* 274 * Initialize an interface's internet address 275 * and routing table entry. 276 */ 277static int 278ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 279 struct sockaddr_ipx *sipx, int scrub) 280{ 281 struct sockaddr_ipx oldaddr; 282 int s = splimp(), error; 283 284 /* 285 * Set up new addresses. 286 */ 287 oldaddr = ia->ia_addr; 288 ia->ia_addr = *sipx; 289 290 /* 291 * The convention we shall adopt for naming is that 292 * a supplied address of zero means that "we don't care". 293 * Use the MAC address of the interface. If it is an 294 * interface without a MAC address, like a serial line, the 295 * address must be supplied. 296 * 297 * Give the interface a chance to initialize 298 * if this is its first address, 299 * and to validate the address if necessary. 300 */ 301 if (ifp->if_ioctl != NULL && 302 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 303 ia->ia_addr = oldaddr; 304 splx(s); 305 return (error); 306 } 307 splx(s); 308 ia->ia_ifa.ifa_metric = ifp->if_metric; 309 /* 310 * Add route for the network. 311 */ 312 if (scrub) { 313 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 314 ipx_ifscrub(ifp, ia); 315 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 316 } 317 if (ifp->if_flags & IFF_POINTOPOINT) 318 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 319 else { 320 ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 321 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 322 } 323 ia->ia_flags |= IFA_ROUTE; 324 return (0); 325} 326 327/* 328 * Return address info for specified internet network. 329 */ 330struct ipx_ifaddr * 331ipx_iaonnetof(struct ipx_addr *dst) 332{ 333 struct ipx_ifaddr *ia; 334 struct ipx_addr *compare; 335 struct ifnet *ifp; 336 struct ipx_ifaddr *ia_maybe = NULL; 337 union ipx_net net = dst->x_net; 338 339 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { 340 if ((ifp = ia->ia_ifp) != NULL) { 341 if (ifp->if_flags & IFF_POINTOPOINT) { 342 compare = &satoipx_addr(ia->ia_dstaddr); 343 if (ipx_hosteq(*dst, *compare)) 344 return (ia); 345 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 346 ia_maybe = ia; 347 } else { 348 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 349 return (ia); 350 } 351 } 352 } 353 return (ia_maybe); 354} 355 356 357void 358ipx_printhost(struct ipx_addr *addr) 359{ 360 u_short port; 361 struct ipx_addr work = *addr; 362 char *p; u_char *q; 363 char *net = "", *host = ""; 364 char cport[10], chost[15], cnet[15]; 365 366 port = ntohs(work.x_port); 367 368 if (ipx_nullnet(work) && ipx_nullhost(work)) { 369 370 if (port) 371 printf("*.%x", port); 372 else 373 printf("*.*"); 374 375 return; 376 } 377 378 if (ipx_wildnet(work)) 379 net = "any"; 380 else if (ipx_nullnet(work)) 381 net = "*"; 382 else { 383 q = work.x_net.c_net; 384 snprintf(cnet, sizeof(cnet), "%x%x%x%x", 385 q[0], q[1], q[2], q[3]); 386 for (p = cnet; *p == '0' && p < cnet + 8; p++) 387 continue; 388 net = p; 389 } 390 391 if (ipx_wildhost(work)) 392 host = "any"; 393 else if (ipx_nullhost(work)) 394 host = "*"; 395 else { 396 q = work.x_host.c_host; 397 snprintf(chost, sizeof(chost), "%x%x%x%x%x%x", 398 q[0], q[1], q[2], q[3], q[4], q[5]); 399 for (p = chost; *p == '0' && p < chost + 12; p++) 400 continue; 401 host = p; 402 } 403 404 if (port) { 405 if (strcmp(host, "*") == 0) { 406 host = ""; 407 snprintf(cport, sizeof(cport), "%x", port); 408 } else 409 snprintf(cport, sizeof(cport), ".%x", port); 410 } else 411 *cport = 0; 412 413 printf("%s.%s%s", net, host, cport); 414} 415