Add SATA ATAPI support for AHCI controllers.
[dragonfly.git] / sys / netproto / ns / idp_usrreq.c
blob75217910d903f15f4ce6e1d5169484001741251b
1 /*
2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 * The Regents of the University of California. All rights reserved.
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.
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.
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.14 2007/04/22 01:13:16 dillon Exp $
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>
49 #include <net/if.h>
50 #include <net/route.h>
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"
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 */
63 struct idpstat idpstat;
66 * IDP protocol implementation.
69 struct sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS };
72 * This may also be called for raw listeners.
74 void
75 idp_input(struct mbuf *m, ...)
77 struct idp *idp = mtod(m, struct idp *);
78 struct ifnet *ifp = m->m_pkthdr.rcvif;
79 struct nspcb *nsp;
80 __va_list ap;
82 __va_start(ap, m);
83 nsp = __va_arg(ap, struct nspcb *);
84 __va_end(ap);
86 if (nsp == NULL)
87 panic("No nspcb");
89 * Construct sockaddr format source address.
90 * Stuff source address and datagram in user buffer.
92 idp_ns.sns_addr = idp->idp_sna;
93 if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) {
94 struct ifaddr *ifa;
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;
103 crit_exit();
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);
111 if (ssb_appendaddr(&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);
120 void
121 idp_abort(struct nspcb *nsp)
123 struct socket *so = nsp->nsp_socket;
125 ns_pcbdisconnect(nsp);
126 soisdisconnected(so);
129 * Drop connection, reporting
130 * the specified error.
132 void
133 idp_drop(struct nspcb *nsp, int errno)
135 struct socket *so = nsp->nsp_socket;
138 * someday, in the xerox world
139 * we will generate error protocol packets
140 * announcing that the socket has gone away.
142 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
143 tp->t_state = TCPS_CLOSED;
144 tcp_output(tp);
146 so->so_error = errno;
147 ns_pcbdisconnect(nsp);
148 soisdisconnected(so);
151 int noIdpRoute;
154 idp_output(struct mbuf *m0, struct socket *so, ...)
156 struct nspcb *nsp = sotonspcb(so);
157 struct mbuf *m;
158 struct idp *idp;
159 int len = 0;
160 struct route *ro;
161 struct mbuf *mprev = NULL;
164 * Calculate data length.
166 for (m = m0; m; m = m->m_next) {
167 mprev = m;
168 len += m->m_len;
171 * Make sure packet is actually of even length.
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(MB_DONTWAIT, MT_DATA);
182 if (m1 == 0) {
183 m_freem(m0);
184 return (ENOBUFS);
186 m1->m_len = 1;
187 * mtod(m1, char *) = 0;
188 m->m_next = m1;
190 m0->m_pkthdr.len++;
194 * Fill in mbuf with extended IDP header
195 * and addresses and length put into network format.
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), MB_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);
212 idp->idp_len = htons((u_short)len);
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;
222 * Output datagram.
224 if (so->so_options & SO_DONTROUTE)
225 return (ns_output(m, (struct route *)0,
226 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
228 * Use cached route for previous datagram if
229 * possible. If the previous net was the same
230 * and the interface was a broadcast medium, or
231 * if the previous destination was identical,
232 * then we are ok.
234 * NB: We don't handle broadcasts because that
235 * would require 3 subroutine calls.
237 ro = &nsp->nsp_route;
238 #ifdef ancient_history
240 * I think that this will all be handled in ns_pcbconnect!
242 if (ro->ro_rt) {
243 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
245 * This assumes we have no GH type routes
247 if (ro->ro_rt->rt_flags & RTF_HOST) {
248 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
249 goto re_route;
252 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
253 struct ns_addr *dst =
254 &satons_addr(ro->ro_dst);
255 dst->x_host = idp->idp_dna.x_host;
258 * Otherwise, we go through the same gateway
259 * and dst is already set up.
261 } else {
262 re_route:
263 RTFREE(ro->ro_rt);
264 ro->ro_rt = (struct rtentry *)0;
267 nsp->nsp_lastdst = idp->idp_dna;
268 #endif /* ancient_history */
269 if (noIdpRoute) ro = 0;
270 return (ns_output(m, ro, so->so_options & SO_BROADCAST));
273 /* ARGSUSED */
275 idp_ctloutput(int req, struct socket *so, int level, int name,
276 struct mbuf **value)
278 struct mbuf *m;
279 struct nspcb *nsp = sotonspcb(so);
280 int mask, error = 0;
282 if (nsp == NULL)
283 return (EINVAL);
285 switch (req) {
287 case PRCO_GETOPT:
288 if (value==NULL)
289 return (EINVAL);
290 m = m_get(MB_DONTWAIT, MT_DATA);
291 if (m==NULL)
292 return (ENOBUFS);
293 switch (name) {
295 case SO_ALL_PACKETS:
296 mask = NSP_ALL_PACKETS;
297 goto get_flags;
299 case SO_HEADERS_ON_INPUT:
300 mask = NSP_RAWIN;
301 goto get_flags;
303 case SO_HEADERS_ON_OUTPUT:
304 mask = NSP_RAWOUT;
305 get_flags:
306 m->m_len = sizeof(short);
307 *mtod(m, short *) = nsp->nsp_flags & mask;
308 break;
310 case SO_DEFAULT_HEADERS:
311 m->m_len = sizeof(struct idp);
313 struct idp *idp = mtod(m, struct idp *);
314 idp->idp_len = 0;
315 idp->idp_sum = 0;
316 idp->idp_tc = 0;
317 idp->idp_pt = nsp->nsp_dpt;
318 idp->idp_dna = nsp->nsp_faddr;
319 idp->idp_sna = nsp->nsp_laddr;
321 break;
323 case SO_SEQNO:
324 m->m_len = sizeof(long);
325 *mtod(m, long *) = ns_pexseq++;
326 break;
328 default:
329 error = EINVAL;
331 *value = m;
332 break;
334 case PRCO_SETOPT:
335 switch (name) {
336 int *ok;
338 case SO_ALL_PACKETS:
339 mask = NSP_ALL_PACKETS;
340 goto set_head;
342 case SO_HEADERS_ON_INPUT:
343 mask = NSP_RAWIN;
344 goto set_head;
346 case SO_HEADERS_ON_OUTPUT:
347 mask = NSP_RAWOUT;
348 set_head:
349 if (value && *value) {
350 ok = mtod(*value, int *);
351 if (*ok)
352 nsp->nsp_flags |= mask;
353 else
354 nsp->nsp_flags &= ~mask;
355 } else error = EINVAL;
356 break;
358 case SO_DEFAULT_HEADERS:
360 struct idp *idp
361 = mtod(*value, struct idp *);
362 nsp->nsp_dpt = idp->idp_pt;
364 break;
365 #ifdef NSIP
367 case SO_NSIP_ROUTE:
368 error = nsip_route(*value);
369 break;
370 #endif /* NSIP */
371 default:
372 error = EINVAL;
374 if (value && *value)
375 m_freem(*value);
376 break;
378 return (error);
383 * IDP_USRREQ PROCEDURES
386 static int
387 idp_usr_abort(struct socket *so)
389 struct nspcb *nsp = sotonspcb(so);
390 int error;
392 if (nsp) {
393 ns_pcbdetach(nsp);
394 sofree(so);
395 soisdisconnected(so);
396 error = 0;
397 } else {
398 error = EINVAL;
400 return(error);
403 static int
404 idp_attach(struct socket *so, int proto, struct pru_attach_info *ai)
406 struct nspcb *nsp = sotonspcb(so);
407 int error;
409 if (nsp != NULL)
410 return(EINVAL);
411 if ((error = ns_pcballoc(so, &nspcb)) != 0)
412 return(error);
413 error = soreserve(so, 2048, 2048, ai->sb_rlimit);
414 return(error);
417 static int
418 idp_raw_attach(struct socket *so, int proto, struct pru_attach_info *ai)
420 struct nspcb *nsp = sotonspcb(so);
421 int error;
423 #ifdef NS_PRIV_SOCKETS
424 if ((so->so_state & SS_PRIV) == 0)
425 return(EINVAL);
426 #endif
427 if (nsp != NULL)
428 return(EINVAL);
429 if ((error = ns_pcballoc(so, &nsrawpcb)) != 0)
430 return(error);
431 if ((error = soreserve(so, 2048, 2048, ai->sb_rlimit)) != 0)
432 return(error);
433 nsp = sotonspcb(so);
434 nsp->nsp_faddr.x_host = ns_broadhost;
435 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
436 return(0);
439 static int
440 idp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
442 struct nspcb *nsp = sotonspcb(so);
443 int error;
445 if (nsp)
446 error = ns_pcbbind(nsp, nam);
447 else
448 error = EINVAL;
449 return(error);
452 static int
453 idp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
455 struct nspcb *nsp = sotonspcb(so);
456 int error;
458 if (nsp) {
459 if (!ns_nullhost(nsp->nsp_faddr))
460 error = EISCONN;
461 else if ((error = ns_pcbconnect(nsp, nam)) == 0)
462 soisconnected(so);
463 } else {
464 error = EINVAL;
466 return(error);
469 static int
470 idp_detach(struct socket *so)
472 struct nspcb *nsp = sotonspcb(so);
473 int error;
475 if (nsp == NULL) {
476 error = ENOTCONN;
477 } else {
478 ns_pcbdetach(nsp);
479 error = 0;
481 return(error);
484 static int
485 idp_usr_disconnect(struct socket *so)
487 struct nspcb *nsp = sotonspcb(so);
488 int error;
490 if (nsp) {
491 if (ns_nullhost(nsp->nsp_faddr)) {
492 error = ENOTCONN;
493 } else {
494 error = 0;
495 ns_pcbdisconnect(nsp);
496 soisdisconnected(so);
498 } else {
499 error = EINVAL;
501 return(error);
504 static int
505 idp_peeraddr(struct socket *so, struct sockaddr **pnam)
507 struct nspcb *nsp = sotonspcb(so);
508 int error;
510 if (nsp) {
511 ns_setpeeraddr(nsp, pnam);
512 error = 0;
513 } else {
514 error = EINVAL;
516 return(error);
519 static int
520 idp_send(struct socket *so, int flags, struct mbuf *m,
521 struct sockaddr *addr, struct mbuf *control,
522 struct thread *td)
524 struct nspcb *nsp = sotonspcb(so);
525 struct ns_addr laddr;
526 int error;
528 if (nsp == NULL)
529 return(EINVAL);
530 if (control && control->m_len) {
531 error = EINVAL;
532 goto release;
535 crit_enter();
536 if (addr) {
537 laddr = nsp->nsp_laddr;
538 if (!ns_nullhost(nsp->nsp_faddr))
539 error = EISCONN;
540 else
541 error = ns_pcbconnect(nsp, addr);
542 } else {
543 if (ns_nullhost(nsp->nsp_faddr))
544 error = ENOTCONN;
545 else
546 error = 0;
548 if (error == 0) {
549 error = idp_output(m, so);
550 m = NULL;
551 if (addr) {
552 ns_pcbdisconnect(nsp);
553 nsp->nsp_laddr.x_host = laddr.x_host;
554 nsp->nsp_laddr.x_port = laddr.x_port;
557 crit_exit();
558 release:
559 if (control)
560 m_freem(control);
561 if (m)
562 m_freem(m);
563 return(error);
566 static int
567 idp_sockaddr(struct socket *so, struct sockaddr **pnam)
569 struct nspcb *nsp = sotonspcb(so);
570 int error;
572 if (nsp) {
573 ns_setsockaddr(nsp, pnam);
574 error = 0;
575 } else {
576 error = EINVAL;
578 return(error);
581 static int
582 idp_shutdown(struct socket *so)
584 socantsendmore(so);
585 return(0);
588 struct pr_usrreqs idp_usrreqs = {
589 .pru_abort = idp_usr_abort,
590 .pru_accept = pru_accept_notsupp,
591 .pru_attach = idp_attach,
592 .pru_bind = idp_bind,
593 .pru_connect = idp_connect,
594 .pru_connect2 = pru_connect2_notsupp,
595 .pru_control = ns_control,
596 .pru_detach = idp_detach,
597 .pru_disconnect = idp_usr_disconnect,
598 .pru_listen = pru_listen_notsupp,
599 .pru_peeraddr = idp_peeraddr,
600 .pru_rcvd = pru_rcvd_notsupp,
601 .pru_rcvoob = pru_rcvoob_notsupp,
602 .pru_send = idp_send,
603 .pru_sense = pru_sense_null,
604 .pru_shutdown = idp_shutdown,
605 .pru_sockaddr = idp_sockaddr,
606 .pru_sosend = sosend,
607 .pru_soreceive = soreceive,
608 .pru_sopoll = sopoll
611 struct pr_usrreqs idp_raw_usrreqs = {
612 .pru_abort = idp_usr_abort,
613 .pru_accept = pru_accept_notsupp,
614 .pru_attach = idp_raw_attach,
615 .pru_bind = idp_bind,
616 .pru_connect = idp_connect,
617 .pru_connect2 = pru_connect2_notsupp,
618 .pru_control = ns_control,
619 .pru_detach = idp_detach,
620 .pru_disconnect = idp_usr_disconnect,
621 .pru_listen = pru_listen_notsupp,
622 .pru_peeraddr = idp_peeraddr,
623 .pru_rcvd = pru_rcvd_notsupp,
624 .pru_rcvoob = pru_rcvoob_notsupp,
625 .pru_send = idp_send,
626 .pru_sense = pru_sense_null,
627 .pru_shutdown = idp_shutdown,
628 .pru_sockaddr = idp_sockaddr,
629 .pru_sosend = sosend,
630 .pru_soreceive = soreceive,
631 .pru_sopoll = sopoll