ipx.c revision 14546
194575Sdes/* 294575Sdes * Copyright (c) 1995, Mike Mitchell 394575Sdes * Copyright (c) 1984, 1985, 1986, 1987, 1993 494575Sdes * The Regents of the University of California. All rights reserved. 594575Sdes * 694575Sdes * Redistribution and use in source and binary forms, with or without 794575Sdes * modification, are permitted provided that the following conditions 894575Sdes * are met: 994575Sdes * 1. Redistributions of source code must retain the above copyright 1094575Sdes * notice, this list of conditions and the following disclaimer. 1194575Sdes * 2. Redistributions in binary form must reproduce the above copyright 1294575Sdes * notice, this list of conditions and the following disclaimer in the 1394575Sdes * documentation and/or other materials provided with the distribution. 1494575Sdes * 3. All advertising materials mentioning features or use of this software 1594575Sdes * must display the following acknowledgement: 1694575Sdes * This product includes software developed by the University of 1794575Sdes * California, Berkeley and its contributors. 1894575Sdes * 4. Neither the name of the University nor the names of its contributors 1994575Sdes * may be used to endorse or promote products derived from this software 2094575Sdes * without specific prior written permission. 2194575Sdes * 2294575Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2394575Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2494575Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2594575Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2694575Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2794575Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2894575Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2994575Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3094575Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3194575Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3294575Sdes * SUCH DAMAGE. 3394575Sdes * 3494575Sdes * @(#)ipx.c 3594575Sdes * 3694575Sdes * $Id: ipx.c,v 1.3 1995/11/04 09:02:34 julian Exp $ 3794575Sdes */ 3894575Sdes 3994575Sdes#include <sys/param.h> 4094575Sdes#include <sys/queue.h> 4194575Sdes#include <sys/systm.h> 4294575Sdes#include <sys/mbuf.h> 4394575Sdes#include <sys/ioctl.h> 4494575Sdes#include <sys/protosw.h> 4594575Sdes#include <sys/errno.h> 4694575Sdes#include <sys/socket.h> 4794575Sdes#include <sys/socketvar.h> 4894575Sdes 4994575Sdes#include <net/if.h> 5094575Sdes#include <net/route.h> 5194575Sdes 5294575Sdes#include <netipx/ipx.h> 5394575Sdes#include <netipx/ipx_if.h> 5494575Sdes 5594575Sdes#ifdef IPX 5694575Sdes 5794575Sdesstruct ipx_ifaddr *ipx_ifaddr; 5894575Sdesint ipx_interfaces; 5994575Sdes 6094575Sdes/* 6194575Sdes * Generic internet control operations (ioctl's). 6294575Sdes */ 63/* ARGSUSED */ 64int 65ipx_control(so, cmd, data, ifp) 66 struct socket *so; 67 int cmd; 68 caddr_t data; 69 register struct ifnet *ifp; 70{ 71 register struct ifreq *ifr = (struct ifreq *)data; 72 register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data; 73 register struct ipx_ifaddr *ia; 74 struct ifaddr *ifa; 75 struct ipx_ifaddr *oia; 76 int dstIsNew, hostIsNew; 77 int error = 0; 78 79 /* 80 * Find address for this interface, if it exists. 81 */ 82 if (ifp == 0) 83 return (EADDRNOTAVAIL); 84 for (ia = ipx_ifaddr; ia; ia = ia->ia_next) 85 if (ia->ia_ifp == ifp) 86 break; 87 88 switch (cmd) { 89 90 case SIOCGIFADDR: 91 if (ia == (struct ipx_ifaddr *)0) 92 return (EADDRNOTAVAIL); 93 *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr; 94 return (0); 95 96 case SIOCGIFBRDADDR: 97 if (ia == (struct ipx_ifaddr *)0) 98 return (EADDRNOTAVAIL); 99 if ((ifp->if_flags & IFF_BROADCAST) == 0) 100 return (EINVAL); 101 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr; 102 return (0); 103 104 case SIOCGIFDSTADDR: 105 if (ia == (struct ipx_ifaddr *)0) 106 return (EADDRNOTAVAIL); 107 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 108 return (EINVAL); 109 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr; 110 return (0); 111 } 112 113 if ((so->so_state & SS_PRIV) == 0) 114 return (EPERM); 115 116 switch (cmd) { 117 case SIOCAIFADDR: 118 case SIOCDIFADDR: 119 if (ifra->ifra_addr.sipx_family == AF_IPX) 120 for (oia = ia; ia; ia = ia->ia_next) { 121 if (ia->ia_ifp == ifp && 122 ipx_neteq(ia->ia_addr.sipx_addr, 123 ifra->ifra_addr.sipx_addr)) 124 break; 125 } 126 if (cmd == SIOCDIFADDR && ia == 0) 127 return (EADDRNOTAVAIL); 128 /* FALLTHROUGH */ 129 130 case SIOCSIFADDR: 131 case SIOCSIFDSTADDR: 132 if (ia == (struct ipx_ifaddr *)0) { 133 oia = (struct ipx_ifaddr *) 134 malloc(sizeof *ia, M_IFADDR, M_WAITOK); 135 if (oia == (struct ipx_ifaddr *)NULL) 136 return (ENOBUFS); 137 bzero((caddr_t)oia, sizeof(*oia)); 138 if ((ia = ipx_ifaddr)) { 139 for ( ; ia->ia_next; ia = ia->ia_next) 140 ; 141 ia->ia_next = oia; 142 } else 143 ipx_ifaddr = oia; 144 ia = oia; 145 if ((ifa = ifp->if_addrlist)) { 146 for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 147 ; 148 ifa->ifa_next = (struct ifaddr *) ia; 149 } else 150 ifp->if_addrlist = (struct ifaddr *) ia; 151 ia->ia_ifp = ifp; 152 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 153 154 ia->ia_ifa.ifa_netmask = 155 (struct sockaddr *)&ipx_netmask; 156 157 ia->ia_ifa.ifa_dstaddr = 158 (struct sockaddr *)&ia->ia_dstaddr; 159 if (ifp->if_flags & IFF_BROADCAST) { 160 ia->ia_broadaddr.sipx_family = AF_IPX; 161 ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr); 162 ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost; 163 } 164 ipx_interfaces++; 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 if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) 192 ifp->if_addrlist = ifa->ifa_next; 193 else { 194 while (ifa->ifa_next && 195 (ifa->ifa_next != (struct ifaddr *)ia)) 196 ifa = ifa->ifa_next; 197 if (ifa->ifa_next) 198 ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; 199 else 200 printf("Couldn't unlink ipxifaddr from ifp\n"); 201 } 202 oia = ia; 203 if (oia == (ia = ipx_ifaddr)) { 204 ipx_ifaddr = ia->ia_next; 205 } else { 206 while (ia->ia_next && (ia->ia_next != oia)) { 207 ia = ia->ia_next; 208 } 209 if (ia->ia_next) 210 ia->ia_next = oia->ia_next; 211 else 212 printf("Didn't unlink ipxifadr from list\n"); 213 } 214 IFAFREE((&oia->ia_ifa)); 215 if (0 == --ipx_interfaces) { 216 /* 217 * We reset to virginity and start all over again 218 */ 219 ipx_thishost = ipx_zerohost; 220 } 221 return (0); 222 223 case SIOCAIFADDR: 224 dstIsNew = 0; hostIsNew = 1; 225 if (ia->ia_addr.sipx_family == AF_IPX) { 226 if (ifra->ifra_addr.sipx_len == 0) { 227 ifra->ifra_addr = ia->ia_addr; 228 hostIsNew = 0; 229 } else if (ipx_neteq(ifra->ifra_addr.sipx_addr, 230 ia->ia_addr.sipx_addr)) 231 hostIsNew = 0; 232 } 233 if ((ifp->if_flags & IFF_POINTOPOINT) && 234 (ifra->ifra_dstaddr.sipx_family == AF_IPX)) { 235 if (hostIsNew == 0) 236 ipx_ifscrub(ifp, ia); 237 ia->ia_dstaddr = ifra->ifra_dstaddr; 238 dstIsNew = 1; 239 } 240 if (ifra->ifra_addr.sipx_family == AF_IPX && 241 (hostIsNew || dstIsNew)) 242 error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0); 243 return (error); 244 245 default: 246 if (ifp->if_ioctl == 0) 247 return (EOPNOTSUPP); 248 return ((*ifp->if_ioctl)(ifp, cmd, data)); 249 } 250} 251 252/* 253* Delete any previous route for an old address. 254*/ 255void 256ipx_ifscrub(ifp, ia) 257 register struct ifnet *ifp; 258 register struct ipx_ifaddr *ia; 259{ 260 if (ia->ia_flags & IFA_ROUTE) { 261 if (ifp->if_flags & IFF_POINTOPOINT) { 262 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 263 } else 264 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 265 ia->ia_flags &= ~IFA_ROUTE; 266 } 267} 268/* 269 * Initialize an interface's internet address 270 * and routing table entry. 271 */ 272int 273ipx_ifinit(ifp, ia, sipx, scrub) 274 register struct ifnet *ifp; 275 register struct ipx_ifaddr *ia; 276 register struct sockaddr_ipx *sipx; 277 int scrub; 278{ 279 struct sockaddr_ipx oldaddr; 280 register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host; 281 int s = splimp(), error; 282 283 /* 284 * Set up new addresses. 285 */ 286 oldaddr = ia->ia_addr; 287 ia->ia_addr = *sipx; 288 /* 289 * The convention we shall adopt for naming is that 290 * a supplied address of zero means that "we don't care". 291 * if there is a single interface, use the address of that 292 * interface as our 6 byte host address. 293 * if there are multiple interfaces, use any address already 294 * used. 295 * 296 * Give the interface a chance to initialize 297 * if this is its first address, 298 * and to validate the address if necessary. 299 */ 300 if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) { 301 if (ifp->if_ioctl && 302 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 303 ia->ia_addr = oldaddr; 304 splx(s); 305 return (error); 306 } 307 ipx_thishost = *h; 308 } else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost) 309 || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) { 310 *h = ipx_thishost; 311 if (ifp->if_ioctl && 312 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) { 313 ia->ia_addr = oldaddr; 314 splx(s); 315 return (error); 316 } 317 if (!ipx_hosteqnh(ipx_thishost,*h)) { 318 ia->ia_addr = oldaddr; 319 splx(s); 320 return (EINVAL); 321 } 322 } else { 323 ia->ia_addr = oldaddr; 324 splx(s); 325 return (EINVAL); 326 } 327 ia->ia_ifa.ifa_metric = ifp->if_metric; 328 /* 329 * Add route for the network. 330 */ 331 if (scrub) { 332 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 333 ipx_ifscrub(ifp, ia); 334 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 335 } 336 if (ifp->if_flags & IFF_POINTOPOINT) 337 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 338 else { 339 ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; 340 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); 341 } 342 ia->ia_flags |= IFA_ROUTE; 343 return (0); 344} 345 346/* 347 * Return address info for specified internet network. 348 */ 349struct ipx_ifaddr * 350ipx_iaonnetof(dst) 351 register struct ipx_addr *dst; 352{ 353 register struct ipx_ifaddr *ia; 354 register struct ipx_addr *compare; 355 register struct ifnet *ifp; 356 struct ipx_ifaddr *ia_maybe = 0; 357 union ipx_net net = dst->x_net; 358 359 for (ia = ipx_ifaddr; ia; ia = ia->ia_next) { 360 if ((ifp = ia->ia_ifp)) { 361 if (ifp->if_flags & IFF_POINTOPOINT) { 362 compare = &satoipx_addr(ia->ia_dstaddr); 363 if (ipx_hosteq(*dst, *compare)) 364 return (ia); 365 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 366 ia_maybe = ia; 367 } else { 368 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) 369 return (ia); 370 } 371 } 372 } 373 return (ia_maybe); 374} 375#endif 376