Merge from vendor branch BINUTILS:
[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.5 2003/09/06 21:51:12 drhodus 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 /*
63  * IDP protocol implementation.
64  */
65
66 struct  sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS };
67
68 /*
69  *  This may also be called for raw listeners.
70  */
71 void
72 idp_input(m, nsp)
73         struct mbuf *m;
74         struct nspcb *nsp;
75 {
76         struct idp *idp = mtod(m, struct idp *);
77         struct ifnet *ifp = m->m_pkthdr.rcvif;
78
79         if (nsp==0)
80                 panic("No nspcb");
81         /*
82          * Construct sockaddr format source address.
83          * Stuff source address and datagram in user buffer.
84          */
85         idp_ns.sns_addr = idp->idp_sna;
86         if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) {
87                 struct ifaddr *ifa;
88                 int s;
89
90                 s = splimp();
91                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
92                         if (ifa->ifa_addr->sa_family == AF_NS) {
93                                 idp_ns.sns_addr.x_net =
94                                         IA_SNS(ifa)->sns_addr.x_net;
95                                 break;
96                         }
97                 splx(s);
98         }
99         nsp->nsp_rpt = idp->idp_pt;
100         if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
101                 m->m_len -= sizeof (struct idp);
102                 m->m_pkthdr.len -= sizeof (struct idp);
103                 m->m_data += sizeof (struct idp);
104         }
105         if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns,
106             m, (struct mbuf *)0) == 0)
107                 goto bad;
108         sorwakeup(nsp->nsp_socket);
109         return;
110 bad:
111         m_freem(m);
112 }
113
114 void
115 idp_abort(nsp)
116         struct nspcb *nsp;
117 {
118         struct socket *so = nsp->nsp_socket;
119
120         ns_pcbdisconnect(nsp);
121         soisdisconnected(so);
122 }
123 /*
124  * Drop connection, reporting
125  * the specified error.
126  */
127 struct nspcb *
128 idp_drop(nsp, errno)
129         struct nspcb *nsp;
130         int errno;
131 {
132         struct socket *so = nsp->nsp_socket;
133
134         /*
135          * someday, in the xerox world
136          * we will generate error protocol packets
137          * announcing that the socket has gone away.
138          */
139         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
140                 tp->t_state = TCPS_CLOSED;
141                 (void) tcp_output(tp);
142         }*/
143         so->so_error = errno;
144         ns_pcbdisconnect(nsp);
145         soisdisconnected(so);
146 }
147
148 int noIdpRoute;
149
150 int
151 idp_output(nsp, m0)
152         struct nspcb *nsp;
153         struct mbuf *m0;
154 {
155         struct mbuf *m;
156         struct idp *idp;
157         struct socket *so;
158         int len = 0;
159         struct route *ro;
160         struct mbuf *mprev = NULL;
161         extern int idpcksum;
162
163         /*
164          * Calculate data length.
165          */
166         for (m = m0; m; m = m->m_next) {
167                 mprev = m;
168                 len += m->m_len;
169         }
170         /*
171          * Make sure packet is actually of even length.
172          */
173
174         if (len & 1) {
175                 m = mprev;
176                 if ((m->m_flags & M_EXT) == 0 &&
177                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
178                         m->m_len++;
179                 } else {
180                         struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
181
182                         if (m1 == 0) {
183                                 m_freem(m0);
184                                 return (ENOBUFS);
185                         }
186                         m1->m_len = 1;
187                         * mtod(m1, char *) = 0;
188                         m->m_next = m1;
189                 }
190                 m0->m_pkthdr.len++;
191         }
192
193         /*
194          * Fill in mbuf with extended IDP header
195          * and addresses and length put into network format.
196          */
197         m = m0;
198         if (nsp->nsp_flags & NSP_RAWOUT) {
199                 idp = mtod(m, struct idp *);
200         } else {
201                 M_PREPEND(m, sizeof (struct idp), M_DONTWAIT);
202                 if (m == 0)
203                         return (ENOBUFS);
204                 idp = mtod(m, struct idp *);
205                 idp->idp_tc = 0;
206                 idp->idp_pt = nsp->nsp_dpt;
207                 idp->idp_sna = nsp->nsp_laddr;
208                 idp->idp_dna = nsp->nsp_faddr;
209                 len += sizeof (struct idp);
210         }
211
212         idp->idp_len = htons((u_short)len);
213
214         if (idpcksum) {
215                 idp->idp_sum = 0;
216                 len = ((len - 1) | 1) + 1;
217                 idp->idp_sum = ns_cksum(m, len);
218         } else
219                 idp->idp_sum = 0xffff;
220
221         /*
222          * Output datagram.
223          */
224         so = nsp->nsp_socket;
225         if (so->so_options & SO_DONTROUTE)
226                 return (ns_output(m, (struct route *)0,
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 = (struct rtentry *)0;
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(req, so, level, name, value)
277         int req, level;
278         struct socket *so;
279         int name;
280         struct mbuf **value;
281 {
282         struct mbuf *m;
283         struct nspcb *nsp = sotonspcb(so);
284         int mask, error = 0;
285
286         if (nsp == NULL)
287                 return (EINVAL);
288
289         switch (req) {
290
291         case PRCO_GETOPT:
292                 if (value==NULL)
293                         return (EINVAL);
294                 m = m_get(M_DONTWAIT, MT_DATA);
295                 if (m==NULL)
296                         return (ENOBUFS);
297                 switch (name) {
298
299                 case SO_ALL_PACKETS:
300                         mask = NSP_ALL_PACKETS;
301                         goto get_flags;
302
303                 case SO_HEADERS_ON_INPUT:
304                         mask = NSP_RAWIN;
305                         goto get_flags;
306
307                 case SO_HEADERS_ON_OUTPUT:
308                         mask = NSP_RAWOUT;
309                 get_flags:
310                         m->m_len = sizeof(short);
311                         *mtod(m, short *) = nsp->nsp_flags & mask;
312                         break;
313
314                 case SO_DEFAULT_HEADERS:
315                         m->m_len = sizeof(struct idp);
316                         {
317                                 struct idp *idp = mtod(m, struct idp *);
318                                 idp->idp_len = 0;
319                                 idp->idp_sum = 0;
320                                 idp->idp_tc = 0;
321                                 idp->idp_pt = nsp->nsp_dpt;
322                                 idp->idp_dna = nsp->nsp_faddr;
323                                 idp->idp_sna = nsp->nsp_laddr;
324                         }
325                         break;
326
327                 case SO_SEQNO:
328                         m->m_len = sizeof(long);
329                         *mtod(m, long *) = ns_pexseq++;
330                         break;
331
332                 default:
333                         error = EINVAL;
334                 }
335                 *value = m;
336                 break;
337
338         case PRCO_SETOPT:
339                 switch (name) {
340                         int *ok;
341
342                 case SO_ALL_PACKETS:
343                         mask = NSP_ALL_PACKETS;
344                         goto set_head;
345
346                 case SO_HEADERS_ON_INPUT:
347                         mask = NSP_RAWIN;
348                         goto set_head;
349
350                 case SO_HEADERS_ON_OUTPUT:
351                         mask = NSP_RAWOUT;
352                 set_head:
353                         if (value && *value) {
354                                 ok = mtod(*value, int *);
355                                 if (*ok)
356                                         nsp->nsp_flags |= mask;
357                                 else
358                                         nsp->nsp_flags &= ~mask;
359                         } else error = EINVAL;
360                         break;
361
362                 case SO_DEFAULT_HEADERS:
363                         {
364                                 struct idp *idp
365                                     = mtod(*value, struct idp *);
366                                 nsp->nsp_dpt = idp->idp_pt;
367                         }
368                         break;
369 #ifdef NSIP
370
371                 case SO_NSIP_ROUTE:
372                         error = nsip_route(*value);
373                         break;
374 #endif /* NSIP */
375                 default:
376                         error = EINVAL;
377                 }
378                 if (value && *value)
379                         m_freem(*value);
380                 break;
381         }
382         return (error);
383 }
384
385 /*ARGSUSED*/
386 int
387 idp_usrreq(so, req, m, nam, control)
388         struct socket *so;
389         int req;
390         struct mbuf *m, *nam, *control;
391 {
392         struct nspcb *nsp = sotonspcb(so);
393         int error = 0;
394
395         if (req == PRU_CONTROL)
396                 return (ns_control(so, (int)m, (caddr_t)nam,
397                         (struct ifnet *)control));
398         if (control && control->m_len) {
399                 error = EINVAL;
400                 goto release;
401         }
402         if (nsp == NULL && req != PRU_ATTACH) {
403                 error = EINVAL;
404                 goto release;
405         }
406         switch (req) {
407
408         case PRU_ATTACH:
409                 if (nsp != NULL) {
410                         error = EINVAL;
411                         break;
412                 }
413                 error = ns_pcballoc(so, &nspcb);
414                 if (error)
415                         break;
416                 error = soreserve(so, (u_long) 2048, (u_long) 2048);
417                 if (error)
418                         break;
419                 break;
420
421         case PRU_DETACH:
422                 if (nsp == NULL) {
423                         error = ENOTCONN;
424                         break;
425                 }
426                 ns_pcbdetach(nsp);
427                 break;
428
429         case PRU_BIND:
430                 error = ns_pcbbind(nsp, nam);
431                 break;
432
433         case PRU_LISTEN:
434                 error = EOPNOTSUPP;
435                 break;
436
437         case PRU_CONNECT:
438                 if (!ns_nullhost(nsp->nsp_faddr)) {
439                         error = EISCONN;
440                         break;
441                 }
442                 error = ns_pcbconnect(nsp, nam);
443                 if (error == 0)
444                         soisconnected(so);
445                 break;
446
447         case PRU_CONNECT2:
448                 error = EOPNOTSUPP;
449                 break;
450
451         case PRU_ACCEPT:
452                 error = EOPNOTSUPP;
453                 break;
454
455         case PRU_DISCONNECT:
456                 if (ns_nullhost(nsp->nsp_faddr)) {
457                         error = ENOTCONN;
458                         break;
459                 }
460                 ns_pcbdisconnect(nsp);
461                 soisdisconnected(so);
462                 break;
463
464         case PRU_SHUTDOWN:
465                 socantsendmore(so);
466                 break;
467
468         case PRU_SEND:
469         {
470                 struct ns_addr laddr;
471                 int s = -1; /* XXX compiler warns improperly */
472
473                 if (nam) {
474                         laddr = nsp->nsp_laddr;
475                         if (!ns_nullhost(nsp->nsp_faddr)) {
476                                 error = EISCONN;
477                                 break;
478                         }
479                         /*
480                          * Must block input while temporarily connected.
481                          */
482                         s = splnet();
483                         error = ns_pcbconnect(nsp, nam);
484                         if (error) {
485                                 splx(s);
486                                 break;
487                         }
488                 } else {
489                         if (ns_nullhost(nsp->nsp_faddr)) {
490                                 error = ENOTCONN;
491                                 break;
492                         }
493                 }
494                 error = idp_output(nsp, m);
495                 m = NULL;
496                 if (nam) {
497                         ns_pcbdisconnect(nsp);
498                         splx(s);
499                         nsp->nsp_laddr.x_host = laddr.x_host;
500                         nsp->nsp_laddr.x_port = laddr.x_port;
501                 }
502         }
503                 break;
504
505         case PRU_ABORT:
506                 ns_pcbdetach(nsp);
507                 sofree(so);
508                 soisdisconnected(so);
509                 break;
510
511         case PRU_SOCKADDR:
512                 ns_setsockaddr(nsp, nam);
513                 break;
514
515         case PRU_PEERADDR:
516                 ns_setpeeraddr(nsp, nam);
517                 break;
518
519         case PRU_SENSE:
520                 /*
521                  * stat: don't bother with a blocksize.
522                  */
523                 return (0);
524
525         case PRU_SENDOOB:
526         case PRU_FASTTIMO:
527         case PRU_SLOWTIMO:
528         case PRU_PROTORCV:
529         case PRU_PROTOSEND:
530                 error =  EOPNOTSUPP;
531                 break;
532
533         case PRU_CONTROL:
534         case PRU_RCVD:
535         case PRU_RCVOOB:
536                 return (EOPNOTSUPP);    /* do not free mbuf's */
537
538         default:
539                 panic("idp_usrreq");
540         }
541 release:
542         if (control != NULL)
543                 m_freem(control);
544         if (m != NULL)
545                 m_freem(m);
546         return (error);
547 }
548 /*ARGSUSED*/
549 int
550 idp_raw_usrreq(so, req, m, nam, control)
551         struct socket *so;
552         int req;
553         struct mbuf *m, *nam, *control;
554 {
555         int error = 0;
556         struct nspcb *nsp = sotonspcb(so);
557
558         switch (req) {
559
560         case PRU_ATTACH:
561
562 #ifdef NS_PRIV_SOCKETS
563                 if (!(so->so_state & SS_PRIV) || (nsp != NULL)) {
564                         error = EINVAL;
565                         break;
566                 }
567 #endif
568
569                 error = ns_pcballoc(so, &nsrawpcb);
570                 if (error)
571                         break;
572                 error = soreserve(so, (u_long) 2048, (u_long) 2048);
573                 if (error)
574                         break;
575                 nsp = sotonspcb(so);
576                 nsp->nsp_faddr.x_host = ns_broadhost;
577                 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
578                 break;
579         default:
580                 error = idp_usrreq(so, req, m, nam, control);
581         }
582         return (error);
583 }
584