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