ipx.c revision 139823
15739Sjkh/*- 250476Speter * Copyright (c) 1995, Mike Mitchell 35739Sjkh * Copyright (c) 1984, 1985, 1986, 1987, 1993 4157707Sru * The Regents of the University of California. All rights reserved. 5157707Sru * 6156813Sru * Redistribution and use in source and binary forms, with or without 7156813Sru * modification, are permitted provided that the following conditions 8127667Sbms * are met: 9127667Sbms * 1. Redistributions of source code must retain the above copyright 10277722Sluigi * notice, this list of conditions and the following disclaimer. 11214529Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 1275111Sfenner * notice, this list of conditions and the following disclaimer in the 13214519Srpaulo * documentation and/or other materials provided with the distribution. 14190235Srpaulo * 3. All advertising materials mentioning features or use of this software 15190235Srpaulo * must display the following acknowledgement: 16172681Smlaier * This product includes software developed by the University of 17190235Srpaulo * California, Berkeley and its contributors. 18190235Srpaulo * 4. Neither the name of the University nor the names of its contributors 19190235Srpaulo * may be used to endorse or promote products derived from this software 20190235Srpaulo * without specific prior written permission. 21190235Srpaulo * 22190226Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23190226Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24190226Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25190226Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26190226Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27190226Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28190226Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29190226Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30190226Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31190226Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32190226Srpaulo * SUCH DAMAGE. 33190226Srpaulo * 34190226Srpaulo * @(#)ipx.c 35190226Srpaulo */ 36190226Srpaulo 37190226Srpaulo#include <sys/cdefs.h> 38190226Srpaulo__FBSDID("$FreeBSD: head/sys/netipx/ipx.c 139823 2005-01-07 01:45:51Z imp $"); 39190226Srpaulo 40190226Srpaulo#include <sys/param.h> 41190226Srpaulo#include <sys/kernel.h> 42190226Srpaulo#include <sys/systm.h> 43190226Srpaulo#include <sys/malloc.h> 44190226Srpaulo#include <sys/sockio.h> 45190226Srpaulo#include <sys/socket.h> 46190226Srpaulo 47190226Srpaulo#include <net/if.h> 48235426Sdelphij#include <net/route.h> 49190226Srpaulo 50190226Srpaulo#include <netipx/ipx.h> 51190226Srpaulo#include <netipx/ipx_if.h> 52190226Srpaulo#include <netipx/ipx_var.h> 53190226Srpaulo 54190226SrpauloNET_NEEDS_GIANT("ipx"); 55190226Srpaulo 56190226Srpaulo/* 57190226Srpaulo * XXXRW: Requires synchronization. 58190226Srpaulo */ 59190226Srpaulostruct ipx_ifaddr *ipx_ifaddr; 60190226Srpaulo 61190226Srpaulostatic void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia); 62190226Srpaulostatic int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia, 63190226Srpaulo struct sockaddr_ipx *sipx, int scrub); 64235426Sdelphij 65190226Srpaulo/* 66190226Srpaulo * Generic internet control operations (ioctl's). 67190226Srpaulo */ 68190226Srpauloint 69190226Srpauloipx_control(so, cmd, data, ifp, td) 70190226Srpaulo struct socket *so; 71190226Srpaulo u_long cmd; 72190226Srpaulo caddr_t data; 73235426Sdelphij register struct ifnet *ifp; 74235426Sdelphij struct thread *td; 75190226Srpaulo{ 76190226Srpaulo register struct ifreq *ifr = (struct ifreq *)data; 77190226Srpaulo register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 78190226Srpaulo register struct ipx_ifaddr *ia; 79235426Sdelphij struct ifaddr *ifa; 80190226Srpaulo struct ipx_ifaddr *oia; 81190226Srpaulo int dstIsNew, hostIsNew; 82235426Sdelphij int error = 0; 83235426Sdelphij 84190226Srpaulo /* 85190226Srpaulo * Find address for this interface, if it exists. 86190226Srpaulo */ 87190226Srpaulo if (ifp == NULL) 88190226Srpaulo return (EADDRNOTAVAIL); 89182368Spjd for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) 90190236Srpaulo if (ia->ia_ifp == ifp) 91190226Srpaulo break; 92190226Srpaulo 935739Sjkh switch (cmd) { 94122029Sgreen 95122029Sgreen case SIOCGIFADDR: 96122029Sgreen if (ia == NULL) 97127667Sbms return (EADDRNOTAVAIL); 98127667Sbms *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 99156813Sru return (0); 10075125Sbde 10159266Ssteve case SIOCGIFBRDADDR: 102172681Smlaier if (ia == NULL) 103172681Smlaier return (EADDRNOTAVAIL); 104172681Smlaier if ((ifp->if_flags & IFF_BROADCAST) == 0) 10517686Spst return (EINVAL); 106201381Sed *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 107201381Sed return (0); 108225227Skib 10917700Spst case SIOCGIFDSTADDR: 11017686Spst if (ia == NULL) 11117686Spst return (EADDRNOTAVAIL); 11217686Spst if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 113313613Sngie return (EINVAL); 11480767Sfenner *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 11517743Spst return (0); 11617743Spst } 11717686Spst 11839295Sfenner if (td && (error = suser(td)) != 0) 11939295Sfenner return (error); 12039295Sfenner 12139295Sfenner switch (cmd) { 122127667Sbms case SIOCAIFADDR: 123127667Sbms case SIOCDIFADDR: 124127667Sbms if (ifra->ifra_addr.sipx_family == AF_IPX) 125127667Sbms for (oia = ia; ia != NULL; ia = ia->ia_next) { 12635840Sbde if (ia->ia_ifp == ifp && 12735840Sbde ipx_neteq(ia->ia_addr.sipx_addr, 1285739Sjkh ifra->ifra_addr.sipx_addr)) 129190226Srpaulo break; 130190226Srpaulo } 131190226Srpaulo if (cmd == SIOCDIFADDR && ia == NULL) 132190226Srpaulo return (EADDRNOTAVAIL); 133190226Srpaulo /* FALLTHROUGH */ 134190226Srpaulo 135190226Srpaulo case SIOCSIFADDR: 136190226Srpaulo case SIOCSIFDSTADDR: 137190226Srpaulo if (ia == NULL) { 138190226Srpaulo oia = (struct ipx_ifaddr *) 139190226Srpaulo malloc(sizeof(*ia), M_IFADDR, 140190226Srpaulo M_WAITOK | M_ZERO); 141190226Srpaulo if (oia == NULL) 142190226Srpaulo return (ENOBUFS); 143190226Srpaulo if ((ia = ipx_ifaddr) != NULL) { 144190226Srpaulo for ( ; ia->ia_next != NULL; ia = ia->ia_next) 1455739Sjkh ; 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