add the 'y' and 'Y' options to ps, and add the 'iac' keyword. The 'y'
[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.9 2004/06/07 07:04:33 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
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(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         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(MB_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
387 /*
388  *  IDP_USRREQ PROCEDURES
389  */
390
391 static int
392 idp_usr_abort(struct socket *so)
393 {
394         struct nspcb *nsp = sotonspcb(so);
395         int error;
396
397         if (nsp) {
398                 ns_pcbdetach(nsp);
399                 sofree(so);
400                 soisdisconnected(so);
401                 error = 0;
402         } else {
403                 error = EINVAL;
404         }
405         return(error);
406 }
407
408 static int
409 idp_attach(struct socket *so, int proto, struct pru_attach_info *ai)
410 {
411         struct nspcb *nsp = sotonspcb(so);
412         int error;
413
414         if (nsp != NULL)
415                 return(EINVAL);
416         if ((error = ns_pcballoc(so, &nspcb)) != 0)
417                 return(error);
418         error = soreserve(so, 2048, 2048, ai->sb_rlimit);
419         return(error);
420 }
421
422 static int
423 idp_raw_attach(struct socket *so, int proto, struct pru_attach_info *ai)
424 {
425         struct nspcb *nsp = sotonspcb(so);
426         int error;
427
428 #ifdef NS_PRIV_SOCKETS
429         if ((so->so_state & SS_PRIV) == 0)
430                 return(EINVAL);
431 #endif
432         if (nsp != NULL)
433                 return(EINVAL);
434         if ((error = ns_pcballoc(so, &nsrawpcb)) != 0)
435                 return(error);
436         if ((error = soreserve(so, 2048, 2048, ai->sb_rlimit)) != 0)
437                 return(error);
438         nsp = sotonspcb(so);
439         nsp->nsp_faddr.x_host = ns_broadhost;
440         nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
441         return(0);
442 }
443
444 static int
445 idp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
446 {
447         struct nspcb *nsp = sotonspcb(so);
448         int error;
449
450         if (nsp)
451                 error = ns_pcbbind(nsp, nam);
452         else
453                 error = EINVAL;
454         return(error);
455 }
456
457 static int
458 idp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
459 {
460         struct nspcb *nsp = sotonspcb(so);
461         int error;
462         
463         if (nsp) {
464                 if (!ns_nullhost(nsp->nsp_faddr))
465                         error = EISCONN;
466                 else if ((error = ns_pcbconnect(nsp, nam)) == 0)
467                         soisconnected(so);
468         } else {
469                 error = EINVAL;
470         }
471         return(error);
472 }
473
474 static int
475 idp_detach(struct socket *so)
476 {
477         struct nspcb *nsp = sotonspcb(so);
478         int error;
479
480         if (nsp == NULL) {
481                 error = ENOTCONN;
482         } else {
483                 ns_pcbdetach(nsp);
484                 error = 0;
485         }
486         return(error);
487 }
488
489 static int
490 idp_usr_disconnect(struct socket *so)
491 {
492         struct nspcb *nsp = sotonspcb(so);
493         int error;
494
495         if (nsp) {
496                 if (ns_nullhost(nsp->nsp_faddr)) {
497                         error = ENOTCONN;
498                 } else {
499                         error = 0;
500                         ns_pcbdisconnect(nsp);
501                         soisdisconnected(so);
502                 }
503         } else {
504                 error = EINVAL;
505         }
506         return(error);
507 }
508
509 static int
510 idp_peeraddr(struct socket *so, struct sockaddr **pnam)
511 {
512         struct nspcb *nsp = sotonspcb(so);
513         int error;
514
515         if (nsp) {
516                 ns_setpeeraddr(nsp, pnam);
517                 error = 0;
518         } else {
519                 error = EINVAL;
520         }
521         return(error);
522 }
523
524 static int
525 idp_send(struct socket *so, int flags, struct mbuf *m,
526         struct sockaddr *addr, struct mbuf *control,
527         struct thread *td)
528 {
529         struct nspcb *nsp = sotonspcb(so);
530         struct ns_addr laddr;
531         int error;
532         int s;
533
534         if (nsp == NULL)
535                 return(EINVAL);
536         if (control && control->m_len) {
537                 error = EINVAL;
538                 goto release;
539         }
540
541         s = splnet();
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(nsp, m);
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         splx(s);
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