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