mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-29 12:03:03 +00:00
bc725eafc7
rather than an error. Detaches do not "fail", they other occur or the protocol flags SS_PROTOREF to take ownership of the socket. soclose() no longer looks at so_pcb to see if it's NULL, relying entirely on the protocol to decide whether it's time to free the socket or not using SS_PROTOREF. so_pcb is now entirely owned and managed by the protocol code. Likewise, no longer test so_pcb in other socket functions, such as soreceive(), which have no business digging into protocol internals. Protocol detach routines no longer try to free the socket on detach, this is performed in the socket code if the protocol permits it. In rts_detach(), no longer test for rp != NULL in detach, and likewise in other protocols that don't permit a NULL so_pcb, reduce the incidence of testing for it during detach. netinet and netinet6 are not fully updated to this change, which will be in an upcoming commit. In their current state they may leak memory or panic. MFC after: 3 months
1313 lines
31 KiB
C
1313 lines
31 KiB
C
/*-
|
|
* ===================================
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* Core ATM Services
|
|
* -----------------
|
|
*
|
|
* ATM common socket protocol processing
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
#include <sys/syslog.h>
|
|
#include <net/if.h>
|
|
#include <netatm/port.h>
|
|
#include <netatm/queue.h>
|
|
#include <netatm/atm.h>
|
|
#include <netatm/atm_sys.h>
|
|
#include <netatm/atm_sap.h>
|
|
#include <netatm/atm_cm.h>
|
|
#include <netatm/atm_if.h>
|
|
#include <netatm/atm_sigmgr.h>
|
|
#include <netatm/atm_stack.h>
|
|
#include <netatm/atm_pcb.h>
|
|
#include <netatm/atm_var.h>
|
|
|
|
|
|
/*
|
|
* Local functions
|
|
*/
|
|
|
|
|
|
/*
|
|
* Local variables
|
|
*/
|
|
static uma_zone_t atm_pcb_zone;
|
|
|
|
static struct t_atm_cause atm_sock_cause = {
|
|
T_ATM_ITU_CODING,
|
|
T_ATM_LOC_USER,
|
|
T_ATM_CAUSE_UNSPECIFIED_NORMAL,
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
void
|
|
atm_sock_init(void)
|
|
{
|
|
|
|
atm_pcb_zone = uma_zcreate("atm pcb", sizeof(Atm_pcb), NULL, NULL,
|
|
NULL, NULL, UMA_ALIGN_PTR, 0);
|
|
if (atm_pcb_zone == NULL)
|
|
panic("atm_sock_init: unable to initialize atm_pcb_zone");
|
|
}
|
|
|
|
/*
|
|
* Allocate resources for a new ATM socket
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* send socket send buffer maximum
|
|
* recv socket receive buffer maximum
|
|
*
|
|
* Returns:
|
|
* 0 attach successful
|
|
* errno attach failed - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_attach(so, send, recv)
|
|
struct socket *so;
|
|
u_long send;
|
|
u_long recv;
|
|
{
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
int err;
|
|
|
|
/*
|
|
* Make sure initialization has happened
|
|
*/
|
|
if (!atm_init)
|
|
atm_initialize();
|
|
|
|
/*
|
|
* Make sure we're not already attached
|
|
*/
|
|
if (atp)
|
|
return (EISCONN);
|
|
|
|
/*
|
|
* Reserve socket buffer space, if not already done
|
|
*/
|
|
if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
|
|
err = soreserve(so, send, recv);
|
|
if (err)
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* Allocate and initialize our control block
|
|
*/
|
|
atp = uma_zalloc(atm_pcb_zone, M_ZERO | M_NOWAIT);
|
|
if (atp == NULL)
|
|
return (ENOMEM);
|
|
|
|
atp->atp_socket = so;
|
|
so->so_pcb = (caddr_t)atp;
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Detach from socket and free resources
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
*
|
|
*/
|
|
void
|
|
atm_sock_detach(so)
|
|
struct socket *so;
|
|
{
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
|
|
/*
|
|
* Make sure we're still attached
|
|
*/
|
|
KASSERT(atp != NULL, ("atm_sock_detach: atp == NULL"));
|
|
|
|
/*
|
|
* Terminate any (possibly pending) connection
|
|
*/
|
|
if (atp->atp_conn) {
|
|
(void) atm_sock_disconnect(so);
|
|
}
|
|
|
|
so->so_pcb = NULL;
|
|
|
|
uma_zfree(atm_pcb_zone, atp);
|
|
}
|
|
|
|
|
|
/*
|
|
* Bind local address to socket
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* addr pointer to protocol address
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_bind(so, addr)
|
|
struct socket *so;
|
|
struct sockaddr *addr;
|
|
{
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
Atm_attributes attr;
|
|
struct sockaddr_atm *satm;
|
|
struct t_atm_sap_addr *sapadr;
|
|
struct t_atm_sap_layer2 *sapl2;
|
|
struct t_atm_sap_layer3 *sapl3;
|
|
struct t_atm_sap_appl *sapapl;
|
|
|
|
/*
|
|
* Make sure we're still attached
|
|
*/
|
|
if (atp == NULL)
|
|
return (ENOTCONN);
|
|
|
|
/*
|
|
* Can't change local address once we've started connection process
|
|
*/
|
|
if (atp->atp_conn != NULL)
|
|
return (EADDRNOTAVAIL);
|
|
|
|
/*
|
|
* Validate requested local address
|
|
*/
|
|
satm = (struct sockaddr_atm *)addr;
|
|
if (satm->satm_family != AF_ATM)
|
|
return (EAFNOSUPPORT);
|
|
|
|
sapadr = &satm->satm_addr.t_atm_sap_addr;
|
|
if (sapadr->SVE_tag_addr == T_ATM_PRESENT) {
|
|
if (sapadr->address_format == T_ATM_ENDSYS_ADDR) {
|
|
if (sapadr->SVE_tag_selector != T_ATM_PRESENT)
|
|
return (EINVAL);
|
|
} else if (sapadr->address_format == T_ATM_E164_ADDR) {
|
|
if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
|
|
return (EINVAL);
|
|
} else
|
|
return (EINVAL);
|
|
} else if ((sapadr->SVE_tag_addr != T_ATM_ABSENT) &&
|
|
(sapadr->SVE_tag_addr != T_ATM_ANY))
|
|
return (EINVAL);
|
|
if (sapadr->address_length > ATM_ADDR_LEN)
|
|
return (EINVAL);
|
|
|
|
sapl2 = &satm->satm_addr.t_atm_sap_layer2;
|
|
if (sapl2->SVE_tag == T_ATM_PRESENT) {
|
|
if ((sapl2->ID_type != T_ATM_SIMPLE_ID) &&
|
|
(sapl2->ID_type != T_ATM_USER_ID))
|
|
return (EINVAL);
|
|
} else if ((sapl2->SVE_tag != T_ATM_ABSENT) &&
|
|
(sapl2->SVE_tag != T_ATM_ANY))
|
|
return (EINVAL);
|
|
|
|
sapl3 = &satm->satm_addr.t_atm_sap_layer3;
|
|
if (sapl3->SVE_tag == T_ATM_PRESENT) {
|
|
if ((sapl3->ID_type != T_ATM_SIMPLE_ID) &&
|
|
(sapl3->ID_type != T_ATM_IPI_ID) &&
|
|
(sapl3->ID_type != T_ATM_SNAP_ID) &&
|
|
(sapl3->ID_type != T_ATM_USER_ID))
|
|
return (EINVAL);
|
|
} else if ((sapl3->SVE_tag != T_ATM_ABSENT) &&
|
|
(sapl3->SVE_tag != T_ATM_ANY))
|
|
return (EINVAL);
|
|
|
|
sapapl = &satm->satm_addr.t_atm_sap_appl;
|
|
if (sapapl->SVE_tag == T_ATM_PRESENT) {
|
|
if ((sapapl->ID_type != T_ATM_ISO_APP_ID) &&
|
|
(sapapl->ID_type != T_ATM_USER_APP_ID) &&
|
|
(sapapl->ID_type != T_ATM_VENDOR_APP_ID))
|
|
return (EINVAL);
|
|
} else if ((sapapl->SVE_tag != T_ATM_ABSENT) &&
|
|
(sapapl->SVE_tag != T_ATM_ANY))
|
|
return (EINVAL);
|
|
|
|
/*
|
|
* Create temporary attributes list so that we can check out the
|
|
* new bind parameters before we modify the socket's values;
|
|
*/
|
|
attr = atp->atp_attr;
|
|
attr.called.tag = sapadr->SVE_tag_addr;
|
|
bcopy(&sapadr->address_format, &attr.called.addr, sizeof(Atm_addr));
|
|
|
|
attr.blli.tag_l2 = sapl2->SVE_tag;
|
|
if (sapl2->SVE_tag == T_ATM_PRESENT) {
|
|
attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type;
|
|
bcopy(&sapl2->ID, &attr.blli.v.layer_2_protocol.ID,
|
|
sizeof(attr.blli.v.layer_2_protocol.ID));
|
|
}
|
|
|
|
attr.blli.tag_l3 = sapl3->SVE_tag;
|
|
if (sapl3->SVE_tag == T_ATM_PRESENT) {
|
|
attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type;
|
|
bcopy(&sapl3->ID, &attr.blli.v.layer_3_protocol.ID,
|
|
sizeof(attr.blli.v.layer_3_protocol.ID));
|
|
}
|
|
|
|
attr.bhli.tag = sapapl->SVE_tag;
|
|
if (sapapl->SVE_tag == T_ATM_PRESENT) {
|
|
attr.bhli.v.ID_type = sapapl->ID_type;
|
|
bcopy(&sapapl->ID, &attr.bhli.v.ID,
|
|
sizeof(attr.bhli.v.ID));
|
|
}
|
|
|
|
/*
|
|
* Make sure we have unique listening attributes
|
|
*/
|
|
if (atm_cm_match(&attr, NULL) != NULL)
|
|
return (EADDRINUSE);
|
|
|
|
/*
|
|
* Looks good, save new attributes
|
|
*/
|
|
atp->atp_attr = attr;
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Listen for incoming connections
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* epp pointer to endpoint definition structure
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_listen(so, epp, backlog)
|
|
struct socket *so;
|
|
Atm_endpoint *epp;
|
|
int backlog;
|
|
{
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
|
|
/*
|
|
* Make sure we're still attached
|
|
*/
|
|
if (atp == NULL)
|
|
return (ENOTCONN);
|
|
|
|
/*
|
|
* Start listening for incoming calls
|
|
*/
|
|
return (atm_cm_listen(so, epp, atp, &atp->atp_attr, &atp->atp_conn,
|
|
backlog));
|
|
}
|
|
|
|
|
|
/*
|
|
* Connect socket to peer
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* addr pointer to protocol address
|
|
* epp pointer to endpoint definition structure
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_connect(so, addr, epp)
|
|
struct socket *so;
|
|
struct sockaddr *addr;
|
|
Atm_endpoint *epp;
|
|
{
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
struct sockaddr_atm *satm;
|
|
struct t_atm_sap_addr *sapadr;
|
|
struct t_atm_sap_layer2 *sapl2;
|
|
struct t_atm_sap_layer3 *sapl3;
|
|
struct t_atm_sap_appl *sapapl;
|
|
int err;
|
|
|
|
/*
|
|
* Make sure we're still attached
|
|
*/
|
|
if (atp == NULL)
|
|
return (ENOTCONN);
|
|
|
|
/*
|
|
* Validate requested peer address
|
|
*/
|
|
satm = (struct sockaddr_atm *)addr;
|
|
if (satm->satm_family != AF_ATM)
|
|
return (EAFNOSUPPORT);
|
|
|
|
sapadr = &satm->satm_addr.t_atm_sap_addr;
|
|
if (sapadr->SVE_tag_addr != T_ATM_PRESENT)
|
|
return (EINVAL);
|
|
if (sapadr->address_format == T_ATM_ENDSYS_ADDR) {
|
|
if (sapadr->SVE_tag_selector != T_ATM_PRESENT)
|
|
return (EINVAL);
|
|
} else if (sapadr->address_format == T_ATM_E164_ADDR) {
|
|
if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
|
|
return (EINVAL);
|
|
} else if (sapadr->address_format == T_ATM_PVC_ADDR) {
|
|
if (sapadr->SVE_tag_selector != T_ATM_ABSENT)
|
|
return (EINVAL);
|
|
} else
|
|
return (EINVAL);
|
|
if (sapadr->address_length > ATM_ADDR_LEN)
|
|
return (EINVAL);
|
|
|
|
sapl2 = &satm->satm_addr.t_atm_sap_layer2;
|
|
if (sapl2->SVE_tag == T_ATM_PRESENT) {
|
|
if ((sapl2->ID_type != T_ATM_SIMPLE_ID) &&
|
|
(sapl2->ID_type != T_ATM_USER_ID))
|
|
return (EINVAL);
|
|
} else if (sapl2->SVE_tag != T_ATM_ABSENT)
|
|
return (EINVAL);
|
|
|
|
sapl3 = &satm->satm_addr.t_atm_sap_layer3;
|
|
if (sapl3->SVE_tag == T_ATM_PRESENT) {
|
|
if ((sapl3->ID_type != T_ATM_SIMPLE_ID) &&
|
|
(sapl3->ID_type != T_ATM_IPI_ID) &&
|
|
(sapl3->ID_type != T_ATM_SNAP_ID) &&
|
|
(sapl3->ID_type != T_ATM_USER_ID))
|
|
return (EINVAL);
|
|
} else if (sapl3->SVE_tag != T_ATM_ABSENT)
|
|
return (EINVAL);
|
|
|
|
sapapl = &satm->satm_addr.t_atm_sap_appl;
|
|
if (sapapl->SVE_tag == T_ATM_PRESENT) {
|
|
if ((sapapl->ID_type != T_ATM_ISO_APP_ID) &&
|
|
(sapapl->ID_type != T_ATM_USER_APP_ID) &&
|
|
(sapapl->ID_type != T_ATM_VENDOR_APP_ID))
|
|
return (EINVAL);
|
|
} else if (sapapl->SVE_tag != T_ATM_ABSENT)
|
|
return (EINVAL);
|
|
|
|
/*
|
|
* Select an outgoing network interface
|
|
*/
|
|
if (atp->atp_attr.nif == NULL) {
|
|
struct atm_pif *pip;
|
|
|
|
for (pip = atm_interface_head; pip != NULL;
|
|
pip = pip->pif_next) {
|
|
if (pip->pif_nif != NULL) {
|
|
atp->atp_attr.nif = pip->pif_nif;
|
|
break;
|
|
}
|
|
}
|
|
if (atp->atp_attr.nif == NULL)
|
|
return (ENXIO);
|
|
}
|
|
|
|
/*
|
|
* Set supplied connection attributes
|
|
*/
|
|
atp->atp_attr.called.tag = T_ATM_PRESENT;
|
|
bcopy(&sapadr->address_format, &atp->atp_attr.called.addr,
|
|
sizeof(Atm_addr));
|
|
|
|
atp->atp_attr.blli.tag_l2 = sapl2->SVE_tag;
|
|
if (sapl2->SVE_tag == T_ATM_PRESENT) {
|
|
atp->atp_attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type;
|
|
bcopy(&sapl2->ID, &atp->atp_attr.blli.v.layer_2_protocol.ID,
|
|
sizeof(atp->atp_attr.blli.v.layer_2_protocol.ID));
|
|
}
|
|
|
|
atp->atp_attr.blli.tag_l3 = sapl3->SVE_tag;
|
|
if (sapl3->SVE_tag == T_ATM_PRESENT) {
|
|
atp->atp_attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type;
|
|
bcopy(&sapl3->ID, &atp->atp_attr.blli.v.layer_3_protocol.ID,
|
|
sizeof(atp->atp_attr.blli.v.layer_3_protocol.ID));
|
|
}
|
|
|
|
atp->atp_attr.bhli.tag = sapapl->SVE_tag;
|
|
if (sapapl->SVE_tag == T_ATM_PRESENT) {
|
|
atp->atp_attr.bhli.v.ID_type = sapapl->ID_type;
|
|
bcopy(&sapapl->ID, &atp->atp_attr.bhli.v.ID,
|
|
sizeof(atp->atp_attr.bhli.v.ID));
|
|
}
|
|
|
|
/*
|
|
* We're finally ready to initiate the ATM connection
|
|
*/
|
|
soisconnecting(so);
|
|
atm_sock_stat.as_connreq[atp->atp_type]++;
|
|
err = atm_cm_connect(epp, atp, &atp->atp_attr, &atp->atp_conn);
|
|
if (err == 0) {
|
|
/*
|
|
* Connection is setup
|
|
*/
|
|
atm_sock_stat.as_conncomp[atp->atp_type]++;
|
|
soisconnected(so);
|
|
|
|
} else if (err == EINPROGRESS) {
|
|
/*
|
|
* We've got to wait for a connected event
|
|
*/
|
|
err = 0;
|
|
|
|
} else {
|
|
/*
|
|
* Call failed...
|
|
*/
|
|
atm_sock_stat.as_connfail[atp->atp_type]++;
|
|
soisdisconnected(so);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
* Disconnect connected socket
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_disconnect(so)
|
|
struct socket *so;
|
|
{
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
struct t_atm_cause *cause;
|
|
int err;
|
|
|
|
/*
|
|
* Make sure we're still attached
|
|
*/
|
|
if (atp == NULL)
|
|
return (ENOTCONN);
|
|
|
|
/*
|
|
* Release the ATM connection
|
|
*/
|
|
if (atp->atp_conn) {
|
|
if (atp->atp_attr.cause.tag == T_ATM_PRESENT)
|
|
cause = &atp->atp_attr.cause.v;
|
|
else
|
|
cause = &atm_sock_cause;
|
|
err = atm_cm_release(atp->atp_conn, cause);
|
|
if (err)
|
|
log(LOG_ERR, "atm_sock_disconnect: release fail (%d)\n",
|
|
err);
|
|
atm_sock_stat.as_connrel[atp->atp_type]++;
|
|
atp->atp_conn = NULL;
|
|
}
|
|
|
|
soisdisconnected(so);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Retrieve local socket address
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* addr pointer to pointer to contain protocol address
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_sockaddr(so, addr)
|
|
struct socket *so;
|
|
struct sockaddr **addr;
|
|
{
|
|
struct sockaddr_atm *satm;
|
|
struct t_atm_sap_addr *saddr;
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
|
|
/*
|
|
* Return local interface address, if known
|
|
*/
|
|
satm = malloc(sizeof(*satm), M_SONAME, M_WAITOK | M_ZERO);
|
|
if (satm == NULL)
|
|
return (ENOMEM);
|
|
|
|
satm->satm_family = AF_ATM;
|
|
satm->satm_len = sizeof(*satm);
|
|
|
|
saddr = &satm->satm_addr.t_atm_sap_addr;
|
|
if (atp->atp_attr.nif && atp->atp_attr.nif->nif_pif->pif_siginst) {
|
|
saddr->SVE_tag_addr = T_ATM_PRESENT;
|
|
ATM_ADDR_SEL_COPY(
|
|
&atp->atp_attr.nif->nif_pif->pif_siginst->si_addr,
|
|
atp->atp_attr.nif->nif_sel, saddr);
|
|
if (saddr->address_format == T_ATM_ENDSYS_ADDR)
|
|
saddr->SVE_tag_selector = T_ATM_PRESENT;
|
|
else
|
|
saddr->SVE_tag_selector = T_ATM_ABSENT;
|
|
} else {
|
|
saddr->SVE_tag_addr = T_ATM_ABSENT;
|
|
saddr->SVE_tag_selector = T_ATM_ABSENT;
|
|
saddr->address_format = T_ATM_ABSENT;
|
|
}
|
|
satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT;
|
|
satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
|
|
satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
|
|
|
|
*addr = (struct sockaddr *)satm;
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Retrieve peer socket address
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* addr pointer to pointer to contain protocol address
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_peeraddr(so, addr)
|
|
struct socket *so;
|
|
struct sockaddr **addr;
|
|
{
|
|
struct sockaddr_atm *satm;
|
|
struct t_atm_sap_addr *saddr;
|
|
Atm_pcb *atp = sotoatmpcb(so);
|
|
Atm_connvc *cvp;
|
|
|
|
/*
|
|
* Return remote address, if known
|
|
*/
|
|
satm = malloc(sizeof(*satm), M_SONAME, M_WAITOK | M_ZERO);
|
|
if (satm == NULL)
|
|
return (ENOMEM);
|
|
|
|
satm->satm_family = AF_ATM;
|
|
satm->satm_len = sizeof(*satm);
|
|
saddr = &satm->satm_addr.t_atm_sap_addr;
|
|
if (so->so_state & SS_ISCONNECTED) {
|
|
cvp = atp->atp_conn->co_connvc;
|
|
saddr->SVE_tag_addr = T_ATM_PRESENT;
|
|
if (cvp->cvc_flags & CVCF_CALLER) {
|
|
ATM_ADDR_COPY(&cvp->cvc_attr.called.addr, saddr);
|
|
} else {
|
|
if (cvp->cvc_attr.calling.tag == T_ATM_PRESENT) {
|
|
ATM_ADDR_COPY(&cvp->cvc_attr.calling.addr,
|
|
saddr);
|
|
} else {
|
|
saddr->SVE_tag_addr = T_ATM_ABSENT;
|
|
saddr->address_format = T_ATM_ABSENT;
|
|
}
|
|
}
|
|
if (saddr->address_format == T_ATM_ENDSYS_ADDR)
|
|
saddr->SVE_tag_selector = T_ATM_PRESENT;
|
|
else
|
|
saddr->SVE_tag_selector = T_ATM_ABSENT;
|
|
} else {
|
|
saddr->SVE_tag_addr = T_ATM_ABSENT;
|
|
saddr->SVE_tag_selector = T_ATM_ABSENT;
|
|
saddr->address_format = T_ATM_ABSENT;
|
|
}
|
|
satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT;
|
|
satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
|
|
satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
|
|
|
|
*addr = (struct sockaddr *)satm;
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Common setsockopt processing
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* sopt pointer to socket option info
|
|
* atp pointer to ATM PCB
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_setopt(so, sopt, atp)
|
|
struct socket *so;
|
|
struct sockopt *sopt;
|
|
Atm_pcb *atp;
|
|
{
|
|
int err = 0;
|
|
union {
|
|
struct t_atm_aal5 aal5;
|
|
struct t_atm_traffic trf;
|
|
struct t_atm_bearer brr;
|
|
struct t_atm_bhli bhl;
|
|
struct t_atm_blli bll;
|
|
Atm_addr addr;
|
|
struct t_atm_cause cau;
|
|
struct t_atm_qos qos;
|
|
struct t_atm_transit trn;
|
|
struct t_atm_net_intf nif;
|
|
struct t_atm_llc llc;
|
|
struct t_atm_app_name appn;
|
|
} p;
|
|
|
|
#define MAXVAL(bits) ((1 << bits) - 1)
|
|
#define MAXMASK(bits) (~MAXVAL(bits))
|
|
|
|
switch (sopt->sopt_name) {
|
|
|
|
case T_ATM_AAL5:
|
|
err = sooptcopyin(sopt, &p.aal5, sizeof p.aal5, sizeof p.aal5);
|
|
if (err)
|
|
break;
|
|
if ((p.aal5.forward_max_SDU_size != T_ATM_ABSENT) &&
|
|
(p.aal5.forward_max_SDU_size & MAXMASK(16)))
|
|
return (EINVAL);
|
|
if ((p.aal5.backward_max_SDU_size != T_ATM_ABSENT) &&
|
|
(p.aal5.backward_max_SDU_size & MAXMASK(16)))
|
|
return (EINVAL);
|
|
if ((p.aal5.SSCS_type != T_ATM_ABSENT) &&
|
|
(p.aal5.SSCS_type != T_ATM_NULL) &&
|
|
(p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_REL) &&
|
|
(p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_UNREL) &&
|
|
(p.aal5.SSCS_type != T_ATM_SSCS_FR))
|
|
return (EINVAL);
|
|
|
|
if ((p.aal5.forward_max_SDU_size == T_ATM_ABSENT) &&
|
|
(p.aal5.backward_max_SDU_size == T_ATM_ABSENT) &&
|
|
(p.aal5.SSCS_type == T_ATM_ABSENT))
|
|
atp->atp_attr.aal.tag = T_ATM_ABSENT;
|
|
else {
|
|
atp->atp_attr.aal.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.aal.type = ATM_AAL5;
|
|
atp->atp_attr.aal.v.aal5 = p.aal5;
|
|
}
|
|
break;
|
|
|
|
case T_ATM_TRAFFIC:
|
|
err = sooptcopyin(sopt, &p.trf, sizeof p.trf, sizeof p.trf);
|
|
if (err)
|
|
break;
|
|
if ((p.trf.forward.PCR_high_priority != T_ATM_ABSENT) &&
|
|
(p.trf.forward.PCR_high_priority & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if (p.trf.forward.PCR_all_traffic & MAXMASK(24))
|
|
return (EINVAL);
|
|
if ((p.trf.forward.SCR_high_priority != T_ATM_ABSENT) &&
|
|
(p.trf.forward.SCR_high_priority & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.forward.SCR_all_traffic != T_ATM_ABSENT) &&
|
|
(p.trf.forward.SCR_all_traffic & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.forward.MBS_high_priority != T_ATM_ABSENT) &&
|
|
(p.trf.forward.MBS_high_priority & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.forward.MBS_all_traffic != T_ATM_ABSENT) &&
|
|
(p.trf.forward.MBS_all_traffic & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.forward.tagging != T_YES) &&
|
|
(p.trf.forward.tagging != T_NO))
|
|
return (EINVAL);
|
|
|
|
if ((p.trf.backward.PCR_high_priority != T_ATM_ABSENT) &&
|
|
(p.trf.backward.PCR_high_priority & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if (p.trf.backward.PCR_all_traffic & MAXMASK(24))
|
|
return (EINVAL);
|
|
if ((p.trf.backward.SCR_high_priority != T_ATM_ABSENT) &&
|
|
(p.trf.backward.SCR_high_priority & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.backward.SCR_all_traffic != T_ATM_ABSENT) &&
|
|
(p.trf.backward.SCR_all_traffic & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.backward.MBS_high_priority != T_ATM_ABSENT) &&
|
|
(p.trf.backward.MBS_high_priority & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.backward.MBS_all_traffic != T_ATM_ABSENT) &&
|
|
(p.trf.backward.MBS_all_traffic & MAXMASK(24)))
|
|
return (EINVAL);
|
|
if ((p.trf.backward.tagging != T_YES) &&
|
|
(p.trf.backward.tagging != T_NO))
|
|
return (EINVAL);
|
|
if ((p.trf.best_effort != T_YES) &&
|
|
(p.trf.best_effort != T_NO))
|
|
return (EINVAL);
|
|
|
|
atp->atp_attr.traffic.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.traffic.v = p.trf;
|
|
break;
|
|
|
|
case T_ATM_BEARER_CAP:
|
|
err = sooptcopyin(sopt, &p.brr, sizeof p.brr, sizeof p.brr);
|
|
if (err)
|
|
break;
|
|
if ((p.brr.bearer_class != T_ATM_CLASS_A) &&
|
|
(p.brr.bearer_class != T_ATM_CLASS_C) &&
|
|
(p.brr.bearer_class != T_ATM_CLASS_X))
|
|
return (EINVAL);
|
|
if ((p.brr.traffic_type != T_ATM_NULL) &&
|
|
(p.brr.traffic_type != T_ATM_CBR) &&
|
|
(p.brr.traffic_type != T_ATM_VBR) &&
|
|
(p.brr.traffic_type != T_ATM_ABR) &&
|
|
(p.brr.traffic_type != T_ATM_UBR))
|
|
return (EINVAL);
|
|
if ((p.brr.timing_requirements != T_ATM_NULL) &&
|
|
(p.brr.timing_requirements != T_ATM_END_TO_END) &&
|
|
(p.brr.timing_requirements != T_ATM_NO_END_TO_END))
|
|
return (EINVAL);
|
|
if ((p.brr.clipping_susceptibility != T_NO) &&
|
|
(p.brr.clipping_susceptibility != T_YES))
|
|
return (EINVAL);
|
|
if ((p.brr.connection_configuration != T_ATM_1_TO_1) &&
|
|
(p.brr.connection_configuration != T_ATM_1_TO_MANY))
|
|
return (EINVAL);
|
|
|
|
atp->atp_attr.bearer.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.bearer.v = p.brr;
|
|
break;
|
|
|
|
case T_ATM_BHLI:
|
|
err = sooptcopyin(sopt, &p.bhl, sizeof p.bhl, sizeof p.bhl);
|
|
if (err)
|
|
break;
|
|
if ((p.bhl.ID_type != T_ATM_ABSENT) &&
|
|
(p.bhl.ID_type != T_ATM_ISO_APP_ID) &&
|
|
(p.bhl.ID_type != T_ATM_USER_APP_ID) &&
|
|
(p.bhl.ID_type != T_ATM_VENDOR_APP_ID))
|
|
return (EINVAL);
|
|
|
|
if (p.bhl.ID_type == T_ATM_ABSENT)
|
|
atp->atp_attr.bhli.tag = T_ATM_ABSENT;
|
|
else {
|
|
atp->atp_attr.bhli.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.bhli.v = p.bhl;
|
|
}
|
|
break;
|
|
|
|
case T_ATM_BLLI:
|
|
err = sooptcopyin(sopt, &p.bll, sizeof p.bll, sizeof p.bll);
|
|
if (err)
|
|
break;
|
|
if ((p.bll.layer_2_protocol.ID_type != T_ATM_ABSENT) &&
|
|
(p.bll.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) &&
|
|
(p.bll.layer_2_protocol.ID_type != T_ATM_USER_ID))
|
|
return (EINVAL);
|
|
if ((p.bll.layer_2_protocol.mode != T_ATM_ABSENT) &&
|
|
(p.bll.layer_2_protocol.mode != T_ATM_BLLI_NORMAL_MODE) &&
|
|
(p.bll.layer_2_protocol.mode != T_ATM_BLLI_EXTENDED_MODE))
|
|
return (EINVAL);
|
|
if ((p.bll.layer_2_protocol.window_size != T_ATM_ABSENT) &&
|
|
(p.bll.layer_2_protocol.window_size < 1))
|
|
return (EINVAL);
|
|
|
|
if ((p.bll.layer_3_protocol.ID_type != T_ATM_ABSENT) &&
|
|
(p.bll.layer_3_protocol.ID_type != T_ATM_SIMPLE_ID) &&
|
|
(p.bll.layer_3_protocol.ID_type != T_ATM_IPI_ID) &&
|
|
(p.bll.layer_3_protocol.ID_type != T_ATM_SNAP_ID) &&
|
|
(p.bll.layer_3_protocol.ID_type != T_ATM_USER_ID))
|
|
return (EINVAL);
|
|
if ((p.bll.layer_3_protocol.mode != T_ATM_ABSENT) &&
|
|
(p.bll.layer_3_protocol.mode != T_ATM_BLLI_NORMAL_MODE) &&
|
|
(p.bll.layer_3_protocol.mode != T_ATM_BLLI_EXTENDED_MODE))
|
|
return (EINVAL);
|
|
if ((p.bll.layer_3_protocol.packet_size != T_ATM_ABSENT) &&
|
|
(p.bll.layer_3_protocol.packet_size & MAXMASK(4)))
|
|
return (EINVAL);
|
|
if ((p.bll.layer_3_protocol.window_size != T_ATM_ABSENT) &&
|
|
(p.bll.layer_3_protocol.window_size < 1))
|
|
return (EINVAL);
|
|
|
|
if (p.bll.layer_2_protocol.ID_type == T_ATM_ABSENT)
|
|
atp->atp_attr.blli.tag_l2 = T_ATM_ABSENT;
|
|
else
|
|
atp->atp_attr.blli.tag_l2 = T_ATM_PRESENT;
|
|
|
|
if (p.bll.layer_3_protocol.ID_type == T_ATM_ABSENT)
|
|
atp->atp_attr.blli.tag_l3 = T_ATM_ABSENT;
|
|
else
|
|
atp->atp_attr.blli.tag_l3 = T_ATM_PRESENT;
|
|
|
|
if ((atp->atp_attr.blli.tag_l2 == T_ATM_PRESENT) ||
|
|
(atp->atp_attr.blli.tag_l3 == T_ATM_PRESENT))
|
|
atp->atp_attr.blli.v = p.bll;
|
|
break;
|
|
|
|
case T_ATM_DEST_ADDR:
|
|
err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr);
|
|
if (err)
|
|
break;
|
|
if ((p.addr.address_format != T_ATM_ENDSYS_ADDR) &&
|
|
(p.addr.address_format != T_ATM_E164_ADDR))
|
|
return (EINVAL);
|
|
if (p.addr.address_length > ATM_ADDR_LEN)
|
|
return (EINVAL);
|
|
|
|
atp->atp_attr.called.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.called.addr = p.addr;
|
|
break;
|
|
|
|
case T_ATM_DEST_SUB:
|
|
err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr);
|
|
if (err)
|
|
break;
|
|
if ((p.addr.address_format != T_ATM_ABSENT) &&
|
|
(p.addr.address_format != T_ATM_NSAP_ADDR))
|
|
return (EINVAL);
|
|
if (p.addr.address_length > ATM_ADDR_LEN)
|
|
return (EINVAL);
|
|
|
|
/* T_ATM_DEST_ADDR controls tag */
|
|
atp->atp_attr.called.subaddr = p.addr;
|
|
break;
|
|
|
|
case T_ATM_ORIG_ADDR:
|
|
return (EACCES);
|
|
|
|
case T_ATM_ORIG_SUB:
|
|
return (EACCES);
|
|
|
|
case T_ATM_CALLER_ID:
|
|
return (EACCES);
|
|
|
|
case T_ATM_CAUSE:
|
|
err = sooptcopyin(sopt, &p.cau, sizeof p.cau, sizeof p.cau);
|
|
if (err)
|
|
break;
|
|
if ((p.cau.coding_standard != T_ATM_ABSENT) &&
|
|
(p.cau.coding_standard != T_ATM_ITU_CODING) &&
|
|
(p.cau.coding_standard != T_ATM_NETWORK_CODING))
|
|
return (EINVAL);
|
|
if ((p.cau.location != T_ATM_LOC_USER) &&
|
|
(p.cau.location != T_ATM_LOC_LOCAL_PRIVATE_NET) &&
|
|
(p.cau.location != T_ATM_LOC_LOCAL_PUBLIC_NET) &&
|
|
(p.cau.location != T_ATM_LOC_TRANSIT_NET) &&
|
|
(p.cau.location != T_ATM_LOC_REMOTE_PUBLIC_NET) &&
|
|
(p.cau.location != T_ATM_LOC_REMOTE_PRIVATE_NET) &&
|
|
(p.cau.location != T_ATM_LOC_INTERNATIONAL_NET) &&
|
|
(p.cau.location != T_ATM_LOC_BEYOND_INTERWORKING))
|
|
return (EINVAL);
|
|
|
|
if (p.cau.coding_standard == T_ATM_ABSENT)
|
|
atp->atp_attr.cause.tag = T_ATM_ABSENT;
|
|
else {
|
|
atp->atp_attr.cause.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.cause.v = p.cau;
|
|
}
|
|
break;
|
|
|
|
case T_ATM_QOS:
|
|
err = sooptcopyin(sopt, &p.qos, sizeof p.qos, sizeof p.qos);
|
|
if (err)
|
|
break;
|
|
if ((p.qos.coding_standard != T_ATM_ABSENT) &&
|
|
(p.qos.coding_standard != T_ATM_ITU_CODING) &&
|
|
(p.qos.coding_standard != T_ATM_NETWORK_CODING))
|
|
return (EINVAL);
|
|
if ((p.qos.forward.qos_class != T_ATM_QOS_CLASS_0) &&
|
|
(p.qos.forward.qos_class != T_ATM_QOS_CLASS_1) &&
|
|
(p.qos.forward.qos_class != T_ATM_QOS_CLASS_2) &&
|
|
(p.qos.forward.qos_class != T_ATM_QOS_CLASS_3) &&
|
|
(p.qos.forward.qos_class != T_ATM_QOS_CLASS_4))
|
|
return (EINVAL);
|
|
if ((p.qos.backward.qos_class != T_ATM_QOS_CLASS_0) &&
|
|
(p.qos.backward.qos_class != T_ATM_QOS_CLASS_1) &&
|
|
(p.qos.backward.qos_class != T_ATM_QOS_CLASS_2) &&
|
|
(p.qos.backward.qos_class != T_ATM_QOS_CLASS_3) &&
|
|
(p.qos.backward.qos_class != T_ATM_QOS_CLASS_4))
|
|
return (EINVAL);
|
|
|
|
if (p.qos.coding_standard == T_ATM_ABSENT)
|
|
atp->atp_attr.qos.tag = T_ATM_ABSENT;
|
|
else {
|
|
atp->atp_attr.qos.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.qos.v = p.qos;
|
|
}
|
|
break;
|
|
|
|
case T_ATM_TRANSIT:
|
|
err = sooptcopyin(sopt, &p.trn, sizeof p.trn, sizeof p.trn);
|
|
if (err)
|
|
break;
|
|
if (p.trn.length > T_ATM_MAX_NET_ID)
|
|
return (EINVAL);
|
|
|
|
if (p.trn.length == 0)
|
|
atp->atp_attr.transit.tag = T_ATM_ABSENT;
|
|
else {
|
|
atp->atp_attr.transit.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.transit.v = p.trn;
|
|
}
|
|
break;
|
|
|
|
case T_ATM_ADD_LEAF:
|
|
return (EPROTONOSUPPORT); /* XXX */
|
|
|
|
case T_ATM_DROP_LEAF:
|
|
return (EPROTONOSUPPORT); /* XXX */
|
|
|
|
case T_ATM_NET_INTF:
|
|
err = sooptcopyin(sopt, &p.nif, sizeof p.nif, sizeof p.nif);
|
|
if (err)
|
|
break;
|
|
|
|
atp->atp_attr.nif = atm_nifname(p.nif.net_intf);
|
|
if (atp->atp_attr.nif == NULL)
|
|
return (ENXIO);
|
|
break;
|
|
|
|
case T_ATM_LLC:
|
|
err = sooptcopyin(sopt, &p.llc, sizeof p.llc, sizeof p.llc);
|
|
if (err)
|
|
break;
|
|
if ((p.llc.llc_len < T_ATM_LLC_MIN_LEN) ||
|
|
(p.llc.llc_len > T_ATM_LLC_MAX_LEN))
|
|
return (EINVAL);
|
|
|
|
atp->atp_attr.llc.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.llc.v = p.llc;
|
|
break;
|
|
|
|
case T_ATM_APP_NAME:
|
|
err = sooptcopyin(sopt, &p.appn, sizeof p.appn, sizeof p.appn);
|
|
if (err)
|
|
break;
|
|
|
|
strncpy(atp->atp_name, p.appn.app_name, T_ATM_APP_NAME_LEN);
|
|
break;
|
|
|
|
default:
|
|
return (ENOPROTOOPT);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
* Common getsockopt processing
|
|
*
|
|
* Called at splnet.
|
|
*
|
|
* Arguments:
|
|
* so pointer to socket
|
|
* sopt pointer to socket option info
|
|
* atp pointer to ATM PCB
|
|
*
|
|
* Returns:
|
|
* 0 request processed
|
|
* errno error processing request - reason indicated
|
|
*
|
|
*/
|
|
int
|
|
atm_sock_getopt(so, sopt, atp)
|
|
struct socket *so;
|
|
struct sockopt *sopt;
|
|
Atm_pcb *atp;
|
|
{
|
|
Atm_attributes *ap;
|
|
|
|
/*
|
|
* If socket is connected, return attributes for the VCC in use,
|
|
* otherwise just return what the user has setup so far.
|
|
*/
|
|
if (so->so_state & SS_ISCONNECTED)
|
|
ap = &atp->atp_conn->co_connvc->cvc_attr;
|
|
else
|
|
ap = &atp->atp_attr;
|
|
|
|
switch (sopt->sopt_name) {
|
|
|
|
case T_ATM_AAL5:
|
|
if ((ap->aal.tag == T_ATM_PRESENT) &&
|
|
(ap->aal.type == ATM_AAL5)) {
|
|
return (sooptcopyout(sopt, &ap->aal.v.aal5,
|
|
sizeof ap->aal.v.aal5));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_TRAFFIC:
|
|
if (ap->traffic.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->traffic.v,
|
|
sizeof ap->traffic.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_BEARER_CAP:
|
|
if (ap->bearer.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->bearer.v,
|
|
sizeof ap->bearer.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_BHLI:
|
|
if (ap->bhli.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->bhli.v,
|
|
sizeof ap->bhli.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_BLLI:
|
|
if ((ap->blli.tag_l2 == T_ATM_PRESENT) ||
|
|
(ap->blli.tag_l3 == T_ATM_PRESENT)) {
|
|
return (sooptcopyout(sopt, &ap->blli.v,
|
|
sizeof ap->blli.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_DEST_ADDR:
|
|
if (ap->called.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->called.addr,
|
|
sizeof ap->called.addr));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_DEST_SUB:
|
|
if (ap->called.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->called.subaddr,
|
|
sizeof ap->called.subaddr));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_ORIG_ADDR:
|
|
if (ap->calling.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->calling.addr,
|
|
sizeof ap->calling.addr));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_ORIG_SUB:
|
|
if (ap->calling.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->calling.subaddr,
|
|
sizeof ap->calling.subaddr));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_CALLER_ID:
|
|
if (ap->calling.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->calling.cid,
|
|
sizeof ap->calling.cid));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_CAUSE:
|
|
if (ap->cause.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->cause.v,
|
|
sizeof ap->cause.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_QOS:
|
|
if (ap->qos.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->qos.v,
|
|
sizeof ap->qos.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_TRANSIT:
|
|
if (ap->transit.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->transit.v,
|
|
sizeof ap->transit.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_LEAF_IND:
|
|
return (EPROTONOSUPPORT); /* XXX */
|
|
|
|
case T_ATM_NET_INTF:
|
|
if (ap->nif) {
|
|
struct t_atm_net_intf netif;
|
|
struct ifnet *ifp;
|
|
|
|
ifp = ANIF2IFP(ap->nif);
|
|
(void) snprintf(netif.net_intf, sizeof(netif.net_intf),
|
|
"%s", ifp->if_xname);
|
|
return (sooptcopyout(sopt, &netif,
|
|
sizeof netif));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
case T_ATM_LLC:
|
|
if (ap->llc.tag == T_ATM_PRESENT) {
|
|
return (sooptcopyout(sopt, &ap->llc.v,
|
|
sizeof ap->llc.v));
|
|
} else {
|
|
return (ENOENT);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return (ENOPROTOOPT);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process Socket VCC Connected Notification
|
|
*
|
|
* Arguments:
|
|
* toku owner's connection token (atm_pcb protocol block)
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
void
|
|
atm_sock_connected(toku)
|
|
void *toku;
|
|
{
|
|
Atm_pcb *atp = (Atm_pcb *)toku;
|
|
|
|
/*
|
|
* Connection is setup
|
|
*/
|
|
atm_sock_stat.as_conncomp[atp->atp_type]++;
|
|
soisconnected(atp->atp_socket);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process Socket VCC Cleared Notification
|
|
*
|
|
* Arguments:
|
|
* toku owner's connection token (atm_pcb protocol block)
|
|
* cause pointer to cause code
|
|
*
|
|
* Returns:
|
|
* none
|
|
*
|
|
*/
|
|
void
|
|
atm_sock_cleared(toku, cause)
|
|
void *toku;
|
|
struct t_atm_cause *cause;
|
|
{
|
|
Atm_pcb *atp = (Atm_pcb *)toku;
|
|
struct socket *so;
|
|
|
|
so = atp->atp_socket;
|
|
|
|
/*
|
|
* Save call clearing cause
|
|
*/
|
|
atp->atp_attr.cause.tag = T_ATM_PRESENT;
|
|
atp->atp_attr.cause.v = *cause;
|
|
|
|
/*
|
|
* Set user error code
|
|
*/
|
|
if (so->so_state & SS_ISCONNECTED) {
|
|
so->so_error = ECONNRESET;
|
|
atm_sock_stat.as_connclr[atp->atp_type]++;
|
|
} else {
|
|
so->so_error = ECONNREFUSED;
|
|
atm_sock_stat.as_connfail[atp->atp_type]++;
|
|
}
|
|
|
|
/*
|
|
* Connection is gone
|
|
*/
|
|
atp->atp_conn = NULL;
|
|
soisdisconnected(so);
|
|
|
|
/*
|
|
* Cleanup failed incoming connection setup
|
|
*/
|
|
if (so->so_state & SS_NOFDREF) {
|
|
(void) atm_sock_detach(so);
|
|
}
|
|
}
|
|
|