Correct BSD License clause numbering from 1-2-4 to 1-2-3.
[dragonfly.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. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *      @(#)ipx_usrreq.c
31  *
32  * $FreeBSD: src/sys/netipx/ipx_usrreq.c,v 1.26.2.1 2001/02/22 09:44:18 bp Exp $
33  */
34
35 #include "opt_ipx.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/mbuf.h>
41 #include <sys/proc.h>
42 #include <sys/priv.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/socketvar2.h>
47 #include <sys/sysctl.h>
48
49 #include <sys/thread2.h>
50 #include <sys/msgport2.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54
55 #include <netinet/in.h>
56
57 #include "ipx.h"
58 #include "ipx_pcb.h"
59 #include "ipx_if.h"
60 #include "ipx_var.h"
61 #include "ipx_ip.h"
62
63 /*
64  * IPX protocol implementation.
65  */
66
67 static int ipxsendspace = IPXSNDQ;
68 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
69             &ipxsendspace, 0, "");
70 static int ipxrecvspace = IPXRCVQ;
71 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
72             &ipxrecvspace, 0, "");
73
74 static void ipx_usr_abort(netmsg_t msg);
75 static void ipx_attach(netmsg_t msg);
76 static void ipx_bind(netmsg_t msg);
77 static void ipx_connect(netmsg_t msg);
78 /*static void ipx_control(netmsg_t msg);*/
79 static void ipx_detach(netmsg_t msg);
80 static void ipx_disconnect(netmsg_t msg);
81 /*static void ipx_peeraddr(netmsg_t msg);*/
82 static void ipx_send(netmsg_t msg);
83 static void ipx_shutdown(netmsg_t msg);
84 /*static void ipx_sockaddr(netmsg_t msg);*/
85 static void ripx_attach(netmsg_t msg);
86
87 struct  pr_usrreqs ipx_usrreqs = {
88         .pru_abort = ipx_usr_abort,
89         .pru_accept = pr_generic_notsupp,
90         .pru_attach = ipx_attach,
91         .pru_bind = ipx_bind,
92         .pru_connect = ipx_connect,
93         .pru_connect2 = pr_generic_notsupp,
94         .pru_control = ipx_control,
95         .pru_detach = ipx_detach,
96         .pru_disconnect = ipx_disconnect,
97         .pru_listen = pr_generic_notsupp,
98         .pru_peeraddr = ipx_peeraddr,
99         .pru_rcvd = pr_generic_notsupp,
100         .pru_rcvoob = pr_generic_notsupp,
101         .pru_send = ipx_send,
102         .pru_sense = pru_sense_null,
103         .pru_shutdown = ipx_shutdown,
104         .pru_sockaddr = ipx_sockaddr,
105         .pru_sosend = sosend,
106         .pru_soreceive = soreceive
107 };
108
109 struct  pr_usrreqs ripx_usrreqs = {
110         .pru_abort = ipx_usr_abort,
111         .pru_accept = pr_generic_notsupp,
112         .pru_attach = ripx_attach,
113         .pru_bind = ipx_bind,
114         .pru_connect = ipx_connect,
115         .pru_connect2 = pr_generic_notsupp,
116         .pru_control = ipx_control,
117         .pru_detach = ipx_detach,
118         .pru_disconnect = ipx_disconnect,
119         .pru_listen = pr_generic_notsupp,
120         .pru_peeraddr = ipx_peeraddr,
121         .pru_rcvd = pr_generic_notsupp,
122         .pru_rcvoob = pr_generic_notsupp,
123         .pru_send = ipx_send,
124         .pru_sense = pru_sense_null,
125         .pru_shutdown = ipx_shutdown,
126         .pru_sockaddr = ipx_sockaddr,
127         .pru_sosend = sosend,
128         .pru_soreceive = soreceive
129 };
130
131 /*
132  *  This may also be called for raw listeners.
133  */
134 void
135 ipx_input(struct mbuf *m, struct ipxpcb *ipxp)
136 {
137         struct ipx *ipx = mtod(m, struct ipx *);
138         struct ifnet *ifp = m->m_pkthdr.rcvif;
139         struct sockaddr_ipx ipx_ipx;
140
141         if (ipxp == NULL)
142                 panic("No ipxpcb");
143         /*
144          * Construct sockaddr format source address.
145          * Stuff source address and datagram in user buffer.
146          */
147         ipx_ipx.sipx_len = sizeof(ipx_ipx);
148         ipx_ipx.sipx_family = AF_IPX;
149         ipx_ipx.sipx_addr = ipx->ipx_sna;
150         ipx_ipx.sipx_zero[0] = '\0';
151         ipx_ipx.sipx_zero[1] = '\0';
152         if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
153                 struct ifaddr_container *ifac;
154
155                 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
156                         struct ifaddr *ifa = ifac->ifa;
157
158                         if (ifa->ifa_addr->sa_family == AF_IPX) {
159                                 ipx_ipx.sipx_addr.x_net =
160                                         IA_SIPX(ifa)->sipx_addr.x_net;
161                                 break;
162                         }
163                 }
164         }
165         ipxp->ipxp_rpt = ipx->ipx_pt;
166         if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
167                 m->m_len -= sizeof(struct ipx);
168                 m->m_pkthdr.len -= sizeof(struct ipx);
169                 m->m_data += sizeof(struct ipx);
170         }
171         if (ssb_appendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
172             m, NULL) == 0)
173                 goto bad;
174         sorwakeup(ipxp->ipxp_socket);
175         return;
176 bad:
177         m_freem(m);
178 }
179
180 void
181 ipx_abort(struct ipxpcb *ipxp)
182 {
183         struct socket *so = ipxp->ipxp_socket;
184
185         soreference(so);
186         ipx_pcbdisconnect(ipxp);
187         soisdisconnected(so);
188         sofree(so);
189 }
190
191 /*
192  * Drop connection, reporting
193  * the specified error.
194  */
195 void
196 ipx_drop(struct ipxpcb *ipxp, int error)
197 {
198         struct socket *so = ipxp->ipxp_socket;
199
200         /*
201          * someday, in the IPX world
202          * we will generate error protocol packets
203          * announcing that the socket has gone away.
204          *
205          * XXX Probably never. IPX does not have error packets.
206          */
207         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
208                 tp->t_state = TCPS_CLOSED;
209                 tcp_output(tp);
210         }*/
211         so->so_error = error;
212         soreference(so);
213         ipx_pcbdisconnect(ipxp);
214         soisdisconnected(so);
215         sofree(so);
216 }
217
218 static int
219 ipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
220 {
221         struct ipx *ipx;
222         struct socket *so;
223         int len = 0;
224         struct route *ro;
225         struct mbuf *m;
226         struct mbuf *mprev = NULL;
227
228         /*
229          * Calculate data length.
230          */
231         for (m = m0; m != NULL; m = m->m_next) {
232                 mprev = m;
233                 len += m->m_len;
234         }
235         /*
236          * Make sure packet is actually of even length.
237          */
238         
239         if (len & 1) {
240                 m = mprev;
241                 if ((m->m_flags & M_EXT) == 0 &&
242                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
243                         mtod(m, char*)[m->m_len++] = 0;
244                 } else {
245                         struct mbuf *m1 = m_get(MB_DONTWAIT, MT_DATA);
246
247                         if (m1 == NULL) {
248                                 m_freem(m0);
249                                 return (ENOBUFS);
250                         }
251                         m1->m_len = 1;
252                         * mtod(m1, char *) = 0;
253                         m->m_next = m1;
254                 }
255                 m0->m_pkthdr.len++;
256         }
257
258         /*
259          * Fill in mbuf with extended IPX header
260          * and addresses and length put into network format.
261          */
262         m = m0;
263         if (ipxp->ipxp_flags & IPXP_RAWOUT) {
264                 ipx = mtod(m, struct ipx *);
265         } else {
266                 M_PREPEND(m, sizeof(struct ipx), MB_DONTWAIT);
267                 if (m == NULL)
268                         return (ENOBUFS);
269                 ipx = mtod(m, struct ipx *);
270                 ipx->ipx_tc = 0;
271                 ipx->ipx_pt = ipxp->ipxp_dpt;
272                 ipx->ipx_sna = ipxp->ipxp_laddr;
273                 ipx->ipx_dna = ipxp->ipxp_faddr;
274                 len += sizeof(struct ipx);
275         }
276
277         ipx->ipx_len = htons((u_short)len);
278
279         if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
280                 ipx->ipx_sum = ipx_cksum(m, len);
281         } else
282                 ipx->ipx_sum = 0xffff;
283
284         /*
285          * Output datagram.
286          */
287         so = ipxp->ipxp_socket;
288         if (so->so_options & SO_DONTROUTE)
289                 return (ipx_outputfl(m, NULL,
290                     (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
291         /*
292          * Use cached route for previous datagram if
293          * possible.  If the previous net was the same
294          * and the interface was a broadcast medium, or
295          * if the previous destination was identical,
296          * then we are ok.
297          *
298          * NB: We don't handle broadcasts because that
299          *     would require 3 subroutine calls.
300          */
301         ro = &ipxp->ipxp_route;
302 #ifdef ancient_history
303         /*
304          * I think that this will all be handled in ipx_pcbconnect!
305          */
306         if (ro->ro_rt != NULL) {
307                 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
308                         /*
309                          * This assumes we have no GH type routes
310                          */
311                         if (ro->ro_rt->rt_flags & RTF_HOST) {
312                                 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
313                                         goto re_route;
314
315                         }
316                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
317                                 struct ipx_addr *dst =
318                                                 &satoipx_addr(ro->ro_dst);
319                                 dst->x_host = ipx->ipx_dna.x_host;
320                         }
321                         /* 
322                          * Otherwise, we go through the same gateway
323                          * and dst is already set up.
324                          */
325                 } else {
326                 re_route:
327                         RTFREE(ro->ro_rt);
328                         ro->ro_rt = NULL;
329                 }
330         }
331         ipxp->ipxp_lastdst = ipx->ipx_dna;
332 #endif /* ancient_history */
333         return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
334 }
335
336 void
337 ipx_ctloutput(netmsg_t msg)
338 {
339         struct socket *so = msg->base.nm_so;
340         struct sockopt *sopt = msg->ctloutput.nm_sopt;
341         struct ipxpcb *ipxp = sotoipxpcb(so);
342         int mask, error, optval;
343         short soptval;
344         struct ipx ioptval;
345
346         error = 0;
347         if (ipxp == NULL) {
348                 error = EINVAL;
349                 goto out;
350         }
351
352         switch (sopt->sopt_dir) {
353         case SOPT_GET:
354                 switch (sopt->sopt_name) {
355                 case SO_ALL_PACKETS:
356                         mask = IPXP_ALL_PACKETS;
357                         goto get_flags;
358
359                 case SO_HEADERS_ON_INPUT:
360                         mask = IPXP_RAWIN;
361                         goto get_flags;
362
363                 case SO_IPX_CHECKSUM:
364                         mask = IPXP_CHECKSUM;
365                         goto get_flags;
366                         
367                 case SO_HEADERS_ON_OUTPUT:
368                         mask = IPXP_RAWOUT;
369                 get_flags:
370                         soptval = ipxp->ipxp_flags & mask;
371                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
372                         break;
373
374                 case SO_DEFAULT_HEADERS:
375                         ioptval.ipx_len = 0;
376                         ioptval.ipx_sum = 0;
377                         ioptval.ipx_tc = 0;
378                         ioptval.ipx_pt = ipxp->ipxp_dpt;
379                         ioptval.ipx_dna = ipxp->ipxp_faddr;
380                         ioptval.ipx_sna = ipxp->ipxp_laddr;
381                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
382                         break;
383
384                 case SO_SEQNO:
385                         error = sooptcopyout(sopt, &ipx_pexseq, 
386                                              sizeof ipx_pexseq);
387                         ipx_pexseq++;
388                         break;
389
390                 default:
391                         error = EINVAL;
392                 }
393                 break;
394
395         case SOPT_SET:
396                 switch (sopt->sopt_name) {
397                 case SO_ALL_PACKETS:
398                         mask = IPXP_ALL_PACKETS;
399                         goto set_head;
400
401                 case SO_HEADERS_ON_INPUT:
402                         mask = IPXP_RAWIN;
403                         goto set_head;
404
405                 case SO_IPX_CHECKSUM:
406                         mask = IPXP_CHECKSUM;
407                         goto set_head;
408
409                 case SO_HEADERS_ON_OUTPUT:
410                         mask = IPXP_RAWOUT;
411                 set_head:
412                         error = sooptcopyin(sopt, &optval, sizeof optval,
413                                             sizeof optval);
414                         if (error)
415                                 break;
416                         if (optval)
417                                 ipxp->ipxp_flags |= mask;
418                         else
419                                 ipxp->ipxp_flags &= ~mask;
420                         break;
421
422                 case SO_DEFAULT_HEADERS:
423                         error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
424                                             sizeof ioptval);
425                         if (error)
426                                 break;
427                         ipxp->ipxp_dpt = ioptval.ipx_pt;
428                         break;
429 #ifdef IPXIP
430                 case SO_IPXIP_ROUTE:
431                         error = ipxip_route(so, sopt);
432                         break;
433 #endif /* IPXIP */
434 #ifdef IPTUNNEL
435 #if 0
436                 case SO_IPXTUNNEL_ROUTE:
437                         error = ipxtun_route(so, sopt);
438                         break;
439 #endif
440 #endif
441                 default:
442                         error = EINVAL;
443                 }
444                 break;
445         }
446 out:
447         lwkt_replymsg(&msg->lmsg, error);
448 }
449
450 /*
451  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
452  *       will sofree() it when we return.
453  */
454 static void
455 ipx_usr_abort(netmsg_t msg)
456 {
457         struct socket *so = msg->base.nm_so;
458         struct ipxpcb *ipxp = sotoipxpcb(so);
459
460         ipx_pcbdetach(ipxp);
461         soisdisconnected(so);
462
463         lwkt_replymsg(&msg->lmsg, 0);
464 }
465
466 static void
467 ipx_attach(netmsg_t msg)
468 {
469         struct socket *so = msg->base.nm_so;
470         struct pru_attach_info *ai = msg->attach.nm_ai;
471         struct ipxpcb *ipxp = sotoipxpcb(so);
472         int error;
473
474         if (ipxp != NULL) {
475                 error = EINVAL;
476         } else {
477                 error = ipx_pcballoc(so, &ipxpcb_list);
478                 if (error == 0) {
479                         error = soreserve(so, ipxsendspace, ipxrecvspace,
480                                           ai->sb_rlimit);
481                 }
482         }
483         lwkt_replymsg(&msg->lmsg, error);
484 }
485
486 static void
487 ipx_bind(netmsg_t msg)
488 {
489         struct socket *so = msg->base.nm_so;
490         struct ipxpcb *ipxp = sotoipxpcb(so);
491         int error;
492
493         error = ipx_pcbbind(ipxp, msg->bind.nm_nam, msg->bind.nm_td);
494         lwkt_replymsg(&msg->lmsg, error);
495 }
496
497 static void
498 ipx_connect(netmsg_t msg)
499 {
500         struct socket *so = msg->base.nm_so;
501         struct ipxpcb *ipxp = sotoipxpcb(so);
502         int error;
503
504         if (ipx_nullhost(ipxp->ipxp_faddr)) {
505                 error = ipx_pcbconnect(ipxp,
506                                        msg->connect.nm_nam,
507                                        msg->connect.nm_td);
508                 if (error == 0)
509                         soisconnected(so);
510         } else {
511                 error = EISCONN;
512         }
513         lwkt_replymsg(&msg->lmsg, error);
514 }
515
516 void
517 ipx_control(netmsg_t msg)
518 {
519         int error;
520
521         error = ipx_control_oncpu(msg->base.nm_so,
522                                   msg->control.nm_cmd,
523                                   msg->control.nm_data,
524                                   msg->control.nm_ifp,
525                                   msg->control.nm_td);
526         lwkt_replymsg(&msg->lmsg, error);
527 }
528
529 static void
530 ipx_detach(netmsg_t msg)
531 {
532         struct socket *so = msg->base.nm_so;
533         struct ipxpcb *ipxp = sotoipxpcb(so);
534         int error;
535
536         if (ipxp) {
537                 ipx_pcbdetach(ipxp);
538                 error = 0;
539         } else {
540                 error = ENOTCONN;
541         }
542         lwkt_replymsg(&msg->lmsg, error);
543 }
544
545 static void
546 ipx_disconnect(netmsg_t msg)
547 {
548         struct socket *so = msg->base.nm_so;
549         struct ipxpcb *ipxp = sotoipxpcb(so);
550         int error;
551
552         if (ipx_nullhost(ipxp->ipxp_faddr)) {
553                 error= ENOTCONN;
554         } else {
555                 soreference(so);
556                 ipx_pcbdisconnect(ipxp);
557                 soisdisconnected(so);
558                 sofree(so);
559                 error = 0;
560         }
561         lwkt_replymsg(&msg->lmsg, error);
562 }
563
564 void
565 ipx_peeraddr(netmsg_t msg)
566 {
567         struct socket *so = msg->base.nm_so;
568         struct ipxpcb *ipxp = sotoipxpcb(so);
569
570         ipx_setpeeraddr(ipxp, msg->peeraddr.nm_nam);
571         lwkt_replymsg(&msg->lmsg, 0);
572 }
573
574 static void
575 ipx_send(netmsg_t msg)
576 {
577         struct socket *so = msg->base.nm_so;
578         struct mbuf *m = msg->send.nm_m;
579         struct sockaddr *nam = msg->send.nm_addr;
580         struct mbuf *control = msg->send.nm_control;
581         struct thread *td = msg->send.nm_td;
582         struct ipxpcb *ipxp = sotoipxpcb(so);
583         struct ipx_addr laddr;
584         int error;
585
586         if (control) {
587                 m_freem(control);
588                 control = NULL;
589         }
590
591         if (nam != NULL) {
592                 laddr = ipxp->ipxp_laddr;
593                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
594                         error = EISCONN;
595                         goto send_release;
596                 }
597                 /*
598                  * Must block input while temporarily connected.
599                  */
600                 error = ipx_pcbconnect(ipxp, nam, td);
601                 if (error) {
602                         goto send_release;
603                 }
604         } else {
605                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
606                         error = ENOTCONN;
607                         goto send_release;
608                 }
609         }
610         error = ipx_output(ipxp, m);
611         m = NULL;
612         if (nam != NULL) {
613                 ipx_pcbdisconnect(ipxp);
614                 ipxp->ipxp_laddr = laddr;
615         }
616 send_release:
617         if (m != NULL)
618                 m_freem(m);
619         lwkt_replymsg(&msg->lmsg, error);
620 }
621
622 static void
623 ipx_shutdown(netmsg_t msg)
624 {
625         struct socket *so = msg->base.nm_so;
626
627         socantsendmore(so);
628
629         lwkt_replymsg(&msg->lmsg, 0);
630 }
631
632 void
633 ipx_sockaddr(netmsg_t msg)
634 {
635         struct socket *so = msg->base.nm_so;
636         struct ipxpcb *ipxp = sotoipxpcb(so);
637
638         /* XXX what if alloc fails? */
639         ipx_setsockaddr(ipxp, msg->sockaddr.nm_nam);
640         lwkt_replymsg(&msg->lmsg, 0);
641 }
642
643 static void
644 ripx_attach(netmsg_t msg)
645 {
646         struct socket *so = msg->base.nm_so;
647         struct pru_attach_info *ai = msg->attach.nm_ai;
648         struct ipxpcb *ipxp;
649         int error;
650
651         error = priv_check_cred(ai->p_ucred, PRIV_ROOT, NULL_CRED_OKAY);
652         if (error)
653                 goto out;
654         error = ipx_pcballoc(so, &ipxrawpcb_list);
655         if (error)
656                 goto out;
657         error = soreserve(so, ipxsendspace, ipxrecvspace, ai->sb_rlimit);
658         if (error)
659                 goto out;
660         ipxp = sotoipxpcb(so);
661         ipxp->ipxp_faddr.x_host = ipx_broadhost;
662         ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
663 out:
664         lwkt_replymsg(&msg->lmsg, error);
665 }