More M_NOWAIT -> M_INTWAIT | M_NULLOK conversions, primarily atm and ipsec.
[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.7 2004/03/05 19:17:25 hsu 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
48 #include <net/if.h>
49 #include <net/route.h>
50
51 #include "ns.h"
52 #include "ns_pcb.h"
53 #include "ns_if.h"
54 #include "idp.h"
55 #include "idp_var.h"
56 #include "ns_error.h"
57
58 extern int idpcksum;    /* from ns_input.c */
59 extern long ns_pexseq;  /* from ns_input.c */
60 extern struct nspcb nsrawpcb; /* from ns_input.c */
61
62 struct  idpstat idpstat;
63
64 /*
65  * IDP protocol implementation.
66  */
67
68 struct  sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS };
69
70 /*
71  *  This may also be called for raw listeners.
72  */
73 void
74 idp_input(m, nsp)
75         struct mbuf *m;
76         struct nspcb *nsp;
77 {
78         struct idp *idp = mtod(m, struct idp *);
79         struct ifnet *ifp = m->m_pkthdr.rcvif;
80
81         if (nsp==0)
82                 panic("No nspcb");
83         /*
84          * Construct sockaddr format source address.
85          * Stuff source address and datagram in user buffer.
86          */
87         idp_ns.sns_addr = idp->idp_sna;
88         if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) {
89                 struct ifaddr *ifa;
90                 int s;
91
92                 s = splimp();
93                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
94                         if (ifa->ifa_addr->sa_family == AF_NS) {
95                                 idp_ns.sns_addr.x_net =
96                                         IA_SNS(ifa)->sns_addr.x_net;
97                                 break;
98                         }
99                 splx(s);
100         }
101         nsp->nsp_rpt = idp->idp_pt;
102         if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
103                 m->m_len -= sizeof (struct idp);
104                 m->m_pkthdr.len -= sizeof (struct idp);
105                 m->m_data += sizeof (struct idp);
106         }
107         if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
108             m, (struct mbuf *)0) == 0)
109                 goto bad;
110         sorwakeup(nsp->nsp_socket);
111         return;
112 bad:
113         m_freem(m);
114 }
115
116 void
117 idp_abort(nsp)
118         struct nspcb *nsp;
119 {
120         struct socket *so = nsp->nsp_socket;
121
122         ns_pcbdisconnect(nsp);
123         soisdisconnected(so);
124 }
125 /*
126  * Drop connection, reporting
127  * the specified error.
128  */
129 void
130 idp_drop(nsp, errno)
131         struct nspcb *nsp;
132         int errno;
133 {
134         struct socket *so = nsp->nsp_socket;
135
136         /*
137          * someday, in the xerox world
138          * we will generate error protocol packets
139          * announcing that the socket has gone away.
140          */
141         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
142                 tp->t_state = TCPS_CLOSED;
143                 (void) tcp_output(tp);
144         }*/
145         so->so_error = errno;
146         ns_pcbdisconnect(nsp);
147         soisdisconnected(so);
148 }
149
150 int noIdpRoute;
151
152 int
153 idp_output(nsp, m0)
154         struct nspcb *nsp;
155         struct mbuf *m0;
156 {
157         struct mbuf *m;
158         struct idp *idp;
159         struct socket *so;
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(M_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), M_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         so = nsp->nsp_socket;
226         if (so->so_options & SO_DONTROUTE)
227                 return (ns_output(m, (struct route *)0,
228                     (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
229         /*
230          * Use cached route for previous datagram if
231          * possible.  If the previous net was the same
232          * and the interface was a broadcast medium, or
233          * if the previous destination was identical,
234          * then we are ok.
235          *
236          * NB: We don't handle broadcasts because that
237          *     would require 3 subroutine calls.
238          */
239         ro = &nsp->nsp_route;
240 #ifdef ancient_history
241         /*
242          * I think that this will all be handled in ns_pcbconnect!
243          */
244         if (ro->ro_rt) {
245                 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
246                         /*
247                          * This assumes we have no GH type routes
248                          */
249                         if (ro->ro_rt->rt_flags & RTF_HOST) {
250                                 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
251                                         goto re_route;
252
253                         }
254                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
255                                 struct ns_addr *dst =
256                                                 &satons_addr(ro->ro_dst);
257                                 dst->x_host = idp->idp_dna.x_host;
258                         }
259                         /*
260                          * Otherwise, we go through the same gateway
261                          * and dst is already set up.
262                          */
263                 } else {
264                 re_route:
265                         RTFREE(ro->ro_rt);
266                         ro->ro_rt = (struct rtentry *)0;
267                 }
268         }
269         nsp->nsp_lastdst = idp->idp_dna;
270 #endif /* ancient_history */
271         if (noIdpRoute) ro = 0;
272         return (ns_output(m, ro, so->so_options & SO_BROADCAST));
273 }
274
275 /* ARGSUSED */
276 int
277 idp_ctloutput(req, so, level, name, value)
278         int req, level;
279         struct socket *so;
280         int name;
281         struct mbuf **value;
282 {
283         struct mbuf *m;
284         struct nspcb *nsp = sotonspcb(so);
285         int mask, error = 0;
286
287         if (nsp == NULL)
288                 return (EINVAL);
289
290         switch (req) {
291
292         case PRCO_GETOPT:
293                 if (value==NULL)
294                         return (EINVAL);
295                 m = m_get(M_DONTWAIT, MT_DATA);
296                 if (m==NULL)
297                         return (ENOBUFS);
298                 switch (name) {
299
300                 case SO_ALL_PACKETS:
301                         mask = NSP_ALL_PACKETS;
302                         goto get_flags;
303
304                 case SO_HEADERS_ON_INPUT:
305                         mask = NSP_RAWIN;
306                         goto get_flags;
307
308                 case SO_HEADERS_ON_OUTPUT:
309                         mask = NSP_RAWOUT;
310                 get_flags:
311                         m->m_len = sizeof(short);
312                         *mtod(m, short *) = nsp->nsp_flags & mask;
313                         break;
314
315                 case SO_DEFAULT_HEADERS:
316                         m->m_len = sizeof(struct idp);
317                         {
318                                 struct idp *idp = mtod(m, struct idp *);
319                                 idp->idp_len = 0;
320                                 idp->idp_sum = 0;
321                                 idp->idp_tc = 0;
322                                 idp->idp_pt = nsp->nsp_dpt;
323                                 idp->idp_dna = nsp->nsp_faddr;
324                                 idp->idp_sna = nsp->nsp_laddr;
325                         }
326                         break;
327
328                 case SO_SEQNO:
329                         m->m_len = sizeof(long);
330                         *mtod(m, long *) = ns_pexseq++;
331                         break;
332
333                 default:
334                         error = EINVAL;
335                 }
336                 *value = m;
337                 break;
338
339         case PRCO_SETOPT:
340                 switch (name) {
341                         int *ok;
342
343                 case SO_ALL_PACKETS:
344                         mask = NSP_ALL_PACKETS;
345                         goto set_head;
346
347                 case SO_HEADERS_ON_INPUT:
348                         mask = NSP_RAWIN;
349                         goto set_head;
350
351                 case SO_HEADERS_ON_OUTPUT:
352                         mask = NSP_RAWOUT;
353                 set_head:
354                         if (value && *value) {
355                                 ok = mtod(*value, int *);
356                                 if (*ok)
357                                         nsp->nsp_flags |= mask;
358                                 else
359                                         nsp->nsp_flags &= ~mask;
360                         } else error = EINVAL;
361                         break;
362
363                 case SO_DEFAULT_HEADERS:
364                         {
365                                 struct idp *idp
366                                     = mtod(*value, struct idp *);
367                                 nsp->nsp_dpt = idp->idp_pt;
368                         }
369                         break;
370 #ifdef NSIP
371
372                 case SO_NSIP_ROUTE:
373                         error = nsip_route(*value);
374                         break;
375 #endif /* NSIP */
376                 default:
377                         error = EINVAL;
378                 }
379                 if (value && *value)
380                         m_freem(*value);
381                 break;
382         }
383         return (error);
384 }
385
386 /*ARGSUSED*/
387 int
388 idp_usrreq(so, req, m, nam, control)
389         struct socket *so;
390         int req;
391         struct mbuf *m, *nam, *control;
392 {
393 #ifdef OBSOLETE         /* not converted to new FreeBSD usrreq style XXX */
394         struct nspcb *nsp = sotonspcb(so);
395         int error = 0;
396
397         if (req == PRU_CONTROL)
398                 return (ns_control(so, (int)m, (caddr_t)nam,
399                         (struct ifnet *)control));
400         if (control && control->m_len) {
401                 error = EINVAL;
402                 goto release;
403         }
404         if (nsp == NULL && req != PRU_ATTACH) {
405                 error = EINVAL;
406                 goto release;
407         }
408         switch (req) {
409
410         case PRU_ATTACH:
411                 if (nsp != NULL) {
412                         error = EINVAL;
413                         break;
414                 }
415                 error = ns_pcballoc(so, &nspcb);
416                 if (error)
417                         break;
418                 error = soreserve(so, (u_long) 2048, (u_long) 2048);
419                 if (error)
420                         break;
421                 break;
422
423         case PRU_DETACH:
424                 if (nsp == NULL) {
425                         error = ENOTCONN;
426                         break;
427                 }
428                 ns_pcbdetach(nsp);
429                 break;
430
431         case PRU_BIND:
432                 error = ns_pcbbind(nsp, nam);
433                 break;
434
435         case PRU_LISTEN:
436                 error = EOPNOTSUPP;
437                 break;
438
439         case PRU_CONNECT:
440                 if (!ns_nullhost(nsp->nsp_faddr)) {
441                         error = EISCONN;
442                         break;
443                 }
444                 error = ns_pcbconnect(nsp, nam);
445                 if (error == 0)
446                         soisconnected(so);
447                 break;
448
449         case PRU_CONNECT2:
450                 error = EOPNOTSUPP;
451                 break;
452
453         case PRU_ACCEPT:
454                 error = EOPNOTSUPP;
455                 break;
456
457         case PRU_DISCONNECT:
458                 if (ns_nullhost(nsp->nsp_faddr)) {
459                         error = ENOTCONN;
460                         break;
461                 }
462                 ns_pcbdisconnect(nsp);
463                 soisdisconnected(so);
464                 break;
465
466         case PRU_SHUTDOWN:
467                 socantsendmore(so);
468                 break;
469
470         case PRU_SEND:
471         {
472                 struct ns_addr laddr;
473                 int s = -1; /* XXX compiler warns improperly */
474
475                 if (nam) {
476                         laddr = nsp->nsp_laddr;
477                         if (!ns_nullhost(nsp->nsp_faddr)) {
478                                 error = EISCONN;
479                                 break;
480                         }
481                         /*
482                          * Must block input while temporarily connected.
483                          */
484                         s = splnet();
485                         error = ns_pcbconnect(nsp, nam);
486                         if (error) {
487                                 splx(s);
488                                 break;
489                         }
490                 } else {
491                         if (ns_nullhost(nsp->nsp_faddr)) {
492                                 error = ENOTCONN;
493                                 break;
494                         }
495                 }
496                 error = idp_output(nsp, m);
497                 m = NULL;
498                 if (nam) {
499                         ns_pcbdisconnect(nsp);
500                         splx(s);
501                         nsp->nsp_laddr.x_host = laddr.x_host;
502                         nsp->nsp_laddr.x_port = laddr.x_port;
503                 }
504         }
505                 break;
506
507         case PRU_ABORT:
508                 ns_pcbdetach(nsp);
509                 sofree(so);
510                 soisdisconnected(so);
511                 break;
512
513         case PRU_SOCKADDR:
514                 ns_setsockaddr(nsp, nam);
515                 break;
516
517         case PRU_PEERADDR:
518                 ns_setpeeraddr(nsp, nam);
519                 break;
520
521         case PRU_SENSE:
522                 /*
523                  * stat: don't bother with a blocksize.
524                  */
525                 return (0);
526
527         case PRU_SENDOOB:
528         case PRU_FASTTIMO:
529         case PRU_SLOWTIMO:
530         case PRU_PROTORCV:
531         case PRU_PROTOSEND:
532                 error =  EOPNOTSUPP;
533                 break;
534
535         case PRU_CONTROL:
536         case PRU_RCVD:
537         case PRU_RCVOOB:
538                 return (EOPNOTSUPP);    /* do not free mbuf's */
539
540         default:
541                 panic("idp_usrreq");
542         }
543 release:
544         if (control != NULL)
545                 m_freem(control);
546         if (m != NULL)
547                 m_freem(m);
548         return (error);
549 #endif
550         return (0);
551 }
552 /*ARGSUSED*/
553 int
554 idp_raw_usrreq(so, req, m, nam, control)
555         struct socket *so;
556         int req;
557         struct mbuf *m, *nam, *control;
558 {
559         int error = 0;
560 #ifdef OBSOLETE         /* not converted to new FreeBSD usrreq style XXX */
561         struct nspcb *nsp = sotonspcb(so);
562
563         switch (req) {
564
565         case PRU_ATTACH:
566
567 #ifdef NS_PRIV_SOCKETS
568                 if (!(so->so_state & SS_PRIV) || (nsp != NULL)) {
569                         error = EINVAL;
570                         break;
571                 }
572 #endif
573
574                 error = ns_pcballoc(so, &nsrawpcb);
575                 if (error)
576                         break;
577                 error = soreserve(so, (u_long) 2048, (u_long) 2048);
578                 if (error)
579                         break;
580                 nsp = sotonspcb(so);
581                 nsp->nsp_faddr.x_host = ns_broadhost;
582                 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
583                 break;
584         default:
585                 error = idp_usrreq(so, req, m, nam, control);
586         }
587 #endif
588         return (error);
589 }
590