Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
#include <netgraph/bluetooth/include/ng_l2cap.h> | #include <netgraph/bluetooth/include/ng_l2cap.h> | ||||
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> | #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> | ||||
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> | #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> | ||||
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> | #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> | ||||
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> | #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> | ||||
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> | #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> | ||||
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> | #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> | ||||
static u_int16_t ng_l2cap_get_cid (ng_l2cap_p); | static u_int16_t ng_l2cap_get_cid (ng_l2cap_p, int); | ||||
/****************************************************************************** | /****************************************************************************** | ||||
****************************************************************************** | ****************************************************************************** | ||||
** Utility routines | ** Utility routines | ||||
****************************************************************************** | ****************************************************************************** | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
/* | /* | ||||
* Send hook information to the upper layer | * Send hook information to the upper layer | ||||
*/ | */ | ||||
void | void | ||||
ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2) | ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2) | ||||
{ | { | ||||
ng_l2cap_p l2cap = NULL; | ng_l2cap_p l2cap = NULL; | ||||
struct ng_mesg *msg = NULL; | struct ng_mesg *msg = NULL; | ||||
int error = 0; | int error = 0; | ||||
ng_l2cap_node_hook_info_ep *ep ; | |||||
if (node == NULL || NG_NODE_NOT_VALID(node) || | if (node == NULL || NG_NODE_NOT_VALID(node) || | ||||
hook == NULL || NG_HOOK_NOT_VALID(hook)) | hook == NULL || NG_HOOK_NOT_VALID(hook)) | ||||
return; | return; | ||||
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); | l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); | ||||
if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) || | if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) || | ||||
bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0) | bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0) | ||||
return; | return; | ||||
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO, | NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO, | ||||
sizeof(bdaddr_t), M_NOWAIT); | sizeof(*ep), M_NOWAIT); | ||||
if (msg != NULL) { | if (msg != NULL) { | ||||
bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t)); | ep = (ng_l2cap_node_hook_info_ep *) &msg->data; | ||||
bcopy(&l2cap->bdaddr, &ep->addr, sizeof(bdaddr_t)); | |||||
NG_SEND_MSG_HOOK(error, node, msg, hook, 0); | NG_SEND_MSG_HOOK(error, node, msg, hook, 0); | ||||
} else | } else | ||||
error = ENOMEM; | error = ENOMEM; | ||||
if (error != 0) | if (error != 0) | ||||
NG_L2CAP_INFO( | NG_L2CAP_INFO( | ||||
"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n", | "%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n", | ||||
__func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook), | __func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook), | ||||
error); | error); | ||||
} /* ng_l2cap_send_hook_info */ | } /* ng_l2cap_send_hook_info */ | ||||
/* | /* | ||||
* Create new connection descriptor for the "remote" unit. | * Create new connection descriptor for the "remote" unit. | ||||
* Will link connection descriptor to the l2cap node. | * Will link connection descriptor to the l2cap node. | ||||
*/ | */ | ||||
ng_l2cap_con_p | ng_l2cap_con_p | ||||
ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr) | ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type) | ||||
{ | { | ||||
static int fake_con_handle = 0x0f00; | static int fake_con_handle = 0x0f00; | ||||
ng_l2cap_con_p con = NULL; | ng_l2cap_con_p con = NULL; | ||||
/* Create new connection descriptor */ | /* Create new connection descriptor */ | ||||
con = malloc(sizeof(*con), M_NETGRAPH_L2CAP, | con = malloc(sizeof(*con), M_NETGRAPH_L2CAP, | ||||
M_NOWAIT|M_ZERO); | M_NOWAIT|M_ZERO); | ||||
if (con == NULL) | if (con == NULL) | ||||
Show All 16 Lines | ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type) | ||||
* went into node's queue | * went into node's queue | ||||
*/ | */ | ||||
con->con_handle = fake_con_handle ++; | con->con_handle = fake_con_handle ++; | ||||
if (fake_con_handle > 0x0fff) | if (fake_con_handle > 0x0fff) | ||||
fake_con_handle = 0x0f00; | fake_con_handle = 0x0f00; | ||||
bcopy(bdaddr, &con->remote, sizeof(con->remote)); | bcopy(bdaddr, &con->remote, sizeof(con->remote)); | ||||
con->linktype = type; | |||||
ng_callout_init(&con->con_timo); | ng_callout_init(&con->con_timo); | ||||
con->ident = NG_L2CAP_FIRST_IDENT - 1; | con->ident = NG_L2CAP_FIRST_IDENT - 1; | ||||
TAILQ_INIT(&con->cmd_list); | TAILQ_INIT(&con->cmd_list); | ||||
/* Link connection */ | /* Link connection */ | ||||
LIST_INSERT_HEAD(&l2cap->con_list, con, next); | LIST_INSERT_HEAD(&l2cap->con_list, con, next); | ||||
▲ Show 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | "%s: %s - timeout pending! state=%d, flags=%#x\n", | ||||
free(con, M_NETGRAPH_L2CAP); | free(con, M_NETGRAPH_L2CAP); | ||||
} /* ng_l2cap_free_con */ | } /* ng_l2cap_free_con */ | ||||
/* | /* | ||||
* Get connection by "remote" address | * Get connection by "remote" address | ||||
*/ | */ | ||||
ng_l2cap_con_p | ng_l2cap_con_p | ||||
ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr) | ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr, unsigned int type) | ||||
{ | { | ||||
ng_l2cap_con_p con = NULL; | ng_l2cap_con_p con = NULL; | ||||
LIST_FOREACH(con, &l2cap->con_list, next) | LIST_FOREACH(con, &l2cap->con_list, next) | ||||
if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0) | if ((bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)&& | ||||
(con->linktype == type)) | |||||
break; | break; | ||||
return (con); | return (con); | ||||
} /* ng_l2cap_con_by_addr */ | } /* ng_l2cap_con_by_addr */ | ||||
/* | /* | ||||
* Get connection by "handle" | * Get connection by "handle" | ||||
*/ | */ | ||||
Show All 11 Lines | |||||
} /* ng_l2cap_con_by_handle */ | } /* ng_l2cap_con_by_handle */ | ||||
/* | /* | ||||
* Allocate new L2CAP channel descriptor on "con" conection with "psm". | * Allocate new L2CAP channel descriptor on "con" conection with "psm". | ||||
* Will link the channel to the l2cap node | * Will link the channel to the l2cap node | ||||
*/ | */ | ||||
ng_l2cap_chan_p | ng_l2cap_chan_p | ||||
ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm) | ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm, int idtype) | ||||
{ | { | ||||
ng_l2cap_chan_p ch = NULL; | ng_l2cap_chan_p ch = NULL; | ||||
ch = malloc(sizeof(*ch), M_NETGRAPH_L2CAP, | ch = malloc(sizeof(*ch), M_NETGRAPH_L2CAP, | ||||
M_NOWAIT|M_ZERO); | M_NOWAIT|M_ZERO); | ||||
if (ch == NULL) | if (ch == NULL) | ||||
return (NULL); | return (NULL); | ||||
if(idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ | |||||
ch->scid = ch->dcid = NG_L2CAP_ATT_CID; | |||||
}else{ | |||||
ch->scid = ng_l2cap_get_cid(l2cap, | |||||
(con->linktype!= NG_HCI_LINK_ACL)); | |||||
} | |||||
ch->scid = ng_l2cap_get_cid(l2cap); | |||||
if (ch->scid != NG_L2CAP_NULL_CID) { | if (ch->scid != NG_L2CAP_NULL_CID) { | ||||
/* Initialize channel */ | /* Initialize channel */ | ||||
ch->psm = psm; | ch->psm = psm; | ||||
ch->con = con; | ch->con = con; | ||||
ch->state = NG_L2CAP_CLOSED; | ch->state = NG_L2CAP_CLOSED; | ||||
/* Set MTU and flow control settings to defaults */ | /* Set MTU and flow control settings to defaults */ | ||||
ch->imtu = NG_L2CAP_MTU_DEFAULT; | ch->imtu = NG_L2CAP_MTU_DEFAULT; | ||||
Show All 12 Lines | if (ch->scid != NG_L2CAP_NULL_CID) { | ||||
bzero(ch, sizeof(*ch)); | bzero(ch, sizeof(*ch)); | ||||
free(ch, M_NETGRAPH_L2CAP); | free(ch, M_NETGRAPH_L2CAP); | ||||
ch = NULL; | ch = NULL; | ||||
} | } | ||||
return (ch); | return (ch); | ||||
} /* ng_l2cap_new_chan */ | } /* ng_l2cap_new_chan */ | ||||
/* | |||||
* Get channel by source (local) channel ID | |||||
*/ | |||||
ng_l2cap_chan_p | ng_l2cap_chan_p | ||||
ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid) | ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid, int idtype) | ||||
{ | { | ||||
ng_l2cap_chan_p ch = NULL; | ng_l2cap_chan_p ch = NULL; | ||||
LIST_FOREACH(ch, &l2cap->chan_list, next) | if(idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ | ||||
return NULL; | |||||
} | |||||
LIST_FOREACH(ch, &l2cap->chan_list, next){ | |||||
if((idtype != NG_L2CAP_L2CA_IDTYPE_BREDR)&& | |||||
(ch->con->linktype == NG_HCI_LINK_ACL )) | |||||
continue; | |||||
if((idtype != NG_L2CAP_L2CA_IDTYPE_LE)&& | |||||
(ch->con->linktype != NG_HCI_LINK_ACL )) | |||||
continue; | |||||
if (ch->scid == scid) | if (ch->scid == scid) | ||||
break; | break; | ||||
} | |||||
return (ch); | |||||
} /* ng_l2cap_chan_by_scid */ | |||||
ng_l2cap_chan_p | |||||
ng_l2cap_chan_by_conhandle(ng_l2cap_p l2cap, uint16_t scid, | |||||
u_int16_t con_handle) | |||||
{ | |||||
ng_l2cap_chan_p ch = NULL; | |||||
LIST_FOREACH(ch, &l2cap->chan_list, next){ | |||||
if ((ch->scid == scid) && | |||||
(ch->con->con_handle == con_handle)) | |||||
break; | |||||
} | |||||
return (ch); | return (ch); | ||||
} /* ng_l2cap_chan_by_scid */ | } /* ng_l2cap_chan_by_scid */ | ||||
/* | /* | ||||
* Free channel descriptor. | * Free channel descriptor. | ||||
*/ | */ | ||||
void | void | ||||
ng_l2cap_free_chan(ng_l2cap_chan_p ch) | ng_l2cap_free_chan(ng_l2cap_chan_p ch) | ||||
{ | { | ||||
ng_l2cap_cmd_p f = NULL, n = NULL; | ng_l2cap_cmd_p f = NULL, n = NULL; | ||||
f = TAILQ_FIRST(&ch->con->cmd_list); | f = TAILQ_FIRST(&ch->con->cmd_list); | ||||
while (f != NULL) { | while (f != NULL) { | ||||
n = TAILQ_NEXT(f, next); | n = TAILQ_NEXT(f, next); | ||||
if (f->ch == ch) { | if (f->ch == ch) { | ||||
ng_l2cap_unlink_cmd(f); | ng_l2cap_unlink_cmd(f); | ||||
if (f->flags & NG_L2CAP_CMD_PENDING) | if (f->flags & NG_L2CAP_CMD_PENDING) | ||||
ng_l2cap_command_untimeout(f); | ng_l2cap_command_untimeout(f); | ||||
ng_l2cap_free_cmd(f); | ng_l2cap_free_cmd(f); | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | |||||
} /* ng_l2cap_default_flow */ | } /* ng_l2cap_default_flow */ | ||||
/* | /* | ||||
* Get next available channel ID | * Get next available channel ID | ||||
* XXX FIXME this is *UGLY* but will do for now | * XXX FIXME this is *UGLY* but will do for now | ||||
*/ | */ | ||||
static u_int16_t | static u_int16_t | ||||
ng_l2cap_get_cid(ng_l2cap_p l2cap) | ng_l2cap_get_cid(ng_l2cap_p l2cap,int isle) | ||||
{ | { | ||||
u_int16_t cid = l2cap->cid + 1; | u_int16_t cid ; | ||||
u_int16_t endcid; | |||||
uint16_t mask; | |||||
int idtype; | |||||
if(isle){ | |||||
endcid = l2cap->lecid; | |||||
/*Assume Last CID is 2^n-1 */ | |||||
mask = NG_L2CAP_LELAST_CID; | |||||
idtype = NG_L2CAP_L2CA_IDTYPE_LE; | |||||
}else{ | |||||
endcid = l2cap->cid; | |||||
/*Assume Last CID is 2^n-1 */ | |||||
mask = NG_L2CAP_LAST_CID; | |||||
idtype = NG_L2CAP_L2CA_IDTYPE_BREDR; | |||||
} | |||||
cid = (endcid+1) & mask; | |||||
if (cid < NG_L2CAP_FIRST_CID) | if (cid < NG_L2CAP_FIRST_CID) | ||||
cid = NG_L2CAP_FIRST_CID; | cid = NG_L2CAP_FIRST_CID; | ||||
while (cid != l2cap->cid) { | while (cid != endcid) { | ||||
if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) { | if (ng_l2cap_chan_by_scid(l2cap, cid, idtype) == NULL) { | ||||
if(!isle){ | |||||
l2cap->cid = cid; | l2cap->cid = cid; | ||||
}else{ | |||||
l2cap->lecid = cid; | |||||
} | |||||
return (cid); | return (cid); | ||||
} | } | ||||
cid ++; | cid ++; | ||||
cid &= mask; | |||||
if (cid < NG_L2CAP_FIRST_CID) | if (cid < NG_L2CAP_FIRST_CID) | ||||
cid = NG_L2CAP_FIRST_CID; | cid = NG_L2CAP_FIRST_CID; | ||||
} | } | ||||
return (NG_L2CAP_NULL_CID); | return (NG_L2CAP_NULL_CID); | ||||
} /* ng_l2cap_get_cid */ | } /* ng_l2cap_get_cid */ | ||||
/* | /* | ||||
Show All 27 Lines |