Allow RFCOMM servers to bind to a ''wildcard'' RFCOMM channel

zero (0). Actual RFCOMM channel will be assigned after listen(2)
call is done on a RFCOMM socket bound to a ''wildcard'' RFCOMM
channel zero (0).

Address locking issues in ng_btsocket_rfcomm_bind()

Submitted by:	Heiko Wundram (Beenic) < wundram at beenic dot net >
MFC after:	1 week
This commit is contained in:
Maksim Yevmenkin 2007-10-29 19:06:47 +00:00
parent 52f0eb2416
commit a6f3c1e3f3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=173151

View File

@ -167,8 +167,6 @@ static int ng_btsocket_rfcomm_pcb_send
(ng_btsocket_rfcomm_pcb_p pcb, int limit);
static void ng_btsocket_rfcomm_pcb_kill
(ng_btsocket_rfcomm_pcb_p pcb, int error);
static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_by_channel
(bdaddr_p src, int channel);
static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_by_dlci
(ng_btsocket_rfcomm_session_p s, int dlci);
static ng_btsocket_rfcomm_pcb_p ng_btsocket_rfcomm_pcb_listener
@ -440,7 +438,7 @@ int
ng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam,
struct thread *td)
{
ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so);
ng_btsocket_rfcomm_pcb_t *pcb = so2rfcomm_pcb(so), *pcb1;
struct sockaddr_rfcomm *sa = (struct sockaddr_rfcomm *) nam;
if (pcb == NULL)
@ -455,13 +453,31 @@ ng_btsocket_rfcomm_bind(struct socket *so, struct sockaddr *nam,
return (EINVAL);
if (sa->rfcomm_channel > 30)
return (EINVAL);
if (sa->rfcomm_channel != 0 &&
ng_btsocket_rfcomm_pcb_by_channel(&sa->rfcomm_bdaddr, sa->rfcomm_channel) != NULL)
return (EADDRINUSE);
mtx_lock(&pcb->pcb_mtx);
if (sa->rfcomm_channel != 0) {
mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next) {
if (pcb1->channel == sa->rfcomm_channel &&
bcmp(&pcb1->src, &sa->rfcomm_bdaddr,
sizeof(pcb1->src)) == 0) {
mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
mtx_unlock(&pcb->pcb_mtx);
return (EADDRINUSE);
}
}
mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
}
bcopy(&sa->rfcomm_bdaddr, &pcb->src, sizeof(pcb->src));
pcb->channel = sa->rfcomm_channel;
mtx_unlock(&pcb->pcb_mtx);
return (0);
} /* ng_btsocket_rfcomm_bind */
@ -796,17 +812,44 @@ ng_btsocket_rfcomm_disconnect(struct socket *so)
int
ng_btsocket_rfcomm_listen(struct socket *so, int backlog, struct thread *td)
{
ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so);
ng_btsocket_rfcomm_pcb_p pcb = so2rfcomm_pcb(so), pcb1;
ng_btsocket_rfcomm_session_p s = NULL;
struct socket *l2so = NULL;
int error;
int socreate_error;
int error, socreate_error, usedchannels;
if (pcb == NULL)
return (EINVAL);
if (pcb->channel < 1 || pcb->channel > 30)
if (pcb->channel > 30)
return (EADDRNOTAVAIL);
usedchannels = 0;
mtx_lock(&pcb->pcb_mtx);
if (pcb->channel == 0) {
mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
LIST_FOREACH(pcb1, &ng_btsocket_rfcomm_sockets, next)
if (pcb1->channel != 0 &&
bcmp(&pcb1->src, &pcb->src, sizeof(pcb->src)) == 0)
usedchannels |= (1 << (pcb1->channel - 1));
for (pcb->channel = 30; pcb->channel > 0; pcb->channel --)
if (!(usedchannels & (1 << (pcb->channel - 1))))
break;
if (pcb->channel == 0) {
mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
mtx_unlock(&pcb->pcb_mtx);
return (EADDRNOTAVAIL);
}
mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
}
mtx_unlock(&pcb->pcb_mtx);
/*
* XXX FIXME - This is FUBAR. socreate() will call soalloc(1), i.e.
* soalloc() is allowed to sleep in MALLOC. This creates "could sleep"
@ -3340,27 +3383,6 @@ ng_btsocket_rfcomm_pcb_kill(ng_btsocket_rfcomm_pcb_p pcb, int error)
}
} /* ng_btsocket_rfcomm_pcb_kill */
/*
* Look for RFCOMM socket with given channel and source address
*/
static ng_btsocket_rfcomm_pcb_p
ng_btsocket_rfcomm_pcb_by_channel(bdaddr_p src, int channel)
{
ng_btsocket_rfcomm_pcb_p pcb = NULL;
mtx_lock(&ng_btsocket_rfcomm_sockets_mtx);
LIST_FOREACH(pcb, &ng_btsocket_rfcomm_sockets, next)
if (pcb->channel == channel &&
bcmp(&pcb->src, src, sizeof(*src)) == 0)
break;
mtx_unlock(&ng_btsocket_rfcomm_sockets_mtx);
return (pcb);
} /* ng_btsocket_rfcomm_pcb_by_channel */
/*
* Look for given dlci for given RFCOMM session. Caller must hold s->session_mtx
*/