예제 #1
0
int
ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
{
	ng_l2cap_p			 l2cap = ch->con->l2cap;
	struct ng_mesg			*msg = NULL;
	ng_l2cap_l2ca_qos_ind_ip	*ip = NULL;
	int				 error = 0;

	/* Check if upstream hook is connected and valid */
	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
		NG_L2CAP_ERR(
"%s: %s - unable to send L2CA_QoSViolationInd message. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);

		return (ENOTCONN);
	}

	/* Create and send L2CA_QoSViolationInd message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
		sizeof(*ip), M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
		bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
	}

	return (error);
} /* ng_l2cap_l2ca_qos_ind */
예제 #2
0
int
ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status)
{
	ng_hci_unit_p		 unit = con->unit;
	struct ng_mesg		*msg = NULL;
	ng_hci_lp_enc_change_ep	*ep = NULL;
	int			 error;


	if (con->link_type != NG_HCI_LINK_SCO) {
		if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
			NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG, 
				sizeof(*ep), M_NOWAIT);
			if (msg != NULL) {
				ep = (ng_hci_lp_enc_change_ep *) msg->data;
				ep->status = status;
				ep->link_type = con->link_type;
				ep->con_handle = con->con_handle;

				NG_SEND_MSG_HOOK(error, unit->node, msg,
					unit->acl, 0);
			}
		} else
			NG_HCI_INFO(
"%s: %s - ACL hook not valid, hook=%p\n",
				__func__, NG_NODE_NAME(unit->node), unit->acl);

	}
	return (0);
} /* ng_hci_lp_con_cfm */
예제 #3
0
int
ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
{
	ng_l2cap_p			 l2cap = ch->con->l2cap;
	struct ng_mesg			*msg = NULL;
	ng_l2cap_l2ca_cfg_rsp_op	*op = NULL;
	int				 error = 0;

	/* Check if upstream hook is connected and valid */
	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
		NG_L2CAP_ERR(
"%s: %s - unable to send L2CA_ConfigRsp response message. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);

		return (ENOTCONN);
	}

	/* Create and send L2CA_ConfigRsp response message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
		sizeof(*op), M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		msg->header.token = token;
		msg->header.flags |= NGF_RESP;

		op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
		op->result = result;

		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
	}

	return (error);
} /* ng_l2cap_l2ca_cfg_rsp_rsp */
예제 #4
0
int
ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
{
	ng_l2cap_p			 l2cap = ch->con->l2cap;
	struct ng_mesg			*msg = NULL;
	ng_l2cap_l2ca_cfg_ind_ip	*ip = NULL;
	int				 error = 0;

	/* Check if upstream hook is connected and valid */
	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
		NG_L2CAP_ERR(
"%s: %s - Unable to send L2CA_ConfigInd message. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);

		return (ENOTCONN);
	}

	/* Create and send L2CA_ConnectInd message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
			sizeof(*ip), M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
		ip->lcid = ch->scid;
		ip->omtu = ch->omtu;
		bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
		ip->flush_timo = ch->flush_timo;

		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
	}

	return (error);
} /* ng_l2cap_l2ca_cfg_ind */
예제 #5
0
int
ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle,
		ng_l2cap_flow_p flow)
{
	struct ng_mesg		*msg = NULL;
	ng_hci_lp_qos_req_ep	*ep = NULL;
	ng_l2cap_con_p		 con = NULL;
	int			 error = 0;

	/* Verify that we have this connection */
	con = ng_l2cap_con_by_handle(l2cap, con_handle);
	if (con == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSSetupReq event. " \
"Connection does not exist, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con_handle);

		return (ENOENT);
	}

	/* Verify connection state */
	if (con->state != NG_L2CAP_CON_OPEN) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSSetupReq event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state,
			con->con_handle);

		return (EINVAL);
	}

	/* Check if lower layer protocol is still connected */
	if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
		NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
			__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);

		return (ENOTCONN);
	}

	/* Create and send LP_QoSSetupReq event */
	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ,
		sizeof(*ep), M_NOWAIT);
	if (msg == NULL)
		return (ENOMEM);

	ep = (ng_hci_lp_qos_req_ep *) (msg->data);
	ep->con_handle = con_handle;
	ep->flags = flow->flags;
	ep->service_type = flow->service_type;
	ep->token_rate = flow->token_rate;
	ep->peak_bandwidth = flow->peak_bandwidth;
	ep->latency = flow->latency;
	ep->delay_variation = flow->delay_variation;

	NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
	
	return (error);
} /* ng_l2cap_lp_con_req */
예제 #6
0
int
ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
{
	struct ng_mesg		*msg = NULL;
	ng_hci_lp_con_req_ep	*ep = NULL;
	ng_l2cap_con_p		 con = NULL;
	int			 error = 0;

	/* Verify that we DO NOT have connection to the remote unit */
	con = ng_l2cap_con_by_addr(l2cap, bdaddr);
	if (con != NULL) {
		NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectReq event. " \
"Connection already exists, state=%d, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state, 
			con->con_handle);

		return (EEXIST);
	}

	/* Check if lower layer protocol is still connected */
	if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
		NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid\n",
			__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);

		return (ENOTCONN);
	}

	/* Create and intialize new connection descriptor */
	con = ng_l2cap_new_con(l2cap, bdaddr);
	if (con == NULL)
		return (ENOMEM);

	/* Create and send LP_ConnectReq event */
	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
		sizeof(*ep), M_NOWAIT);
	if (msg == NULL) {
		ng_l2cap_free_con(con);

		return (ENOMEM);
	}

	ep = (ng_hci_lp_con_req_ep *) (msg->data);
	bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
	ep->link_type = NG_HCI_LINK_ACL;

	con->state = NG_L2CAP_W4_LP_CON_CFM;
	ng_l2cap_lp_timeout(con);

	NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, NULL);
	if (error != 0)
		ng_l2cap_free_con(con); /* will remove timeout */
	
	return (error);
} /* ng_l2cap_lp_con_req */
예제 #7
0
int
ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
		u_int16_t status)
{
	ng_l2cap_p		 l2cap = ch->con->l2cap;
	struct ng_mesg		*msg = NULL;
	ng_l2cap_l2ca_con_op	*op = NULL;
	int			 error = 0;

	/* Check if upstream hook is connected and valid */
	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
		NG_L2CAP_ERR(
"%s: %s - unable to send L2CA_Connect response message. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);

		return (ENOTCONN);
	}

	/* Create and send L2CA_Connect response message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
		sizeof(*op), M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		msg->header.token = token;
		msg->header.flags |= NGF_RESP;

		op = (ng_l2cap_l2ca_con_op *)(msg->data);
		
		/*
		 * XXX Spec. says we should only populate LCID when result == 0
		 * What about PENDING? What the heck, for now always populate
		 * LCID :)
		 */
		if(ch->scid == NG_L2CAP_ATT_CID){
			op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
			op->lcid = ch->con->con_handle;
		}else if(ch->scid == NG_L2CAP_SMP_CID){
			op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
			op->lcid = ch->con->con_handle;
		}else{
			op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
				NG_L2CAP_L2CA_IDTYPE_BREDR :
				NG_L2CAP_L2CA_IDTYPE_LE;
			op->lcid = ch->scid;				
		}
		op->encryption = ch->con->encryption;
		op->result = result;
		op->status = status;

		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
	}

	return (error);
} /* ng_l2cap_l2ca_con_rsp */
예제 #8
0
int
ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
		u_int16_t length)
{
	ng_l2cap_p		 l2cap = ch->con->l2cap;
	struct ng_mesg		*msg = NULL;
	ng_l2cap_l2ca_write_op	*op = NULL;
	int			 error = 0;

	/* Check if upstream hook is connected and valid */
	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
		NG_L2CAP_ERR(
"%s: %s - unable to send L2CA_WriteRsp message. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);

		return (ENOTCONN);
	}

	/* Create and send L2CA_WriteRsp message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
			sizeof(*op), M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		msg->header.token = token;
		msg->header.flags |= NGF_RESP;

		op = (ng_l2cap_l2ca_write_op *)(msg->data);
		op->result = result;
		op->length = length;
		if(ch->scid == NG_L2CAP_ATT_CID){
			op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
			op->lcid = ch->con->con_handle;
		}else if(ch->scid == NG_L2CAP_SMP_CID){
			op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
			op->lcid = ch->con->con_handle;
		}else{
			op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
				NG_L2CAP_L2CA_IDTYPE_BREDR :
				NG_L2CAP_L2CA_IDTYPE_LE;
			op->lcid = ch->scid;				
			
		}
		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
	}

	return (error);
} /* ng_l2cap_l2ca_write_rsp */
예제 #9
0
int
ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
		struct mbuf *data)
{
	ng_l2cap_p		 l2cap = con->l2cap;
	struct ng_mesg		*msg = NULL;
	ng_l2cap_l2ca_ping_op	*op = NULL;
	int			 error = 0, size = 0;

	/* Check if control hook is connected and valid */
	if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
		NG_L2CAP_WARN(
"%s: %s - unable to send L2CA_Ping response message. " \
"Hook is not connected or valid\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = ENOTCONN;
		goto out;
	}

	size = (data == NULL)? 0 : data->m_pkthdr.len;

	/* Create and send L2CA_Ping response message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
		sizeof(*op) + size, M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		msg->header.token = token;
		msg->header.flags |= NGF_RESP;

		op = (ng_l2cap_l2ca_ping_op *)(msg->data);
		op->result = result;
		bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
		if (data != NULL && size > 0) {
			op->echo_size = size;
			m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
		}

		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
	}
out:
	NG_FREE_M(data);

	return (error);
} /* ng_l2cap_l2ca_ping_rsp */
예제 #10
0
void
ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
{
	ng_hci_unit_p		 unit = NULL;
	struct ng_mesg		*msg = NULL;
	ng_hci_node_up_ep	*ep = NULL;
	int			 error;

	if (node == NULL || NG_NODE_NOT_VALID(node) ||
	    hook == NULL || NG_HOOK_NOT_VALID(hook))
		return;

	unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
		return;

	if (hook != unit->acl && hook != unit->sco)
		return;

	NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT);
	if (msg != NULL) {
		ep = (ng_hci_node_up_ep *)(msg->data);

		if (hook == unit->acl) {
			NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
		} else {
			NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
		} 

		bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));

		NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
	} else
		error = ENOMEM;

	if (error != 0)
		NG_HCI_INFO(
"%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
			__func__, NG_NODE_NAME(unit->node), 
			NG_HOOK_NAME(hook), error);
} /* ng_hci_node_is_up */
예제 #11
0
int
ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass)
{
	ng_hci_unit_p		 unit = con->unit;
	struct ng_mesg		*msg = NULL;
	ng_hci_lp_con_ind_ep	*ep = NULL;
	hook_p			 hook = NULL;
	int			 error = 0;

	/*
	 * Connection_Request event is generated for specific link type.
	 * Use link_type to select upstream hook.
	 */

	if (con->link_type == NG_HCI_LINK_ACL)
		hook = unit->acl;
	else
		hook = unit->sco;

	if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
		NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND, 
			sizeof(*ep), M_NOWAIT);
		if (msg == NULL)
			return (ENOMEM);

		ep = (ng_hci_lp_con_ind_ep *)(msg->data);
		ep->link_type = con->link_type;
		bcopy(uclass, ep->uclass, sizeof(ep->uclass));
		bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));

		NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0);
	} else {
		NG_HCI_WARN(
"%s: %s - Upstream hook is not connected or not valid, hook=%p\n",
			__func__, NG_NODE_NAME(unit->node), hook);

		error = ENOTCONN;
	}

	return (error);
} /* ng_hci_lp_con_ind */
예제 #12
0
int
ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
{
	ng_l2cap_p			 l2cap = ch->con->l2cap;
	struct ng_mesg			*msg = NULL;
	ng_l2cap_l2ca_discon_ind_ip	*ip = NULL;
	int				 error = 0;

	/* Check if upstream hook is connected and valid */
	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
		NG_L2CAP_ERR(
"%s: %s - unable to send L2CA_DisconnectInd message. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);

		return (ENOTCONN);
	}

	/* Create and send L2CA_DisconnectInd message */
	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
		sizeof(*ip), M_NOWAIT);
	if (msg == NULL)
		error = ENOMEM;
	else {
		ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
		ip->idtype = ch->idtype;
		if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
		   ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
			ip->lcid = ch->con->con_handle;
		else
			ip->lcid = ch->scid;
		
		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
	} 

	return (error);
} /* ng_l2cap_l2ca_discon_ind */
예제 #13
0
/*
 * When incoming data is appended to the socket, we get notified here.
 * This is also called whenever a significant event occurs for the socket.
 * Our original caller may have queued this even some time ago and
 * we cannot trust that he even still exists. The node however is being
 * held with a reference by the queueing code and guarantied to be valid.
 */
static void
ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2)
{
	struct socket *so = arg1;
	const priv_p priv = NG_NODE_PRIVATE(node);
	struct ng_mesg *response;
	struct uio auio;
	int flags, error;

	KASSERT(so == priv->so, ("%s: wrong socket", __func__));

	/* Allow next incoming event to be queued. */
	atomic_store_rel_int(&priv->fn_sent, 0);

	/* Check whether a pending connect operation has completed */
	if (priv->flags & KSF_CONNECTING) {
		if ((error = so->so_error) != 0) {
			so->so_error = 0;
			so->so_state &= ~SS_ISCONNECTING;
		}
		if (!(so->so_state & SS_ISCONNECTING)) {
			NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE,
			    NGM_KSOCKET_CONNECT, sizeof(int32_t), M_NOWAIT);
			if (response != NULL) {
				response->header.flags |= NGF_RESP;
				response->header.token = priv->response_token;
				*(int32_t *)response->data = error;
				/*
				 * send an async "response" message
				 * to the node that set us up
				 * (if it still exists)
				 */
				NG_SEND_MSG_ID(error, node,
				    response, priv->response_addr, 0);
			}
			priv->flags &= ~KSF_CONNECTING;
		}
	}

	/* Check whether a pending accept operation has completed */
	if (priv->flags & KSF_ACCEPTING) {
		error = ng_ksocket_check_accept(priv);
		if (error != EWOULDBLOCK)
			priv->flags &= ~KSF_ACCEPTING;
		if (error == 0)
			ng_ksocket_finish_accept(priv);
	}

	/*
	 * If we don't have a hook, we must handle data events later.  When
	 * the hook gets created and is connected, this upcall function
	 * will be called again.
	 */
	if (priv->hook == NULL)
		return;

	/* Read and forward available mbuf's */
	auio.uio_td = NULL;
	auio.uio_resid = MJUMPAGESIZE;	/* XXXGL: sane limit? */
	flags = MSG_DONTWAIT;
	while (1) {
		struct sockaddr *sa = NULL;
		struct mbuf *m;

		/* Try to get next packet from socket */
		if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ?
		    NULL : &sa, &auio, &m, NULL, &flags)) != 0)
			break;

		/* See if we got anything */
		if (m == NULL) {
			if (sa != NULL)
				free(sa, M_SONAME);
			break;
		}

		KASSERT(m->m_nextpkt == NULL, ("%s: nextpkt", __func__));

		/*
		 * Stream sockets do not have packet boundaries, so
		 * we have to allocate a header mbuf and attach the
		 * stream of data to it.
		 */
		if (so->so_type == SOCK_STREAM) {
			struct mbuf *mh;

			mh = m_gethdr(M_NOWAIT, MT_DATA);
			if (mh == NULL) {
				m_freem(m);
				if (sa != NULL)
					free(sa, M_SONAME);
				break;
			}

			mh->m_next = m;
			for (; m; m = m->m_next)
				mh->m_pkthdr.len += m->m_len;
			m = mh;
		}

		/* Put peer's socket address (if any) into a tag */
		if (sa != NULL) {
			struct sa_tag	*stag;

			stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE,
			    NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) +
			    sa->sa_len, M_NOWAIT);
			if (stag == NULL) {
				free(sa, M_SONAME);
				goto sendit;
			}
			bcopy(sa, &stag->sa, sa->sa_len);
			free(sa, M_SONAME);
			stag->id = NG_NODE_ID(node);
			m_tag_prepend(m, &stag->tag);
		}

sendit:		/* Forward data with optional peer sockaddr as packet tag */
		NG_SEND_DATA_ONLY(error, priv->hook, m);
	}

	/*
	 * If the peer has closed the connection, forward a 0-length mbuf
	 * to indicate end-of-file.
	 */
	if (so->so_rcv.sb_state & SBS_CANTRCVMORE &&
	    !(priv->flags & KSF_EOFSEEN)) {
		struct mbuf *m;

		m = m_gethdr(M_NOWAIT, MT_DATA);
		if (m != NULL)
			NG_SEND_DATA_ONLY(error, priv->hook, m);
		priv->flags |= KSF_EOFSEEN;
	}
}
예제 #14
0
int
ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_enable_clt_ip	*ip = NULL;
	int				 error = 0;
#if 0
 *	ng_l2cap_l2ca_enable_clt_op	*op = NULL;
 *	u_int16_t			 result; 
 * 	u_int32_t			 token;
#endif

	/* Check message */
	if (msg->header.arglen != sizeof(*ip)) {
		NG_L2CAP_ALERT(
"%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
			__func__, NG_NODE_NAME(l2cap->node),
			msg->header.arglen);

		return (EMSGSIZE);
	}

	/* Process request */
	ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
#if 0
 *	result = NG_L2CAP_SUCCESS;
#endif

	switch (ip->psm) 
	{
	case 0:
		/* Special case: disable/enable all PSM */
		if (ip->enable)
			l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED    |
					  NG_L2CAP_CLT_RFCOMM_DISABLED |
					  NG_L2CAP_CLT_TCP_DISABLED);
		else
			l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED    |
					 NG_L2CAP_CLT_RFCOMM_DISABLED |
					 NG_L2CAP_CLT_TCP_DISABLED);
		break;

	case NG_L2CAP_PSM_SDP:
		if (ip->enable)
			l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
		else
			l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
		break;

	case NG_L2CAP_PSM_RFCOMM:
		if (ip->enable)
			l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
		else
			l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
		break;

	case NG_L2CAP_PSM_TCP:
		if (ip->enable)
			l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
		else
			l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
		break;
	
	default:
		NG_L2CAP_ERR(
"%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
#if 0
 *		result = NG_L2CAP_PSM_NOT_SUPPORTED;
#endif
		error = ENOTSUP;
		break;
	}

#if 0
 *	/* Create and send response message */
 * 	token = msg->header.token;
 * 	NG_FREE_MSG(msg);
 * 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
 * 		sizeof(*op), M_NOWAIT);
 * 	if (msg == NULL)
 * 		error = ENOMEM;
 * 	else {
 * 		msg->header.token = token;
 * 		msg->header.flags |= NGF_RESP;
 * 
 * 		op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
 * 		op->result = result;
 * 	}
 * 
 * 	/* Send response to control hook */
 * 	if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
 * 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
#endif

	return (error);
} /* ng_l2cap_l2ca_enable_clt */
예제 #15
0
static int
ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type)
{
	struct acl_con_req {
		ng_hci_cmd_pkt_t	 hdr;
		ng_hci_le_create_connection_cp	 cp;
	} __attribute__ ((packed))	*req = NULL;
	ng_hci_lp_con_req_ep		*ep = NULL;
	ng_hci_unit_con_p		 con = NULL;
	struct mbuf			*m = NULL;
	int				 error = 0;

	ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
	if((link_type != NG_HCI_LINK_LE_PUBLIC)&&
	   (link_type != NG_HCI_LINK_LE_RANDOM)){
		printf("%s: Link type %d Cannot be here \n", __func__, 
		       link_type);
	}
	/*
	 * Only one ACL connection can exist between each pair of units.
	 * So try to find ACL connection descriptor (in any state) that
	 * has requested remote BD_ADDR.
	 *
	 * Two cases:
	 *
	 * 1) We do not have connection to the remote unit. This is simple.
	 *    Just create new connection descriptor and send HCI command to
	 *    create new connection.
	 *
	 * 2) We do have connection descriptor. We need to check connection
	 *    state:
	 * 
	 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
	 *      accepting connection from the remote unit. This is a race
	 *      condition. We will ignore this message.
	 *
	 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
	 *      requested connection or we just accepted it. In any case
	 *      all we need to do here is set appropriate notification bit
	 *      and wait.
	 *	
	 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
	 *      and let upper layer know that we have connection already.
	 */

	con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type);
	if (con != NULL) {
		switch (con->state) {
		case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
			error = EALREADY;
			break;

		case NG_HCI_CON_W4_CONN_COMPLETE:
			if (hook != unit->sco)
				con->flags |= NG_HCI_CON_NOTIFY_ACL;
			else
				con->flags |= NG_HCI_CON_NOTIFY_SCO;
			break;

		case NG_HCI_CON_OPEN: {
			struct ng_mesg		*msg = NULL;
			ng_hci_lp_con_cfm_ep	*cfm = NULL;

			if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
				NGI_GET_MSG(item, msg);
				NG_FREE_MSG(msg);

				NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 
					NGM_HCI_LP_CON_CFM, sizeof(*cfm), 
					M_NOWAIT);
				if (msg != NULL) {
					cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
					cfm->status = 0;
					cfm->link_type = con->link_type;
					cfm->con_handle = con->con_handle;
					bcopy(&con->bdaddr, &cfm->bdaddr, 
						sizeof(cfm->bdaddr));

					/*
					 * This will forward item back to
					 * sender and set item to NULL
					 */

					_NGI_MSG(item) = msg;
					NG_FWD_ITEM_HOOK(error, item, hook);
				} else
					error = ENOMEM;
			} else
				NG_HCI_INFO(
"%s: %s - Source hook is not valid, hook=%p\n",
					__func__, NG_NODE_NAME(unit->node), 
					hook);
			} break;

		default:
			panic(
"%s: %s - Invalid connection state=%d\n",
				__func__, NG_NODE_NAME(unit->node), con->state);
			break;
		}

		goto out;
	}

	/*
	 * If we got here then we need to create new ACL connection descriptor
	 * and submit HCI command. First create new connection desriptor, set
	 * bdaddr and notification flags.
	 */

	con = ng_hci_new_con(unit, link_type);
	if (con == NULL) {
		error = ENOMEM;
		goto out;
	}

	bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));

	/* 
	 * Create HCI command 
	 */

	MGETHDR(m, M_NOWAIT, MT_DATA);
	if (m == NULL) {
		ng_hci_free_con(con);
		error = ENOBUFS;
		goto out;
	}

	m->m_pkthdr.len = m->m_len = sizeof(*req);
	req = mtod(m, struct acl_con_req *);
	req->hdr.type = NG_HCI_CMD_PKT;
	req->hdr.length = sizeof(req->cp);
	req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE,
					NG_HCI_OCF_LE_CREATE_CONNECTION));
	
	bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr));
	req->cp.own_address_type = 0;
	req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0;
	req->cp.scan_interval = htole16(4);
	req->cp.scan_window = htole16(4);
	req->cp.filter_policy = 0;
	req->cp.conn_interval_min = htole16(0xf);
	req->cp.conn_interval_max = htole16(0xf);
	req->cp.conn_latency = htole16(0);
	req->cp.supervision_timeout = htole16(0xc80);
	req->cp.min_ce_length = htole16(1);
	req->cp.max_ce_length = htole16(1);
	/* 
	 * Adust connection state 
	 */

	if (hook != unit->sco)
		con->flags |= NG_HCI_CON_NOTIFY_ACL;
	else
		con->flags |= NG_HCI_CON_NOTIFY_SCO;

	con->state = NG_HCI_CON_W4_CONN_COMPLETE;
	ng_hci_con_timeout(con);

	/* 
	 * Queue and send HCI command 
	 */

	NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
		error = ng_hci_send_command(unit);
out:
	if (item != NULL)
		NG_FREE_ITEM(item);

	return (error);
} /* ng_hci_lp_acl_con_req */
예제 #16
0
int
ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status)
{
	ng_hci_unit_p		 unit = con->unit;
	struct ng_mesg		*msg = NULL;
	ng_hci_lp_con_cfm_ep	*ep = NULL;
	int			 error;

	/*
	 * Check who wants to be notified. For ACL links both ACL and SCO
	 * upstream hooks will be notified (if required). For SCO links
	 * only SCO upstream hook will receive notification
	 */

	if (con->link_type == NG_HCI_LINK_ACL && 
	    con->flags & NG_HCI_CON_NOTIFY_ACL) {
		if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
			NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 
				sizeof(*ep), M_NOWAIT);
			if (msg != NULL) {
				ep = (ng_hci_lp_con_cfm_ep *) msg->data;
				ep->status = status;
				ep->link_type = con->link_type;
				ep->con_handle = con->con_handle;
				bcopy(&con->bdaddr, &ep->bdaddr, 
					sizeof(ep->bdaddr));

				NG_SEND_MSG_HOOK(error, unit->node, msg,
					unit->acl, 0);
			}
		} else
			NG_HCI_INFO(
"%s: %s - ACL hook not valid, hook=%p\n",
				__func__, NG_NODE_NAME(unit->node), unit->acl);

		con->flags &= ~NG_HCI_CON_NOTIFY_ACL;
	}

	if (con->flags & NG_HCI_CON_NOTIFY_SCO) {
		if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
			NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 
				sizeof(*ep), M_NOWAIT);
			if (msg != NULL) {
				ep = (ng_hci_lp_con_cfm_ep *) msg->data;
				ep->status = status;
				ep->link_type = con->link_type;
				ep->con_handle = con->con_handle;
				bcopy(&con->bdaddr, &ep->bdaddr, 
					sizeof(ep->bdaddr));

				NG_SEND_MSG_HOOK(error, unit->node, msg,
					unit->sco, 0);
			}
		} else
			NG_HCI_INFO(
"%s: %s - SCO hook not valid, hook=%p\n",
				__func__, NG_NODE_NAME(unit->node), unit->acl);

		con->flags &= ~NG_HCI_CON_NOTIFY_SCO;
	}

	return (0);
} /* ng_hci_lp_con_cfm */
예제 #17
0
static int
ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
{
	struct acl_con_req {
		ng_hci_cmd_pkt_t	 hdr;
		ng_hci_create_con_cp	 cp;
	} __attribute__ ((packed))	*req = NULL;
	ng_hci_lp_con_req_ep		*ep = NULL;
	ng_hci_unit_con_p		 con = NULL;
	ng_hci_neighbor_t		*n = NULL;
	struct mbuf			*m = NULL;
	int				 error = 0;

	ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);

	/*
	 * Only one ACL connection can exist between each pair of units.
	 * So try to find ACL connection descriptor (in any state) that
	 * has requested remote BD_ADDR.
	 *
	 * Two cases:
	 *
	 * 1) We do not have connection to the remote unit. This is simple.
	 *    Just create new connection descriptor and send HCI command to
	 *    create new connection.
	 *
	 * 2) We do have connection descriptor. We need to check connection
	 *    state:
	 * 
	 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
	 *      accepting connection from the remote unit. This is a race
	 *      condition. We will ignore this message.
	 *
	 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
	 *      requested connection or we just accepted it. In any case
	 *      all we need to do here is set appropriate notification bit
	 *      and wait.
	 *	
	 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
	 *      and let upper layer know that we have connection already.
	 */

	con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
	if (con != NULL) {
		switch (con->state) {
		case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
			error = EALREADY;
			break;

		case NG_HCI_CON_W4_CONN_COMPLETE:
			if (hook == unit->acl)
				con->flags |= NG_HCI_CON_NOTIFY_ACL;
			else
				con->flags |= NG_HCI_CON_NOTIFY_SCO;
			break;

		case NG_HCI_CON_OPEN: {
			struct ng_mesg		*msg = NULL;
			ng_hci_lp_con_cfm_ep	*cfm = NULL;

			if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
				NGI_GET_MSG(item, msg);
				NG_FREE_MSG(msg);

				NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 
					NGM_HCI_LP_CON_CFM, sizeof(*cfm), 
					M_NOWAIT);
				if (msg != NULL) {
					cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
					cfm->status = 0;
					cfm->link_type = con->link_type;
					cfm->con_handle = con->con_handle;
					bcopy(&con->bdaddr, &cfm->bdaddr, 
						sizeof(cfm->bdaddr));

					/*
					 * This will forward item back to
					 * sender and set item to NULL
					 */

					_NGI_MSG(item) = msg;
					NG_FWD_ITEM_HOOK(error, item, hook);
				} else
					error = ENOMEM;
			} else
				NG_HCI_INFO(
"%s: %s - Source hook is not valid, hook=%p\n",
					__func__, NG_NODE_NAME(unit->node), 
					hook);
			} break;

		default:
			panic(
"%s: %s - Invalid connection state=%d\n",
				__func__, NG_NODE_NAME(unit->node), con->state);
			break;
		}

		goto out;
	}

	/*
	 * If we got here then we need to create new ACL connection descriptor
	 * and submit HCI command. First create new connection desriptor, set
	 * bdaddr and notification flags.
	 */

	con = ng_hci_new_con(unit, NG_HCI_LINK_ACL);
	if (con == NULL) {
		error = ENOMEM;
		goto out;
	}

	bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));

	/* 
	 * Create HCI command 
	 */

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL) {
		ng_hci_free_con(con);
		error = ENOBUFS;
		goto out;
	}

	m->m_pkthdr.len = m->m_len = sizeof(*req);
	req = mtod(m, struct acl_con_req *);
	req->hdr.type = NG_HCI_CMD_PKT;
	req->hdr.length = sizeof(req->cp);
	req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
					NG_HCI_OCF_CREATE_CON));

	bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr));

	req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1);
	if (unit->features[0] & NG_HCI_LMP_3SLOT)
		req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3);
	if (unit->features[0] & NG_HCI_LMP_5SLOT)
		req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5);

	req->cp.pkt_type &= unit->packet_mask;
	if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1|
				 NG_HCI_PKT_DM3|NG_HCI_PKT_DH3|
				 NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0)
		req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1);

	req->cp.pkt_type = htole16(req->cp.pkt_type);

	if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch)
		req->cp.accept_role_switch = 1;
	else
		req->cp.accept_role_switch = 0;

	/*
	 * We may speed up connect by specifying valid parameters. 
	 * So check the neighbor cache.
	 */

	n = ng_hci_get_neighbor(unit, &ep->bdaddr);
	if (n == NULL) {
		req->cp.page_scan_rep_mode = 0;
		req->cp.page_scan_mode = 0;
		req->cp.clock_offset = 0;
	} else {
		req->cp.page_scan_rep_mode = n->page_scan_rep_mode;
		req->cp.page_scan_mode = n->page_scan_mode;
		req->cp.clock_offset = htole16(n->clock_offset);
	}

	/* 
	 * Adust connection state 
	 */

	if (hook == unit->acl)
		con->flags |= NG_HCI_CON_NOTIFY_ACL;
	else
		con->flags |= NG_HCI_CON_NOTIFY_SCO;

	con->state = NG_HCI_CON_W4_CONN_COMPLETE;
	ng_hci_con_timeout(con);

	/* 
	 * Queue and send HCI command 
	 */

	NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
		error = ng_hci_send_command(unit);
out:
	if (item != NULL)
		NG_FREE_ITEM(item);

	return (error);
} /* ng_hci_lp_acl_con_req */
예제 #18
0
void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
{
    struct ifnet *ifp;
    struct ifreq ifreq;
    int error;
    node_p node;
    struct ng_mesg *msg;
    struct ngm_connect *con;
    struct ngm_rmhook *rm;
    char path[NG_PATHSIZ];

    Log(("%s: fActive:%d\n", __func__, fActive));

    ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
    VBOXCURVNET_SET(ifp->if_vnet);
    node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p);

    memset(&ifreq, 0, sizeof(struct ifreq));
    /* Activate interface */
    if (fActive)
    {
        pThis->u.s.flags = ifp->if_flags;
        ifpromisc(ifp, 1);

        /* ng_ether nodes are named after the interface name */
        snprintf(path, sizeof(path), "%s:", ifp->if_xname);

        /*
         * Send a netgraph connect message to the ng_ether node
         * assigned to the bridged interface. Connecting
         * the hooks 'lower' (ng_ether) to out 'input'.
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
                     sizeof(struct ngm_connect), M_NOWAIT);
        if (msg == NULL)
            return;
        con = (struct ngm_connect *)msg->data;
        snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname);
        strlcpy(con->ourhook, "lower", NG_HOOKSIZ);
        strlcpy(con->peerhook, "input", NG_HOOKSIZ);
        NG_SEND_MSG_PATH(error, node, msg, path, 0);

        /*
         * Do the same for the hooks 'upper' (ng_ether) and our
         * 'output' hook.
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
                     sizeof(struct ngm_connect), M_NOWAIT);
        if (msg == NULL)
            return;
        con = (struct ngm_connect *)msg->data;
        snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:",
                 ifp->if_xname);
        strlcpy(con->ourhook, "upper", sizeof(con->ourhook));
        strlcpy(con->peerhook, "output", sizeof(con->peerhook));
        NG_SEND_MSG_PATH(error, node, msg, path, 0);
    }
    else
    {
        /* De-activate interface */
        pThis->u.s.flags = 0;
        ifpromisc(ifp, 0);

        /* Disconnect msgs are addressed to ourself */
        snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname);

        /*
         * Send a netgraph message to disconnect our 'input' hook
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
                     sizeof(struct ngm_rmhook), M_NOWAIT);
        if (msg == NULL)
            return;
        rm = (struct ngm_rmhook *)msg->data;
        strlcpy(rm->ourhook, "input", NG_HOOKSIZ);
        NG_SEND_MSG_PATH(error, node, msg, path, 0);

        /*
         * Send a netgraph message to disconnect our 'output' hook
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
                     sizeof(struct ngm_rmhook), M_NOWAIT);
        if (msg == NULL)
            return;
        rm = (struct ngm_rmhook *)msg->data;
        strlcpy(rm->ourhook, "output", NG_HOOKSIZ);
        NG_SEND_MSG_PATH(error, node, msg, path, 0);
    }
    VBOXCURVNET_RESTORE();
}
예제 #19
0
int
ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_hci_lp_con_ind_ep	*ep = NULL;
	ng_hci_lp_con_rsp_ep	*rp = NULL;
	struct ng_mesg		*rsp = NULL;
	ng_l2cap_con_p		 con = NULL;
	int			 error = 0;

	/* Check message */
	if (msg->header.arglen != sizeof(*ep)) {
		NG_L2CAP_ALERT(
"%s: %s - invalid LP_ConnectInd message size\n",
			__func__, NG_NODE_NAME(l2cap->node));

		return (EMSGSIZE);
	}

 	ep = (ng_hci_lp_con_ind_ep *) (msg->data);

	/* Make sure we have only one connection to the remote unit */
	con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
	if (con != NULL) {
		NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectInd event. " \
"Connection already exists, state=%d, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state, 
			con->con_handle);

		return (EEXIST);
	}

	/* Check if lower layer protocol is still connected */
	if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
		NG_L2CAP_ERR(
"%s: %s - hook \"%s\" is not connected or valid",
			__func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);

		return (ENOTCONN);
	}

	/* Create and intialize new connection descriptor */
	con = ng_l2cap_new_con(l2cap, &ep->bdaddr);
	if (con == NULL)
		return (ENOMEM);

	/* Create and send LP_ConnectRsp event */
	NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
		sizeof(*rp), M_NOWAIT);
	if (rsp == NULL) {
		ng_l2cap_free_con(con);

		return (ENOMEM);
	}

	rp = (ng_hci_lp_con_rsp_ep *)(rsp->data);
	rp->status = 0x00; /* accept connection */
	rp->link_type = NG_HCI_LINK_ACL;
	bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr));

	con->state = NG_L2CAP_W4_LP_CON_CFM;
	ng_l2cap_lp_timeout(con);

	NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0);
	if (error != 0) {
		if (ng_l2cap_lp_untimeout(con) == 0)
			ng_l2cap_free_con(con);

		/*
		 * Do not free connection if ng_l2cap_lp_untimeout() failed
		 * let timeout handler deal with it. Always return error to
		 * the caller.
		 */
	}

	return (error);
} /* ng_l2cap_lp_con_ind */
예제 #20
0
/*
 * Handle the first completed incoming connection, assumed to be already
 * on the socket's so_comp queue.
 */
static void
ng_ksocket_finish_accept(priv_p priv)
{
	struct socket *const head = priv->so;
	struct socket *so;
	struct sockaddr *sa = NULL;
	struct ng_mesg *resp;
	struct ng_ksocket_accept *resp_data;
	node_p node;
	priv_p priv2;
	int len;
	int error;

	ACCEPT_LOCK();
	so = TAILQ_FIRST(&head->so_comp);
	if (so == NULL) {	/* Should never happen */
		ACCEPT_UNLOCK();
		return;
	}
	TAILQ_REMOVE(&head->so_comp, so, so_list);
	head->so_qlen--;
	so->so_qstate &= ~SQ_COMP;
	so->so_head = NULL;
	SOCK_LOCK(so);
	soref(so);
	sosetstate(so, SS_NBIO);
	SOCK_UNLOCK(so);
	ACCEPT_UNLOCK();

	/* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */

	soaccept(so, &sa);

	len = OFFSETOF(struct ng_ksocket_accept, addr);
	if (sa != NULL)
		len += sa->sa_len;

	NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len,
	    M_WAITOK | M_NULLOK);
	if (resp == NULL) {
		soclose(so);
		goto out;
	}
	resp->header.flags |= NGF_RESP;
	resp->header.token = priv->response_token;

	/* Clone a ksocket node to wrap the new socket */
        error = ng_make_node_common(&ng_ksocket_typestruct, &node);
        if (error) {
		kfree(resp, M_NETGRAPH);
		soclose(so);
		goto out;
	}

	if (ng_ksocket_constructor(node) != 0) {
		NG_NODE_UNREF(node);
		kfree(resp, M_NETGRAPH);
		soclose(so);
		goto out;
	}

	priv2 = NG_NODE_PRIVATE(node);
	priv2->so = so;
	priv2->flags |= KSF_CLONED | KSF_EMBRYONIC;

	/*
	 * Insert the cloned node into a list of embryonic children
	 * on the parent node.  When a hook is created on the cloned
	 * node it will be removed from this list.  When the parent
	 * is destroyed it will destroy any embryonic children it has.
	 */
	LIST_INSERT_HEAD(&priv->embryos, priv2, siblings);

	so->so_upcallarg = (caddr_t)node;
	so->so_upcall = ng_ksocket_incoming;
	SOCKBUF_LOCK(&so->so_rcv);
	so->so_rcv.sb_flags |= SB_UPCALL;
	SOCKBUF_UNLOCK(&so->so_rcv);
	SOCKBUF_LOCK(&so->so_snd);
	so->so_snd.sb_flags |= SB_UPCALL;
	SOCKBUF_UNLOCK(&so->so_snd);

	/* Fill in the response data and send it or return it to the caller */
	resp_data = (struct ng_ksocket_accept *)resp->data;
	resp_data->nodeid = NG_NODE_ID(node);
	if (sa != NULL)
		bcopy(sa, &resp_data->addr, sa->sa_len);
	NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0);

out:
	if (sa != NULL)
		kfree(sa, M_SONAME);
}
예제 #21
0
/*
 * When incoming data is appended to the socket, we get notified here.
 * This is also called whenever a significant event occurs for the socket.
 * Our original caller may have queued this even some time ago and 
 * we cannot trust that he even still exists. The node however is being
 * held with a reference by the queueing code and guarantied to be valid.
 */
static void
ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2)
{
	struct socket *so = arg1;
	const priv_p priv = NG_NODE_PRIVATE(node);
	struct mbuf *m;
	struct ng_mesg *response;
	struct uio auio;
	int s, flags, error;

	s = splnet();

	/* so = priv->so; *//* XXX could have derived this like so */
	KASSERT(so == priv->so, ("%s: wrong socket", __func__));
	
	/* Allow next incoming event to be queued. */
	atomic_store_rel_int(&priv->fn_sent, 0);

	/* Check whether a pending connect operation has completed */
	if (priv->flags & KSF_CONNECTING) {
		if ((error = so->so_error) != 0) {
			so->so_error = 0;
			soclrstate(so, SS_ISCONNECTING);
		}
		if (!(so->so_state & SS_ISCONNECTING)) {
			NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE,
			    NGM_KSOCKET_CONNECT, sizeof(int32_t), M_WAITOK | M_NULLOK);
			if (response != NULL) {
				response->header.flags |= NGF_RESP;
				response->header.token = priv->response_token;
				*(int32_t *)response->data = error;
				/* 
				 * send an async "response" message
				 * to the node that set us up
				 * (if it still exists)
				 */
				NG_SEND_MSG_ID(error, node,
				    response, priv->response_addr, 0);
			}
			priv->flags &= ~KSF_CONNECTING;
		}
	}

	/* Check whether a pending accept operation has completed */
	if (priv->flags & KSF_ACCEPTING) {
		error = ng_ksocket_check_accept(priv);
		if (error != EWOULDBLOCK)
			priv->flags &= ~KSF_ACCEPTING;
		if (error == 0)
			ng_ksocket_finish_accept(priv);
	}

	/*
	 * If we don't have a hook, we must handle data events later.  When
	 * the hook gets created and is connected, this upcall function
	 * will be called again.
	 */
	if (priv->hook == NULL) {
		splx(s);
		return;
	}

	/* Read and forward available mbuf's */
	auio.uio_td = NULL;
	auio.uio_resid = 1000000000;
	flags = MSG_DONTWAIT;
	while (1) {
		struct sockaddr *sa = NULL;
		struct mbuf *n;

		/* Try to get next packet from socket */
		if ((error = soreceive(so, (so->so_state & SS_ISCONNECTED) ?
		    NULL : &sa, &auio, &m, NULL, &flags)) != 0)
			break;

		/* See if we got anything */
		if (m == NULL) {
			if (sa != NULL)
				kfree(sa, M_SONAME);
			break;
		}

		/*
		 * Don't trust the various socket layers to get the
		 * packet header and length correct (e.g. kern/15175).
		 *
		 * Also, do not trust that soreceive() will clear m_nextpkt
		 * for us (e.g. kern/84952, kern/82413).
		 */
		m->m_pkthdr.csum_flags = 0;
		for (n = m, m->m_pkthdr.len = 0; n != NULL; n = n->m_next) {
			m->m_pkthdr.len += n->m_len;
			n->m_nextpkt = NULL;
		}

		/* Put peer's socket address (if any) into a tag */
		if (sa != NULL) {
			struct sa_tag	*stag;

			stag = (struct sa_tag *)m_tag_alloc(NGM_KSOCKET_COOKIE,
			    NG_KSOCKET_TAG_SOCKADDR, sizeof(ng_ID_t) +
			    sa->sa_len, MB_DONTWAIT);
			if (stag == NULL) {
				kfree(sa, M_SONAME);
				goto sendit;
			}
			bcopy(sa, &stag->sa, sa->sa_len);
			kfree(sa, M_SONAME);
			stag->id = NG_NODE_ID(node);
			m_tag_prepend(m, &stag->tag);
		}

sendit:		/* Forward data with optional peer sockaddr as packet tag */
		NG_SEND_DATA_ONLY(error, priv->hook, m);
	}

	/*
	 * If the peer has closed the connection, forward a 0-length mbuf
	 * to indicate end-of-file.
	 */
	if (so->so_rcv.sb_state & SBS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) {
		MGETHDR(m, MB_DONTWAIT, MT_DATA);
		if (m != NULL) {
			m->m_len = m->m_pkthdr.len = 0;
			NG_SEND_DATA_ONLY(error, priv->hook, m);
		}
		priv->flags |= KSF_EOFSEEN;
	}
	splx(s);
}