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