diff options
Diffstat (limited to 'freebsd/netatalk/ddp_usrreq.c')
-rw-r--r-- | freebsd/netatalk/ddp_usrreq.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/freebsd/netatalk/ddp_usrreq.c b/freebsd/netatalk/ddp_usrreq.c new file mode 100644 index 00000000..1d1990c4 --- /dev/null +++ b/freebsd/netatalk/ddp_usrreq.c @@ -0,0 +1,333 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/malloc.h> +#include <freebsd/sys/mbuf.h> +#include <freebsd/sys/socket.h> +#include <freebsd/sys/socketvar.h> +#include <freebsd/sys/protosw.h> +#include <freebsd/net/if.h> +#include <freebsd/net/route.h> +#include <freebsd/net/netisr.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/ddp_var.h> +#include <freebsd/netatalk/ddp_pcb.h> +#include <freebsd/netatalk/at_extern.h> + +static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ +static u_long ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at)); + +static const struct netisr_handler atalk1_nh = { + .nh_name = "atalk1", + .nh_handler = at1intr, + .nh_proto = NETISR_ATALK1, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static const struct netisr_handler atalk2_nh = { + .nh_name = "atalk2", + .nh_handler = at2intr, + .nh_proto = NETISR_ATALK2, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static const struct netisr_handler aarp_nh = { + .nh_name = "aarp", + .nh_handler = aarpintr, + .nh_proto = NETISR_AARP, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static int +ddp_attach(struct socket *so, int proto, struct thread *td) +{ + int error = 0; + + KASSERT(sotoddpcb(so) == NULL, ("ddp_attach: ddp != NULL")); + + /* + * Allocate socket buffer space first so that it's present + * before first use. + */ + error = soreserve(so, ddp_sendspace, ddp_recvspace); + if (error) + return (error); + + DDP_LIST_XLOCK(); + error = at_pcballoc(so); + DDP_LIST_XUNLOCK(); + return (error); +} + +static void +ddp_detach(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + at_pcbdetach(so, ddp); + DDP_LIST_XUNLOCK(); +} + +static int +ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + error = at_pcbsetaddr(ddp, nam, td); + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + return (error); +} + +static int +ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + return (EISCONN); + } + + error = at_pcbconnect( ddp, nam, td ); + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + if (error == 0) + soisconnected(so); + return (error); +} + +static int +ddp_disconnect(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); + + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { + DDP_UNLOCK(ddp); + return (ENOTCONN); + } + + at_pcbdisconnect(ddp); + ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; + DDP_UNLOCK(ddp); + soisdisconnected(so); + return (0); +} + +static int +ddp_shutdown(struct socket *so) +{ + + KASSERT(sotoddpcb(so) != NULL, ("ddp_shutdown: ddp == NULL")); + + socantsendmore(so); + return (0); +} + +static int +ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, + struct mbuf *control, struct thread *td) +{ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); + + if (control && control->m_len) + return (EINVAL); + + if (addr != NULL) { + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { + error = EISCONN; + goto out; + } + + error = at_pcbconnect(ddp, addr, td); + if (error == 0) { + error = ddp_output(m, so); + at_pcbdisconnect(ddp); + } +out: + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + } else { + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) + error = ENOTCONN; + else + error = ddp_output(m, so); + DDP_UNLOCK(ddp); + } + return (error); +} + +/* + * XXXRW: This is never called because we only invoke abort on stream + * protocols. + */ +static void +ddp_abort(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); + + DDP_LOCK(ddp); + at_pcbdisconnect(ddp); + DDP_UNLOCK(ddp); + soisdisconnected(so); +} + +static void +ddp_close(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_close: ddp == NULL")); + + DDP_LOCK(ddp); + at_pcbdisconnect(ddp); + DDP_UNLOCK(ddp); + soisdisconnected(so); +} + +void +ddp_init(void) +{ + + DDP_LIST_LOCK_INIT(); + TAILQ_INIT(&at_ifaddrhead); + netisr_register(&atalk1_nh); + netisr_register(&atalk2_nh); + netisr_register(&aarp_nh); +} + +#if 0 +static void +ddp_clean(void) +{ + struct ddpcp *ddp; + + for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) + at_pcbdetach(ddp->ddp_socket, ddp); + DDP_LIST_LOCK_DESTROY(); +} +#endif + +static int +at_getpeeraddr(struct socket *so, struct sockaddr **nam) +{ + + return (EOPNOTSUPP); +} + +static int +at_getsockaddr(struct socket *so, struct sockaddr **nam) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("at_getsockaddr: ddp == NULL")); + + DDP_LOCK(ddp); + at_sockaddr(ddp, nam); + DDP_UNLOCK(ddp); + return (0); +} + +struct pr_usrreqs ddp_usrreqs = { + .pru_abort = ddp_abort, + .pru_attach = ddp_attach, + .pru_bind = ddp_bind, + .pru_connect = ddp_connect, + .pru_control = at_control, + .pru_detach = ddp_detach, + .pru_disconnect = ddp_disconnect, + .pru_peeraddr = at_getpeeraddr, + .pru_send = ddp_send, + .pru_shutdown = ddp_shutdown, + .pru_sockaddr = at_getsockaddr, + .pru_close = ddp_close, +}; |