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