ipx_usrreq.c revision 26965
1114402Sru/* 2114402Sru * Copyright (c) 1995, Mike Mitchell 3114402Sru * Copyright (c) 1984, 1985, 1986, 1987, 1993 4114402Sru * The Regents of the University of California. All rights reserved. 5114402Sru * 6114402Sru * Redistribution and use in source and binary forms, with or without 7114402Sru * modification, are permitted provided that the following conditions 8114402Sru * are met: 9114402Sru * 1. Redistributions of source code must retain the above copyright 10114402Sru * notice, this list of conditions and the following disclaimer. 11114402Sru * 2. Redistributions in binary form must reproduce the above copyright 12114402Sru * notice, this list of conditions and the following disclaimer in the 13114402Sru * documentation and/or other materials provided with the distribution. 14114402Sru * 3. All advertising materials mentioning features or use of this software 15114402Sru * must display the following acknowledgement: 16114402Sru * This product includes software developed by the University of 17114402Sru * California, Berkeley and its contributors. 18114402Sru * 4. Neither the name of the University nor the names of its contributors 19151503Sru * may be used to endorse or promote products derived from this software 20114402Sru * without specific prior written permission. 21114411Sru * 22114411Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23114402Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24114411Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25114411Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26114411Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27114402Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28114402Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29114402Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30114402Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31114402Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32114411Sru * SUCH DAMAGE. 33114402Sru * 34114402Sru * @(#)ipx_usrreq.c 35114402Sru * 36114402Sru * $Id: ipx_usrreq.c,v 1.14 1997/05/10 09:58:55 jhay Exp $ 37114402Sru */ 38114402Sru 39114402Sru#include <sys/param.h> 40114402Sru#include <sys/systm.h> 41114402Sru#include <sys/kernel.h> 42114402Sru#include <sys/mbuf.h> 43114402Sru#include <sys/proc.h> 44114402Sru#include <sys/protosw.h> 45114402Sru#include <sys/socket.h> 46114402Sru#include <sys/socketvar.h> 47114402Sru#include <sys/sysctl.h> 48114402Sru 49114402Sru#include <net/if.h> 50114402Sru#include <net/route.h> 51114402Sru 52114402Sru#include <netinet/in.h> 53114402Sru 54114402Sru#include <netipx/ipx.h> 55114402Sru#include <netipx/ipx_pcb.h> 56114402Sru#include <netipx/ipx_if.h> 57114411Sru#include <netipx/ipx_var.h> 58114411Sru#include <netipx/ipx_ip.h> 59114411Sru 60114402Sru/* 61114402Sru * IPX protocol implementation. 62114402Sru */ 63114402Sru 64114402Sruint ipxsendspace = IPXSNDQ; 65SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 66 &ipxsendspace, 0, ""); 67int ipxrecvspace = IPXRCVQ; 68SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 69 &ipxrecvspace, 0, ""); 70 71static int ipx_usr_abort(struct socket *so); 72static int ipx_attach(struct socket *so, int proto, struct proc *p); 73static int ipx_bind(struct socket *so, struct mbuf *nam, struct proc *p); 74static int ipx_connect(struct socket *so, struct mbuf *nam, struct proc *p); 75static int ipx_detach(struct socket *so); 76static int ipx_disconnect(struct socket *so); 77static int ipx_send(struct socket *so, int flags, struct mbuf *m, 78 struct mbuf *addr, struct mbuf *control, struct proc *p); 79static int ipx_shutdown(struct socket *so); 80static int ripx_attach(struct socket *so, int proto, struct proc *p); 81static int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 82 83struct pr_usrreqs ipx_usrreqs = { 84 ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind, 85 ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 86 ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 87 pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 88 ipx_sockaddr, sosend, soreceive, soselect 89}; 90 91struct pr_usrreqs ripx_usrreqs = { 92 ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind, 93 ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 94 ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 95 pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 96 ipx_sockaddr, sosend, soreceive, soselect 97}; 98 99/* 100 * This may also be called for raw listeners. 101 */ 102void 103ipx_input(m, ipxp) 104 struct mbuf *m; 105 register struct ipxpcb *ipxp; 106{ 107 register struct ipx *ipx = mtod(m, struct ipx *); 108 struct ifnet *ifp = m->m_pkthdr.rcvif; 109 struct sockaddr_ipx ipx_ipx; 110 111 if (ipxp == NULL) 112 panic("No ipxpcb"); 113 /* 114 * Construct sockaddr format source address. 115 * Stuff source address and datagram in user buffer. 116 */ 117 ipx_ipx.sipx_len = sizeof(ipx_ipx); 118 ipx_ipx.sipx_family = AF_IPX; 119 ipx_ipx.sipx_addr = ipx->ipx_sna; 120 ipx_ipx.sipx_zero[0] = '\0'; 121 ipx_ipx.sipx_zero[1] = '\0'; 122 if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 123 register struct ifaddr *ifa; 124 125 for (ifa = ifp->if_addrhead.tqh_first; ifa != NULL; 126 ifa = ifa->ifa_link.tqe_next) { 127 if (ifa->ifa_addr->sa_family == AF_IPX) { 128 ipx_ipx.sipx_addr.x_net = 129 IA_SIPX(ifa)->sipx_addr.x_net; 130 break; 131 } 132 } 133 } 134 ipxp->ipxp_rpt = ipx->ipx_pt; 135 if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 136 m->m_len -= sizeof(struct ipx); 137 m->m_pkthdr.len -= sizeof(struct ipx); 138 m->m_data += sizeof(struct ipx); 139 } 140 if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 141 m, (struct mbuf *)NULL) == 0) 142 goto bad; 143 sorwakeup(ipxp->ipxp_socket); 144 return; 145bad: 146 m_freem(m); 147} 148 149void 150ipx_abort(ipxp) 151 struct ipxpcb *ipxp; 152{ 153 struct socket *so = ipxp->ipxp_socket; 154 155 ipx_pcbdisconnect(ipxp); 156 soisdisconnected(so); 157} 158 159/* 160 * Drop connection, reporting 161 * the specified error. 162 */ 163void 164ipx_drop(ipxp, errno) 165 register struct ipxpcb *ipxp; 166 int errno; 167{ 168 struct socket *so = ipxp->ipxp_socket; 169 170 /* 171 * someday, in the IPX world 172 * we will generate error protocol packets 173 * announcing that the socket has gone away. 174 * 175 * XXX Probably never. IPX does not have error packets. 176 */ 177 /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 178 tp->t_state = TCPS_CLOSED; 179 tcp_output(tp); 180 }*/ 181 so->so_error = errno; 182 ipx_pcbdisconnect(ipxp); 183 soisdisconnected(so); 184} 185 186static int 187ipx_output(ipxp, m0) 188 struct ipxpcb *ipxp; 189 struct mbuf *m0; 190{ 191 register struct mbuf *m; 192 register struct ipx *ipx; 193 register struct socket *so; 194 register int len = 0; 195 register struct route *ro; 196 struct mbuf *mprev = NULL; 197 198 /* 199 * Calculate data length. 200 */ 201 for (m = m0; m != NULL; m = m->m_next) { 202 mprev = m; 203 len += m->m_len; 204 } 205 /* 206 * Make sure packet is actually of even length. 207 */ 208 209 if (len & 1) { 210 m = mprev; 211 if ((m->m_flags & M_EXT) == 0 && 212 (m->m_len + m->m_data < &m->m_dat[MLEN])) { 213 m->m_len++; 214 } else { 215 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 216 217 if (m1 == NULL) { 218 m_freem(m0); 219 return (ENOBUFS); 220 } 221 m1->m_len = 1; 222 * mtod(m1, char *) = 0; 223 m->m_next = m1; 224 } 225 m0->m_pkthdr.len++; 226 } 227 228 /* 229 * Fill in mbuf with extended IPX header 230 * and addresses and length put into network format. 231 */ 232 m = m0; 233 if (ipxp->ipxp_flags & IPXP_RAWOUT) { 234 ipx = mtod(m, struct ipx *); 235 } else { 236 M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 237 if (m == NULL) 238 return (ENOBUFS); 239 ipx = mtod(m, struct ipx *); 240 ipx->ipx_tc = 0; 241 ipx->ipx_pt = ipxp->ipxp_dpt; 242 ipx->ipx_sna = ipxp->ipxp_laddr; 243 ipx->ipx_dna = ipxp->ipxp_faddr; 244 len += sizeof(struct ipx); 245 } 246 247 ipx->ipx_len = htons((u_short)len); 248 249 if (ipxcksum) { 250 ipx->ipx_sum = 0; 251 len = ((len - 1) | 1) + 1; 252 ipx->ipx_sum = ipx_cksum(m, len); 253 } else 254 ipx->ipx_sum = 0xffff; 255 256 /* 257 * Output datagram. 258 */ 259 so = ipxp->ipxp_socket; 260 if (so->so_options & SO_DONTROUTE) 261 return (ipx_outputfl(m, (struct route *)NULL, 262 (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 263 /* 264 * Use cached route for previous datagram if 265 * possible. If the previous net was the same 266 * and the interface was a broadcast medium, or 267 * if the previous destination was identical, 268 * then we are ok. 269 * 270 * NB: We don't handle broadcasts because that 271 * would require 3 subroutine calls. 272 */ 273 ro = &ipxp->ipxp_route; 274#ifdef ancient_history 275 /* 276 * I think that this will all be handled in ipx_pcbconnect! 277 */ 278 if (ro->ro_rt != NULL) { 279 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 280 /* 281 * This assumes we have no GH type routes 282 */ 283 if (ro->ro_rt->rt_flags & RTF_HOST) { 284 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 285 goto re_route; 286 287 } 288 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 289 register struct ipx_addr *dst = 290 &satoipx_addr(ro->ro_dst); 291 dst->x_host = ipx->ipx_dna.x_host; 292 } 293 /* 294 * Otherwise, we go through the same gateway 295 * and dst is already set up. 296 */ 297 } else { 298 re_route: 299 RTFREE(ro->ro_rt); 300 ro->ro_rt = NULL; 301 } 302 } 303 ipxp->ipxp_lastdst = ipx->ipx_dna; 304#endif /* ancient_history */ 305 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 306} 307 308int 309ipx_ctloutput(req, so, level, name, value, p) 310 int req, level; 311 struct socket *so; 312 int name; 313 struct mbuf **value; 314 struct proc *p; 315{ 316 register struct mbuf *m; 317 struct ipxpcb *ipxp = sotoipxpcb(so); 318 int mask, error = 0; 319 320 if (ipxp == NULL) 321 return (EINVAL); 322 323 switch (req) { 324 325 case PRCO_GETOPT: 326 if (value == NULL) 327 return (EINVAL); 328 m = m_get(M_DONTWAIT, MT_DATA); 329 if (m == NULL) 330 return (ENOBUFS); 331 switch (name) { 332 333 case SO_ALL_PACKETS: 334 mask = IPXP_ALL_PACKETS; 335 goto get_flags; 336 337 case SO_HEADERS_ON_INPUT: 338 mask = IPXP_RAWIN; 339 goto get_flags; 340 341 case SO_HEADERS_ON_OUTPUT: 342 mask = IPXP_RAWOUT; 343 get_flags: 344 m->m_len = sizeof(short); 345 *mtod(m, short *) = ipxp->ipxp_flags & mask; 346 break; 347 348 case SO_DEFAULT_HEADERS: 349 m->m_len = sizeof(struct ipx); 350 { 351 register struct ipx *ipx = mtod(m, struct ipx *); 352 ipx->ipx_len = 0; 353 ipx->ipx_sum = 0; 354 ipx->ipx_tc = 0; 355 ipx->ipx_pt = ipxp->ipxp_dpt; 356 ipx->ipx_dna = ipxp->ipxp_faddr; 357 ipx->ipx_sna = ipxp->ipxp_laddr; 358 } 359 break; 360 361 case SO_SEQNO: 362 m->m_len = sizeof(long); 363 *mtod(m, long *) = ipx_pexseq++; 364 break; 365 366 default: 367 error = EINVAL; 368 } 369 *value = m; 370 break; 371 372 case PRCO_SETOPT: 373 switch (name) { 374 int *ok; 375 376 case SO_ALL_PACKETS: 377 mask = IPXP_ALL_PACKETS; 378 goto set_head; 379 380 case SO_HEADERS_ON_INPUT: 381 mask = IPXP_RAWIN; 382 goto set_head; 383 384 case SO_HEADERS_ON_OUTPUT: 385 mask = IPXP_RAWOUT; 386 set_head: 387 if (value && *value) { 388 ok = mtod(*value, int *); 389 if (*ok) 390 ipxp->ipxp_flags |= mask; 391 else 392 ipxp->ipxp_flags &= ~mask; 393 } else error = EINVAL; 394 break; 395 396 case SO_DEFAULT_HEADERS: 397 { 398 register struct ipx *ipx 399 = mtod(*value, struct ipx *); 400 ipxp->ipxp_dpt = ipx->ipx_pt; 401 } 402 break; 403#ifdef IPXIP 404 case SO_IPXIP_ROUTE: 405 error = ipxip_route(so, *value, p); 406 break; 407#endif /* IPXIP */ 408#ifdef IPXTUNNEL 409 case SO_IPXTUNNEL_ROUTE 410 error = ipxtun_route(so, *value, p); 411 break; 412#endif 413 default: 414 error = EINVAL; 415 } 416 if (value && *value) 417 m_freem(*value); 418 break; 419 } 420 return (error); 421} 422 423static int 424ipx_usr_abort(so) 425 struct socket *so; 426{ 427 int s; 428 struct ipxpcb *ipxp = sotoipxpcb(so); 429 430 s = splnet(); 431 ipx_pcbdetach(ipxp); 432 splx(s); 433 sofree(so); 434 soisdisconnected(so); 435 return (0); 436} 437 438static int 439ipx_attach(so, proto, p) 440 struct socket *so; 441 int proto; 442 struct proc *p; 443{ 444 int error; 445 int s; 446 struct ipxpcb *ipxp = sotoipxpcb(so); 447 448 if (ipxp != NULL) 449 return (EINVAL); 450 s = splnet(); 451 error = ipx_pcballoc(so, &ipxpcb, p); 452 splx(s); 453 if (error == 0) 454 error = soreserve(so, ipxsendspace, ipxrecvspace); 455 return (error); 456} 457 458static int 459ipx_bind(so, nam, p) 460 struct socket *so; 461 struct mbuf *nam; 462 struct proc *p; 463{ 464 struct ipxpcb *ipxp = sotoipxpcb(so); 465 466 return (ipx_pcbbind(ipxp, nam, p)); 467} 468 469static int 470ipx_connect(so, nam, p) 471 struct socket *so; 472 struct mbuf *nam; 473 struct proc *p; 474{ 475 int error; 476 int s; 477 struct ipxpcb *ipxp = sotoipxpcb(so); 478 479 if (!ipx_nullhost(ipxp->ipxp_faddr)) 480 return (EISCONN); 481 s = splnet(); 482 error = ipx_pcbconnect(ipxp, nam, p); 483 splx(s); 484 if (error == 0) 485 soisconnected(so); 486 return (error); 487} 488 489static int 490ipx_detach(so) 491 struct socket *so; 492{ 493 int s; 494 struct ipxpcb *ipxp = sotoipxpcb(so); 495 496 if (ipxp == NULL) 497 return (ENOTCONN); 498 s = splnet(); 499 ipx_pcbdetach(ipxp); 500 splx(s); 501 return (0); 502} 503 504static int 505ipx_disconnect(so) 506 struct socket *so; 507{ 508 int s; 509 struct ipxpcb *ipxp = sotoipxpcb(so); 510 511 if (ipx_nullhost(ipxp->ipxp_faddr)) 512 return (ENOTCONN); 513 s = splnet(); 514 ipx_pcbdisconnect(ipxp); 515 splx(s); 516 soisdisconnected(so); 517 return (0); 518} 519 520int 521ipx_peeraddr(so, nam) 522 struct socket *so; 523 struct mbuf *nam; 524{ 525 struct ipxpcb *ipxp = sotoipxpcb(so); 526 527 ipx_setpeeraddr(ipxp, nam); 528 return (0); 529} 530 531static int 532ipx_send(so, flags, m, nam, control, p) 533 struct socket *so; 534 int flags; 535 struct mbuf *m; 536 struct mbuf *nam; 537 struct mbuf *control; 538 struct proc *p; 539{ 540 int error; 541 struct ipxpcb *ipxp = sotoipxpcb(so); 542 struct ipx_addr laddr; 543 int s = 0; 544 545 if (nam != NULL) { 546 laddr = ipxp->ipxp_laddr; 547 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 548 error = EISCONN; 549 goto send_release; 550 } 551 /* 552 * Must block input while temporarily connected. 553 */ 554 s = splnet(); 555 error = ipx_pcbconnect(ipxp, nam, p); 556 if (error) { 557 splx(s); 558 goto send_release; 559 } 560 } else { 561 if (ipx_nullhost(ipxp->ipxp_faddr)) { 562 error = ENOTCONN; 563 goto send_release; 564 } 565 } 566 error = ipx_output(ipxp, m); 567 m = NULL; 568 if (nam != NULL) { 569 ipx_pcbdisconnect(ipxp); 570 splx(s); 571 ipxp->ipxp_laddr.x_host = laddr.x_host; 572 ipxp->ipxp_laddr.x_port = laddr.x_port; 573 } 574 575send_release: 576 if (m != NULL) 577 m_freem(m); 578 return (error); 579} 580 581static int 582ipx_shutdown(so) 583 struct socket *so; 584{ 585 socantsendmore(so); 586 return (0); 587} 588 589int 590ipx_sockaddr(so, nam) 591 struct socket *so; 592 struct mbuf *nam; 593{ 594 struct ipxpcb *ipxp = sotoipxpcb(so); 595 596 ipx_setsockaddr(ipxp, nam); 597 return (0); 598} 599 600static int 601ripx_attach(so, proto, p) 602 struct socket *so; 603 int proto; 604 struct proc *p; 605{ 606 int error = 0; 607 int s; 608 struct ipxpcb *ipxp = sotoipxpcb(so); 609 610 if (p != NULL && (error = suser(p->p_ucred, &p->p_acflag)) != 0) 611 return (error); 612 s = splnet(); 613 error = ipx_pcballoc(so, &ipxrawpcb, p); 614 splx(s); 615 if (error) 616 return (error); 617 error = soreserve(so, ipxsendspace, ipxrecvspace); 618 if (error) 619 return (error); 620 ipxp = sotoipxpcb(so); 621 ipxp->ipxp_faddr.x_host = ipx_broadhost; 622 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 623 return (error); 624} 625