예제 #1
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->flags |= NG_L2CAP_CON_OUTGOING;
	con->state = NG_L2CAP_W4_LP_CON_CFM;
	ng_l2cap_lp_timeout(con);

	NG_SEND_MSG_HOOK(error, l2cap->node, msg, 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_req */
예제 #2
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 */
예제 #3
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 */
예제 #4
0
int
ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m)
{
	ng_hci_acldata_pkt_t	*acl_hdr = NULL;
	ng_l2cap_hdr_t		*l2cap_hdr = NULL;
	ng_l2cap_con_p		 con = NULL;
	u_int16_t		 con_handle, length, pb;
	int			 error = 0;

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

	/* Strip ACL data packet header */
	NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr));
	if (m == NULL)
		return (ENOBUFS);

	acl_hdr = mtod(m, ng_hci_acldata_pkt_t *);
	m_adj(m, sizeof(*acl_hdr));

	/* Get ACL connection handle, PB flag and payload length */
	acl_hdr->con_handle = le16toh(acl_hdr->con_handle);
	con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle);
	pb = NG_HCI_PB_FLAG(acl_hdr->con_handle);
	length = le16toh(acl_hdr->length);

	NG_L2CAP_INFO(
"%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n",
		__func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length);

	/* Get connection descriptor */
	con = ng_l2cap_con_by_handle(l2cap, con_handle);
	if (con == NULL) {
		NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet. " \
"Connection does not exist, con_handle=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con_handle);
		error = ENOENT;
		goto drop;
	}

	/* Verify connection state */
	if (con->state != NG_L2CAP_CON_OPEN) {
		NG_L2CAP_ERR(
"%s: %s - unexpected ACL data packet. Invalid connection state=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con->state);
		error = EHOSTDOWN;
		goto drop;
	}

	/* Process packet */
	if (pb == NG_HCI_PACKET_START) {
		if (con->rx_pkt != NULL) {
			NG_L2CAP_ERR(
"%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n",
				__func__, NG_NODE_NAME(l2cap->node),
				con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
			NG_FREE_M(con->rx_pkt);
			con->rx_pkt_len = 0;
		}

		/* Get L2CAP header */
		if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) {
			NG_L2CAP_ERR(
"%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n",
				__func__, NG_NODE_NAME(l2cap->node),
				m->m_pkthdr.len);
			error = EMSGSIZE;
			goto drop;
		}

		NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr));
		if (m == NULL)
			return (ENOBUFS);

		l2cap_hdr = mtod(m, ng_l2cap_hdr_t *);

		NG_L2CAP_INFO(
"%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), con_handle,
			le16toh(l2cap_hdr->length));

		/* Start new L2CAP packet */
		con->rx_pkt = m;
		con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr);
	} else if (pb == NG_HCI_PACKET_FRAGMENT) {
예제 #5
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 */
예제 #6
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 */
예제 #7
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 */
예제 #8
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 */
예제 #9
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 */
예제 #10
0
int
ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_con_rsp_ip	*ip = NULL;
	ng_l2cap_con_p			 con = NULL;
	ng_l2cap_chan_p			 ch = NULL;
	ng_l2cap_cmd_p			 cmd = NULL;
	u_int16_t			 dcid;
	int				 error = 0;

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

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

	/* Check if we have this channel */
	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
	if (ch == NULL) {
		NG_L2CAP_ALERT(
"%s: %s - unexpected L2CA_ConnectRsp 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_W4_L2CA_CON_RSP) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_ConnectRsp request message. " \
"Invalid channel state, state=%d, lcid=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->state,
			ip->lcid);
		error = EINVAL;
		goto out;
	}

	dcid = ch->dcid;
	con = ch->con;

	/*
	 * Now we are pretty much sure it is our response. So create and send 
	 * L2CAP_ConnectRsp message to our peer.
	 */

	if (ch->ident != ip->ident)
		NG_L2CAP_WARN(
"%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
"Will use response ident=%d\n",
			__func__, NG_NODE_NAME(l2cap->node), ch->scid, 
			ch->ident, ip->ident);

	/* Check result */
	switch (ip->result) {
	case NG_L2CAP_SUCCESS:
		ch->state = NG_L2CAP_CONFIG;
		ch->cfg_state = 0;
		break;

	case NG_L2CAP_PENDING:
		break;

	default:
		ng_l2cap_free_chan(ch);
		ch = NULL;
		break;
	}

	/* Create L2CAP command */
	cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
			msg->header.token);
	if (cmd == NULL) {
		if (ch != NULL)
			ng_l2cap_free_chan(ch);

		error = ENOMEM;
		goto out;
	}

	_ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid, 
		ip->result, ip->status);
	if (cmd->aux == NULL) {
		if (ch != NULL)
			ng_l2cap_free_chan(ch);

		ng_l2cap_free_cmd(cmd);
		error = ENOBUFS;
		goto out;
	} 

	/* Link command to the queue */
	ng_l2cap_link_cmd(con, cmd);
	ng_l2cap_lp_deliver(con);
out:
	return (error);
} /* ng_l2cap_l2ca_con_rsp_req */
예제 #11
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 */
예제 #12
0
int
ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_get_info_ip	*ip = NULL;
	ng_l2cap_con_p			 con = NULL;
	ng_l2cap_cmd_p			 cmd = NULL;
	int				 error = 0;

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

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

	/* Check if we have connection to the 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 L2CAP command descriptor */
	cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
			NG_L2CAP_INFO_REQ, msg->header.token);
	if (cmd == NULL) {
		error = ENOMEM;
		goto out;
	}

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

	/* Create L2CAP command packet */
	_ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
	if (cmd->aux == NULL) {
		ng_l2cap_free_cmd(cmd);
		error = ENOBUFS;
		goto out;
	}

        /* Link command to the queue */
	ng_l2cap_link_cmd(con, cmd);
	ng_l2cap_lp_deliver(con);
out:
	return (error);
} /* ng_l2cap_l2ca_get_info_req */
예제 #13
0
int
ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
{
	ng_l2cap_l2ca_discon_ip	*ip = 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_Disconnect request message size, size=%d\n",
			__func__, NG_NODE_NAME(l2cap->node),
			msg->header.arglen);
		error = EMSGSIZE;
		goto out;
	}

	ip = (ng_l2cap_l2ca_discon_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_Disconnect 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 && ch->state != NG_L2CAP_OPEN && 
	    ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
		NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_Disconnect request message. " \
"Invalid channel state, state=%d, lcid=%d\n", 
			__func__, NG_NODE_NAME(l2cap->node), ch->state,
			ch->scid);
		error = EINVAL;
		goto out;
	}

	/* Create and send L2CAP_DisconReq message */
	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
			NG_L2CAP_DISCON_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_chan(ch);
		ng_l2cap_free_cmd(cmd);
		error = EIO;
		goto out;
	}

	_ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
	if (cmd->aux == NULL) {
		ng_l2cap_free_chan(ch);
		ng_l2cap_free_cmd(cmd);
		error = ENOBUFS;
		goto out;
	}

	ch->state = NG_L2CAP_W4_L2CAP_DISCON_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_discon_req */