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