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