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