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