ipx_usrreq.c revision 71999
190926Snectar/* 290926Snectar * Copyright (c) 1995, Mike Mitchell 390926Snectar * Copyright (c) 1984, 1985, 1986, 1987, 1993 490926Snectar * The Regents of the University of California. All rights reserved. 590926Snectar * 690926Snectar * Redistribution and use in source and binary forms, with or without 790926Snectar * modification, are permitted provided that the following conditions 890926Snectar * are met: 990926Snectar * 1. Redistributions of source code must retain the above copyright 1090926Snectar * notice, this list of conditions and the following disclaimer. 1190926Snectar * 2. Redistributions in binary form must reproduce the above copyright 1290926Snectar * notice, this list of conditions and the following disclaimer in the 1390926Snectar * documentation and/or other materials provided with the distribution. 1490926Snectar * 3. All advertising materials mentioning features or use of this software 1590926Snectar * must display the following acknowledgement: 1690926Snectar * This product includes software developed by the University of 1755682Smarkm * California, Berkeley and its contributors. 1855682Smarkm * 4. Neither the name of the University nor the names of its contributors 1955682Smarkm * may be used to endorse or promote products derived from this software 2055682Smarkm * without specific prior written permission. 21233294Sstas * 2255682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2355682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2455682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2555682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2655682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2755682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2855682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2955682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3055682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3155682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3255682Smarkm * SUCH DAMAGE. 3355682Smarkm * 3455682Smarkm * @(#)ipx_usrreq.c 3555682Smarkm * 3655682Smarkm * $FreeBSD: head/sys/netipx/ipx_usrreq.c 71999 2001-02-04 13:13:25Z phk $ 3755682Smarkm */ 3855682Smarkm 3955682Smarkm#include "opt_ipx.h" 4078527Sassar 4155682Smarkm#include <sys/param.h> 4255682Smarkm#include <sys/systm.h> 4355682Smarkm#include <sys/kernel.h> 4455682Smarkm#include <sys/mbuf.h> 4555682Smarkm#include <sys/protosw.h> 4655682Smarkm#include <sys/socket.h> 4755682Smarkm#include <sys/socketvar.h> 4855682Smarkm#include <sys/sysctl.h> 4955682Smarkm 5055682Smarkm#include <net/if.h> 5155682Smarkm#include <net/route.h> 5255682Smarkm 5355682Smarkm#include <netinet/in.h> 54233294Sstas 5555682Smarkm#include <netipx/ipx.h> 5655682Smarkm#include <netipx/ipx_pcb.h> 5755682Smarkm#include <netipx/ipx_if.h> 5855682Smarkm#include <netipx/ipx_var.h> 5955682Smarkm#include <netipx/ipx_ip.h> 6055682Smarkm 6155682Smarkm/* 6255682Smarkm * IPX protocol implementation. 6355682Smarkm */ 6455682Smarkm 6555682Smarkmstatic int ipxsendspace = IPXSNDQ; 6655682SmarkmSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 6755682Smarkm &ipxsendspace, 0, ""); 6855682Smarkmstatic int ipxrecvspace = IPXRCVQ; 6955682SmarkmSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 7055682Smarkm &ipxrecvspace, 0, ""); 7155682Smarkm 7255682Smarkmstatic int ipx_usr_abort(struct socket *so); 7355682Smarkmstatic int ipx_attach(struct socket *so, int proto, struct proc *p); 7455682Smarkmstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct proc *p); 7555682Smarkmstatic int ipx_connect(struct socket *so, struct sockaddr *nam, 7655682Smarkm struct proc *p); 7755682Smarkmstatic int ipx_detach(struct socket *so); 7855682Smarkmstatic int ipx_disconnect(struct socket *so); 7955682Smarkmstatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 8055682Smarkm struct sockaddr *addr, struct mbuf *control, 8155682Smarkm struct proc *p); 8255682Smarkmstatic int ipx_shutdown(struct socket *so); 8355682Smarkmstatic int ripx_attach(struct socket *so, int proto, struct proc *p); 8455682Smarkmstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 8555682Smarkm 8655682Smarkmstruct pr_usrreqs ipx_usrreqs = { 8755682Smarkm ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind, 8855682Smarkm ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 8955682Smarkm ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 9055682Smarkm pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 9155682Smarkm ipx_sockaddr, sosend, soreceive, sopoll 9255682Smarkm}; 9355682Smarkm 9455682Smarkmstruct pr_usrreqs ripx_usrreqs = { 9555682Smarkm ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind, 9655682Smarkm ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach, 9755682Smarkm ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp, 9855682Smarkm pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown, 9955682Smarkm ipx_sockaddr, sosend, soreceive, sopoll 10055682Smarkm}; 10155682Smarkm 10255682Smarkm/* 10355682Smarkm * This may also be called for raw listeners. 10455682Smarkm */ 10555682Smarkmvoid 106ipx_input(m, ipxp) 107 struct mbuf *m; 108 register struct ipxpcb *ipxp; 109{ 110 register struct ipx *ipx = mtod(m, struct ipx *); 111 struct ifnet *ifp = m->m_pkthdr.rcvif; 112 struct sockaddr_ipx ipx_ipx; 113 114 if (ipxp == NULL) 115 panic("No ipxpcb"); 116 /* 117 * Construct sockaddr format source address. 118 * Stuff source address and datagram in user buffer. 119 */ 120 ipx_ipx.sipx_len = sizeof(ipx_ipx); 121 ipx_ipx.sipx_family = AF_IPX; 122 ipx_ipx.sipx_addr = ipx->ipx_sna; 123 ipx_ipx.sipx_zero[0] = '\0'; 124 ipx_ipx.sipx_zero[1] = '\0'; 125 if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 126 register struct ifaddr *ifa; 127 128 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 129 ifa = TAILQ_NEXT(ifa, ifa_link)) { 130 if (ifa->ifa_addr->sa_family == AF_IPX) { 131 ipx_ipx.sipx_addr.x_net = 132 IA_SIPX(ifa)->sipx_addr.x_net; 133 break; 134 } 135 } 136 } 137 ipxp->ipxp_rpt = ipx->ipx_pt; 138 if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 139 m->m_len -= sizeof(struct ipx); 140 m->m_pkthdr.len -= sizeof(struct ipx); 141 m->m_data += sizeof(struct ipx); 142 } 143 if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 144 m, (struct mbuf *)NULL) == 0) 145 goto bad; 146 sorwakeup(ipxp->ipxp_socket); 147 return; 148bad: 149 m_freem(m); 150} 151 152void 153ipx_abort(ipxp) 154 struct ipxpcb *ipxp; 155{ 156 struct socket *so = ipxp->ipxp_socket; 157 158 ipx_pcbdisconnect(ipxp); 159 soisdisconnected(so); 160} 161 162/* 163 * Drop connection, reporting 164 * the specified error. 165 */ 166void 167ipx_drop(ipxp, errno) 168 register struct ipxpcb *ipxp; 169 int errno; 170{ 171 struct socket *so = ipxp->ipxp_socket; 172 173 /* 174 * someday, in the IPX world 175 * we will generate error protocol packets 176 * announcing that the socket has gone away. 177 * 178 * XXX Probably never. IPX does not have error packets. 179 */ 180 /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 181 tp->t_state = TCPS_CLOSED; 182 tcp_output(tp); 183 }*/ 184 so->so_error = errno; 185 ipx_pcbdisconnect(ipxp); 186 soisdisconnected(so); 187} 188 189static int 190ipx_output(ipxp, m0) 191 struct ipxpcb *ipxp; 192 struct mbuf *m0; 193{ 194 register struct ipx *ipx; 195 register struct socket *so; 196 register int len = 0; 197 register struct route *ro; 198 struct mbuf *m; 199 struct mbuf *mprev = NULL; 200 201 /* 202 * Calculate data length. 203 */ 204 for (m = m0; m != NULL; m = m->m_next) { 205 mprev = m; 206 len += m->m_len; 207 } 208 /* 209 * Make sure packet is actually of even length. 210 */ 211 212 if (len & 1) { 213 m = mprev; 214 if ((m->m_flags & M_EXT) == 0 && 215 (m->m_len + m->m_data < &m->m_dat[MLEN])) { 216 mtod(m, char*)[m->m_len++] = 0; 217 } else { 218 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 219 220 if (m1 == NULL) { 221 m_freem(m0); 222 return (ENOBUFS); 223 } 224 m1->m_len = 1; 225 * mtod(m1, char *) = 0; 226 m->m_next = m1; 227 } 228 m0->m_pkthdr.len++; 229 } 230 231 /* 232 * Fill in mbuf with extended IPX header 233 * and addresses and length put into network format. 234 */ 235 m = m0; 236 if (ipxp->ipxp_flags & IPXP_RAWOUT) { 237 ipx = mtod(m, struct ipx *); 238 } else { 239 M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 240 if (m == NULL) 241 return (ENOBUFS); 242 ipx = mtod(m, struct ipx *); 243 ipx->ipx_tc = 0; 244 ipx->ipx_pt = ipxp->ipxp_dpt; 245 ipx->ipx_sna = ipxp->ipxp_laddr; 246 ipx->ipx_dna = ipxp->ipxp_faddr; 247 len += sizeof(struct ipx); 248 } 249 250 ipx->ipx_len = htons((u_short)len); 251 252 if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 253 ipx->ipx_sum = ipx_cksum(m, len); 254 } else 255 ipx->ipx_sum = 0xffff; 256 257 /* 258 * Output datagram. 259 */ 260 so = ipxp->ipxp_socket; 261 if (so->so_options & SO_DONTROUTE) 262 return (ipx_outputfl(m, (struct route *)NULL, 263 (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 264 /* 265 * Use cached route for previous datagram if 266 * possible. If the previous net was the same 267 * and the interface was a broadcast medium, or 268 * if the previous destination was identical, 269 * then we are ok. 270 * 271 * NB: We don't handle broadcasts because that 272 * would require 3 subroutine calls. 273 */ 274 ro = &ipxp->ipxp_route; 275#ifdef ancient_history 276 /* 277 * I think that this will all be handled in ipx_pcbconnect! 278 */ 279 if (ro->ro_rt != NULL) { 280 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 281 /* 282 * This assumes we have no GH type routes 283 */ 284 if (ro->ro_rt->rt_flags & RTF_HOST) { 285 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 286 goto re_route; 287 288 } 289 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 290 register struct ipx_addr *dst = 291 &satoipx_addr(ro->ro_dst); 292 dst->x_host = ipx->ipx_dna.x_host; 293 } 294 /* 295 * Otherwise, we go through the same gateway 296 * and dst is already set up. 297 */ 298 } else { 299 re_route: 300 RTFREE(ro->ro_rt); 301 ro->ro_rt = NULL; 302 } 303 } 304 ipxp->ipxp_lastdst = ipx->ipx_dna; 305#endif /* ancient_history */ 306 return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 307} 308 309int 310ipx_ctloutput(so, sopt) 311 struct socket *so; 312 struct sockopt *sopt; 313{ 314 struct ipxpcb *ipxp = sotoipxpcb(so); 315 int mask, error, optval; 316 short soptval; 317 struct ipx ioptval; 318 319 error = 0; 320 if (ipxp == NULL) 321 return (EINVAL); 322 323 switch (sopt->sopt_dir) { 324 case SOPT_GET: 325 switch (sopt->sopt_name) { 326 case SO_ALL_PACKETS: 327 mask = IPXP_ALL_PACKETS; 328 goto get_flags; 329 330 case SO_HEADERS_ON_INPUT: 331 mask = IPXP_RAWIN; 332 goto get_flags; 333 334 case SO_IPX_CHECKSUM: 335 mask = IPXP_CHECKSUM; 336 goto get_flags; 337 338 case SO_HEADERS_ON_OUTPUT: 339 mask = IPXP_RAWOUT; 340 get_flags: 341 soptval = ipxp->ipxp_flags & mask; 342 error = sooptcopyout(sopt, &soptval, sizeof soptval); 343 break; 344 345 case SO_DEFAULT_HEADERS: 346 ioptval.ipx_len = 0; 347 ioptval.ipx_sum = 0; 348 ioptval.ipx_tc = 0; 349 ioptval.ipx_pt = ipxp->ipxp_dpt; 350 ioptval.ipx_dna = ipxp->ipxp_faddr; 351 ioptval.ipx_sna = ipxp->ipxp_laddr; 352 error = sooptcopyout(sopt, &soptval, sizeof soptval); 353 break; 354 355 case SO_SEQNO: 356 error = sooptcopyout(sopt, &ipx_pexseq, 357 sizeof ipx_pexseq); 358 ipx_pexseq++; 359 break; 360 361 default: 362 error = EINVAL; 363 } 364 break; 365 366 case SOPT_SET: 367 switch (sopt->sopt_name) { 368 case SO_ALL_PACKETS: 369 mask = IPXP_ALL_PACKETS; 370 goto set_head; 371 372 case SO_HEADERS_ON_INPUT: 373 mask = IPXP_RAWIN; 374 goto set_head; 375 376 case SO_IPX_CHECKSUM: 377 mask = IPXP_CHECKSUM; 378 379 case SO_HEADERS_ON_OUTPUT: 380 mask = IPXP_RAWOUT; 381 set_head: 382 error = sooptcopyin(sopt, &optval, sizeof optval, 383 sizeof optval); 384 if (error) 385 break; 386 if (optval) 387 ipxp->ipxp_flags |= mask; 388 else 389 ipxp->ipxp_flags &= ~mask; 390 break; 391 392 case SO_DEFAULT_HEADERS: 393 error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 394 sizeof ioptval); 395 if (error) 396 break; 397 ipxp->ipxp_dpt = ioptval.ipx_pt; 398 break; 399#ifdef IPXIP 400 case SO_IPXIP_ROUTE: 401 error = ipxip_route(so, sopt); 402 break; 403#endif /* IPXIP */ 404#ifdef IPTUNNEL 405#if 0 406 case SO_IPXTUNNEL_ROUTE: 407 error = ipxtun_route(so, sopt); 408 break; 409#endif 410#endif 411 default: 412 error = EINVAL; 413 } 414 break; 415 } 416 return (error); 417} 418 419static int 420ipx_usr_abort(so) 421 struct socket *so; 422{ 423 int s; 424 struct ipxpcb *ipxp = sotoipxpcb(so); 425 426 s = splnet(); 427 ipx_pcbdetach(ipxp); 428 splx(s); 429 sofree(so); 430 soisdisconnected(so); 431 return (0); 432} 433 434static int 435ipx_attach(so, proto, p) 436 struct socket *so; 437 int proto; 438 struct proc *p; 439{ 440 int error; 441 int s; 442 struct ipxpcb *ipxp = sotoipxpcb(so); 443 444 if (ipxp != NULL) 445 return (EINVAL); 446 s = splnet(); 447 error = ipx_pcballoc(so, &ipxpcb, p); 448 splx(s); 449 if (error == 0) 450 error = soreserve(so, ipxsendspace, ipxrecvspace); 451 return (error); 452} 453 454static int 455ipx_bind(so, nam, p) 456 struct socket *so; 457 struct sockaddr *nam; 458 struct proc *p; 459{ 460 struct ipxpcb *ipxp = sotoipxpcb(so); 461 462 return (ipx_pcbbind(ipxp, nam, p)); 463} 464 465static int 466ipx_connect(so, nam, p) 467 struct socket *so; 468 struct sockaddr *nam; 469 struct proc *p; 470{ 471 int error; 472 int s; 473 struct ipxpcb *ipxp = sotoipxpcb(so); 474 475 if (!ipx_nullhost(ipxp->ipxp_faddr)) 476 return (EISCONN); 477 s = splnet(); 478 error = ipx_pcbconnect(ipxp, nam, p); 479 splx(s); 480 if (error == 0) 481 soisconnected(so); 482 return (error); 483} 484 485static int 486ipx_detach(so) 487 struct socket *so; 488{ 489 int s; 490 struct ipxpcb *ipxp = sotoipxpcb(so); 491 492 if (ipxp == NULL) 493 return (ENOTCONN); 494 s = splnet(); 495 ipx_pcbdetach(ipxp); 496 splx(s); 497 return (0); 498} 499 500static int 501ipx_disconnect(so) 502 struct socket *so; 503{ 504 int s; 505 struct ipxpcb *ipxp = sotoipxpcb(so); 506 507 if (ipx_nullhost(ipxp->ipxp_faddr)) 508 return (ENOTCONN); 509 s = splnet(); 510 ipx_pcbdisconnect(ipxp); 511 splx(s); 512 soisdisconnected(so); 513 return (0); 514} 515 516int 517ipx_peeraddr(so, nam) 518 struct socket *so; 519 struct sockaddr **nam; 520{ 521 struct ipxpcb *ipxp = sotoipxpcb(so); 522 523 ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 524 return (0); 525} 526 527static int 528ipx_send(so, flags, m, nam, control, p) 529 struct socket *so; 530 int flags; 531 struct mbuf *m; 532 struct sockaddr *nam; 533 struct mbuf *control; 534 struct proc *p; 535{ 536 int error; 537 struct ipxpcb *ipxp = sotoipxpcb(so); 538 struct ipx_addr laddr; 539 int s = 0; 540 541 if (nam != NULL) { 542 laddr = ipxp->ipxp_laddr; 543 if (!ipx_nullhost(ipxp->ipxp_faddr)) { 544 error = EISCONN; 545 goto send_release; 546 } 547 /* 548 * Must block input while temporarily connected. 549 */ 550 s = splnet(); 551 error = ipx_pcbconnect(ipxp, nam, p); 552 if (error) { 553 splx(s); 554 goto send_release; 555 } 556 } else { 557 if (ipx_nullhost(ipxp->ipxp_faddr)) { 558 error = ENOTCONN; 559 goto send_release; 560 } 561 } 562 error = ipx_output(ipxp, m); 563 m = NULL; 564 if (nam != NULL) { 565 ipx_pcbdisconnect(ipxp); 566 splx(s); 567 ipxp->ipxp_laddr = laddr; 568 } 569 570send_release: 571 if (m != NULL) 572 m_freem(m); 573 return (error); 574} 575 576static int 577ipx_shutdown(so) 578 struct socket *so; 579{ 580 socantsendmore(so); 581 return (0); 582} 583 584int 585ipx_sockaddr(so, nam) 586 struct socket *so; 587 struct sockaddr **nam; 588{ 589 struct ipxpcb *ipxp = sotoipxpcb(so); 590 591 ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 592 return (0); 593} 594 595static int 596ripx_attach(so, proto, p) 597 struct socket *so; 598 int proto; 599 struct proc *p; 600{ 601 int error = 0; 602 int s; 603 struct ipxpcb *ipxp = sotoipxpcb(so); 604 605 if (p != NULL && (error = suser(p)) != 0) 606 return (error); 607 s = splnet(); 608 error = ipx_pcballoc(so, &ipxrawpcb, p); 609 splx(s); 610 if (error) 611 return (error); 612 error = soreserve(so, ipxsendspace, ipxrecvspace); 613 if (error) 614 return (error); 615 ipxp = sotoipxpcb(so); 616 ipxp->ipxp_faddr.x_host = ipx_broadhost; 617 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 618 return (error); 619} 620