ipx_usrreq.c revision 95759
1175702Smarius/* 2175702Smarius * Copyright (c) 1995, Mike Mitchell 3175702Smarius * Copyright (c) 1984, 1985, 1986, 1987, 1993 4175702Smarius * The Regents of the University of California. All rights reserved. 5175702Smarius * 6175702Smarius * Redistribution and use in source and binary forms, with or without 7175702Smarius * modification, are permitted provided that the following conditions 8175702Smarius * are met: 9175702Smarius * 1. Redistributions of source code must retain the above copyright 10175702Smarius * notice, this list of conditions and the following disclaimer. 11175702Smarius * 2. Redistributions in binary form must reproduce the above copyright 12175702Smarius * notice, this list of conditions and the following disclaimer in the 13175702Smarius * documentation and/or other materials provided with the distribution. 14175702Smarius * 3. All advertising materials mentioning features or use of this software 15175702Smarius * must display the following acknowledgement: 16175702Smarius * This product includes software developed by the University of 17175702Smarius * California, Berkeley and its contributors. 18175702Smarius * 4. Neither the name of the University nor the names of its contributors 19175702Smarius * may be used to endorse or promote products derived from this software 20175702Smarius * without specific prior written permission. 21175702Smarius * 22175702Smarius * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23175702Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24175702Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25175702Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26175702Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27175702Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28175702Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29175702Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30175702Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31175702Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32175702Smarius * SUCH DAMAGE. 33175702Smarius * 34175702Smarius * @(#)ipx_usrreq.c 35175702Smarius * 36175702Smarius * $FreeBSD: head/sys/netipx/ipx_usrreq.c 95759 2002-04-30 01:54:54Z tanimura $ 37175702Smarius */ 38175702Smarius 39175702Smarius#include "opt_ipx.h" 40175702Smarius 41175702Smarius#include <sys/param.h> 42175702Smarius#include <sys/kernel.h> 43175702Smarius#include <sys/lock.h> 44175702Smarius#include <sys/mbuf.h> 45175702Smarius#include <sys/protosw.h> 46175702Smarius#include <sys/signalvar.h> 47175702Smarius#include <sys/socket.h> 48175702Smarius#include <sys/socketvar.h> 49175702Smarius#include <sys/sx.h> 50175702Smarius#include <sys/sysctl.h> 51175702Smarius#include <sys/systm.h> 52175702Smarius 53175702Smarius#include <net/if.h> 54175702Smarius#include <net/route.h> 55175702Smarius 56175702Smarius#include <netinet/in.h> 57175702Smarius 58175702Smarius#include <netipx/ipx.h> 59175702Smarius#include <netipx/ipx_if.h> 60175702Smarius#include <netipx/ipx_ip.h> 61231914Smarius#include <netipx/ipx_pcb.h> 62231914Smarius#include <netipx/ipx_var.h> 63231914Smarius 64175702Smarius/* 65175702Smarius * IPX protocol implementation. 66175702Smarius */ 67175702Smarius 68175702Smariusstatic int ipxsendspace = IPXSNDQ; 69175702SmariusSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 70175702Smarius &ipxsendspace, 0, ""); 71175702Smariusstatic int ipxrecvspace = IPXRCVQ; 72175702SmariusSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 73175702Smarius &ipxrecvspace, 0, ""); 74175702Smarius 75175702Smariusstatic int ipx_usr_abort(struct socket *so); 76175702Smariusstatic int ipx_attach(struct socket *so, int proto, struct thread *td); 77175702Smariusstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 78175702Smariusstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 79175702Smarius struct thread *td); 80175702Smariusstatic int ipx_detach(struct socket *so); 81175702Smariusstatic int ipx_disconnect(struct socket *so); 82175702Smariusstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 83175702Smarius struct sockaddr *addr, struct mbuf *control, 84175702Smarius struct thread *td); 85175702Smariusstatic int ipx_shutdown(struct socket *so); 86175702Smariusstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 87175702Smariusstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 88175702Smarius 89175702Smariusstruct pr_usrreqs ipx_usrreqs = { 90175702Smarius ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind, 91175702Smarius ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 92175702Smarius ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 93175702Smarius pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 94175702Smarius ipx_sockaddr, sosend, soreceive, sopoll 95175702Smarius}; 96175702Smarius 97227908Smariusstruct pr_usrreqs ripx_usrreqs = { 98175702Smarius ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind, 99175702Smarius ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 100175702Smarius ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 101175702Smarius pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 102175702Smarius ipx_sockaddr, sosend, soreceive, sopoll 103175702Smarius}; 104175702Smarius 105175702Smarius/* 106175702Smarius * This may also be called for raw listeners. 107175702Smarius */ 108175702Smariusvoid 109175702Smariusipx_input(m, ipxp) 110175702Smarius struct mbuf *m; 111175702Smarius register struct ipxpcb *ipxp; 112175702Smarius{ 113175702Smarius register struct ipx *ipx = mtod(m, struct ipx *); 114221407Smarius struct ifnet *ifp = m->m_pkthdr.rcvif; 115221407Smarius struct sockaddr_ipx ipx_ipx; 116221407Smarius 117221407Smarius if (ipxp == NULL) 118231914Smarius panic("No ipxpcb"); 119175702Smarius /* 120175702Smarius * Construct sockaddr format source address. 121175702Smarius * Stuff source address and datagram in user buffer. 122221407Smarius */ 123221407Smarius ipx_ipx.sipx_len = sizeof(ipx_ipx); 124221407Smarius ipx_ipx.sipx_family = AF_IPX; 125221407Smarius ipx_ipx.sipx_addr = ipx->ipx_sna; 126221407Smarius ipx_ipx.sipx_zero[0] = '\0'; 127221407Smarius ipx_ipx.sipx_zero[1] = '\0'; 128175702Smarius if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 129175702Smarius register struct ifaddr *ifa; 130175702Smarius 131175702Smarius for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 132221407Smarius ifa = TAILQ_NEXT(ifa, ifa_link)) { 133175702Smarius if (ifa->ifa_addr->sa_family == AF_IPX) { 134175702Smarius ipx_ipx.sipx_addr.x_net = 135175702Smarius IA_SIPX(ifa)->sipx_addr.x_net; 136175702Smarius break; 137175702Smarius } 138175702Smarius } 139221407Smarius } 140175702Smarius ipxp->ipxp_rpt = ipx->ipx_pt; 141175702Smarius if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 142175702Smarius m->m_len -= sizeof(struct ipx); 143175702Smarius m->m_pkthdr.len -= sizeof(struct ipx); 144175702Smarius m->m_data += sizeof(struct ipx); 145175702Smarius } 146175702Smarius if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 147175702Smarius m, (struct mbuf *)NULL) == 0) 148175702Smarius goto bad; 149175702Smarius sorwakeup(ipxp->ipxp_socket); 150175702Smarius return; 151175702Smariusbad: 152175702Smarius m_freem(m); 153175702Smarius} 154175702Smarius 155175702Smariusvoid 156175702Smariusipx_abort(ipxp) 157175702Smarius struct ipxpcb *ipxp; 158175702Smarius{ 159175702Smarius struct socket *so = ipxp->ipxp_socket; 160175702Smarius 161175702Smarius ipx_pcbdisconnect(ipxp); 162175702Smarius soisdisconnected(so); 163175702Smarius} 164175702Smarius 165175702Smarius/* 166175702Smarius * Drop connection, reporting 167175702Smarius * the specified error. 168221407Smarius */ 169175702Smariusvoid 170175702Smariusipx_drop(ipxp, errno) 171175702Smarius register struct ipxpcb *ipxp; 172175702Smarius int errno; 173175702Smarius{ 174175702Smarius struct socket *so = ipxp->ipxp_socket; 175175702Smarius 176175702Smarius /* 177175702Smarius * someday, in the IPX world 178175702Smarius * we will generate error protocol packets 179175702Smarius * announcing that the socket has gone away. 180175702Smarius * 181175702Smarius * XXX Probably never. IPX does not have error packets. 182175702Smarius */ 183175702Smarius /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 184175702Smarius tp->t_state = TCPS_CLOSED; 185175702Smarius tcp_output(tp); 186175702Smarius }*/ 187175702Smarius so->so_error = errno; 188175702Smarius ipx_pcbdisconnect(ipxp); 189175702Smarius soisdisconnected(so); 190175702Smarius} 191175702Smarius 192175702Smariusstatic int 193175702Smariusipx_output(ipxp, m0) 194175702Smarius struct ipxpcb *ipxp; 195175702Smarius struct mbuf *m0; 196175702Smarius{ 197175702Smarius register struct ipx *ipx; 198175702Smarius register struct socket *so; 199175702Smarius register int len = 0; 200175702Smarius register struct route *ro; 201175702Smarius struct mbuf *m; 202175702Smarius struct mbuf *mprev = NULL; 203175702Smarius 204175702Smarius /* 205175702Smarius * Calculate data length. 206175702Smarius */ 207175702Smarius for (m = m0; m != NULL; m = m->m_next) { 208175702Smarius mprev = m; 209175702Smarius len += m->m_len; 210175702Smarius } 211175702Smarius /* 212175702Smarius * Make sure packet is actually of even length. 213175702Smarius */ 214175702Smarius 215175702Smarius if (len & 1) { 216175702Smarius m = mprev; 217175702Smarius if ((m->m_flags & M_EXT) == 0 && 218175702Smarius (m->m_len + m->m_data < &m->m_dat[MLEN])) { 219175702Smarius mtod(m, char*)[m->m_len++] = 0; 220175702Smarius } else { 221175702Smarius struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 222175702Smarius 223175702Smarius if (m1 == NULL) { 224175702Smarius m_freem(m0); 225175702Smarius return (ENOBUFS); 226175702Smarius } 227175702Smarius m1->m_len = 1; 228175702Smarius * mtod(m1, char *) = 0; 229175702Smarius m->m_next = m1; 230175702Smarius } 231175702Smarius m0->m_pkthdr.len++; 232175702Smarius } 233175702Smarius 234175702Smarius /* 235175702Smarius * Fill in mbuf with extended IPX header 236175702Smarius * and addresses and length put into network format. 237175702Smarius */ 238175702Smarius m = m0; 239175702Smarius if (ipxp->ipxp_flags & IPXP_RAWOUT) { 240175702Smarius ipx = mtod(m, struct ipx *); 241175702Smarius } else { 242175702Smarius M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 243175702Smarius if (m == NULL) 244175702Smarius return (ENOBUFS); 245175702Smarius ipx = mtod(m, struct ipx *); 246175702Smarius ipx->ipx_tc = 0; 247175702Smarius ipx->ipx_pt = ipxp->ipxp_dpt; 248175702Smarius ipx->ipx_sna = ipxp->ipxp_laddr; 249175702Smarius ipx->ipx_dna = ipxp->ipxp_faddr; 250175702Smarius len += sizeof(struct ipx); 251175702Smarius } 252175702Smarius 253175702Smarius ipx->ipx_len = htons((u_short)len); 254175702Smarius 255175702Smarius if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 256175702Smarius ipx->ipx_sum = ipx_cksum(m, len); 257175702Smarius } else 258175702Smarius ipx->ipx_sum = 0xffff; 259175702Smarius 260175702Smarius /* 261175702Smarius * Output datagram. 262175702Smarius */ 263175702Smarius so = ipxp->ipxp_socket; 264175702Smarius if (so->so_options & SO_DONTROUTE) 265175702Smarius return (ipx_outputfl(m, (struct route *)NULL, 266175702Smarius (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 267175702Smarius /* 268175702Smarius * Use cached route for previous datagram if 269 * possible. If the previous net was the same 270 * and the interface was a broadcast medium, or 271 * if the previous destination was identical, 272 * then we are ok. 273 * 274 * NB: We don't handle broadcasts because that 275 * would require 3 subroutine calls. 276 */ 277 ro = &ipxp->ipxp_route; 278#ifdef ancient_history 279 /* 280 * I think that this will all be handled in ipx_pcbconnect! 281 */ 282 if (ro->ro_rt != NULL) { 283 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 284 /* 285 * This assumes we have no GH type routes 286 */ 287 if (ro->ro_rt->rt_flags & RTF_HOST) { 288 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 289 goto re_route; 290 291 } 292 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 293 register struct ipx_addr *dst = 294 &satoipx_addr(ro->ro_dst); 295 dst->x_host = ipx->ipx_dna.x_host; 296 } 297 /* 298 * Otherwise, we go through the same gateway 299 * and dst is already set up. 300 */ 301 } else { 302 re_route: 303 RTFREE(ro->ro_rt); 304 ro->ro_rt = NULL; 305 } 306 } 307 ipxp->ipxp_lastdst = ipx->ipx_dna; 308#endif /* ancient_history */ 309 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 310} 311 312int 313ipx_ctloutput(so, sopt) 314 struct socket *so; 315 struct sockopt *sopt; 316{ 317 struct ipxpcb *ipxp = sotoipxpcb(so); 318 int mask, error, optval; 319 short soptval; 320 struct ipx ioptval; 321 322 error = 0; 323 if (ipxp == NULL) 324 return (EINVAL); 325 326 switch (sopt->sopt_dir) { 327 case SOPT_GET: 328 switch (sopt->sopt_name) { 329 case SO_ALL_PACKETS: 330 mask = IPXP_ALL_PACKETS; 331 goto get_flags; 332 333 case SO_HEADERS_ON_INPUT: 334 mask = IPXP_RAWIN; 335 goto get_flags; 336 337 case SO_IPX_CHECKSUM: 338 mask = IPXP_CHECKSUM; 339 goto get_flags; 340 341 case SO_HEADERS_ON_OUTPUT: 342 mask = IPXP_RAWOUT; 343 get_flags: 344 soptval = ipxp->ipxp_flags & mask; 345 error = sooptcopyout(sopt, &soptval, sizeof soptval); 346 break; 347 348 case SO_DEFAULT_HEADERS: 349 ioptval.ipx_len = 0; 350 ioptval.ipx_sum = 0; 351 ioptval.ipx_tc = 0; 352 ioptval.ipx_pt = ipxp->ipxp_dpt; 353 ioptval.ipx_dna = ipxp->ipxp_faddr; 354 ioptval.ipx_sna = ipxp->ipxp_laddr; 355 error = sooptcopyout(sopt, &soptval, sizeof soptval); 356 break; 357 358 case SO_SEQNO: 359 error = sooptcopyout(sopt, &ipx_pexseq, 360 sizeof ipx_pexseq); 361 ipx_pexseq++; 362 break; 363 364 default: 365 error = EINVAL; 366 } 367 break; 368 369 case SOPT_SET: 370 switch (sopt->sopt_name) { 371 case SO_ALL_PACKETS: 372 mask = IPXP_ALL_PACKETS; 373 goto set_head; 374 375 case SO_HEADERS_ON_INPUT: 376 mask = IPXP_RAWIN; 377 goto set_head; 378 379 case SO_IPX_CHECKSUM: 380 mask = IPXP_CHECKSUM; 381 382 case SO_HEADERS_ON_OUTPUT: 383 mask = IPXP_RAWOUT; 384 set_head: 385 error = sooptcopyin(sopt, &optval, sizeof optval, 386 sizeof optval); 387 if (error) 388 break; 389 if (optval) 390 ipxp->ipxp_flags |= mask; 391 else 392 ipxp->ipxp_flags &= ~mask; 393 break; 394 395 case SO_DEFAULT_HEADERS: 396 error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 397 sizeof ioptval); 398 if (error) 399 break; 400 ipxp->ipxp_dpt = ioptval.ipx_pt; 401 break; 402#ifdef IPXIP 403 case SO_IPXIP_ROUTE: 404 error = ipxip_route(so, sopt); 405 break; 406#endif /* IPXIP */ 407#ifdef IPTUNNEL 408#if 0 409 case SO_IPXTUNNEL_ROUTE: 410 error = ipxtun_route(so, sopt); 411 break; 412#endif 413#endif 414 default: 415 error = EINVAL; 416 } 417 break; 418 } 419 return (error); 420} 421 422static int 423ipx_usr_abort(so) 424 struct socket *so; 425{ 426 int s; 427 struct ipxpcb *ipxp = sotoipxpcb(so); 428 429 s = splnet(); 430 ipx_pcbdetach(ipxp); 431 splx(s); 432 sotryfree(so); 433 soisdisconnected(so); 434 return (0); 435} 436 437static int 438ipx_attach(so, proto, td) 439 struct socket *so; 440 int proto; 441 struct thread *td; 442{ 443 int error; 444 int s; 445 struct ipxpcb *ipxp = sotoipxpcb(so); 446 447 if (ipxp != NULL) 448 return (EINVAL); 449 s = splnet(); 450 error = ipx_pcballoc(so, &ipxpcb, td); 451 splx(s); 452 if (error == 0) 453 error = soreserve(so, ipxsendspace, ipxrecvspace); 454 return (error); 455} 456 457static int 458ipx_bind(so, nam, td) 459 struct socket *so; 460 struct sockaddr *nam; 461 struct thread *td; 462{ 463 struct ipxpcb *ipxp = sotoipxpcb(so); 464 465 return (ipx_pcbbind(ipxp, nam, td)); 466} 467 468static int 469ipx_connect(so, nam, td) 470 struct socket *so; 471 struct sockaddr *nam; 472 struct thread *td; 473{ 474 int error; 475 int s; 476 struct ipxpcb *ipxp = sotoipxpcb(so); 477 478 if (!ipx_nullhost(ipxp->ipxp_faddr)) 479 return (EISCONN); 480 s = splnet(); 481 error = ipx_pcbconnect(ipxp, nam, td); 482 splx(s); 483 if (error == 0) 484 soisconnected(so); 485 return (error); 486} 487 488static int 489ipx_detach(so) 490 struct socket *so; 491{ 492 int s; 493 struct ipxpcb *ipxp = sotoipxpcb(so); 494 495 if (ipxp == NULL) 496 return (ENOTCONN); 497 s = splnet(); 498 ipx_pcbdetach(ipxp); 499 splx(s); 500 return (0); 501} 502 503static int 504ipx_disconnect(so) 505 struct socket *so; 506{ 507 int s; 508 struct ipxpcb *ipxp = sotoipxpcb(so); 509 510 if (ipx_nullhost(ipxp->ipxp_faddr)) 511 return (ENOTCONN); 512 s = splnet(); 513 ipx_pcbdisconnect(ipxp); 514 splx(s); 515 soisdisconnected(so); 516 return (0); 517} 518 519int 520ipx_peeraddr(so, nam) 521 struct socket *so; 522 struct sockaddr **nam; 523{ 524 struct ipxpcb *ipxp = sotoipxpcb(so); 525 526 ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 527 return (0); 528} 529 530static int 531ipx_send(so, flags, m, nam, control, td) 532 struct socket *so; 533 int flags; 534 struct mbuf *m; 535 struct sockaddr *nam; 536 struct mbuf *control; 537 struct thread *td; 538{ 539 int error; 540 struct ipxpcb *ipxp = sotoipxpcb(so); 541 struct ipx_addr laddr; 542 int s = 0; 543 544 if (nam != NULL) { 545 laddr = ipxp->ipxp_laddr; 546 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 547 error = EISCONN; 548 goto send_release; 549 } 550 /* 551 * Must block input while temporarily connected. 552 */ 553 s = splnet(); 554 error = ipx_pcbconnect(ipxp, nam, td); 555 if (error) { 556 splx(s); 557 goto send_release; 558 } 559 } else { 560 if (ipx_nullhost(ipxp->ipxp_faddr)) { 561 error = ENOTCONN; 562 goto send_release; 563 } 564 } 565 error = ipx_output(ipxp, m); 566 m = NULL; 567 if (nam != NULL) { 568 ipx_pcbdisconnect(ipxp); 569 splx(s); 570 ipxp->ipxp_laddr = laddr; 571 } 572 573send_release: 574 if (m != NULL) 575 m_freem(m); 576 return (error); 577} 578 579static int 580ipx_shutdown(so) 581 struct socket *so; 582{ 583 socantsendmore(so); 584 return (0); 585} 586 587int 588ipx_sockaddr(so, nam) 589 struct socket *so; 590 struct sockaddr **nam; 591{ 592 struct ipxpcb *ipxp = sotoipxpcb(so); 593 594 ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 595 return (0); 596} 597 598static int 599ripx_attach(so, proto, td) 600 struct socket *so; 601 int proto; 602 struct thread *td; 603{ 604 int error = 0; 605 int s; 606 struct ipxpcb *ipxp = sotoipxpcb(so); 607 608 if (td != NULL && (error = suser(td)) != 0) 609 return (error); 610 s = splnet(); 611 error = ipx_pcballoc(so, &ipxrawpcb, td); 612 splx(s); 613 if (error) 614 return (error); 615 error = soreserve(so, ipxsendspace, ipxrecvspace); 616 if (error) 617 return (error); 618 ipxp = sotoipxpcb(so); 619 ipxp->ipxp_faddr.x_host = ipx_broadhost; 620 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 621 return (error); 622} 623