ipx_usrreq.c revision 15688
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_usrreq.c 35 * 36 * $Id: ipx_usrreq.c,v 1.6 1996/04/13 14:37:22 jhay Exp $ 37 */ 38 39#include <sys/param.h> 40#include <sys/queue.h> 41#include <sys/systm.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/protosw.h> 45#include <sys/socket.h> 46#include <sys/socketvar.h> 47#include <sys/errno.h> 48#include <sys/stat.h> 49 50#include <net/if.h> 51#include <net/route.h> 52 53#include <netinet/in.h> 54 55#include <netipx/ipx.h> 56#include <netipx/ipx_pcb.h> 57#include <netipx/ipx_if.h> 58#include <netipx/ipx_var.h> 59#include <netipx/ipx_error.h> 60#include <netipx/ipx_ip.h> 61 62/* 63 * IPX protocol implementation. 64 */ 65 66int noipxRoute; 67 68/* 69 * This may also be called for raw listeners. 70 */ 71void 72ipx_input(m, ipxp) 73 struct mbuf *m; 74 register struct ipxpcb *ipxp; 75{ 76 register struct ipx *ipx = mtod(m, struct ipx *); 77 struct ifnet *ifp = m->m_pkthdr.rcvif; 78 struct sockaddr_ipx ipx_ipx; 79 80 if (ipxp==0) 81 panic("No ipxpcb"); 82 /* 83 * Construct sockaddr format source address. 84 * Stuff source address and datagram in user buffer. 85 */ 86 ipx_ipx.sipx_len = sizeof(ipx_ipx); 87 ipx_ipx.sipx_family = AF_IPX; 88 ipx_ipx.sipx_addr = ipx->ipx_sna; 89 ipx_ipx.sipx_zero[0] = '\0'; 90 ipx_ipx.sipx_zero[1] = '\0'; 91 if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp) { 92 register struct ifaddr *ifa; 93 94 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 95 if (ifa->ifa_addr->sa_family == AF_IPX) { 96 ipx_ipx.sipx_addr.x_net = 97 IA_SIPX(ifa)->sipx_addr.x_net; 98 break; 99 } 100 } 101 } 102 ipxp->ipxp_rpt = ipx->ipx_pt; 103 if ( ! (ipxp->ipxp_flags & IPXP_RAWIN) ) { 104 m->m_len -= sizeof (struct ipx); 105 m->m_pkthdr.len -= sizeof (struct ipx); 106 m->m_data += sizeof (struct ipx); 107 } 108 if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 109 m, (struct mbuf *)0) == 0) 110 goto bad; 111 sorwakeup(ipxp->ipxp_socket); 112 return; 113bad: 114 m_freem(m); 115} 116 117void 118ipx_abort(ipxp) 119 struct ipxpcb *ipxp; 120{ 121 struct socket *so = ipxp->ipxp_socket; 122 123 ipx_pcbdisconnect(ipxp); 124 soisdisconnected(so); 125} 126/* 127 * Drop connection, reporting 128 * the specified error. 129 */ 130/* struct ipxpcb * DELETE THIS */ 131void 132ipx_drop(ipxp, errno) 133 register struct ipxpcb *ipxp; 134 int errno; 135{ 136 struct socket *so = ipxp->ipxp_socket; 137 138 /* 139 * someday, in the xerox world 140 * we will generate error protocol packets 141 * announcing that the socket has gone away. 142 */ 143 /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 144 tp->t_state = TCPS_CLOSED; 145 (void) tcp_output(tp); 146 }*/ 147 so->so_error = errno; 148 ipx_pcbdisconnect(ipxp); 149 soisdisconnected(so); 150} 151 152int 153ipx_output(ipxp, m0) 154 struct ipxpcb *ipxp; 155 struct mbuf *m0; 156{ 157 register struct mbuf *m; 158 register struct ipx *ipx; 159 register struct socket *so; 160 register int len = 0; 161 register struct route *ro; 162 struct mbuf *mprev = NULL; 163 164 /* 165 * Calculate data length. 166 */ 167 for (m = m0; m; m = m->m_next) { 168 mprev = m; 169 len += m->m_len; 170 } 171 /* 172 * Make sure packet is actually of even length. 173 */ 174 175 if (len & 1) { 176 m = mprev; 177 if ((m->m_flags & M_EXT) == 0 && 178 (m->m_len + m->m_data < &m->m_dat[MLEN])) { 179 m->m_len++; 180 } else { 181 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 182 183 if (m1 == 0) { 184 m_freem(m0); 185 return (ENOBUFS); 186 } 187 m1->m_len = 1; 188 * mtod(m1, char *) = 0; 189 m->m_next = m1; 190 } 191 m0->m_pkthdr.len++; 192 } 193 194 /* 195 * Fill in mbuf with extended IPX header 196 * and addresses and length put into network format. 197 */ 198 m = m0; 199 if (ipxp->ipxp_flags & IPXP_RAWOUT) { 200 ipx = mtod(m, struct ipx *); 201 } else { 202 M_PREPEND(m, sizeof (struct ipx), M_DONTWAIT); 203 if (m == 0) 204 return (ENOBUFS); 205 ipx = mtod(m, struct ipx *); 206 ipx->ipx_tc = 0; 207 ipx->ipx_pt = ipxp->ipxp_dpt; 208 ipx->ipx_sna = ipxp->ipxp_laddr; 209 ipx->ipx_dna = ipxp->ipxp_faddr; 210 len += sizeof (struct ipx); 211 } 212 213 ipx->ipx_len = htons((u_short)len); 214 215 if (ipxcksum) { 216 ipx->ipx_sum = 0; 217 len = ((len - 1) | 1) + 1; 218 ipx->ipx_sum = ipx_cksum(m, len); 219 } else 220 ipx->ipx_sum = 0xffff; 221 222 /* 223 * Output datagram. 224 */ 225 so = ipxp->ipxp_socket; 226 if (so->so_options & SO_DONTROUTE) 227 return (ipx_outputfl(m, (struct route *)0, 228 (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 229 /* 230 * Use cached route for previous datagram if 231 * possible. If the previous net was the same 232 * and the interface was a broadcast medium, or 233 * if the previous destination was identical, 234 * then we are ok. 235 * 236 * NB: We don't handle broadcasts because that 237 * would require 3 subroutine calls. 238 */ 239 ro = &ipxp->ipxp_route; 240#ifdef ancient_history 241 /* 242 * I think that this will all be handled in ipx_pcbconnect! 243 */ 244 if (ro->ro_rt) { 245 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 246 /* 247 * This assumes we have no GH type routes 248 */ 249 if (ro->ro_rt->rt_flags & RTF_HOST) { 250 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 251 goto re_route; 252 253 } 254 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 255 register struct ipx_addr *dst = 256 &satoipx_addr(ro->ro_dst); 257 dst->x_host = ipx->ipx_dna.x_host; 258 } 259 /* 260 * Otherwise, we go through the same gateway 261 * and dst is already set up. 262 */ 263 } else { 264 re_route: 265 RTFREE(ro->ro_rt); 266 ro->ro_rt = (struct rtentry *)0; 267 } 268 } 269 ipxp->ipxp_lastdst = ipx->ipx_dna; 270#endif /* ancient_history */ 271 if (noipxRoute) ro = 0; 272 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 273} 274/* ARGSUSED */ 275int 276ipx_ctloutput(req, so, level, name, value) 277 int req, level; 278 struct socket *so; 279 int name; 280 struct mbuf **value; 281{ 282 register struct mbuf *m; 283 struct ipxpcb *ipxp = sotoipxpcb(so); 284 int mask, error = 0; 285 /*extern long ipx_pexseq;*/ /*XXX*//*JRE*/ 286 287 if (ipxp == NULL) 288 return (EINVAL); 289 290 switch (req) { 291 292 case PRCO_GETOPT: 293 if (value==NULL) 294 return (EINVAL); 295 m = m_get(M_DONTWAIT, MT_DATA); 296 if (m==NULL) 297 return (ENOBUFS); 298 switch (name) { 299 300 case SO_ALL_PACKETS: 301 mask = IPXP_ALL_PACKETS; 302 goto get_flags; 303 304 case SO_HEADERS_ON_INPUT: 305 mask = IPXP_RAWIN; 306 goto get_flags; 307 308 case SO_HEADERS_ON_OUTPUT: 309 mask = IPXP_RAWOUT; 310 get_flags: 311 m->m_len = sizeof(short); 312 *mtod(m, short *) = ipxp->ipxp_flags & mask; 313 break; 314 315 case SO_DEFAULT_HEADERS: 316 m->m_len = sizeof(struct ipx); 317 { 318 register struct ipx *ipx = mtod(m, struct ipx *); 319 ipx->ipx_len = 0; 320 ipx->ipx_sum = 0; 321 ipx->ipx_tc = 0; 322 ipx->ipx_pt = ipxp->ipxp_dpt; 323 ipx->ipx_dna = ipxp->ipxp_faddr; 324 ipx->ipx_sna = ipxp->ipxp_laddr; 325 } 326 break; 327 328 case SO_SEQNO: 329 m->m_len = sizeof(long); 330 *mtod(m, long *) = ipx_pexseq++; 331 break; 332 333 default: 334 error = EINVAL; 335 } 336 *value = m; 337 break; 338 339 case PRCO_SETOPT: 340 switch (name) { 341 int *ok; 342 343 case SO_ALL_PACKETS: 344 mask = IPXP_ALL_PACKETS; 345 goto set_head; 346 347 case SO_HEADERS_ON_INPUT: 348 mask = IPXP_RAWIN; 349 goto set_head; 350 351 case SO_HEADERS_ON_OUTPUT: 352 mask = IPXP_RAWOUT; 353 set_head: 354 if (value && *value) { 355 ok = mtod(*value, int *); 356 if (*ok) 357 ipxp->ipxp_flags |= mask; 358 else 359 ipxp->ipxp_flags &= ~mask; 360 } else error = EINVAL; 361 break; 362 363 case SO_DEFAULT_HEADERS: 364 { 365 register struct ipx *ipx 366 = mtod(*value, struct ipx *); 367 ipxp->ipxp_dpt = ipx->ipx_pt; 368 } 369 break; 370#ifdef IPXIP 371 case SO_IPXIP_ROUTE: 372 error = ipxip_route(so, *value); 373 break; 374#endif /* IPXIP */ 375#ifdef IPXTUNNEL 376 case SO_IPXTUNNEL_ROUTE 377 error = ipxtun_route(so, *value); 378 break; 379#endif 380 default: 381 error = EINVAL; 382 } 383 if (value && *value) 384 m_freem(*value); 385 break; 386 } 387 return (error); 388} 389 390/*ARGSUSED*/ 391int 392ipx_usrreq(so, req, m, nam, control) 393 struct socket *so; 394 int req; 395 struct mbuf *m, *nam, *control; 396{ 397 struct ipxpcb *ipxp = sotoipxpcb(so); 398 int error = 0; 399 400 if (req == PRU_CONTROL) 401 return (ipx_control(so, (int)m, (caddr_t)nam, 402 (struct ifnet *)control)); 403 if (control && control->m_len) { 404 error = EINVAL; 405 goto release; 406 } 407 if (ipxp == NULL && req != PRU_ATTACH) { 408 error = EINVAL; 409 goto release; 410 } 411 switch (req) { 412 413 case PRU_ATTACH: 414 if (ipxp != NULL) { 415 error = EINVAL; 416 break; 417 } 418 error = ipx_pcballoc(so, &ipxpcb); 419 if (error) 420 break; 421 error = soreserve(so, (u_long) 2048, (u_long) 2048); 422 if (error) 423 break; 424 break; 425 426 case PRU_DETACH: 427 if (ipxp == NULL) { 428 error = ENOTCONN; 429 break; 430 } 431 ipx_pcbdetach(ipxp); 432 break; 433 434 case PRU_BIND: 435 error = ipx_pcbbind(ipxp, nam); 436 break; 437 438 case PRU_LISTEN: 439 error = EOPNOTSUPP; 440 break; 441 442 case PRU_CONNECT: 443 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 444 error = EISCONN; 445 break; 446 } 447 error = ipx_pcbconnect(ipxp, nam); 448 if (error == 0) 449 soisconnected(so); 450 break; 451 452 case PRU_CONNECT2: 453 error = EOPNOTSUPP; 454 break; 455 456 case PRU_ACCEPT: 457 error = EOPNOTSUPP; 458 break; 459 460 case PRU_DISCONNECT: 461 if (ipx_nullhost(ipxp->ipxp_faddr)) { 462 error = ENOTCONN; 463 break; 464 } 465 ipx_pcbdisconnect(ipxp); 466 soisdisconnected(so); 467 break; 468 469 case PRU_SHUTDOWN: 470 socantsendmore(so); 471 break; 472 473 case PRU_SEND: 474 { 475 struct ipx_addr laddr; 476 int s = 0; 477 478 if (nam) { 479 laddr = ipxp->ipxp_laddr; 480 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 481 error = EISCONN; 482 break; 483 } 484 /* 485 * Must block input while temporarily connected. 486 */ 487 s = splnet(); 488 error = ipx_pcbconnect(ipxp, nam); 489 if (error) { 490 splx(s); 491 break; 492 } 493 } else { 494 if (ipx_nullhost(ipxp->ipxp_faddr)) { 495 error = ENOTCONN; 496 break; 497 } 498 } 499 error = ipx_output(ipxp, m); 500 m = NULL; 501 if (nam) { 502 ipx_pcbdisconnect(ipxp); 503 splx(s); 504 ipxp->ipxp_laddr.x_host = laddr.x_host; 505 ipxp->ipxp_laddr.x_port = laddr.x_port; 506 } 507 } 508 break; 509 510 case PRU_ABORT: 511 ipx_pcbdetach(ipxp); 512 sofree(so); 513 soisdisconnected(so); 514 break; 515 516 case PRU_SOCKADDR: 517 ipx_setsockaddr(ipxp, nam); 518 break; 519 520 case PRU_PEERADDR: 521 ipx_setpeeraddr(ipxp, nam); 522 break; 523 524 case PRU_SENSE: 525 /* 526 * stat: don't bother with a blocksize. 527 */ 528 return (0); 529 530 case PRU_SENDOOB: 531 case PRU_FASTTIMO: 532 case PRU_SLOWTIMO: 533 case PRU_PROTORCV: 534 case PRU_PROTOSEND: 535 error = EOPNOTSUPP; 536 break; 537 538 case PRU_CONTROL: 539 case PRU_RCVD: 540 case PRU_RCVOOB: 541 return (EOPNOTSUPP); /* do not free mbuf's */ 542 543 default: 544 panic("ipx_usrreq"); 545 } 546release: 547 if (control != NULL) 548 m_freem(control); 549 if (m != NULL) 550 m_freem(m); 551 return (error); 552} 553/*ARGSUSED*/ 554int 555ipx_raw_usrreq(so, req, m, nam, control) 556 struct socket *so; 557 int req; 558 struct mbuf *m, *nam, *control; 559{ 560 int error = 0; 561 struct ipxpcb *ipxp = sotoipxpcb(so); 562 /*extern struct ipxpcb ipxrawpcb;*//*XXX*//*JRE*/ 563 564 switch (req) { 565 566 case PRU_ATTACH: 567 568 if (!(so->so_state & SS_PRIV) || (ipxp != NULL)) { 569 error = EINVAL; 570 break; 571 } 572 error = ipx_pcballoc(so, &ipxrawpcb); 573 if (error) 574 break; 575 error = soreserve(so, (u_long) 2048, (u_long) 2048); 576 if (error) 577 break; 578 ipxp = sotoipxpcb(so); 579 ipxp->ipxp_faddr.x_host = ipx_broadhost; 580 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 581 break; 582 default: 583 error = ipx_usrreq(so, req, m, nam, control); 584 } 585 return (error); 586} 587 588