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