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