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