diff options
Diffstat (limited to 'sys/netatm/atm_aal5.c')
-rw-r--r-- | sys/netatm/atm_aal5.c | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/sys/netatm/atm_aal5.c b/sys/netatm/atm_aal5.c new file mode 100644 index 000000000000..c0e8fe49fd02 --- /dev/null +++ b/sys/netatm/atm_aal5.c @@ -0,0 +1,905 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: atm_aal5.c,v 1.4 1998/07/30 22:30:46 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM AAL5 socket protocol processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_aal5.c,v 1.4 1998/07/30 22:30:46 mks Exp $"; +#endif + +#include <netatm/kern_include.h> +#include <sys/stat.h> + + +/* + * Global variables + */ +u_long atm_aal5_sendspace = 64 * 1024; /* XXX */ +u_long atm_aal5_recvspace = 64 * 1024; /* XXX */ + + +/* + * Local functions + */ +static int atm_aal5_attach __P((struct socket *, int, struct proc *)); +static int atm_aal5_detach __P((struct socket *)); +static int atm_aal5_bind __P((struct socket *, struct sockaddr *, + struct proc *)); +static int atm_aal5_listen __P((struct socket *, struct proc *)); +static int atm_aal5_connect __P((struct socket *, struct sockaddr *, + struct proc *)); +static int atm_aal5_accept __P((struct socket *, struct sockaddr **)); +static int atm_aal5_disconnect __P((struct socket *)); +static int atm_aal5_shutdown __P((struct socket *)); +static int atm_aal5_send __P((struct socket *, int, KBuffer *, + struct sockaddr *, KBuffer *, struct proc *)); +static int atm_aal5_abort __P((struct socket *)); +static int atm_aal5_control __P((struct socket *, u_long, caddr_t, + struct ifnet *, struct proc *)); +static int atm_aal5_sense __P((struct socket *, struct stat *)); +static int atm_aal5_sockaddr __P((struct socket *, struct sockaddr **)); +static int atm_aal5_peeraddr __P((struct socket *, struct sockaddr **)); +static int atm_aal5_incoming __P((void *, Atm_connection *, + Atm_attributes *, void **)); +static void atm_aal5_cpcs_data __P((void *, KBuffer *)); +static caddr_t atm_aal5_getname __P((void *)); + + +#if (defined(__FreeBSD__) && (BSD >= 199506)) +/* + * New-style socket request routines + */ +struct pr_usrreqs atm_aal5_usrreqs = { + atm_aal5_abort, /* pru_abort */ + atm_aal5_accept, /* pru_accept */ + atm_aal5_attach, /* pru_attach */ + atm_aal5_bind, /* pru_bind */ + atm_aal5_connect, /* pru_connect */ + pru_connect2_notsupp, /* pru_connect2 */ + atm_aal5_control, /* pru_control */ + atm_aal5_detach, /* pru_detach */ + atm_aal5_disconnect, /* pru_disconnect */ + atm_aal5_listen, /* pru_listen */ + atm_aal5_peeraddr, /* pru_peeraddr */ + pru_rcvd_notsupp, /* pru_rcvd */ + pru_rcvoob_notsupp, /* pru_rcvoob */ + atm_aal5_send, /* pru_send */ + atm_aal5_sense, /* pru_sense */ + atm_aal5_shutdown, /* pru_shutdown */ + atm_aal5_sockaddr, /* pru_sockaddr */ + sosend, /* pru_sosend */ + soreceive, /* pru_soreceive */ + sopoll /* pru_sopoll */ +}; +#endif + + +/* + * Local variables + */ +static Atm_endpoint atm_aal5_endpt = { + NULL, + ENDPT_SOCK_AAL5, + NULL, + atm_aal5_getname, + atm_sock_connected, + atm_sock_cleared, + atm_aal5_incoming, + NULL, + NULL, + NULL, + atm_aal5_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +static Atm_attributes atm_aal5_defattr = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_ABSENT, + }, + { /* bearer */ + T_ATM_ABSENT, + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT, + }, + { /* llc */ + T_ATM_ABSENT, + }, + { /* called */ + T_ATM_ABSENT, + { + T_ATM_ABSENT, + 0 + }, + { + T_ATM_ABSENT, + 0 + } + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_ABSENT, + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + + +/* + * Handy common code macros + */ +#ifdef DIAGNOSTIC +#define ATM_INTRO(f) \ + int s, err = 0; \ + s = splnet(); \ + ATM_DEBUG2("aal5 socket %s (0x%x)\n", f, (int)so); \ + /* \ + * Stack queue should have been drained \ + */ \ + if (atm_stackq_head != NULL) \ + panic("atm_aal5: stack queue not empty"); \ + ; +#else +#define ATM_INTRO(f) \ + int s, err = 0; \ + s = splnet(); \ + ; +#endif + +#define ATM_OUTRO() \ +out: \ + /* \ + * Drain any deferred calls \ + */ \ + STACK_DRAIN(); \ + (void) splx(s); \ + return (err); \ + ; + +#define ATM_RETERR(errno) { \ + err = errno; \ + goto out; \ +} + + +/* + * Attach protocol to socket + * + * Arguments: + * so pointer to socket + * proto protocol identifier + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_attach(so, proto, p) + struct socket *so; + int proto; + struct proc *p; +{ + Atm_pcb *atp; + + ATM_INTRO("attach"); + + /* + * Do general attach stuff + */ + err = atm_sock_attach(so, atm_aal5_sendspace, atm_aal5_recvspace); + if (err) + goto out; + + /* + * Finish up any protocol specific stuff + */ + atp = sotoatmpcb(so); + atp->atp_type = ATPT_AAL5; + + /* + * Set default connection attributes + */ + atp->atp_attr = atm_aal5_defattr; + strncpy(atp->atp_name, "(AAL5)", T_ATM_APP_NAME_LEN); + + ATM_OUTRO(); +} + + +/* + * Detach protocol from socket + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_detach(so) + struct socket *so; +{ + ATM_INTRO("detach"); + + err = atm_sock_detach(so); + + ATM_OUTRO(); +} + + +/* + * Bind address to socket + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_bind(so, addr, p) + struct socket *so; + struct sockaddr *addr; + struct proc *p; +{ + ATM_INTRO("bind"); + + err = atm_sock_bind(so, addr); + + ATM_OUTRO(); +} + + +/* + * Listen for incoming connections + * + * Arguments: + * so pointer to socket + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_listen(so, p) + struct socket *so; + struct proc *p; +{ + ATM_INTRO("listen"); + + err = atm_sock_listen(so, &atm_aal5_endpt); + + ATM_OUTRO(); +} + + +/* + * Connect socket to peer + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_connect(so, addr, p) + struct socket *so; + struct sockaddr *addr; + struct proc *p; +{ + Atm_pcb *atp; + + ATM_INTRO("connect"); + + atp = sotoatmpcb(so); + + /* + * Resize send socket buffer to maximum sdu size + */ + if (atp->atp_attr.aal.tag == T_ATM_PRESENT) { + long size; + + size = atp->atp_attr.aal.v.aal5.forward_max_SDU_size; + if (size != T_ATM_ABSENT) + (void) sbreserve(&so->so_snd, size); + } + + /* + * Now get the socket connected + */ + err = atm_sock_connect(so, addr, &atm_aal5_endpt); + + ATM_OUTRO(); +} + + +/* + * Accept pending connection + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_accept(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + ATM_INTRO("accept"); + + /* + * Everything is pretty much done already, we just need to + * return the caller's address to the user. + */ + err = atm_sock_peeraddr(so, addr); + + ATM_OUTRO(); +} + + +/* + * Disconnect connected socket + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_disconnect(so) + struct socket *so; +{ + ATM_INTRO("disconnect"); + + err = atm_sock_disconnect(so); + + ATM_OUTRO(); +} + + +/* + * Shut down socket data transmission + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_shutdown(so) + struct socket *so; +{ + ATM_INTRO("shutdown"); + + socantsendmore(so); + + ATM_OUTRO(); +} + + +/* + * Send user data + * + * Arguments: + * so pointer to socket + * flags send data flags + * m pointer to buffer containing user data + * addr pointer to protocol address + * control pointer to buffer containing protocol control data + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_send(so, flags, m, addr, control, p) + struct socket *so; + int flags; + KBuffer *m; + struct sockaddr *addr; + KBuffer *control; + struct proc *p; +{ + Atm_pcb *atp; + + ATM_INTRO("send"); + + /* + * We don't support any control functions + */ + if (control) { + int clen; + + clen = KB_LEN(control); + KB_FREEALL(control); + if (clen) { + KB_FREEALL(m); + ATM_RETERR(EINVAL); + } + } + + /* + * We also don't support any flags or send-level addressing + */ + if (flags || addr) { + KB_FREEALL(m); + ATM_RETERR(EINVAL); + } + + /* + * All we've got left is the data, so push it out + */ + atp = sotoatmpcb(so); + err = atm_cm_cpcs_data(atp->atp_conn, m); + if (err) { + /* + * Output problem, drop packet + */ + atm_sock_stat.as_outdrop[atp->atp_type]++; + KB_FREEALL(m); + } + + ATM_OUTRO(); +} + + +/* + * Abnormally terminate service + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_abort(so) + struct socket *so; +{ + ATM_INTRO("abort"); + + so->so_error = ECONNABORTED; + err = atm_sock_detach(so); + + ATM_OUTRO(); +} + + +/* + * Do control operation - ioctl system call + * + * Arguments: + * so pointer to socket + * cmd ioctl code + * data pointer to code specific parameter data area + * ifp pointer to ifnet structure if it's an interface ioctl + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_control(so, cmd, data, ifp, p) + struct socket *so; + u_long cmd; + caddr_t data; + struct ifnet *ifp; + struct proc *p; +{ + ATM_INTRO("control"); + + switch (cmd) { + + default: + err = EOPNOTSUPP; + } + + ATM_OUTRO(); +} + +/* + * Sense socket status - fstat system call + * + * Arguments: + * so pointer to socket + * st pointer to file status structure + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_sense(so, st) + struct socket *so; + struct stat *st; +{ + ATM_INTRO("sense"); + + /* + * Just return the max sdu size for the connection + */ + st->st_blksize = so->so_snd.sb_hiwat; + + ATM_OUTRO(); +} + + +/* + * Retrieve local socket address + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_sockaddr(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + ATM_INTRO("sockaddr"); + + err = atm_sock_sockaddr(so, addr); + + ATM_OUTRO(); +} + + +/* + * Retrieve peer socket address + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_peeraddr(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + ATM_INTRO("peeraddr"); + + err = atm_sock_peeraddr(so, addr); + + ATM_OUTRO(); +} + + +/* + * Process Incoming Calls + * + * This function will receive control when an incoming call has been matched + * to one of our registered listen parameter blocks. Assuming the call passes + * acceptance criteria and all required resources are available, we will + * create a new protocol control block and socket association. We must + * then await notification of the final SVC setup results. If any + * problems are encountered, we will just tell the connection manager to + * reject the call. + * + * Called at splnet. + * + * Arguments: + * tok owner's matched listening token + * cop pointer to incoming call's connection block + * ap pointer to incoming call's attributes + * tokp pointer to location to store our connection token + * + * Returns: + * 0 call is accepted + * errno call rejected - reason indicated + * + */ +static int +atm_aal5_incoming(tok, cop, ap, tokp) + void *tok; + Atm_connection *cop; + Atm_attributes *ap; + void **tokp; +{ + Atm_pcb *atp = tok; + struct socket *so; + int err = 0; + + /* + * Allocate a new socket and pcb for this connection. + * + * Note that our attach function will be called via sonewconn + * and it will allocate and setup most of the pcb. + */ + atm_sock_stat.as_inconn[atp->atp_type]++; +#if (defined(BSD) && (BSD >= 199103)) + so = sonewconn(atp->atp_socket, 0); +#else + so = sonewconn(atp->atp_socket); +#endif + + if (so) { + /* + * Finish pcb setup and pass pcb back to CM + */ + atp = sotoatmpcb(so); + atp->atp_conn = cop; + *tokp = atp; + } else { + err = ECONNABORTED; + atm_sock_stat.as_connfail[atp->atp_type]++; + } + + return (err); +} + + +/* + * Process Socket VCC Input Data + * + * Arguments: + * tok owner's connection token (atm_pcb) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +atm_aal5_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + Atm_pcb *atp = tok; + struct socket *so; + int len; + + so = atp->atp_socket; + + KB_PLENGET(m, len); + + /* + * Ensure that the socket is able to receive data and + * that there's room in the socket buffer + */ + if (((so->so_state & SS_ISCONNECTED) == 0) || + (so->so_state & SS_CANTRCVMORE) || + (len > sbspace(&so->so_rcv))) { + atm_sock_stat.as_indrop[atp->atp_type]++; + KB_FREEALL(m); + return; + } + + /* + * Queue the data and notify the user + */ + sbappendrecord(&so->so_rcv, m); + sorwakeup(so); + + return; +} + + +/* + * Process getsockopt/setsockopt system calls + * + * Arguments: + * so pointer to socket + * sopt pointer to socket option info + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_aal5_ctloutput(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + Atm_pcb *atp; + + ATM_INTRO("ctloutput"); + + /* + * Make sure this is for us + */ + if (sopt->sopt_level != T_ATM_SIGNALING) { + ATM_RETERR(EINVAL); + } + atp = sotoatmpcb(so); + if (atp == NULL) { + ATM_RETERR(ENOTCONN); + } + + switch (sopt->sopt_dir) { + + case SOPT_SET: + /* + * setsockopt() + */ + + /* + * Validate socket state + */ + switch (sopt->sopt_name) { + + case T_ATM_ADD_LEAF: + case T_ATM_DROP_LEAF: + if ((so->so_state & SS_ISCONNECTED) == 0) { + ATM_RETERR(ENOTCONN); + } + break; + + case T_ATM_CAUSE: + break; + + default: + if (so->so_state & SS_ISCONNECTED) { + ATM_RETERR(EISCONN); + } + break; + } + + /* + * Validate and save user-supplied option data + */ + err = atm_sock_setopt(so, sopt, atp); + + break; + + case SOPT_GET: + /* + * getsockopt() + */ + + /* + * Return option data + */ + err = atm_sock_getopt(so, sopt, atp); + + break; + } + + ATM_OUTRO(); +} + + +/* + * Initialize AAL5 Sockets + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atm_aal5_init() +{ + /* + * Register our endpoint + */ + if (atm_endpoint_register(&atm_aal5_endpt)) + panic("atm_aal5_init: register"); + + /* + * Set default connection attributes + */ + atm_aal5_defattr.aal.v.aal5.forward_max_SDU_size = T_ATM_ABSENT; + atm_aal5_defattr.aal.v.aal5.backward_max_SDU_size = T_ATM_ABSENT; + atm_aal5_defattr.aal.v.aal5.SSCS_type = T_ATM_NULL; +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok owner's connection token (atm_pcb) + * + * Returns: + * addr pointer to string containing our name + * + */ +static caddr_t +atm_aal5_getname(tok) + void *tok; +{ + Atm_pcb *atp = tok; + + return (atp->atp_name); +} + |