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