Fix LINT build.
[dragonfly.git] / sys / netproto / ns / idp_usrreq.c
1 /*
2  * Copyright (c) 1984, 1985, 1986, 1987, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *      @(#)idp_usrreq.c        8.1 (Berkeley) 6/10/93
34  * $FreeBSD: src/sys/netns/idp_usrreq.c,v 1.9 1999/08/28 00:49:47 peter Exp $
35  * $DragonFly: src/sys/netproto/ns/idp_usrreq.c,v 1.15 2008/03/07 11:34:21 sephe Exp $
36  */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/socketvar2.h>
46 #include <sys/errno.h>
47 #include <sys/stat.h>
48 #include <sys/thread2.h>
49
50 #include <net/if.h>
51 #include <net/route.h>
52
53 #include "ns.h"
54 #include "ns_pcb.h"
55 #include "ns_if.h"
56 #include "idp.h"
57 #include "idp_var.h"
58 #include "ns_error.h"
59
60 extern int idpcksum;    /* from ns_input.c */
61 extern long ns_pexseq;  /* from ns_input.c */
62 extern struct nspcb nsrawpcb; /* from ns_input.c */
63
64 struct  idpstat idpstat;
65
66 /*
67  * IDP protocol implementation.
68  */
69
70 struct  sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS };
71
72 /*
73  *  This may also be called for raw listeners.
74  */
75 void
76 idp_input(struct mbuf *m, ...)
77 {
78         struct idp *idp = mtod(m, struct idp *);
79         struct ifnet *ifp = m->m_pkthdr.rcvif;
80         struct nspcb *nsp;
81         __va_list ap;
82
83         __va_start(ap, m);
84         nsp = __va_arg(ap, struct nspcb *);
85         __va_end(ap);
86
87         if (nsp == NULL)
88                 panic("No nspcb");
89         /*
90          * Construct sockaddr format source address.
91          * Stuff source address and datagram in user buffer.
92          */
93         idp_ns.sns_addr = idp->idp_sna;
94         if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) {
95                 struct ifaddr_container *ifac;
96
97                 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
98                         struct ifaddr *ifa = ifac->ifa;
99
100                         if (ifa->ifa_addr->sa_family == AF_NS) {
101                                 idp_ns.sns_addr.x_net =
102                                         IA_SNS(ifa)->sns_addr.x_net;
103                                 break;
104                         }
105                 }
106         }
107         nsp->nsp_rpt = idp->idp_pt;
108         if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
109                 m->m_len -= sizeof (struct idp);
110                 m->m_pkthdr.len -= sizeof (struct idp);
111                 m->m_data += sizeof (struct idp);
112         }
113         if (ssb_appendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
114             m, NULL) == 0)
115                 goto bad;
116         sorwakeup(nsp->nsp_socket);
117         return;
118 bad:
119         m_freem(m);
120 }
121
122 void
123 idp_abort(struct nspcb *nsp)
124 {
125         struct socket *so = nsp->nsp_socket;
126
127         soreference(so);
128         ns_pcbdisconnect(nsp);
129         soisdisconnected(so);
130         sofree(so);
131 }
132
133 /*
134  * Drop connection, reporting
135  * the specified error.
136  */
137 void
138 idp_drop(struct nspcb *nsp, int errno)
139 {
140         struct socket *so = nsp->nsp_socket;
141
142         /*
143          * someday, in the xerox world
144          * we will generate error protocol packets
145          * announcing that the socket has gone away.
146          */
147         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
148                 tp->t_state = TCPS_CLOSED;
149                 tcp_output(tp);
150         }*/
151         so->so_error = errno;
152         soreference(so);
153         ns_pcbdisconnect(nsp);
154         soisdisconnected(so);
155         sofree(so);
156 }
157
158 int noIdpRoute;
159
160 int
161 idp_output(struct mbuf *m0, struct socket *so, ...)
162 {
163         struct nspcb *nsp = sotonspcb(so);
164         struct mbuf *m;
165         struct idp *idp;
166         int len = 0;
167         struct route *ro;
168         struct mbuf *mprev = NULL;
169
170         /*
171          * Calculate data length.
172          */
173         for (m = m0; m; m = m->m_next) {
174                 mprev = m;
175                 len += m->m_len;
176         }
177         /*
178          * Make sure packet is actually of even length.
179          */
180
181         if (len & 1) {
182                 m = mprev;
183                 if ((m->m_flags & M_EXT) == 0 &&
184                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
185                         m->m_len++;
186                 } else {
187                         struct mbuf *m1 = m_get(MB_DONTWAIT, MT_DATA);
188
189                         if (m1 == 0) {
190                                 m_freem(m0);
191                                 return (ENOBUFS);
192                         }
193                         m1->m_len = 1;
194                         * mtod(m1, char *) = 0;
195                         m->m_next = m1;
196                 }
197                 m0->m_pkthdr.len++;
198         }
199
200         /*
201          * Fill in mbuf with extended IDP header
202          * and addresses and length put into network format.
203          */
204         m = m0;
205         if (nsp->nsp_flags & NSP_RAWOUT) {
206                 idp = mtod(m, struct idp *);
207         } else {
208                 M_PREPEND(m, sizeof (struct idp), MB_DONTWAIT);
209                 if (m == 0)
210                         return (ENOBUFS);
211                 idp = mtod(m, struct idp *);
212                 idp->idp_tc = 0;
213                 idp->idp_pt = nsp->nsp_dpt;
214                 idp->idp_sna = nsp->nsp_laddr;
215                 idp->idp_dna = nsp->nsp_faddr;
216                 len += sizeof (struct idp);
217         }
218
219         idp->idp_len = htons((u_short)len);
220
221         if (idpcksum) {
222                 idp->idp_sum = 0;
223                 len = ((len - 1) | 1) + 1;
224                 idp->idp_sum = ns_cksum(m, len);
225         } else
226                 idp->idp_sum = 0xffff;
227
228         /*
229          * Output datagram.
230          */
231         if (so->so_options & SO_DONTROUTE)
232                 return (ns_output(m, NULL,
233                     (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
234         /*
235          * Use cached route for previous datagram if
236          * possible.  If the previous net was the same
237          * and the interface was a broadcast medium, or
238          * if the previous destination was identical,
239          * then we are ok.
240          *
241          * NB: We don't handle broadcasts because that
242          *     would require 3 subroutine calls.
243          */
244         ro = &nsp->nsp_route;
245 #ifdef ancient_history
246         /*
247          * I think that this will all be handled in ns_pcbconnect!
248          */
249         if (ro->ro_rt) {
250                 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
251                         /*
252                          * This assumes we have no GH type routes
253                          */
254                         if (ro->ro_rt->rt_flags & RTF_HOST) {
255                                 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
256                                         goto re_route;
257
258                         }
259                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
260                                 struct ns_addr *dst =
261                                                 &satons_addr(ro->ro_dst);
262                                 dst->x_host = idp->idp_dna.x_host;
263                         }
264                         /*
265                          * Otherwise, we go through the same gateway
266                          * and dst is already set up.
267                          */
268                 } else {
269                 re_route:
270                         RTFREE(ro->ro_rt);
271                         ro->ro_rt = NULL;
272                 }
273         }
274         nsp->nsp_lastdst = idp->idp_dna;
275 #endif /* ancient_history */
276         if (noIdpRoute) ro = 0;
277         return (ns_output(m, ro, so->so_options & SO_BROADCAST));
278 }
279
280 /* ARGSUSED */
281 int
282 idp_ctloutput(int req, struct socket *so, int level, int name,
283               struct mbuf **value)
284 {
285         struct mbuf *m;
286         struct nspcb *nsp = sotonspcb(so);
287         int mask, error = 0;
288
289         if (nsp == NULL)
290                 return (EINVAL);
291
292         switch (req) {
293
294         case PRCO_GETOPT:
295                 if (value==NULL)
296                         return (EINVAL);
297                 m = m_get(MB_DONTWAIT, MT_DATA);
298                 if (m==NULL)
299                         return (ENOBUFS);
300                 switch (name) {
301
302                 case SO_ALL_PACKETS:
303                         mask = NSP_ALL_PACKETS;
304                         goto get_flags;
305
306                 case SO_HEADERS_ON_INPUT:
307                         mask = NSP_RAWIN;
308                         goto get_flags;
309
310                 case SO_HEADERS_ON_OUTPUT:
311                         mask = NSP_RAWOUT;
312                 get_flags:
313                         m->m_len = sizeof(short);
314                         *mtod(m, short *) = nsp->nsp_flags & mask;
315                         break;
316
317                 case SO_DEFAULT_HEADERS:
318                         m->m_len = sizeof(struct idp);
319                         {
320                                 struct idp *idp = mtod(m, struct idp *);
321                                 idp->idp_len = 0;
322                                 idp->idp_sum = 0;
323                                 idp->idp_tc = 0;
324                                 idp->idp_pt = nsp->nsp_dpt;
325                                 idp->idp_dna = nsp->nsp_faddr;
326                                 idp->idp_sna = nsp->nsp_laddr;
327                         }
328                         break;
329
330                 case SO_SEQNO:
331                         m->m_len = sizeof(long);
332                         *mtod(m, long *) = ns_pexseq++;
333                         break;
334
335                 default:
336                         error = EINVAL;
337                 }
338                 *value = m;
339                 break;
340
341         case PRCO_SETOPT:
342                 switch (name) {
343                         int *ok;
344
345                 case SO_ALL_PACKETS:
346                         mask = NSP_ALL_PACKETS;
347                         goto set_head;
348
349                 case SO_HEADERS_ON_INPUT:
350                         mask = NSP_RAWIN;
351                         goto set_head;
352
353                 case SO_HEADERS_ON_OUTPUT:
354                         mask = NSP_RAWOUT;
355                 set_head:
356                         if (value && *value) {
357                                 ok = mtod(*value, int *);
358                                 if (*ok)
359                                         nsp->nsp_flags |= mask;
360                                 else
361                                         nsp->nsp_flags &= ~mask;
362                         } else error = EINVAL;
363                         break;
364
365                 case SO_DEFAULT_HEADERS:
366                         {
367                                 struct idp *idp
368                                     = mtod(*value, struct idp *);
369                                 nsp->nsp_dpt = idp->idp_pt;
370                         }
371                         break;
372 #ifdef NSIP
373
374                 case SO_NSIP_ROUTE:
375                         error = nsip_route(*value);
376                         break;
377 #endif /* NSIP */
378                 default:
379                         error = EINVAL;
380                 }
381                 if (value && *value)
382                         m_freem(*value);
383                 break;
384         }
385         return (error);
386 }
387
388
389 /*
390  *  IDP_USRREQ PROCEDURES
391  */
392
393 /*
394  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
395  *      will sofree() it when we return.
396  */
397 static int
398 idp_usr_abort(struct socket *so)
399 {
400         struct nspcb *nsp = sotonspcb(so);
401         int error;
402
403         if (nsp) {
404                 ns_pcbdetach(nsp);
405                 soisdisconnected(so);
406                 error = 0;
407         } else {
408                 error = EINVAL;
409         }
410
411         return(error);
412 }
413
414 static int
415 idp_attach(struct socket *so, int proto, struct pru_attach_info *ai)
416 {
417         struct nspcb *nsp = sotonspcb(so);
418         int error;
419
420         if (nsp != NULL)
421                 return(EINVAL);
422         if ((error = ns_pcballoc(so, &nspcb)) != 0)
423                 return(error);
424         error = soreserve(so, 2048, 2048, ai->sb_rlimit);
425         return(error);
426 }
427
428 static int
429 idp_raw_attach(struct socket *so, int proto, struct pru_attach_info *ai)
430 {
431         struct nspcb *nsp = sotonspcb(so);
432         int error;
433
434 #ifdef NS_PRIV_SOCKETS
435         if ((so->so_state & SS_PRIV) == 0)
436                 return(EINVAL);
437 #endif
438         if (nsp != NULL)
439                 return(EINVAL);
440         if ((error = ns_pcballoc(so, &nsrawpcb)) != 0)
441                 return(error);
442         if ((error = soreserve(so, 2048, 2048, ai->sb_rlimit)) != 0)
443                 return(error);
444         nsp = sotonspcb(so);
445         nsp->nsp_faddr.x_host = ns_broadhost;
446         nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
447         return(0);
448 }
449
450 static int
451 idp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
452 {
453         struct nspcb *nsp = sotonspcb(so);
454         int error;
455
456         if (nsp)
457                 error = ns_pcbbind(nsp, nam);
458         else
459                 error = EINVAL;
460         return(error);
461 }
462
463 static int
464 idp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
465 {
466         struct nspcb *nsp = sotonspcb(so);
467         int error;
468         
469         if (nsp) {
470                 if (!ns_nullhost(nsp->nsp_faddr))
471                         error = EISCONN;
472                 else if ((error = ns_pcbconnect(nsp, nam)) == 0)
473                         soisconnected(so);
474         } else {
475                 error = EINVAL;
476         }
477         return(error);
478 }
479
480 static int
481 idp_detach(struct socket *so)
482 {
483         struct nspcb *nsp = sotonspcb(so);
484         int error;
485
486         if (nsp == NULL) {
487                 error = ENOTCONN;
488         } else {
489                 ns_pcbdetach(nsp);
490                 error = 0;
491         }
492         return(error);
493 }
494
495 static int
496 idp_usr_disconnect(struct socket *so)
497 {
498         struct nspcb *nsp = sotonspcb(so);
499         int error;
500
501         if (nsp) {
502                 if (ns_nullhost(nsp->nsp_faddr)) {
503                         error = ENOTCONN;
504                 } else {
505                         error = 0;
506                         soreference(so);
507                         ns_pcbdisconnect(nsp);
508                         soisdisconnected(so);
509                         sofree(so);
510                 }
511         } else {
512                 error = EINVAL;
513         }
514         return(error);
515 }
516
517 static int
518 idp_peeraddr(struct socket *so, struct sockaddr **pnam)
519 {
520         struct nspcb *nsp = sotonspcb(so);
521         int error;
522
523         if (nsp) {
524                 ns_setpeeraddr(nsp, pnam);
525                 error = 0;
526         } else {
527                 error = EINVAL;
528         }
529         return(error);
530 }
531
532 static int
533 idp_send(struct socket *so, int flags, struct mbuf *m,
534         struct sockaddr *addr, struct mbuf *control,
535         struct thread *td)
536 {
537         struct nspcb *nsp = sotonspcb(so);
538         struct ns_addr laddr;
539         int error;
540
541         if (nsp == NULL)
542                 return(EINVAL);
543         if (control && control->m_len) {
544                 error = EINVAL;
545                 goto release;
546         }
547
548         crit_enter();
549         if (addr) {
550                 laddr = nsp->nsp_laddr;
551                 if (!ns_nullhost(nsp->nsp_faddr))
552                         error = EISCONN;
553                 else
554                         error = ns_pcbconnect(nsp, addr);
555         } else {
556                 if (ns_nullhost(nsp->nsp_faddr))
557                         error = ENOTCONN;
558                 else
559                         error = 0;
560         }
561         if (error == 0) {
562                 error = idp_output(m, so);
563                 m = NULL;
564                 if (addr) {
565                         ns_pcbdisconnect(nsp);
566                         nsp->nsp_laddr.x_host = laddr.x_host;
567                         nsp->nsp_laddr.x_port = laddr.x_port;
568                 }
569         }
570         crit_exit();
571 release:
572         if (control)
573                 m_freem(control);
574         if (m)
575                 m_freem(m);
576         return(error);
577 }
578
579 static int
580 idp_sockaddr(struct socket *so, struct sockaddr **pnam)
581 {
582         struct nspcb *nsp = sotonspcb(so);
583         int error;
584
585         if (nsp) {
586                 ns_setsockaddr(nsp, pnam);
587                 error = 0;
588         } else {
589                 error = EINVAL;
590         }
591         return(error);
592 }
593
594 static int
595 idp_shutdown(struct socket *so)
596 {
597         socantsendmore(so);
598         return(0);
599 }
600
601 struct pr_usrreqs idp_usrreqs = {
602         .pru_abort = idp_usr_abort,
603         .pru_accept = pru_accept_notsupp,
604         .pru_attach = idp_attach,
605         .pru_bind = idp_bind,
606         .pru_connect = idp_connect,
607         .pru_connect2 = pru_connect2_notsupp,
608         .pru_control = ns_control,
609         .pru_detach = idp_detach,
610         .pru_disconnect = idp_usr_disconnect,
611         .pru_listen = pru_listen_notsupp,
612         .pru_peeraddr = idp_peeraddr,
613         .pru_rcvd = pru_rcvd_notsupp,
614         .pru_rcvoob = pru_rcvoob_notsupp,
615         .pru_send = idp_send,
616         .pru_sense = pru_sense_null,
617         .pru_shutdown = idp_shutdown,
618         .pru_sockaddr = idp_sockaddr,
619         .pru_sosend = sosend,
620         .pru_soreceive = soreceive
621 };
622
623 struct pr_usrreqs idp_raw_usrreqs = {
624         .pru_abort = idp_usr_abort,
625         .pru_accept = pru_accept_notsupp,
626         .pru_attach = idp_raw_attach,
627         .pru_bind = idp_bind,
628         .pru_connect = idp_connect,
629         .pru_connect2 = pru_connect2_notsupp,
630         .pru_control = ns_control,
631         .pru_detach = idp_detach,
632         .pru_disconnect = idp_usr_disconnect,
633         .pru_listen = pru_listen_notsupp,
634         .pru_peeraddr = idp_peeraddr,
635         .pru_rcvd = pru_rcvd_notsupp,
636         .pru_rcvoob = pru_rcvoob_notsupp,
637         .pru_send = idp_send,
638         .pru_sense = pru_sense_null,
639         .pru_shutdown = idp_shutdown,
640         .pru_sockaddr = idp_sockaddr,
641         .pru_sosend = sosend,
642         .pru_soreceive = soreceive
643 };
644