diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-02-09 20:59:10 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-02-14 16:39:30 -0500 |
commit | c10a848cea89a8f0418fa0efec33c4e8507aab4b (patch) | |
tree | 1c6eaf6a370f29ca4438bac6a8654c1fabbb1ae2 | |
parent | c949c224cfd7d5445ef947e8b93c0657323d5be5 (diff) |
Bluetooth: Verify dlci not in use before rfcomm_dev create
Only one session/channel combination may be in use at any one
time. However, the failure does not occur until the tty is
opened (in rfcomm_dlc_open()).
Because these settings are actually bound at rfcomm device
creation (via RFCOMMCREATEDEV ioctl), validate and fail before
creating the rfcomm tty device.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Tested-By: Alexander Holler <holler@ahsoftware.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/bluetooth/rfcomm.h | 1 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 26 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 8 |
3 files changed, 34 insertions, 1 deletions
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 0d69936831fa..f8262a2783ec 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h | |||
@@ -241,6 +241,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); | |||
241 | int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); | 241 | int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); |
242 | int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); | 242 | int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); |
243 | void rfcomm_dlc_accept(struct rfcomm_dlc *d); | 243 | void rfcomm_dlc_accept(struct rfcomm_dlc *d); |
244 | struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel); | ||
244 | 245 | ||
245 | #define rfcomm_dlc_lock(d) spin_lock(&d->lock) | 246 | #define rfcomm_dlc_lock(d) spin_lock(&d->lock) |
246 | #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) | 247 | #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) |
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index ba115d472f7b..b378bbb6f8a7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -360,6 +360,11 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) | |||
360 | return NULL; | 360 | return NULL; |
361 | } | 361 | } |
362 | 362 | ||
363 | static int rfcomm_check_channel(u8 channel) | ||
364 | { | ||
365 | return channel < 1 || channel > 30; | ||
366 | } | ||
367 | |||
363 | static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) | 368 | static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) |
364 | { | 369 | { |
365 | struct rfcomm_session *s; | 370 | struct rfcomm_session *s; |
@@ -369,7 +374,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, | |||
369 | BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d", | 374 | BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d", |
370 | d, d->state, src, dst, channel); | 375 | d, d->state, src, dst, channel); |
371 | 376 | ||
372 | if (channel < 1 || channel > 30) | 377 | if (rfcomm_check_channel(channel)) |
373 | return -EINVAL; | 378 | return -EINVAL; |
374 | 379 | ||
375 | if (d->state != BT_OPEN && d->state != BT_CLOSED) | 380 | if (d->state != BT_OPEN && d->state != BT_CLOSED) |
@@ -514,6 +519,25 @@ no_session: | |||
514 | return r; | 519 | return r; |
515 | } | 520 | } |
516 | 521 | ||
522 | struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel) | ||
523 | { | ||
524 | struct rfcomm_session *s; | ||
525 | struct rfcomm_dlc *dlc = NULL; | ||
526 | u8 dlci; | ||
527 | |||
528 | if (rfcomm_check_channel(channel)) | ||
529 | return ERR_PTR(-EINVAL); | ||
530 | |||
531 | rfcomm_lock(); | ||
532 | s = rfcomm_session_get(src, dst); | ||
533 | if (s) { | ||
534 | dlci = __dlci(!s->initiator, channel); | ||
535 | dlc = rfcomm_dlc_get(s, dlci); | ||
536 | } | ||
537 | rfcomm_unlock(); | ||
538 | return dlc; | ||
539 | } | ||
540 | |||
517 | int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) | 541 | int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) |
518 | { | 542 | { |
519 | int len = skb->len; | 543 | int len = skb->len; |
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 6ea08b05b53a..a58d693e1e61 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -385,6 +385,14 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) | |||
385 | dlc = rfcomm_pi(sk)->dlc; | 385 | dlc = rfcomm_pi(sk)->dlc; |
386 | rfcomm_dlc_hold(dlc); | 386 | rfcomm_dlc_hold(dlc); |
387 | } else { | 387 | } else { |
388 | /* Validate the channel is unused */ | ||
389 | dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel); | ||
390 | if (IS_ERR(dlc)) | ||
391 | return PTR_ERR(dlc); | ||
392 | else if (dlc) { | ||
393 | rfcomm_dlc_put(dlc); | ||
394 | return -EBUSY; | ||
395 | } | ||
388 | dlc = rfcomm_dlc_alloc(GFP_KERNEL); | 396 | dlc = rfcomm_dlc_alloc(GFP_KERNEL); |
389 | if (!dlc) | 397 | if (!dlc) |
390 | return -ENOMEM; | 398 | return -ENOMEM; |