ipx_usrreq.c revision 139444
1184610Salfred/* 2184610Salfred * Copyright (c) 2004, Robert N. M. Watson 3184610Salfred * Copyright (c) 1995, Mike Mitchell 4184610Salfred * Copyright (c) 1984, 1985, 1986, 1987, 1993 5184610Salfred * The Regents of the University of California. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 3. All advertising materials mentioning features or use of this software 16184610Salfred * must display the following acknowledgement: 17184610Salfred * This product includes software developed by the University of 18184610Salfred * California, Berkeley and its contributors. 19184610Salfred * 4. Neither the name of the University nor the names of its contributors 20184610Salfred * may be used to endorse or promote products derived from this software 21184610Salfred * without specific prior written permission. 22184610Salfred * 23184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33184610Salfred * SUCH DAMAGE. 34184610Salfred * 35184610Salfred * @(#)ipx_usrreq.c 36184610Salfred */ 37184610Salfred 38184610Salfred#include <sys/cdefs.h> 39184610Salfred__FBSDID("$FreeBSD: head/sys/netipx/ipx_usrreq.c 139444 2004-12-30 17:49:40Z rwatson $"); 40184610Salfred 41184610Salfred#include "opt_ipx.h" 42184610Salfred 43184610Salfred#include <sys/param.h> 44184610Salfred#include <sys/kernel.h> 45184610Salfred#include <sys/lock.h> 46184610Salfred#include <sys/mbuf.h> 47184610Salfred#include <sys/protosw.h> 48184610Salfred#include <sys/signalvar.h> 49184610Salfred#include <sys/socket.h> 50184610Salfred#include <sys/socketvar.h> 51194677Sthompsa#include <sys/sx.h> 52194677Sthompsa#include <sys/sysctl.h> 53194677Sthompsa#include <sys/systm.h> 54194677Sthompsa 55194677Sthompsa#include <net/if.h> 56194677Sthompsa#include <net/route.h> 57194677Sthompsa 58194677Sthompsa#include <netinet/in.h> 59194677Sthompsa 60194677Sthompsa#include <netipx/ipx.h> 61194677Sthompsa#include <netipx/ipx_if.h> 62194677Sthompsa#include <netipx/ipx_ip.h> 63194677Sthompsa#include <netipx/ipx_pcb.h> 64194677Sthompsa#include <netipx/ipx_var.h> 65194677Sthompsa 66194677Sthompsa/* 67194677Sthompsa * IPX protocol implementation. 68194677Sthompsa */ 69194677Sthompsa 70194677Sthompsastatic int ipxsendspace = IPXSNDQ; 71188942SthompsaSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW, 72194677Sthompsa &ipxsendspace, 0, ""); 73184610Salfredstatic int ipxrecvspace = IPXRCVQ; 74188942SthompsaSYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, 75188942Sthompsa &ipxrecvspace, 0, ""); 76188942Sthompsa 77188942Sthompsastatic int ipx_usr_abort(struct socket *so); 78188942Sthompsastatic int ipx_attach(struct socket *so, int proto, struct thread *td); 79184610Salfredstatic int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 80188942Sthompsastatic int ipx_connect(struct socket *so, struct sockaddr *nam, 81188942Sthompsa struct thread *td); 82188942Sthompsastatic int ipx_detach(struct socket *so); 83188942Sthompsastatic int ipx_disconnect(struct socket *so); 84198151Sthompsastatic int ipx_send(struct socket *so, int flags, struct mbuf *m, 85184610Salfred struct sockaddr *addr, struct mbuf *control, 86184610Salfred struct thread *td); 87184610Salfredstatic int ipx_shutdown(struct socket *so); 88184610Salfredstatic int ripx_attach(struct socket *so, int proto, struct thread *td); 89184610Salfredstatic int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0); 90184610Salfred 91184610Salfredstruct pr_usrreqs ipx_usrreqs = { 92184610Salfred .pru_abort = ipx_usr_abort, 93184610Salfred .pru_attach = ipx_attach, 94184610Salfred .pru_bind = ipx_bind, 95184610Salfred .pru_connect = ipx_connect, 96184610Salfred .pru_control = ipx_control, 97184610Salfred .pru_detach = ipx_detach, 98184610Salfred .pru_disconnect = ipx_disconnect, 99184610Salfred .pru_peeraddr = ipx_peeraddr, 100184610Salfred .pru_send = ipx_send, 101184610Salfred .pru_shutdown = ipx_shutdown, 102184610Salfred .pru_sockaddr = ipx_sockaddr, 103184610Salfred}; 104184610Salfred 105184610Salfredstruct pr_usrreqs ripx_usrreqs = { 106184610Salfred .pru_abort = ipx_usr_abort, 107184610Salfred .pru_attach = ripx_attach, 108184610Salfred .pru_bind = ipx_bind, 109184610Salfred .pru_connect = ipx_connect, 110184610Salfred .pru_control = ipx_control, 111184610Salfred .pru_detach = ipx_detach, 112184610Salfred .pru_disconnect = ipx_disconnect, 113184610Salfred .pru_peeraddr = ipx_peeraddr, 114184610Salfred .pru_send = ipx_send, 115184610Salfred .pru_shutdown = ipx_shutdown, 116184610Salfred .pru_sockaddr = ipx_sockaddr, 117184610Salfred}; 118198501Sthompsa 119198501Sthompsa/* 120184610Salfred * This may also be called for raw listeners. 121184610Salfred */ 122184610Salfredvoid 123184610Salfredipx_input(m, ipxp) 124184610Salfred struct mbuf *m; 125184610Salfred register struct ipxpcb *ipxp; 126184610Salfred{ 127184610Salfred register struct ipx *ipx = mtod(m, struct ipx *); 128184610Salfred struct ifnet *ifp = m->m_pkthdr.rcvif; 129184610Salfred struct sockaddr_ipx ipx_ipx; 130184610Salfred 131184610Salfred if (ipxp == NULL) 132184610Salfred panic("No ipxpcb"); 133184610Salfred /* 134184610Salfred * Construct sockaddr format source address. 135184610Salfred * Stuff source address and datagram in user buffer. 136184610Salfred */ 137184610Salfred ipx_ipx.sipx_len = sizeof(ipx_ipx); 138184610Salfred ipx_ipx.sipx_family = AF_IPX; 139184610Salfred ipx_ipx.sipx_addr = ipx->ipx_sna; 140184610Salfred ipx_ipx.sipx_zero[0] = '\0'; 141184610Salfred ipx_ipx.sipx_zero[1] = '\0'; 142184610Salfred if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { 143184610Salfred register struct ifaddr *ifa; 144184610Salfred 145184610Salfred for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 146184610Salfred ifa = TAILQ_NEXT(ifa, ifa_link)) { 147184610Salfred if (ifa->ifa_addr->sa_family == AF_IPX) { 148184610Salfred ipx_ipx.sipx_addr.x_net = 149184610Salfred IA_SIPX(ifa)->sipx_addr.x_net; 150184610Salfred break; 151184610Salfred } 152184610Salfred } 153184610Salfred } 154184610Salfred ipxp->ipxp_rpt = ipx->ipx_pt; 155184610Salfred if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) { 156184610Salfred m->m_len -= sizeof(struct ipx); 157184610Salfred m->m_pkthdr.len -= sizeof(struct ipx); 158184610Salfred m->m_data += sizeof(struct ipx); 159184610Salfred } 160184610Salfred if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, 161184610Salfred m, (struct mbuf *)NULL) == 0) 162184610Salfred goto bad; 163184610Salfred sorwakeup(ipxp->ipxp_socket); 164184610Salfred return; 165184610Salfredbad: 166184610Salfred m_freem(m); 167184610Salfred} 168184610Salfred 169184610Salfredvoid 170184610Salfredipx_abort(ipxp) 171184610Salfred struct ipxpcb *ipxp; 172184610Salfred{ 173184610Salfred struct socket *so = ipxp->ipxp_socket; 174184610Salfred 175184610Salfred ipx_pcbdisconnect(ipxp); 176184610Salfred soisdisconnected(so); 177184610Salfred} 178184610Salfred 179184610Salfred/* 180184610Salfred * Drop connection, reporting 181184610Salfred * the specified error. 182184610Salfred */ 183184610Salfredvoid 184184610Salfredipx_drop(ipxp, errno) 185184610Salfred register struct ipxpcb *ipxp; 186184610Salfred int errno; 187184610Salfred{ 188184610Salfred struct socket *so = ipxp->ipxp_socket; 189184610Salfred 190184610Salfred /* 191184610Salfred * someday, in the IPX world 192184610Salfred * we will generate error protocol packets 193184610Salfred * announcing that the socket has gone away. 194184610Salfred * 195184610Salfred * XXX Probably never. IPX does not have error packets. 196184610Salfred */ 197184610Salfred /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 198184610Salfred tp->t_state = TCPS_CLOSED; 199184610Salfred tcp_output(tp); 200184610Salfred }*/ 201184610Salfred so->so_error = errno; 202184610Salfred ipx_pcbdisconnect(ipxp); 203184610Salfred soisdisconnected(so); 204195958Salfred} 205195958Salfred 206195958Salfredstatic int 207195958Salfredipx_output(ipxp, m0) 208195958Salfred struct ipxpcb *ipxp; 209195958Salfred struct mbuf *m0; 210195958Salfred{ 211195958Salfred register struct ipx *ipx; 212195958Salfred register struct socket *so; 213184610Salfred register int len = 0; 214184610Salfred register struct route *ro; 215184610Salfred struct mbuf *m; 216184610Salfred struct mbuf *mprev = NULL; 217184610Salfred 218184610Salfred /* 219184610Salfred * Calculate data length. 220184610Salfred */ 221184610Salfred for (m = m0; m != NULL; m = m->m_next) { 222184610Salfred mprev = m; 223184610Salfred len += m->m_len; 224184610Salfred } 225184610Salfred /* 226184610Salfred * Make sure packet is actually of even length. 227184610Salfred */ 228184610Salfred 229184610Salfred if (len & 1) { 230184610Salfred m = mprev; 231184610Salfred if ((m->m_flags & M_EXT) == 0 && 232184610Salfred (m->m_len + m->m_data < &m->m_dat[MLEN])) { 233184610Salfred mtod(m, char*)[m->m_len++] = 0; 234184610Salfred } else { 235184610Salfred struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 236184610Salfred 237184610Salfred if (m1 == NULL) { 238184610Salfred m_freem(m0); 239184610Salfred return (ENOBUFS); 240184610Salfred } 241184610Salfred m1->m_len = 1; 242184610Salfred * mtod(m1, char *) = 0; 243184610Salfred m->m_next = m1; 244184610Salfred } 245184610Salfred m0->m_pkthdr.len++; 246184610Salfred } 247184610Salfred 248184610Salfred /* 249184610Salfred * Fill in mbuf with extended IPX header 250184610Salfred * and addresses and length put into network format. 251184610Salfred */ 252184610Salfred m = m0; 253184610Salfred if (ipxp->ipxp_flags & IPXP_RAWOUT) { 254184610Salfred ipx = mtod(m, struct ipx *); 255184610Salfred } else { 256184610Salfred M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT); 257184610Salfred if (m == NULL) 258184610Salfred return (ENOBUFS); 259184610Salfred ipx = mtod(m, struct ipx *); 260184610Salfred ipx->ipx_tc = 0; 261184610Salfred ipx->ipx_pt = ipxp->ipxp_dpt; 262184610Salfred ipx->ipx_sna = ipxp->ipxp_laddr; 263184610Salfred ipx->ipx_dna = ipxp->ipxp_faddr; 264184610Salfred len += sizeof(struct ipx); 265184610Salfred } 266184610Salfred 267184610Salfred ipx->ipx_len = htons((u_short)len); 268184610Salfred 269184610Salfred if (ipxp->ipxp_flags & IPXP_CHECKSUM) { 270184610Salfred ipx->ipx_sum = ipx_cksum(m, len); 271184610Salfred } else 272184610Salfred ipx->ipx_sum = 0xffff; 273184610Salfred 274184610Salfred /* 275184610Salfred * Output datagram. 276184610Salfred */ 277187170Sthompsa so = ipxp->ipxp_socket; 278187170Sthompsa if (so->so_options & SO_DONTROUTE) 279187170Sthompsa return (ipx_outputfl(m, (struct route *)NULL, 280187170Sthompsa (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); 281187170Sthompsa /* 282184610Salfred * Use cached route for previous datagram if 283194228Sthompsa * possible. If the previous net was the same 284184610Salfred * and the interface was a broadcast medium, or 285184610Salfred * if the previous destination was identical, 286184610Salfred * then we are ok. 287184610Salfred * 288184610Salfred * NB: We don't handle broadcasts because that 289184610Salfred * would require 3 subroutine calls. 290184610Salfred */ 291184610Salfred ro = &ipxp->ipxp_route; 292184610Salfred#ifdef ancient_history 293184610Salfred /* 294184610Salfred * I think that this will all be handled in ipx_pcbconnect! 295184610Salfred */ 296184610Salfred if (ro->ro_rt != NULL) { 297184610Salfred if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) { 298184610Salfred /* 299184610Salfred * This assumes we have no GH type routes 300184610Salfred */ 301184610Salfred if (ro->ro_rt->rt_flags & RTF_HOST) { 302184610Salfred if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) 303184610Salfred goto re_route; 304184610Salfred 305184610Salfred } 306184610Salfred if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) { 307184610Salfred register struct ipx_addr *dst = 308184610Salfred &satoipx_addr(ro->ro_dst); 309184610Salfred dst->x_host = ipx->ipx_dna.x_host; 310184610Salfred } 311184610Salfred /* 312184610Salfred * Otherwise, we go through the same gateway 313184610Salfred * and dst is already set up. 314184610Salfred */ 315184610Salfred } else { 316184610Salfred re_route: 317184610Salfred RTFREE(ro->ro_rt); 318184610Salfred ro->ro_rt = NULL; 319184610Salfred } 320184610Salfred } 321184610Salfred ipxp->ipxp_lastdst = ipx->ipx_dna; 322184610Salfred#endif /* ancient_history */ 323184610Salfred return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); 324184610Salfred} 325184610Salfred 326184610Salfredint 327184610Salfredipx_ctloutput(so, sopt) 328184610Salfred struct socket *so; 329184610Salfred struct sockopt *sopt; 330184610Salfred{ 331184610Salfred struct ipxpcb *ipxp = sotoipxpcb(so); 332184610Salfred int mask, error, optval; 333184610Salfred short soptval; 334184610Salfred struct ipx ioptval; 335184610Salfred 336184610Salfred error = 0; 337184610Salfred if (ipxp == NULL) 338184610Salfred return (EINVAL); 339184610Salfred 340184610Salfred switch (sopt->sopt_dir) { 341184610Salfred case SOPT_GET: 342184610Salfred switch (sopt->sopt_name) { 343184610Salfred case SO_ALL_PACKETS: 344184610Salfred mask = IPXP_ALL_PACKETS; 345184610Salfred goto get_flags; 346184610Salfred 347187186Sthompsa case SO_HEADERS_ON_INPUT: 348187186Sthompsa mask = IPXP_RAWIN; 349187186Sthompsa goto get_flags; 350184610Salfred 351184610Salfred case SO_IPX_CHECKSUM: 352184610Salfred mask = IPXP_CHECKSUM; 353184610Salfred goto get_flags; 354184610Salfred 355190183Sthompsa case SO_HEADERS_ON_OUTPUT: 356184610Salfred mask = IPXP_RAWOUT; 357184610Salfred get_flags: 358190183Sthompsa soptval = ipxp->ipxp_flags & mask; 359184610Salfred error = sooptcopyout(sopt, &soptval, sizeof soptval); 360184610Salfred break; 361184610Salfred 362184610Salfred case SO_DEFAULT_HEADERS: 363184610Salfred ioptval.ipx_len = 0; 364184610Salfred ioptval.ipx_sum = 0; 365184610Salfred ioptval.ipx_tc = 0; 366198501Sthompsa ioptval.ipx_pt = ipxp->ipxp_dpt; 367198501Sthompsa ioptval.ipx_dna = ipxp->ipxp_faddr; 368198501Sthompsa ioptval.ipx_sna = ipxp->ipxp_laddr; 369198501Sthompsa error = sooptcopyout(sopt, &soptval, sizeof soptval); 370198501Sthompsa break; 371198501Sthompsa 372198501Sthompsa case SO_SEQNO: 373198501Sthompsa error = sooptcopyout(sopt, &ipx_pexseq, 374198501Sthompsa sizeof ipx_pexseq); 375198501Sthompsa ipx_pexseq++; 376198501Sthompsa break; 377198501Sthompsa 378198501Sthompsa default: 379184610Salfred error = EINVAL; 380184610Salfred } 381184610Salfred break; 382184610Salfred 383184610Salfred case SOPT_SET: 384184610Salfred switch (sopt->sopt_name) { 385184610Salfred case SO_ALL_PACKETS: 386184610Salfred mask = IPXP_ALL_PACKETS; 387184610Salfred goto set_head; 388184610Salfred 389184610Salfred case SO_HEADERS_ON_INPUT: 390184610Salfred mask = IPXP_RAWIN; 391184610Salfred goto set_head; 392184610Salfred 393184610Salfred case SO_IPX_CHECKSUM: 394184610Salfred mask = IPXP_CHECKSUM; 395184610Salfred 396184610Salfred case SO_HEADERS_ON_OUTPUT: 397184610Salfred mask = IPXP_RAWOUT; 398184610Salfred set_head: 399184610Salfred error = sooptcopyin(sopt, &optval, sizeof optval, 400184610Salfred sizeof optval); 401184610Salfred if (error) 402184610Salfred break; 403184610Salfred if (optval) 404184610Salfred ipxp->ipxp_flags |= mask; 405184610Salfred else 406184610Salfred ipxp->ipxp_flags &= ~mask; 407184610Salfred break; 408184610Salfred 409184610Salfred case SO_DEFAULT_HEADERS: 410184610Salfred error = sooptcopyin(sopt, &ioptval, sizeof ioptval, 411184610Salfred sizeof ioptval); 412184610Salfred if (error) 413184610Salfred break; 414184824Sthompsa ipxp->ipxp_dpt = ioptval.ipx_pt; 415184610Salfred break; 416184610Salfred#ifdef IPXIP 417184610Salfred case SO_IPXIP_ROUTE: 418184610Salfred error = ipxip_route(so, sopt); 419184824Sthompsa break; 420184610Salfred#endif /* IPXIP */ 421184610Salfred default: 422184610Salfred error = EINVAL; 423184610Salfred } 424184610Salfred break; 425184610Salfred } 426184610Salfred return (error); 427184610Salfred} 428184610Salfred 429184610Salfredstatic int 430184610Salfredipx_usr_abort(so) 431184610Salfred struct socket *so; 432184610Salfred{ 433184610Salfred int s; 434184610Salfred struct ipxpcb *ipxp = sotoipxpcb(so); 435184610Salfred 436184610Salfred s = splnet(); 437184610Salfred ipx_pcbdetach(ipxp); 438184610Salfred splx(s); 439184610Salfred soisdisconnected(so); 440184610Salfred ACCEPT_LOCK(); 441184610Salfred SOCK_LOCK(so); 442194228Sthompsa sotryfree(so); 443184610Salfred return (0); 444184610Salfred} 445184610Salfred 446184610Salfredstatic int 447184610Salfredipx_attach(so, proto, td) 448184610Salfred struct socket *so; 449184610Salfred int proto; 450184610Salfred struct thread *td; 451184610Salfred{ 452184610Salfred int error; 453184610Salfred int s; 454184610Salfred struct ipxpcb *ipxp = sotoipxpcb(so); 455184610Salfred 456184610Salfred if (ipxp != NULL) 457184610Salfred return (EINVAL); 458184610Salfred s = splnet(); 459184610Salfred error = ipx_pcballoc(so, &ipxpcb_list, td); 460184610Salfred splx(s); 461184610Salfred if (error == 0) 462184610Salfred error = soreserve(so, ipxsendspace, ipxrecvspace); 463184610Salfred return (error); 464184610Salfred} 465184610Salfred 466184610Salfredstatic int 467184610Salfredipx_bind(so, nam, td) 468184610Salfred struct socket *so; 469184610Salfred struct sockaddr *nam; 470188942Sthompsa struct thread *td; 471{ 472 struct ipxpcb *ipxp = sotoipxpcb(so); 473 474 return (ipx_pcbbind(ipxp, nam, td)); 475} 476 477static int 478ipx_connect(so, nam, td) 479 struct socket *so; 480 struct sockaddr *nam; 481 struct thread *td; 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(); 490 error = ipx_pcbconnect(ipxp, nam, td); 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 sockaddr **nam; 532{ 533 struct ipxpcb *ipxp = sotoipxpcb(so); 534 535 ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */ 536 return (0); 537} 538 539static int 540ipx_send(so, flags, m, nam, control, td) 541 struct socket *so; 542 int flags; 543 struct mbuf *m; 544 struct sockaddr *nam; 545 struct mbuf *control; 546 struct thread *td; 547{ 548 int error; 549 struct ipxpcb *ipxp = sotoipxpcb(so); 550 struct ipx_addr laddr; 551 int s = 0; 552 553 if (nam != NULL) { 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(); 563 error = ipx_pcbconnect(ipxp, nam, td); 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 != NULL) { 577 ipx_pcbdisconnect(ipxp); 578 splx(s); 579 ipxp->ipxp_laddr = laddr; 580 } 581 582send_release: 583 if (m != NULL) 584 m_freem(m); 585 return (error); 586} 587 588static int 589ipx_shutdown(so) 590 struct socket *so; 591{ 592 socantsendmore(so); 593 return (0); 594} 595 596int 597ipx_sockaddr(so, nam) 598 struct socket *so; 599 struct sockaddr **nam; 600{ 601 struct ipxpcb *ipxp = sotoipxpcb(so); 602 603 ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */ 604 return (0); 605} 606 607static int 608ripx_attach(so, proto, td) 609 struct socket *so; 610 int proto; 611 struct thread *td; 612{ 613 int error = 0; 614 int s; 615 struct ipxpcb *ipxp = sotoipxpcb(so); 616 617 if (td != NULL && (error = suser(td)) != 0) 618 return (error); 619 s = splnet(); 620 error = ipx_pcballoc(so, &ipxrawpcb_list, td); 621 splx(s); 622 if (error) 623 return (error); 624 error = soreserve(so, ipxsendspace, ipxrecvspace); 625 if (error) 626 return (error); 627 ipxp = sotoipxpcb(so); 628 ipxp->ipxp_faddr.x_host = ipx_broadhost; 629 ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT; 630 return (error); 631} 632