int
ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_hci_lp_con_cfm_ep	*ep = 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_ConnectCfm[Neg] message size\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = EMSGSIZE;
		goto out;
	}

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

	/* Check if we have requested/accepted this connection */
	con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
	if (con == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = ENOENT;
		goto out;
	}

	/* Check connection state */
	if (con->state != NG_L2CAP_W4_LP_CON_CFM) {
		NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectCfm event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state, 
			con->con_handle);
		error = EINVAL;
		goto out;
	}

	/*
	 * Looks like it is our confirmation. It is safe now to cancel 
	 * connection timer and notify upper layer. If timeout already
	 * happened then ignore connection confirmation and let timeout
	 * handle that.
 	 */

	if ((error = ng_l2cap_lp_untimeout(con)) != 0)
		goto out;

	if (ep->status == 0) {
		con->state = NG_L2CAP_CON_OPEN;
		con->con_handle = ep->con_handle;
		ng_l2cap_lp_deliver(con);
	} else /* Negative confirmation - remove connection descriptor */
		ng_l2cap_con_fail(con, ep->status);
out:
	return (error);
} /* ng_l2cap_lp_con_cfm */
Beispiel #2
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 */
Beispiel #3
0
int
ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_hci_lp_discon_ind_ep	*ep = 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_DisconnectInd message size\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = EMSGSIZE;
		goto out;
	}

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

	/* Check if we have this connection */
	con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
	if (con == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Connection does not exist, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
		error = ENOENT;
		goto out;
	}

	/* XXX Verify connection state -- do we need to check this? */
	if (con->state != NG_L2CAP_CON_OPEN) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state, 
			con->con_handle);
		error = EINVAL;
		goto out;
	}

	/*
	 * Notify upper layer and remove connection
	 * Note: The connection could have auto disconnect timeout set. Try
	 * to remove it. If auto disconnect timeout happened then ignore
	 * disconnect indication and let timeout handle that.
	 */

	if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
		if ((error = ng_l2cap_discon_untimeout(con)) != 0)
			return (error);

	ng_l2cap_con_fail(con, ep->reason);
out:
	return (error);
} /* ng_l2cap_lp_discon_ind */
Beispiel #4
0
int
ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
{
	int link_type;
	
	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
		NG_HCI_WARN(
"%s: %s - unit is not ready, state=%#x\n",
			__func__, NG_NODE_NAME(unit->node), unit->state);

		NG_FREE_ITEM(item);

		return (ENXIO);
	}

	if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) {
		NG_HCI_ALERT(
"%s: %s - invalid LP_ConnectReq message size=%d\n",
			__func__, NG_NODE_NAME(unit->node),
			NGI_MSG(item)->header.arglen);

		NG_FREE_ITEM(item);

		return (EMSGSIZE);
	}
	link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type;
	switch(link_type){
	case NG_HCI_LINK_ACL:
		return (ng_hci_lp_acl_con_req(unit, item, hook));
	case NG_HCI_LINK_SCO:
		if (hook != unit->sco ) {
			NG_HCI_WARN(
				"%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
				__func__, NG_NODE_NAME(unit->node), hook);
			
			NG_FREE_ITEM(item);
			
			return (EINVAL);
		}
		
		return (ng_hci_lp_sco_con_req(unit, item, hook));
	case NG_HCI_LINK_LE_PUBLIC:
	case NG_HCI_LINK_LE_RANDOM:		
		return (ng_hci_lp_le_con_req(unit, item, hook, link_type));
	default:
		panic("%s: link_type invalid.", __func__);
	}
	
	return (EINVAL);
} /* ng_hci_lp_con_req */
Beispiel #5
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 */
Beispiel #6
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 */
Beispiel #7
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 */
Beispiel #8
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 */
Beispiel #9
0
int
ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_hci_lp_discon_ind_ep	*ep = 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_DisconnectInd message size\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = EMSGSIZE;
		goto out;
	}

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

	/* Check if we have this connection */
	con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
	if (con == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Connection does not exist, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
		error = ENOENT;
		goto out;
	}

	/* XXX Verify connection state -- do we need to check this? */
	if (con->state != NG_L2CAP_CON_OPEN) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_DisconnectInd event. " \
"Invalid connection state, state=%d, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state, 
			con->con_handle);
		error = EINVAL;
		goto out;
	}

	/* Notify upper layer and remove connection */
	con->state = NG_L2CAP_CON_CLOSED;
	ng_l2cap_con_fail(con, ep->reason);
out:
	return (error);
} /* ng_l2cap_lp_discon_ind */
Beispiel #10
0
/*
 * Used for both data and control sockets
 */
static void
ng_getsockaddr(netmsg_t msg)
{
	struct socket *so = msg->sockaddr.base.nm_so;
	struct sockaddr **addr = msg->sockaddr.nm_nam;
	struct ngpcb *pcbp;
	struct sockaddr_ng *sg;
	int sg_len;
	int error = 0;

	/* Why isn't sg_data a `char[1]' ? :-( */
	sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1;

	pcbp = sotongpcb(so);
	if ((pcbp == NULL) || (pcbp->sockdata == NULL)) {
		/* XXXGL: can this still happen? */
		error = EINVAL;
		goto replymsg;
	}

	mtx_lock(&pcbp->sockdata->mtx);
	if (pcbp->sockdata->node != NULL) {
		node_p node = pcbp->sockdata->node;
		int namelen = 0;	/* silence compiler! */

		if (NG_NODE_HAS_NAME(node))
			sg_len += namelen = strlen(NG_NODE_NAME(node));

		sg = kmalloc(sg_len, M_SONAME, M_WAITOK | M_ZERO);

		if (NG_NODE_HAS_NAME(node))
			bcopy(NG_NODE_NAME(node), sg->sg_data, namelen);

		sg->sg_len = sg_len;
		sg->sg_family = AF_NETGRAPH;
		*addr = (struct sockaddr *)sg;
		mtx_unlock(&pcbp->sockdata->mtx);
	} else {
		mtx_unlock(&pcbp->sockdata->mtx);
		error = EINVAL;
	}

replymsg:
	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
}
Beispiel #11
0
int
ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_hci_lp_qos_ind_ep	*ep = 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_QoSViolation message size\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = EMSGSIZE;
		goto out;
	}

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

	/* Check if we have this connection */
	con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
	if (con == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected LP_QoSViolationInd event. " \
"Connection does not exist, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
		error = ENOENT;
		goto out;
	}

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

	/* XXX FIXME Notify upper layer and terminate channels if required */
out:
	return (error);
} /* ng_l2cap_qos_ind */
Beispiel #12
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 */
int
ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
{
	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
		NG_HCI_WARN(
"%s: %s - unit is not ready, state=%#x\n",
			__func__, NG_NODE_NAME(unit->node), unit->state);

		NG_FREE_ITEM(item);

		return (ENXIO);
	}

	if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) {
		NG_HCI_ALERT(
"%s: %s - invalid LP_ConnectReq message size=%d\n",
			__func__, NG_NODE_NAME(unit->node),
			NGI_MSG(item)->header.arglen);

		NG_FREE_ITEM(item);

		return (EMSGSIZE);
	}

	if (((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type == NG_HCI_LINK_ACL)
		return (ng_hci_lp_acl_con_req(unit, item, hook));

	if (hook != unit->sco) {
		NG_HCI_WARN(
"%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
			__func__, NG_NODE_NAME(unit->node), hook);

		NG_FREE_ITEM(item);

		return (EINVAL);
	}

	return (ng_hci_lp_sco_con_req(unit, item, hook));
} /* ng_hci_lp_con_req */
int
ng_hci_command_timeout(ng_hci_unit_p unit)
{
	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
		panic(
"%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node));

	unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
	ng_callout(&unit->cmd_timo, unit->node, NULL,
				bluetooth_hci_command_timeout(),
				ng_hci_process_command_timeout, NULL, 0);

	return (0);
} /* ng_hci_command_timeout */
int
ng_hci_con_untimeout(ng_hci_unit_con_p con)
{
	if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING))
		panic(
"%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node));

	if (ng_uncallout(&con->con_timo, con->unit->node) == 0)
		return (ETIMEDOUT);

	con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;

	return (0);
} /* ng_hci_con_untimeout */
int
ng_hci_command_untimeout(ng_hci_unit_p unit)
{
	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
		panic(
"%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node));

	if (ng_uncallout(&unit->cmd_timo, unit->node) == 0)
		return (ETIMEDOUT);

	unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;

	return (0);
} /* ng_hci_command_untimeout */
Beispiel #17
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 */
int
ng_hci_con_timeout(ng_hci_unit_con_p con)
{
	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
		panic(
"%s: %s - Duplicated connection timeout!\n",
			__func__, NG_NODE_NAME(con->unit->node));

	con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
	ng_callout(&con->con_timo, con->unit->node, NULL,
				bluetooth_hci_connect_timeout(),
				ng_hci_process_con_timeout, NULL,
				con->con_handle);

	return (0);
} /* ng_hci_con_timeout */
void
ng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
{
	struct mbuf	*m = NULL;
	int		 error = 0;

	if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
		m = m_dup(m0, M_DONTWAIT);
		if (m != NULL)
			NG_SEND_DATA_ONLY(error, unit->raw, m);

		if (error != 0)
			NG_HCI_INFO(
"%s: %s - Could not forward packet, error=%d\n",
				__func__, NG_NODE_NAME(unit->node), error);
	}
} /* ng_hci_mtap */
Beispiel #20
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 */
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 */
Beispiel #22
0
int
ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_hci_lp_qos_cfm_ep	*ep = NULL;
	int			 error = 0;

	/* Check message */
	if (msg->header.arglen != sizeof(*ep)) {
		NG_L2CAP_ALERT(
"%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n",
			__func__, NG_NODE_NAME(l2cap->node));
		error = EMSGSIZE;
		goto out;
	}

	ep = (ng_hci_lp_qos_cfm_ep *) (msg->data);
	/* XXX FIXME do something */
out:
	return (error);
} /* ng_l2cap_lp_qos_cfm */
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 */
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 */
Beispiel #25
0
int
ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
{
	struct _clt_pkt {
		ng_l2cap_hdr_t		 h;
		ng_l2cap_clt_hdr_t	 c_h;
	} __attribute__ ((packed))	*hdr = NULL;
	ng_l2cap_p			 l2cap = con->l2cap;
	int				 length, error = 0;

	NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
	if (con->rx_pkt == NULL)
		return (ENOBUFS);

	hdr = mtod(con->rx_pkt, struct _clt_pkt *);

	/* Check packet */
	length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
	if (length < 0) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), length);
		error = EMSGSIZE;
		goto drop;
	}

	/* Check payload size against CLT MTU */
	if (length > NG_L2CAP_MTU_DEFAULT) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), length,
			NG_L2CAP_MTU_DEFAULT);
		error = EMSGSIZE;
		goto drop;
	}

	hdr->c_h.psm = le16toh(hdr->c_h.psm);

	/*
	 * If we got here then everything looks good and we can sent packet
	 * to the upper layer protocol.
	 */

	/* Select upstream hook based on PSM */
	switch (hdr->c_h.psm) {
	case NG_L2CAP_PSM_SDP:
		if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
			goto drop;
		break;

	case NG_L2CAP_PSM_RFCOMM:
		if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
			goto drop;
		break;

	case NG_L2CAP_PSM_TCP:
		if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
			goto drop;
		break;
        }

	/* 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 L2CAP CLT data packet. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
		error = ENOTCONN;
		goto drop;
	}

	NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
	con->rx_pkt = NULL;
drop:
	NG_FREE_M(con->rx_pkt); /* checks for != NULL */

	return (error);
} /* ng_l2cap_l2ca_clt_receive */
Beispiel #26
0
int
ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
{
	ng_l2cap_p	 l2cap = con->l2cap;
	ng_l2cap_hdr_t	*hdr = NULL;
	ng_l2cap_chan_p  ch = NULL;
	int		 error = 0;

	NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
	if (con->rx_pkt == NULL)
		return (ENOBUFS);

	hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);

	/* Check channel */
	ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid);
	if (ch == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), hdr->dcid);
		error = ENOENT;
		goto drop;
	}

	/* Check channel state */
	if (ch->state != NG_L2CAP_OPEN) {
		NG_L2CAP_WARN(
"%s: %s - unexpected L2CAP data packet. " \
"Invalid channel state, cid=%d, state=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->scid,
			ch->state);
		error = EHOSTDOWN; /* XXX not always - re-configuration */
		goto drop;
	}

	/* Check payload size and channel's MTU */
	if (hdr->length > ch->imtu) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CAP data packet. " \
"Packet too big, length=%d, imtu=%d, cid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), hdr->length, 
			ch->imtu, ch->scid);
		error = EMSGSIZE;
		goto drop;
	}

	/*
	 * If we got here then everything looks good and we can sent packet
	 * to the upper layer protocol.
	 */

	/* 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 L2CAP data packet. " \
"Hook is not connected or valid, psm=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
		error = ENOTCONN;
		goto drop;
	}

	NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
	con->rx_pkt = NULL;
drop:
	NG_FREE_M(con->rx_pkt); /* checks for != NULL */

	return (error);
} /* ng_l2cap_receive */
Beispiel #27
0
int
ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
{
	ng_l2cap_l2ca_hdr_t	*l2ca_hdr = NULL;
	ng_l2cap_chan_p		 ch = NULL;
	ng_l2cap_cmd_p		 cmd = NULL;
	int			 error = 0;
	u_int32_t		 token = 0;

	/* Make sure we can access L2CA data packet header */
	if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
		NG_L2CAP_ERR(
"%s: %s - L2CA Data packet too small, len=%d\n",
			__func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
		error = EMSGSIZE;
		goto drop;
	}

	/* Get L2CA data packet header */
	NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
	if (m == NULL)
		return (ENOBUFS);

	l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
	token = l2ca_hdr->token;
	m_adj(m, sizeof(*l2ca_hdr));

	/* Verify payload size */
	if (l2ca_hdr->length != m->m_pkthdr.len) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CA Data packet. " \
"Payload length does not match, length=%d, len=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
			m->m_pkthdr.len);
		error = EMSGSIZE;
		goto drop;
	}

	/* Check channel ID */
	if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
		error = EINVAL;
		goto drop;
	}

	/* Verify that we have the channel and make sure it is open */
	ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid);
	if (ch == NULL) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
		error = ENOENT;
		goto drop;
	}

	if (ch->state != NG_L2CAP_OPEN) {
		NG_L2CAP_ERR(
"%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
			 __func__, NG_NODE_NAME(l2cap->node), ch->scid, 
			ch->state);
		error = EHOSTDOWN;
		goto drop; /* XXX not always - re-configure */
	}

	/* Create L2CAP command descriptor */
	cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
	if (cmd == NULL) {
		error = ENOMEM;
		goto drop;
	}

	/* Attach data packet and link command to the queue */
	cmd->aux = m;
	ng_l2cap_link_cmd(ch->con, cmd);
	ng_l2cap_lp_deliver(ch->con);

	return (error);
drop:
	NG_FREE_M(m);

	return (error);
} /* ng_l2cap_l2ca_write_req */
Beispiel #28
0
int
ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_cfg_ip	*ip = NULL;
	ng_l2cap_chan_p		 ch = NULL;
	ng_l2cap_cmd_p		 cmd = NULL;
	struct mbuf		*opt = NULL;
        u_int16_t		*mtu = NULL, *flush_timo = NULL;
        ng_l2cap_flow_p		 flow = NULL;
	int			 error = 0;

	/* Check message */
	if (msg->header.arglen != sizeof(*ip)) {
		NG_L2CAP_ALERT(
"%s: %s - Invalid L2CA_Config request message size, size=%d\n",
			__func__, NG_NODE_NAME(l2cap->node),
			msg->header.arglen);
		error = EMSGSIZE;
		goto out;
	}

	ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);

	/* Check if we have this channel */
	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
	if (ch == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_Config request message. " \
"Channel does not exist, lcid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
		error = ENOENT;
		goto out;
	}

	/* Check channel state */
	if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_Config request message. " \
"Invalid channel state, state=%d, lcid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->state,
			ch->scid);
		error = EINVAL;
		goto out;
	}

	/* Set requested channel configuration options */
	ch->imtu = ip->imtu;
	bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
	ch->flush_timo = ip->flush_timo;
	ch->link_timo = ip->link_timo;

	/* Compare channel settings with defaults */
	if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
		mtu = &ch->imtu;
	if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
		flush_timo = &ch->flush_timo;
	if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
		flow = &ch->oflow;

	/* Create configuration options */
	_ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
	if (opt == NULL) {
                error = ENOBUFS;
		goto out;
	}

	/* Create L2CAP command descriptor */
	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
			NG_L2CAP_CFG_REQ, msg->header.token);
	if (cmd == NULL) {
		NG_FREE_M(opt);
		error = ENOMEM;
		goto out;
	}

	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
		ng_l2cap_free_cmd(cmd);
		NG_FREE_M(opt);
		error = EIO;
		goto out;
	}

	/* Create L2CAP command packet */
	_ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
	if (cmd->aux == NULL) {
		ng_l2cap_free_cmd(cmd);
		error =  ENOBUFS;
		goto out;
	}

	/* Adjust channel state for re-configuration */
	if (ch->state == NG_L2CAP_OPEN) {
		ch->state = NG_L2CAP_CONFIG;
		ch->cfg_state = 0;
	}

        /* Link command to the queue */
	ng_l2cap_link_cmd(ch->con, cmd);
	ng_l2cap_lp_deliver(ch->con);
out:
	return (error);
} /* ng_l2cap_l2ca_cfg_req */
Beispiel #29
0
int
ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_cfg_rsp_ip	*ip = NULL;
	ng_l2cap_chan_p			 ch = NULL;
	ng_l2cap_cmd_p			 cmd = NULL;
	struct mbuf			*opt = NULL;
	u_int16_t			*mtu = NULL;
	ng_l2cap_flow_p			 flow = NULL;
	int				 error = 0;

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

	ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);

	/* Check if we have this channel */
	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
	if (ch == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_ConfigRsp request message. " \
"Channel does not exist, lcid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
		error = ENOENT;
		goto out;
	}

	/* Check channel state */
	if (ch->state != NG_L2CAP_CONFIG) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_ConfigRsp request message. " \
"Invalid channel state, state=%d, lcid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->state,
			ch->scid);
		error = EINVAL;
		goto out;
	}

	/* Set channel settings */
	if (ip->omtu != ch->omtu) {
		ch->omtu = ip->omtu;
		mtu = &ch->omtu;
	}

	if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { 
		bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
		flow = &ch->iflow;
	}

	if (mtu != NULL || flow != NULL) {
		_ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
		if (opt == NULL) {
			error = ENOBUFS;
			goto out;
		}
	}

	/* Create L2CAP command */
	cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
			msg->header.token);
	if (cmd == NULL) {
		NG_FREE_M(opt);
		error = ENOMEM;
		goto out;
	}

	_ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
	if (cmd->aux == NULL) {
		ng_l2cap_free_cmd(cmd);
		error = ENOBUFS;
		goto out;
	}

	/* XXX FIXME - not here ??? */
	ch->cfg_state |= NG_L2CAP_CFG_OUT;
	if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
		ch->state = NG_L2CAP_OPEN;

	/* Link command to the queue */
	ng_l2cap_link_cmd(ch->con, cmd);
	ng_l2cap_lp_deliver(ch->con);
out:
	return (error);
} /* ng_l2cap_l2ca_cfg_rsp_req */
Beispiel #30
0
int
ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_con_ip	*ip = NULL;
	ng_l2cap_con_p		 con = NULL;
	ng_l2cap_chan_p		 ch = NULL;
	ng_l2cap_cmd_p		 cmd = NULL;
	int			 error = 0;

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

	ip = (ng_l2cap_l2ca_con_ip *)(msg->data);

	/* Check if we have connection to the remote unit */
	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
	if (con == NULL) {
		/* Submit LP_ConnectReq to the lower layer */
		error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr);
		if (error != 0) {
			NG_L2CAP_ERR(
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
				__func__, NG_NODE_NAME(l2cap->node), error);
			goto out;
		}

		/* This should not fail */
		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
		KASSERT((con != NULL),
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
	}

	/*
	 * Create new empty channel descriptor. In case of any failure do 
	 * not touch connection descriptor.
	 */

	ch = ng_l2cap_new_chan(l2cap, con, ip->psm);
	if (ch == NULL) {
		error = ENOMEM;
		goto out;
	}

	/* Now create L2CAP_ConnectReq command */
	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),
			NG_L2CAP_CON_REQ, msg->header.token);
	if (cmd == NULL) {
		ng_l2cap_free_chan(ch);
		error = ENOMEM;
		goto out;
	}

	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
		ng_l2cap_free_cmd(cmd);
		ng_l2cap_free_chan(ch);
		error = EIO;
		goto out;
	}

	/* Create L2CAP command packet */
	_ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
	if (cmd->aux == NULL) {
		ng_l2cap_free_cmd(cmd);
		ng_l2cap_free_chan(ch);
		error = ENOBUFS;
		goto out;
	}

	ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;

	/* Link command to the queue */
	ng_l2cap_link_cmd(ch->con, cmd);
	ng_l2cap_lp_deliver(ch->con);
out:
	return (error);
} /* ng_l2cap_l2ca_con_req */