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