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