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