Add 'service level' security for L2CAP and RFCOMM connections, following
the Linux (BlueZ) API. - L2CAP or RFCOMM connections can require the baseband radio link mode be any of: authenticated (devices are paired) encrypted (implies authentication) secured (encryption, plus generate new link key) - for sockets, the mode is set using setsockopt(2) and the socket connection will be aborted if the mode change fails. - mode settings will be applied during connection establishment, and for safety, we enter a wait state and will only proceed when the mode settings are successfuly set. - It is possible to change the mode on already open connections, but not possible to guarantee that data already queued (from either end) will not be delivered. (this is a feature, not a bug) - bthidev(4) and rfcomm_sppd(1) support "auth", "encrypt" and "secure" options - btdevctl(8) by default enables "auth" for HIDs, and "encrypt" for keyboards (which are required to support it)
This commit is contained in:
parent
c4ec0fc4f8
commit
f5db72e7b7
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: bluetooth.4,v 1.4 2006/09/02 23:52:45 wiz Exp $
|
||||
.\" $NetBSD: bluetooth.4,v 1.5 2007/04/21 06:15:22 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006 Itronix Inc.
|
||||
.\" All rights reserved.
|
||||
@ -30,7 +30,7 @@
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd August 27, 2006
|
||||
.Dd April 10, 2007
|
||||
.Dt BLUETOOTH 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -142,6 +142,30 @@ L2CAP socket options:
|
||||
Incoming MTU
|
||||
.It Dv SO_L2CAP_OMTU Op Ar uint16_t
|
||||
Outgoing MTU (read-only)
|
||||
.It Dv SO_L2CAP_LM Op Ar int
|
||||
Link Mode.
|
||||
The following bits may be set:
|
||||
.Pp
|
||||
.Bl -tag -compact -width ".Dv L2CAP_LM_ENCRYPT"
|
||||
.It Dv L2CAP_LM_AUTH
|
||||
Request authentication
|
||||
.Pq pairing .
|
||||
.It Dv L2CAP_LM_ENCRYPT
|
||||
Request encryption
|
||||
.Pq includes auth .
|
||||
.It Dv L2CAP_LM_SECURE
|
||||
Request secured link
|
||||
.Pq encryption, plus change link key .
|
||||
.El
|
||||
.Pp
|
||||
Link mode settings will be applied to the baseband link during L2CAP
|
||||
connection establishment.
|
||||
If the L2CAP connection is already established,
|
||||
.Dv EINPROGRESS
|
||||
may be returned, and it is not possible to guarantee that data already queued
|
||||
.Pq from either end
|
||||
will not be delivered.
|
||||
If the mode change fails, the L2CAP connection will be aborted.
|
||||
.El
|
||||
.Pp
|
||||
L2CAP
|
||||
@ -174,6 +198,30 @@ RFCOMM socket options:
|
||||
.Bl -tag -width XXX
|
||||
.It Dv SO_RFCOMM_MTU Op Ar uint16_t
|
||||
Maximum Frame Size to use for this link.
|
||||
.It Dv SO_RFCOMM_LM Op Ar int
|
||||
Link Mode.
|
||||
The following bits may be set at any time:
|
||||
.Pp
|
||||
.Bl -tag -compact -width ".Dv RFCOMM_LM_ENCRYPT"
|
||||
.It Dv RFCOMM_LM_AUTH
|
||||
Request authentication
|
||||
.Pq pairing .
|
||||
.It Dv RFCOMM_LM_ENCRYPT
|
||||
Request encryption
|
||||
.Pq includes auth .
|
||||
.It Dv RFCOMM_LM_SECURE
|
||||
Request secured link
|
||||
.Pq encryption, plus change link key .
|
||||
.El
|
||||
.Pp
|
||||
Link mode settings will be applied to the baseband link during RFCOMM
|
||||
connection establishment.
|
||||
If the RFCOMM connection is already established,
|
||||
.Dv EINPROGRESS
|
||||
may be returned, and it is not possible to guarantee that data already queued
|
||||
.Pq from either end
|
||||
will not be delivered.
|
||||
If the mode change fails, the RFCOMM connection will be aborted.
|
||||
.El
|
||||
.Pp
|
||||
RFCOMM
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: bthidev.4,v 1.7 2006/10/04 19:29:25 wiz Exp $
|
||||
.\" $NetBSD: bthidev.4,v 1.8 2007/04/21 06:15:22 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006 Itronix Inc.
|
||||
.\" All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd October 4, 2006
|
||||
.Dd April 10, 2007
|
||||
.Dt BTHIDEV 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -88,6 +88,13 @@ If this boolean value is set, and is true, then the
|
||||
.Nm
|
||||
driver will initiate reconnections to the remote device when no
|
||||
connection is present.
|
||||
.It link-mode
|
||||
This optional string represents the link mode of the baseband link, and
|
||||
may be one of
|
||||
.Sq auth ,
|
||||
.Sq encrypt
|
||||
or
|
||||
.Sq secure .
|
||||
.El
|
||||
.Pp
|
||||
When the
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: bluetooth.9,v 1.1 2006/06/19 15:44:44 gdamore Exp $
|
||||
.\" $NetBSD: bluetooth.9,v 1.2 2007/04/21 06:15:22 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006 Itronix Inc.
|
||||
.\" All rights reserved.
|
||||
@ -30,7 +30,7 @@
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd March 4, 2006
|
||||
.Dd April 10, 2007
|
||||
.Dt BLUETOOTH 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -143,6 +143,7 @@ struct btproto {
|
||||
void (*disconnected)(void *, int);
|
||||
void *(*newconn)(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
void (*complete)(void *, int);
|
||||
void (*linkmode)(void *, int);
|
||||
void (*input)(void *, struct mbuf *);
|
||||
};
|
||||
.Ed
|
||||
@ -347,6 +348,11 @@ amount of data can be removed from the socket buffer. The units of the
|
||||
.Ar count
|
||||
value will be dependent on the protocol being used (eg RFCOMM is bytes,
|
||||
but L2CAP is packets)
|
||||
.It Fn "(*linkmode)" "ref" "mode"
|
||||
This function will be called for established connections, when the link mode
|
||||
of the baseband link has changed.
|
||||
.Ar mode
|
||||
is the new mode.
|
||||
.It Fn "(*input)" "ref" "mbuf"
|
||||
This function is called to supply new data on the connection described by
|
||||
.Ar ref .
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: btdev.h,v 1.5 2006/10/04 19:23:59 plunky Exp $ */
|
||||
/* $NetBSD: btdev.h,v 1.6 2007/04/21 06:15:22 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -43,6 +43,10 @@
|
||||
#define BTDEVladdr "local-bdaddr"
|
||||
#define BTDEVraddr "remote-bdaddr"
|
||||
#define BTDEVservice "service-name"
|
||||
#define BTDEVmode "link-mode"
|
||||
#define BTDEVauth "auth"
|
||||
#define BTDEVencrypt "encrypt"
|
||||
#define BTDEVsecure "secure"
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct btdev {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: bthidev.c,v 1.7 2006/11/16 01:32:48 christos Exp $ */
|
||||
/* $NetBSD: bthidev.c,v 1.8 2007/04/21 06:15:22 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: bthidev.c,v 1.7 2006/11/16 01:32:48 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: bthidev.c,v 1.8 2007/04/21 06:15:22 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
@ -72,6 +72,7 @@ struct bthidev_softc {
|
||||
|
||||
bdaddr_t sc_laddr; /* local address */
|
||||
bdaddr_t sc_raddr; /* remote address */
|
||||
int sc_mode; /* link mode */
|
||||
|
||||
uint16_t sc_ctlpsm; /* control PSM */
|
||||
struct l2cap_channel *sc_ctl; /* control channel */
|
||||
@ -125,6 +126,7 @@ static void bthidev_int_disconnected(void *, int);
|
||||
static void *bthidev_ctl_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void *bthidev_int_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void bthidev_complete(void *, int);
|
||||
static void bthidev_linkmode(void *, int);
|
||||
static void bthidev_input(void *, struct mbuf *);
|
||||
|
||||
static const struct btproto bthidev_ctl_proto = {
|
||||
@ -133,6 +135,7 @@ static const struct btproto bthidev_ctl_proto = {
|
||||
bthidev_ctl_disconnected,
|
||||
bthidev_ctl_newconn,
|
||||
bthidev_complete,
|
||||
bthidev_linkmode,
|
||||
bthidev_input,
|
||||
};
|
||||
|
||||
@ -142,6 +145,7 @@ static const struct btproto bthidev_int_proto = {
|
||||
bthidev_int_disconnected,
|
||||
bthidev_int_newconn,
|
||||
bthidev_complete,
|
||||
bthidev_linkmode,
|
||||
bthidev_input,
|
||||
};
|
||||
|
||||
@ -198,6 +202,23 @@ bthidev_attach(struct device *parent, struct device *self, void *aux)
|
||||
obj = prop_dictionary_get(dict, BTDEVraddr);
|
||||
bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj));
|
||||
|
||||
obj = prop_dictionary_get(dict, BTDEVmode);
|
||||
if (prop_object_type(obj) == PROP_TYPE_STRING) {
|
||||
if (prop_string_equals_cstring(obj, BTDEVauth))
|
||||
sc->sc_mode = L2CAP_LM_AUTH;
|
||||
else if (prop_string_equals_cstring(obj, BTDEVencrypt))
|
||||
sc->sc_mode = L2CAP_LM_ENCRYPT;
|
||||
else if (prop_string_equals_cstring(obj, BTDEVsecure))
|
||||
sc->sc_mode = L2CAP_LM_SECURE;
|
||||
else {
|
||||
aprint_error(" unknown %s\n", BTDEVmode);
|
||||
return;
|
||||
}
|
||||
|
||||
aprint_verbose(" %s %s", BTDEVmode,
|
||||
prop_string_cstring_nocopy(obj));
|
||||
}
|
||||
|
||||
obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm);
|
||||
if (prop_object_type(obj) == PROP_TYPE_NUMBER) {
|
||||
sc->sc_ctlpsm = prop_number_integer_value(obj);
|
||||
@ -435,6 +456,10 @@ bthidev_listen(struct bthidev_softc *sc)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = l2cap_setopt(sc->sc_ctl_l, SO_L2CAP_LM, &sc->sc_mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sa.bt_psm = sc->sc_ctlpsm;
|
||||
err = l2cap_bind(sc->sc_ctl_l, &sa);
|
||||
if (err)
|
||||
@ -451,6 +476,10 @@ bthidev_listen(struct bthidev_softc *sc)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = l2cap_setopt(sc->sc_int_l, SO_L2CAP_LM, &sc->sc_mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sa.bt_psm = sc->sc_intpsm;
|
||||
err = l2cap_bind(sc->sc_int_l, &sa);
|
||||
if (err)
|
||||
@ -488,6 +517,10 @@ bthidev_connect(struct bthidev_softc *sc)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = l2cap_setopt(sc->sc_ctl, SO_L2CAP_LM, &sc->sc_mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
|
||||
err = l2cap_bind(sc->sc_ctl, &sa);
|
||||
if (err) {
|
||||
@ -543,6 +576,10 @@ bthidev_ctl_connected(void *arg)
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = l2cap_setopt(sc->sc_int, SO_L2CAP_LM, &sc->sc_mode);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.bt_len = sizeof(sa);
|
||||
sa.bt_family = AF_BLUETOOTH;
|
||||
@ -707,6 +744,27 @@ bthidev_complete(void *arg, int count)
|
||||
/* dont care */
|
||||
}
|
||||
|
||||
static void
|
||||
bthidev_linkmode(void *arg, int new)
|
||||
{
|
||||
struct bthidev_softc *sc = arg;
|
||||
|
||||
if ((sc->sc_mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
|
||||
printf("%s: auth failed\n", device_xname((struct device *)sc));
|
||||
else if ((sc->sc_mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
|
||||
printf("%s: encrypt off\n", device_xname((struct device *)sc));
|
||||
else if ((sc->sc_mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))
|
||||
printf("%s: insecure\n", device_xname((struct device *)sc));
|
||||
else
|
||||
return;
|
||||
|
||||
if (sc->sc_int != NULL)
|
||||
l2cap_disconnect(sc->sc_int, 0);
|
||||
|
||||
if (sc->sc_ctl != NULL)
|
||||
l2cap_disconnect(sc->sc_ctl, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive reports from the protocol stack.
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: btsco.c,v 1.13 2007/03/13 19:26:06 plunky Exp $ */
|
||||
/* $NetBSD: btsco.c,v 1.14 2007/04/21 06:15:22 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.13 2007/03/13 19:26:06 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.14 2007/04/21 06:15:22 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/audioio.h>
|
||||
@ -215,6 +215,7 @@ static void btsco_sco_connected(void *);
|
||||
static void btsco_sco_disconnected(void *, int);
|
||||
static void *btsco_sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void btsco_sco_complete(void *, int);
|
||||
static void btsco_sco_linkmode(void *, int);
|
||||
static void btsco_sco_input(void *, struct mbuf *);
|
||||
|
||||
static const struct btproto btsco_sco_proto = {
|
||||
@ -223,6 +224,7 @@ static const struct btproto btsco_sco_proto = {
|
||||
btsco_sco_disconnected,
|
||||
btsco_sco_newconn,
|
||||
btsco_sco_complete,
|
||||
btsco_sco_linkmode,
|
||||
btsco_sco_input,
|
||||
};
|
||||
|
||||
@ -501,6 +503,14 @@ btsco_sco_complete(void *arg, int count)
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static void
|
||||
btsco_sco_linkmode(void *arg, int new)
|
||||
{
|
||||
/* struct btsco_softc *sc = arg; */
|
||||
|
||||
/* dont care */
|
||||
}
|
||||
|
||||
static void
|
||||
btsco_sco_input(void *arg, struct mbuf *m)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: bluetooth.h,v 1.4 2006/11/16 01:33:44 christos Exp $ */
|
||||
/* $NetBSD: bluetooth.h,v 1.5 2007/04/21 06:15:22 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -115,6 +115,7 @@ struct btproto {
|
||||
void (*disconnected)(void *, int);
|
||||
void *(*newconn)(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
void (*complete)(void *, int);
|
||||
void (*linkmode)(void *, int);
|
||||
void (*input)(void *, struct mbuf *);
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: hci.h,v 1.9 2007/02/20 16:53:21 kiyohara Exp $ */
|
||||
/* $NetBSD: hci.h,v 1.10 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -54,7 +54,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: hci.h,v 1.9 2007/02/20 16:53:21 kiyohara Exp $
|
||||
* $Id: hci.h,v 1.10 2007/04/21 06:15:23 plunky Exp $
|
||||
* $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $
|
||||
*/
|
||||
|
||||
@ -2044,6 +2044,7 @@ struct hci_link {
|
||||
|
||||
/* common info */
|
||||
uint16_t hl_state; /* connection state */
|
||||
uint16_t hl_flags; /* link flags */
|
||||
bdaddr_t hl_bdaddr; /* dest address */
|
||||
uint16_t hl_handle; /* connection handle */
|
||||
uint8_t hl_type; /* link type */
|
||||
@ -2066,11 +2067,22 @@ struct hci_link {
|
||||
MBUFQ_HEAD() hl_data; /* SCO outgoing data */
|
||||
};
|
||||
|
||||
/* hci_link state bits */
|
||||
/* hci_link state */
|
||||
#define HCI_LINK_CLOSED 0 /* closed */
|
||||
#define HCI_LINK_WAIT_CONNECT 1 /* waiting to connect */
|
||||
#define HCI_LINK_OPEN 2 /* ready and willing */
|
||||
#define HCI_LINK_BLOCK 3 /* open but blocking (see hci_acl_start) */
|
||||
#define HCI_LINK_WAIT_AUTH 2 /* waiting for auth */
|
||||
#define HCI_LINK_WAIT_ENCRYPT 3 /* waiting for encrypt */
|
||||
#define HCI_LINK_WAIT_SECURE 4 /* waiting for secure */
|
||||
#define HCI_LINK_OPEN 5 /* ready and willing */
|
||||
#define HCI_LINK_BLOCK 6 /* open but blocking (see hci_acl_start) */
|
||||
|
||||
/* hci_link flags */
|
||||
#define HCI_LINK_AUTH_REQ (1<<0) /* authentication requested */
|
||||
#define HCI_LINK_ENCRYPT_REQ (1<<1) /* encryption requested */
|
||||
#define HCI_LINK_SECURE_REQ (1<<2) /* secure link requested */
|
||||
#define HCI_LINK_AUTH (1<<3) /* link is authenticated */
|
||||
#define HCI_LINK_ENCRYPT (1<<4) /* link is encrypted */
|
||||
#define HCI_LINK_SECURE (1<<5) /* link is secured */
|
||||
|
||||
/*
|
||||
* Bluetooth Memo
|
||||
@ -2166,6 +2178,8 @@ struct hci_link *hci_acl_open(struct hci_unit *, bdaddr_t *);
|
||||
struct hci_link *hci_acl_newconn(struct hci_unit *, bdaddr_t *);
|
||||
void hci_acl_close(struct hci_link *, int);
|
||||
void hci_acl_timeout(void *);
|
||||
int hci_acl_setmode(struct hci_link *);
|
||||
void hci_acl_linkmode(struct hci_link *);
|
||||
void hci_acl_recv(struct mbuf *, struct hci_unit *);
|
||||
int hci_acl_send(struct mbuf *, struct hci_link *, struct l2cap_channel *);
|
||||
void hci_acl_start(struct hci_link *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: hci_event.c,v 1.5 2007/04/05 19:22:18 plunky Exp $ */
|
||||
/* $NetBSD: hci_event.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.5 2007/04/05 19:22:18 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.6 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -51,6 +51,9 @@ static void hci_event_con_compl(struct hci_unit *, struct mbuf *);
|
||||
static void hci_event_discon_compl(struct hci_unit *, struct mbuf *);
|
||||
static void hci_event_con_req(struct hci_unit *, struct mbuf *);
|
||||
static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *);
|
||||
static void hci_event_auth_compl(struct hci_unit *, struct mbuf *);
|
||||
static void hci_event_encryption_change(struct hci_unit *, struct mbuf *);
|
||||
static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *);
|
||||
static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *);
|
||||
static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *);
|
||||
static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *);
|
||||
@ -174,12 +177,21 @@ hci_event(struct mbuf *m, struct hci_unit *unit)
|
||||
hci_event_con_req(unit, m);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_AUTH_COMPL:
|
||||
hci_event_auth_compl(unit, m);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_ENCRYPTION_CHANGE:
|
||||
hci_event_encryption_change(unit, m);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
|
||||
hci_event_change_con_link_key_compl(unit, m);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_SCO_CON_COMPL:
|
||||
case HCI_EVENT_INQUIRY_COMPL:
|
||||
case HCI_EVENT_AUTH_COMPL:
|
||||
case HCI_EVENT_REMOTE_NAME_REQ_COMPL:
|
||||
case HCI_EVENT_ENCRYPTION_CHANGE:
|
||||
case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
|
||||
case HCI_EVENT_MASTER_LINK_KEY_COMPL:
|
||||
case HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
|
||||
case HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
|
||||
@ -231,9 +243,10 @@ hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
|
||||
m_copydata(m, 0, sizeof(ep), &ep);
|
||||
m_adj(m, sizeof(ep));
|
||||
|
||||
DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n",
|
||||
DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
|
||||
unit->hci_devname,
|
||||
HCI_OGF(le16toh(ep.opcode)), HCI_OCF(le16toh(ep.opcode)),
|
||||
ep.status,
|
||||
ep.num_cmd_pkts);
|
||||
|
||||
unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
|
||||
@ -493,6 +506,11 @@ hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX could check auth_enable here */
|
||||
|
||||
if (ep.encryption_mode)
|
||||
link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
|
||||
|
||||
link->hl_state = HCI_LINK_OPEN;
|
||||
link->hl_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
|
||||
|
||||
@ -505,7 +523,11 @@ hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
|
||||
printf("%s: Warning, could not write link policy\n",
|
||||
unit->hci_devname);
|
||||
|
||||
hci_acl_start(link);
|
||||
err = hci_acl_setmode(link);
|
||||
if (err == EINPROGRESS)
|
||||
return;
|
||||
|
||||
hci_acl_linkmode(link);
|
||||
} else {
|
||||
(*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper);
|
||||
}
|
||||
@ -584,6 +606,133 @@ hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Auth Complete
|
||||
*
|
||||
* Authentication has been completed on an ACL link. We can notify the
|
||||
* upper layer protocols unless further mode changes are pending.
|
||||
*/
|
||||
static void
|
||||
hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
|
||||
{
|
||||
hci_auth_compl_ep ep;
|
||||
struct hci_link *link;
|
||||
int err;
|
||||
|
||||
KASSERT(m->m_pkthdr.len >= sizeof(ep));
|
||||
m_copydata(m, 0, sizeof(ep), &ep);
|
||||
m_adj(m, sizeof(ep));
|
||||
|
||||
ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
|
||||
|
||||
DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
|
||||
|
||||
link = hci_link_lookup_handle(unit, ep.con_handle);
|
||||
if (link == NULL || link->hl_type != HCI_LINK_ACL)
|
||||
return;
|
||||
|
||||
if (ep.status == 0) {
|
||||
link->hl_flags |= HCI_LINK_AUTH;
|
||||
|
||||
if (link->hl_state == HCI_LINK_WAIT_AUTH)
|
||||
link->hl_state = HCI_LINK_OPEN;
|
||||
|
||||
err = hci_acl_setmode(link);
|
||||
if (err == EINPROGRESS)
|
||||
return;
|
||||
}
|
||||
|
||||
hci_acl_linkmode(link);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encryption Change
|
||||
*
|
||||
* The encryption status has changed. Basically, we note the change
|
||||
* then notify the upper layer protocol unless further mode changes
|
||||
* are pending.
|
||||
* Note that if encryption gets disabled when it has been requested,
|
||||
* we will attempt to enable it again.. (its a feature not a bug :)
|
||||
*/
|
||||
static void
|
||||
hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
|
||||
{
|
||||
hci_encryption_change_ep ep;
|
||||
struct hci_link *link;
|
||||
int err;
|
||||
|
||||
KASSERT(m->m_pkthdr.len >= sizeof(ep));
|
||||
m_copydata(m, 0, sizeof(ep), &ep);
|
||||
m_adj(m, sizeof(ep));
|
||||
|
||||
ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
|
||||
|
||||
DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n",
|
||||
ep.con_handle, ep.status, ep.encryption_enable);
|
||||
|
||||
link = hci_link_lookup_handle(unit, ep.con_handle);
|
||||
if (link == NULL || link->hl_type != HCI_LINK_ACL)
|
||||
return;
|
||||
|
||||
if (ep.status == 0) {
|
||||
if (ep.encryption_enable == 0)
|
||||
link->hl_flags &= ~HCI_LINK_ENCRYPT;
|
||||
else
|
||||
link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
|
||||
|
||||
if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
|
||||
link->hl_state = HCI_LINK_OPEN;
|
||||
|
||||
err = hci_acl_setmode(link);
|
||||
if (err == EINPROGRESS)
|
||||
return;
|
||||
}
|
||||
|
||||
hci_acl_linkmode(link);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change Connection Link Key Complete
|
||||
*
|
||||
* Link keys are handled in userland but if we are waiting to secure
|
||||
* this link, we should notify the upper protocols. A SECURE request
|
||||
* only needs a single key change, so we can cancel the request.
|
||||
*/
|
||||
static void
|
||||
hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
|
||||
{
|
||||
hci_change_con_link_key_compl_ep ep;
|
||||
struct hci_link *link;
|
||||
int err;
|
||||
|
||||
KASSERT(m->m_pkthdr.len >= sizeof(ep));
|
||||
m_copydata(m, 0, sizeof(ep), &ep);
|
||||
m_adj(m, sizeof(ep));
|
||||
|
||||
ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
|
||||
|
||||
DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
|
||||
|
||||
link = hci_link_lookup_handle(unit, ep.con_handle);
|
||||
if (link == NULL || link->hl_type != HCI_LINK_ACL)
|
||||
return;
|
||||
|
||||
link->hl_flags &= ~HCI_LINK_SECURE_REQ;
|
||||
|
||||
if (ep.status == 0) {
|
||||
link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE);
|
||||
|
||||
if (link->hl_state == HCI_LINK_WAIT_SECURE)
|
||||
link->hl_state = HCI_LINK_OPEN;
|
||||
|
||||
err = hci_acl_setmode(link);
|
||||
if (err == EINPROGRESS)
|
||||
return;
|
||||
}
|
||||
|
||||
hci_acl_linkmode(link);
|
||||
}
|
||||
|
||||
/*
|
||||
* process results of read_bdaddr command_complete event
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: hci_link.c,v 1.10 2007/03/30 20:47:02 plunky Exp $ */
|
||||
/* $NetBSD: hci_link.c,v 1.11 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: hci_link.c,v 1.10 2007/03/30 20:47:02 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: hci_link.c,v 1.11 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -114,6 +114,9 @@ hci_acl_open(struct hci_unit *unit, bdaddr_t *bdaddr)
|
||||
break;
|
||||
|
||||
case HCI_LINK_WAIT_CONNECT:
|
||||
case HCI_LINK_WAIT_AUTH:
|
||||
case HCI_LINK_WAIT_ENCRYPT:
|
||||
case HCI_LINK_WAIT_SECURE:
|
||||
/*
|
||||
* somebody else already trying to connect, we just
|
||||
* sit on the bench with them..
|
||||
@ -211,6 +214,9 @@ hci_acl_timeout(void *arg)
|
||||
hci_link_free(link, ECONNRESET);
|
||||
break;
|
||||
|
||||
case HCI_LINK_WAIT_AUTH:
|
||||
case HCI_LINK_WAIT_ENCRYPT:
|
||||
case HCI_LINK_WAIT_SECURE:
|
||||
case HCI_LINK_OPEN:
|
||||
cp.con_handle = htole16(link->hl_handle);
|
||||
cp.reason = 0x13; /* "Remote User Terminated Connection" */
|
||||
@ -234,6 +240,168 @@ out:
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate any Link Mode change requests.
|
||||
*/
|
||||
int
|
||||
hci_acl_setmode(struct hci_link *link)
|
||||
{
|
||||
int err;
|
||||
|
||||
KASSERT(link != NULL);
|
||||
KASSERT(link->hl_unit != NULL);
|
||||
|
||||
if (link->hl_state != HCI_LINK_OPEN)
|
||||
return EINPROGRESS;
|
||||
|
||||
if ((link->hl_flags & HCI_LINK_AUTH_REQ)
|
||||
&& !(link->hl_flags & HCI_LINK_AUTH)) {
|
||||
hci_auth_req_cp cp;
|
||||
|
||||
DPRINTF("requesting auth for handle #%d\n",
|
||||
link->hl_handle);
|
||||
|
||||
link->hl_state = HCI_LINK_WAIT_AUTH;
|
||||
cp.con_handle = htole16(link->hl_handle);
|
||||
err = hci_send_cmd(link->hl_unit, HCI_CMD_AUTH_REQ,
|
||||
&cp, sizeof(cp));
|
||||
|
||||
return (err == 0 ? EINPROGRESS : err);
|
||||
}
|
||||
|
||||
if ((link->hl_flags & HCI_LINK_ENCRYPT_REQ)
|
||||
&& !(link->hl_flags & HCI_LINK_ENCRYPT)) {
|
||||
hci_set_con_encryption_cp cp;
|
||||
|
||||
/* XXX we should check features for encryption capability */
|
||||
|
||||
DPRINTF("requesting encryption for handle #%d\n",
|
||||
link->hl_handle);
|
||||
|
||||
link->hl_state = HCI_LINK_WAIT_ENCRYPT;
|
||||
cp.con_handle = htole16(link->hl_handle);
|
||||
cp.encryption_enable = 0x01;
|
||||
|
||||
err = hci_send_cmd(link->hl_unit, HCI_CMD_SET_CON_ENCRYPTION,
|
||||
&cp, sizeof(cp));
|
||||
|
||||
return (err == 0 ? EINPROGRESS : err);
|
||||
}
|
||||
|
||||
if ((link->hl_flags & HCI_LINK_SECURE_REQ)) {
|
||||
hci_change_con_link_key_cp cp;
|
||||
|
||||
/* always change link key for SECURE requests */
|
||||
link->hl_flags &= ~HCI_LINK_SECURE;
|
||||
|
||||
DPRINTF("changing link key for handle #%d\n",
|
||||
link->hl_handle);
|
||||
|
||||
link->hl_state = HCI_LINK_WAIT_SECURE;
|
||||
cp.con_handle = htole16(link->hl_handle);
|
||||
|
||||
err = hci_send_cmd(link->hl_unit, HCI_CMD_CHANGE_CON_LINK_KEY,
|
||||
&cp, sizeof(cp));
|
||||
|
||||
return (err == 0 ? EINPROGRESS : err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Link Mode changed.
|
||||
*
|
||||
* This is called from event handlers when the mode change
|
||||
* is complete. We notify upstream and restart the link.
|
||||
*/
|
||||
void
|
||||
hci_acl_linkmode(struct hci_link *link)
|
||||
{
|
||||
struct l2cap_channel *chan, *next;
|
||||
int err, mode = 0;
|
||||
|
||||
DPRINTF("handle #%d, auth %s, encrypt %s, secure %s\n",
|
||||
link->hl_handle,
|
||||
(link->hl_flags & HCI_LINK_AUTH ? "on" : "off"),
|
||||
(link->hl_flags & HCI_LINK_ENCRYPT ? "on" : "off"),
|
||||
(link->hl_flags & HCI_LINK_SECURE ? "on" : "off"));
|
||||
|
||||
if (link->hl_flags & HCI_LINK_AUTH)
|
||||
mode |= L2CAP_LM_AUTH;
|
||||
|
||||
if (link->hl_flags & HCI_LINK_ENCRYPT)
|
||||
mode |= L2CAP_LM_ENCRYPT;
|
||||
|
||||
if (link->hl_flags & HCI_LINK_SECURE)
|
||||
mode |= L2CAP_LM_SECURE;
|
||||
|
||||
/*
|
||||
* The link state will only be OPEN here if the mode change
|
||||
* was successful. So, we can proceed with L2CAP connections,
|
||||
* or notify already establshed channels, to allow any that
|
||||
* are dissatisfied to disconnect before we restart.
|
||||
*/
|
||||
next = LIST_FIRST(&l2cap_active_list);
|
||||
while ((chan = next) != NULL) {
|
||||
next = LIST_NEXT(chan, lc_ncid);
|
||||
|
||||
if (chan->lc_link != link)
|
||||
continue;
|
||||
|
||||
switch(chan->lc_state) {
|
||||
case L2CAP_WAIT_SEND_CONNECT_REQ: /* we are connecting */
|
||||
if ((mode & chan->lc_mode) != chan->lc_mode) {
|
||||
l2cap_close(chan, ECONNABORTED);
|
||||
break;
|
||||
}
|
||||
|
||||
chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP;
|
||||
err = l2cap_send_connect_req(chan);
|
||||
if (err) {
|
||||
l2cap_close(chan, err);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_WAIT_SEND_CONNECT_RSP: /* they are connecting */
|
||||
if ((mode & chan->lc_mode) != chan->lc_mode) {
|
||||
l2cap_send_connect_rsp(link, chan->lc_ident,
|
||||
0, chan->lc_rcid,
|
||||
L2CAP_SECURITY_BLOCK);
|
||||
|
||||
l2cap_close(chan, ECONNABORTED);
|
||||
break;
|
||||
}
|
||||
|
||||
l2cap_send_connect_rsp(link, chan->lc_ident,
|
||||
chan->lc_lcid, chan->lc_rcid,
|
||||
L2CAP_SUCCESS);
|
||||
|
||||
chan->lc_state = L2CAP_WAIT_CONFIG;
|
||||
chan->lc_flags |= (L2CAP_WAIT_CONFIG_RSP | L2CAP_WAIT_CONFIG_REQ);
|
||||
err = l2cap_send_config_req(chan);
|
||||
if (err) {
|
||||
l2cap_close(chan, err);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_WAIT_RECV_CONNECT_RSP:
|
||||
case L2CAP_WAIT_CONFIG:
|
||||
case L2CAP_OPEN: /* already established */
|
||||
(*chan->lc_proto->linkmode)(chan->lc_upper, mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
link->hl_state = HCI_LINK_OPEN;
|
||||
hci_acl_start(link);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive ACL Data
|
||||
*
|
||||
@ -425,12 +593,13 @@ nomem:
|
||||
/*
|
||||
* Start sending ACL data on link.
|
||||
*
|
||||
* This is called when the queue may need restarting: as new data
|
||||
* is queued, after link mode changes have completed, or when device
|
||||
* buffers have cleared.
|
||||
*
|
||||
* We may use all the available packet slots. The reason that we add
|
||||
* the ACL encapsulation here rather than in hci_acl_send() is that L2CAP
|
||||
* signal packets may be queued before the handle is given to us..
|
||||
*
|
||||
* this is called from hci_acl_send() above, and the event processing
|
||||
* code (for CON_COMPL and NUM_COMPL_PKTS)
|
||||
*/
|
||||
void
|
||||
hci_acl_start(struct hci_link *link)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: l2cap.h,v 1.4 2007/03/12 20:34:46 plunky Exp $ */
|
||||
/* $NetBSD: l2cap.h,v 1.5 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -54,7 +54,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: l2cap.h,v 1.4 2007/03/12 20:34:46 plunky Exp $
|
||||
* $Id: l2cap.h,v 1.5 2007/04/21 06:15:23 plunky Exp $
|
||||
* $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $
|
||||
*/
|
||||
|
||||
@ -338,11 +338,18 @@ typedef union {
|
||||
**************************************************************************
|
||||
**************************************************************************/
|
||||
|
||||
#define SO_L2CAP_IMTU 1
|
||||
#define SO_L2CAP_OMTU 2
|
||||
#define SO_L2CAP_IQOS 3
|
||||
#define SO_L2CAP_OQOS 4
|
||||
#define SO_L2CAP_FLUSH 5
|
||||
/* Socket options */
|
||||
#define SO_L2CAP_IMTU 1 /* incoming MTU */
|
||||
#define SO_L2CAP_OMTU 2 /* outgoing MTU */
|
||||
#define SO_L2CAP_IQOS 3 /* incoming QoS */
|
||||
#define SO_L2CAP_OQOS 4 /* outgoing QoS */
|
||||
#define SO_L2CAP_FLUSH 5 /* flush timeout */
|
||||
#define SO_L2CAP_LM 6 /* link mode */
|
||||
|
||||
/* L2CAP link mode flags */
|
||||
#define L2CAP_LM_AUTH (1<<0) /* want authentication */
|
||||
#define L2CAP_LM_ENCRYPT (1<<1) /* want encryption */
|
||||
#define L2CAP_LM_SECURE (1<<2) /* want secured link */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
@ -367,6 +374,7 @@ struct l2cap_channel {
|
||||
struct hci_link *lc_link; /* ACL connection (down) */
|
||||
uint16_t lc_state; /* channel state */
|
||||
uint16_t lc_flags; /* channel flags */
|
||||
uint8_t lc_ident; /* cached request id */
|
||||
|
||||
uint16_t lc_lcid; /* local channel ID */
|
||||
struct sockaddr_bt lc_laddr; /* local address */
|
||||
@ -374,6 +382,7 @@ struct l2cap_channel {
|
||||
uint16_t lc_rcid; /* remote channel ID */
|
||||
struct sockaddr_bt lc_raddr; /* remote address */
|
||||
|
||||
int lc_mode; /* link mode */
|
||||
uint16_t lc_imtu; /* incoming mtu */
|
||||
uint16_t lc_omtu; /* outgoing mtu */
|
||||
uint16_t lc_flush; /* flush timeout */
|
||||
@ -390,11 +399,13 @@ struct l2cap_channel {
|
||||
};
|
||||
|
||||
/* l2cap_channel state */
|
||||
#define L2CAP_CLOSED 0 /* closed */
|
||||
#define L2CAP_WAIT_CONNECT_RSP 1 /* have sent connect request */
|
||||
#define L2CAP_WAIT_CONFIG 2 /* waiting for configuration */
|
||||
#define L2CAP_OPEN 3 /* user data transfer state */
|
||||
#define L2CAP_WAIT_DISCONNECT 4 /* have sent disconnect request */
|
||||
#define L2CAP_CLOSED 0 /* closed */
|
||||
#define L2CAP_WAIT_SEND_CONNECT_REQ 1 /* waiting to send connect request */
|
||||
#define L2CAP_WAIT_RECV_CONNECT_RSP 2 /* waiting to recv connect response */
|
||||
#define L2CAP_WAIT_SEND_CONNECT_RSP 3 /* waiting to send connect response */
|
||||
#define L2CAP_WAIT_CONFIG 4 /* waiting for configuration */
|
||||
#define L2CAP_OPEN 5 /* user data transfer state */
|
||||
#define L2CAP_WAIT_DISCONNECT 6 /* have sent disconnect request */
|
||||
|
||||
/* l2cap_channel flags */
|
||||
#define L2CAP_SHUTDOWN (1<<0) /* channel is closing */
|
||||
@ -436,6 +447,7 @@ void l2cap_recv_frame(struct mbuf *, struct hci_link *);
|
||||
int l2cap_start(struct l2cap_channel *);
|
||||
|
||||
/* l2cap_misc.c */
|
||||
int l2cap_setmode(struct l2cap_channel *);
|
||||
int l2cap_cid_alloc(struct l2cap_channel *);
|
||||
struct l2cap_channel *l2cap_cid_lookup(uint16_t);
|
||||
int l2cap_request_alloc(struct l2cap_channel *, uint8_t);
|
||||
@ -448,6 +460,7 @@ void l2cap_recv_signal(struct mbuf *, struct hci_link *);
|
||||
int l2cap_send_connect_req(struct l2cap_channel *);
|
||||
int l2cap_send_config_req(struct l2cap_channel *);
|
||||
int l2cap_send_disconnect_req(struct l2cap_channel *);
|
||||
int l2cap_send_connect_rsp(struct hci_link *, uint8_t, uint16_t, uint16_t, uint16_t);
|
||||
|
||||
/* l2cap_socket.c */
|
||||
int l2cap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: l2cap_lower.c,v 1.5 2007/03/30 20:47:03 plunky Exp $ */
|
||||
/* $NetBSD: l2cap_lower.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_lower.c,v 1.5 2007/03/30 20:47:03 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_lower.c,v 1.6 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -58,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: l2cap_lower.c,v 1.5 2007/03/30 20:47:03 plunky Exp $
|
||||
* Config failed
|
||||
* Other end reported invalid CID
|
||||
* Normal disconnection
|
||||
* Change link mode failed
|
||||
*/
|
||||
void
|
||||
l2cap_close(struct l2cap_channel *chan, int err)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: l2cap_misc.c,v 1.2 2007/03/12 18:18:35 ad Exp $ */
|
||||
/* $NetBSD: l2cap_misc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_misc.c,v 1.2 2007/03/12 18:18:35 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_misc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -70,6 +70,33 @@ const l2cap_qos_t l2cap_default_qos = {
|
||||
int l2cap_response_timeout = 30; /* seconds */
|
||||
int l2cap_response_extended_timeout = 180; /* seconds */
|
||||
|
||||
/*
|
||||
* Set Link Mode on channel
|
||||
*/
|
||||
int
|
||||
l2cap_setmode(struct l2cap_channel *chan)
|
||||
{
|
||||
|
||||
KASSERT(chan != NULL);
|
||||
KASSERT(chan->lc_link != NULL);
|
||||
|
||||
DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid,
|
||||
(chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
|
||||
(chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
|
||||
(chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
|
||||
|
||||
if (chan->lc_mode & L2CAP_LM_AUTH)
|
||||
chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
|
||||
|
||||
if (chan->lc_mode & L2CAP_LM_ENCRYPT)
|
||||
chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
|
||||
|
||||
if (chan->lc_mode & L2CAP_LM_SECURE)
|
||||
chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
|
||||
|
||||
return hci_acl_setmode(chan->lc_link);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new Request structure & ID and set the timer going
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: l2cap_signal.c,v 1.6 2007/03/15 19:47:51 plunky Exp $ */
|
||||
/* $NetBSD: l2cap_signal.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_signal.c,v 1.6 2007/03/15 19:47:51 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_signal.c,v 1.7 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -240,7 +240,6 @@ l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link)
|
||||
struct l2cap_channel *chan, *new;
|
||||
l2cap_cmd_hdr_t cmd;
|
||||
l2cap_con_req_cp cp;
|
||||
l2cap_con_rsp_cp rp;
|
||||
int err;
|
||||
|
||||
/* extract cmd */
|
||||
@ -251,20 +250,19 @@ l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link)
|
||||
m_copydata(m, 0, sizeof(cp), &cp);
|
||||
m_adj(m, sizeof(cp));
|
||||
|
||||
/* init response */
|
||||
memset(&rp, 0, sizeof(rp));
|
||||
rp.scid = cp.scid;
|
||||
cp.scid = le16toh(cp.scid);
|
||||
cp.psm = le16toh(cp.psm);
|
||||
|
||||
memset(&laddr, 0, sizeof(struct sockaddr_bt));
|
||||
laddr.bt_len = sizeof(struct sockaddr_bt);
|
||||
laddr.bt_family = AF_BLUETOOTH;
|
||||
laddr.bt_psm = le16toh(cp.psm);
|
||||
laddr.bt_psm = cp.psm;
|
||||
bdaddr_copy(&laddr.bt_bdaddr, &link->hl_unit->hci_bdaddr);
|
||||
|
||||
memset(&raddr, 0, sizeof(struct sockaddr_bt));
|
||||
raddr.bt_len = sizeof(struct sockaddr_bt);
|
||||
raddr.bt_family = AF_BLUETOOTH;
|
||||
raddr.bt_psm = le16toh(cp.psm);
|
||||
raddr.bt_psm = cp.psm;
|
||||
bdaddr_copy(&raddr.bt_bdaddr, &link->hl_bdaddr);
|
||||
|
||||
LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
|
||||
@ -282,9 +280,10 @@ l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link)
|
||||
|
||||
err = l2cap_cid_alloc(new);
|
||||
if (err) {
|
||||
rp.result = htole16(L2CAP_NO_RESOURCES);
|
||||
l2cap_send_signal(link, L2CAP_CONNECT_RSP,
|
||||
cmd.ident, sizeof(rp), &rp);
|
||||
l2cap_send_connect_rsp(link, cmd.ident,
|
||||
0, cp.scid,
|
||||
L2CAP_NO_RESOURCES);
|
||||
|
||||
(*new->lc_proto->disconnected)(new->lc_upper, err);
|
||||
return;
|
||||
}
|
||||
@ -292,24 +291,53 @@ l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link)
|
||||
new->lc_link = hci_acl_open(link->hl_unit, &link->hl_bdaddr);
|
||||
KASSERT(new->lc_link == link);
|
||||
|
||||
new->lc_rcid = le16toh(cp.scid);
|
||||
new->lc_rcid = cp.scid;
|
||||
new->lc_ident = cmd.ident;
|
||||
|
||||
memcpy(&new->lc_laddr, &laddr, sizeof(struct sockaddr_bt));
|
||||
memcpy(&new->lc_raddr, &raddr, sizeof(struct sockaddr_bt));
|
||||
|
||||
rp.dcid = htole16(new->lc_lcid);
|
||||
rp.result = htole16(L2CAP_SUCCESS);
|
||||
l2cap_send_signal(link, L2CAP_CONNECT_RSP, cmd.ident,
|
||||
sizeof(rp), &rp);
|
||||
new->lc_mode = chan->lc_mode;
|
||||
|
||||
err = l2cap_setmode(new);
|
||||
if (err == EINPROGRESS) {
|
||||
new->lc_state = L2CAP_WAIT_SEND_CONNECT_RSP;
|
||||
(*new->lc_proto->connecting)(new->lc_upper);
|
||||
return;
|
||||
}
|
||||
if (err) {
|
||||
new->lc_state = L2CAP_CLOSED;
|
||||
hci_acl_close(link, err);
|
||||
new->lc_link = NULL;
|
||||
|
||||
l2cap_send_connect_rsp(link, cmd.ident,
|
||||
0, cp.scid,
|
||||
L2CAP_NO_RESOURCES);
|
||||
|
||||
(*new->lc_proto->disconnected)(new->lc_upper, err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = l2cap_send_connect_rsp(link, cmd.ident,
|
||||
new->lc_lcid, new->lc_rcid,
|
||||
L2CAP_SUCCESS);
|
||||
if (err) {
|
||||
l2cap_close(new, err);
|
||||
return;
|
||||
}
|
||||
|
||||
new->lc_state = L2CAP_WAIT_CONFIG;
|
||||
new->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP);
|
||||
l2cap_send_config_req(new);
|
||||
err = l2cap_send_config_req(new);
|
||||
if (err)
|
||||
l2cap_close(new, err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rp.result = htole16(L2CAP_PSM_NOT_SUPPORTED);
|
||||
l2cap_send_signal(link, L2CAP_CONNECT_RSP, cmd.ident, sizeof(rp), &rp);
|
||||
l2cap_send_connect_rsp(link, cmd.ident,
|
||||
0, cp.scid,
|
||||
L2CAP_PSM_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -341,7 +369,7 @@ l2cap_recv_connect_rsp(struct mbuf *m, struct hci_link *link)
|
||||
if (chan != NULL && chan->lc_lcid != cp.scid)
|
||||
return;
|
||||
|
||||
if (chan == NULL || chan->lc_state != L2CAP_WAIT_CONNECT_RSP) {
|
||||
if (chan == NULL || chan->lc_state != L2CAP_WAIT_RECV_CONNECT_RSP) {
|
||||
l2cap_request_free(req);
|
||||
return;
|
||||
}
|
||||
@ -1063,3 +1091,19 @@ l2cap_send_disconnect_req(struct l2cap_channel *chan)
|
||||
return l2cap_send_signal(chan->lc_link, L2CAP_DISCONNECT_REQ,
|
||||
chan->lc_link->hl_lastid, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send Connect Response
|
||||
*/
|
||||
int
|
||||
l2cap_send_connect_rsp(struct hci_link *link, uint8_t ident, uint16_t dcid, uint16_t scid, uint16_t result)
|
||||
{
|
||||
l2cap_con_rsp_cp cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.dcid = htole16(dcid);
|
||||
cp.scid = htole16(scid);
|
||||
cp.result = htole16(result);
|
||||
|
||||
return l2cap_send_signal(link, L2CAP_CONNECT_RSP, ident, sizeof(cp), &cp);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: l2cap_socket.c,v 1.6 2007/03/31 18:17:13 plunky Exp $ */
|
||||
/* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.6 2007/03/31 18:17:13 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
/* load symbolic names */
|
||||
#ifdef BLUETOOTH_DEBUG
|
||||
@ -65,6 +65,7 @@ static void l2cap_connected(void *);
|
||||
static void l2cap_disconnected(void *, int);
|
||||
static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void l2cap_complete(void *, int);
|
||||
static void l2cap_linkmode(void *, int);
|
||||
static void l2cap_input(void *, struct mbuf *);
|
||||
|
||||
static const struct btproto l2cap_proto = {
|
||||
@ -73,7 +74,8 @@ static const struct btproto l2cap_proto = {
|
||||
l2cap_disconnected,
|
||||
l2cap_newconn,
|
||||
l2cap_complete,
|
||||
l2cap_input
|
||||
l2cap_linkmode,
|
||||
l2cap_input,
|
||||
};
|
||||
|
||||
/* sysctl variables */
|
||||
@ -361,6 +363,24 @@ l2cap_complete(void *arg, int count)
|
||||
sowwakeup(so);
|
||||
}
|
||||
|
||||
static void
|
||||
l2cap_linkmode(void *arg, int new)
|
||||
{
|
||||
struct socket *so = arg;
|
||||
int mode;
|
||||
|
||||
DPRINTF("auth %s, encrypt %s, secure %s\n",
|
||||
(new & L2CAP_LM_AUTH ? "on" : "off"),
|
||||
(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
|
||||
(new & L2CAP_LM_SECURE ? "on" : "off"));
|
||||
|
||||
(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
|
||||
if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
|
||||
|| ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
|
||||
|| ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
|
||||
l2cap_disconnect(so->so_pcb, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
l2cap_input(void *arg, struct mbuf *m)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: l2cap_upper.c,v 1.6 2007/04/06 17:09:00 plunky Exp $ */
|
||||
/* $NetBSD: l2cap_upper.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Iain Hibbert.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.6 2007/04/06 17:09:00 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.7 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -176,21 +176,33 @@ l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest)
|
||||
if (chan->lc_link == NULL)
|
||||
return EHOSTUNREACH;
|
||||
|
||||
/*
|
||||
* We queue a connect request right away even though the link
|
||||
* may not yet be open; the queue will be started automatically
|
||||
* at the right time.
|
||||
*/
|
||||
chan->lc_state = L2CAP_WAIT_CONNECT_RSP;
|
||||
err = l2cap_send_connect_req(chan);
|
||||
if (err) {
|
||||
chan->lc_state = L2CAP_CLOSED;
|
||||
hci_acl_close(chan->lc_link, err);
|
||||
chan->lc_link = NULL;
|
||||
return err;
|
||||
/* set the link mode */
|
||||
err = l2cap_setmode(chan);
|
||||
if (err == EINPROGRESS) {
|
||||
chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ;
|
||||
(*chan->lc_proto->connecting)(chan->lc_upper);
|
||||
return 0;
|
||||
}
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* We can queue a connect request now even though the link may
|
||||
* not yet be open; Our mode setting is assured, and the queue
|
||||
* will be started automatically at the right time.
|
||||
*/
|
||||
chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP;
|
||||
err = l2cap_send_connect_req(chan);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
chan->lc_state = L2CAP_CLOSED;
|
||||
hci_acl_close(chan->lc_link, err);
|
||||
chan->lc_link = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -395,15 +407,22 @@ l2cap_send(struct l2cap_channel *chan, struct mbuf *m)
|
||||
}
|
||||
|
||||
/*
|
||||
* l2cap_setopt(channel, opt, addr)
|
||||
* l2cap_setopt(l2cap_channel, opt, addr)
|
||||
*
|
||||
* Apply configuration options to channel. This corresponds to
|
||||
* "Configure Channel Request" in the L2CAP specification.
|
||||
*
|
||||
* for SO_L2CAP_LM, the settings will take effect when the
|
||||
* channel is established. If the channel is already open,
|
||||
* a call to
|
||||
* proto->linkmode(upper, new)
|
||||
*
|
||||
* will be made when the change is complete.
|
||||
*/
|
||||
int
|
||||
l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
|
||||
{
|
||||
int err = 0;
|
||||
int mode, err = 0;
|
||||
uint16_t mtu;
|
||||
|
||||
switch (opt) {
|
||||
@ -418,6 +437,23 @@ l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
|
||||
|
||||
break;
|
||||
|
||||
case SO_L2CAP_LM: /* set link mode */
|
||||
mode = *(int *)addr;
|
||||
mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
|
||||
|
||||
if (mode & L2CAP_LM_SECURE)
|
||||
mode |= L2CAP_LM_ENCRYPT;
|
||||
|
||||
if (mode & L2CAP_LM_ENCRYPT)
|
||||
mode |= L2CAP_LM_AUTH;
|
||||
|
||||
chan->lc_mode = mode;
|
||||
|
||||
if (chan->lc_state == L2CAP_OPEN)
|
||||
err = l2cap_setmode(chan);
|
||||
|
||||
break;
|
||||
|
||||
case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */
|
||||
case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */
|
||||
default:
|
||||
@ -428,6 +464,11 @@ l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* l2cap_getopt(l2cap_channel, opt, addr)
|
||||
*
|
||||
* Return configuration parameters.
|
||||
*/
|
||||
int
|
||||
l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
|
||||
{
|
||||
@ -453,6 +494,10 @@ l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
|
||||
*(uint16_t *)addr = chan->lc_flush;
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case SO_L2CAP_LM: /* get link mode */
|
||||
*(int *)addr = chan->lc_mode;
|
||||
return sizeof(int);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rfcomm.h,v 1.2 2006/10/01 06:08:08 plunky Exp $ */
|
||||
/* $NetBSD: rfcomm.h,v 1.3 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -55,7 +55,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: rfcomm.h,v 1.2 2006/10/01 06:08:08 plunky Exp $
|
||||
* $Id: rfcomm.h,v 1.3 2007/04/21 06:15:23 plunky Exp $
|
||||
* $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $
|
||||
*/
|
||||
|
||||
@ -236,8 +236,10 @@ struct rfcomm_mcc_pn
|
||||
*************************************************************************
|
||||
*************************************************************************/
|
||||
|
||||
/* Socket options */
|
||||
#define SO_RFCOMM_MTU 1 /* mtu */
|
||||
#define SO_RFCOMM_FC_INFO 2 /* flow control info (below) */
|
||||
#define SO_RFCOMM_LM 3 /* link mode */
|
||||
|
||||
/* Flow control information */
|
||||
struct rfcomm_fc_info {
|
||||
@ -249,6 +251,11 @@ struct rfcomm_fc_info {
|
||||
uint8_t reserved;
|
||||
};
|
||||
|
||||
/* RFCOMM link mode flags */
|
||||
#define RFCOMM_LM_AUTH (1<<0) /* want authentication */
|
||||
#define RFCOMM_LM_ENCRYPT (1<<1) /* want encryption */
|
||||
#define RFCOMM_LM_SECURE (1<<2) /* want secured link */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
/* sysctl variables */
|
||||
@ -313,6 +320,7 @@ struct rfcomm_dlc {
|
||||
uint16_t rd_flags; /* DLC flags */
|
||||
uint16_t rd_state; /* DLC state */
|
||||
uint16_t rd_mtu; /* MTU */
|
||||
int rd_mode; /* link mode */
|
||||
|
||||
struct sockaddr_bt rd_laddr; /* local address */
|
||||
struct sockaddr_bt rd_raddr; /* remote address */
|
||||
@ -361,9 +369,12 @@ struct rfcomm_dlc {
|
||||
#define RFCOMM_DLC_CLOSED 0 /* no session */
|
||||
#define RFCOMM_DLC_WAIT_SESSION 1 /* waiting for session */
|
||||
#define RFCOMM_DLC_WAIT_CONNECT 2 /* waiting for connect */
|
||||
#define RFCOMM_DLC_OPEN 3 /* can send/receive */
|
||||
#define RFCOMM_DLC_WAIT_DISCONNECT 4 /* waiting for disconnect */
|
||||
#define RFCOMM_DLC_LISTEN 5 /* listening DLC */
|
||||
#define RFCOMM_DLC_WAIT_SEND_SABM 3 /* waiting to send SABM */
|
||||
#define RFCOMM_DLC_WAIT_SEND_UA 4 /* waiting to send UA */
|
||||
#define RFCOMM_DLC_WAIT_RECV_UA 5 /* waiting to receive UA */
|
||||
#define RFCOMM_DLC_OPEN 6 /* can send/receive */
|
||||
#define RFCOMM_DLC_WAIT_DISCONNECT 7 /* waiting for disconnect */
|
||||
#define RFCOMM_DLC_LISTEN 8 /* listening DLC */
|
||||
|
||||
/*
|
||||
* Bluetooth RFCOMM socket kernel prototypes
|
||||
@ -376,7 +387,9 @@ struct rfcomm_dlc *rfcomm_dlc_lookup(struct rfcomm_session *, int);
|
||||
struct rfcomm_dlc *rfcomm_dlc_newconn(struct rfcomm_session *, int);
|
||||
void rfcomm_dlc_close(struct rfcomm_dlc *, int);
|
||||
void rfcomm_dlc_timeout(void *);
|
||||
int rfcomm_dlc_setmode(struct rfcomm_dlc *);
|
||||
int rfcomm_dlc_connect(struct rfcomm_dlc *);
|
||||
int rfcomm_dlc_open(struct rfcomm_dlc *);
|
||||
void rfcomm_dlc_start(struct rfcomm_dlc *);
|
||||
|
||||
/* rfcomm_session.c */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rfcomm_dlc.c,v 1.2 2007/03/15 19:47:51 plunky Exp $ */
|
||||
/* $NetBSD: rfcomm_dlc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_dlc.c,v 1.2 2007/03/15 19:47:51 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_dlc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -72,7 +72,7 @@ struct rfcomm_dlc *
|
||||
rfcomm_dlc_newconn(struct rfcomm_session *rs, int dlci)
|
||||
{
|
||||
struct rfcomm_session *ls;
|
||||
struct rfcomm_dlc *dlc, *any, *best;
|
||||
struct rfcomm_dlc *new, *dlc, *any, *best;
|
||||
struct sockaddr_bt laddr, raddr, addr;
|
||||
int chan;
|
||||
|
||||
@ -86,6 +86,7 @@ rfcomm_dlc_newconn(struct rfcomm_session *rs, int dlci)
|
||||
l2cap_sockaddr(rs->rs_l2cap, &laddr);
|
||||
l2cap_peeraddr(rs->rs_l2cap, &raddr);
|
||||
chan = RFCOMM_CHANNEL(dlci);
|
||||
new = NULL;
|
||||
|
||||
any = best = NULL;
|
||||
LIST_FOREACH(ls, &rfcomm_session_listen, rs_next) {
|
||||
@ -117,27 +118,28 @@ rfcomm_dlc_newconn(struct rfcomm_session *rs, int dlci)
|
||||
* listening DLC's so all can be checked in turn..
|
||||
*/
|
||||
if (dlc != NULL)
|
||||
dlc = (*dlc->rd_proto->newconn)(dlc->rd_upper, &laddr, &raddr);
|
||||
new = (*dlc->rd_proto->newconn)(dlc->rd_upper, &laddr, &raddr);
|
||||
|
||||
if (dlc == NULL) {
|
||||
if (new == NULL) {
|
||||
rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dlc->rd_dlci = dlci;
|
||||
dlc->rd_mtu = rfcomm_mtu_default;
|
||||
new->rd_dlci = dlci;
|
||||
new->rd_mtu = rfcomm_mtu_default;
|
||||
new->rd_mode = dlc->rd_mode;
|
||||
|
||||
memcpy(&dlc->rd_laddr, &laddr, sizeof(struct sockaddr_bt));
|
||||
dlc->rd_laddr.bt_channel = chan;
|
||||
memcpy(&new->rd_laddr, &laddr, sizeof(struct sockaddr_bt));
|
||||
new->rd_laddr.bt_channel = chan;
|
||||
|
||||
memcpy(&dlc->rd_raddr, &raddr, sizeof(struct sockaddr_bt));
|
||||
dlc->rd_raddr.bt_channel = chan;
|
||||
memcpy(&new->rd_raddr, &raddr, sizeof(struct sockaddr_bt));
|
||||
new->rd_raddr.bt_channel = chan;
|
||||
|
||||
dlc->rd_session = rs;
|
||||
dlc->rd_state = RFCOMM_DLC_WAIT_CONNECT;
|
||||
LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
|
||||
new->rd_session = rs;
|
||||
new->rd_state = RFCOMM_DLC_WAIT_CONNECT;
|
||||
LIST_INSERT_HEAD(&rs->rs_dlcs, new, rd_next);
|
||||
|
||||
return dlc;
|
||||
return new;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -206,6 +208,38 @@ rfcomm_dlc_timeout(void *arg)
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* rfcomm_dlc_setmode(rfcomm_dlc)
|
||||
*
|
||||
* Set link mode for DLC. This is only called when the session is
|
||||
* already open, so we don't need to worry about any previous mode
|
||||
* settings.
|
||||
*/
|
||||
int
|
||||
rfcomm_dlc_setmode(struct rfcomm_dlc *dlc)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
KASSERT(dlc->rd_session != NULL);
|
||||
KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
|
||||
|
||||
DPRINTF("dlci %d, auth %s, encrypt %s, secure %s\n", dlc->rd_dlci,
|
||||
(dlc->rd_mode & RFCOMM_LM_AUTH ? "yes" : "no"),
|
||||
(dlc->rd_mode & RFCOMM_LM_ENCRYPT ? "yes" : "no"),
|
||||
(dlc->rd_mode & RFCOMM_LM_SECURE ? "yes" : "no"));
|
||||
|
||||
if (dlc->rd_mode & RFCOMM_LM_AUTH)
|
||||
mode |= L2CAP_LM_AUTH;
|
||||
|
||||
if (dlc->rd_mode & RFCOMM_LM_ENCRYPT)
|
||||
mode |= L2CAP_LM_ENCRYPT;
|
||||
|
||||
if (dlc->rd_mode & RFCOMM_LM_SECURE)
|
||||
mode |= L2CAP_LM_SECURE;
|
||||
|
||||
return l2cap_setopt(dlc->rd_session->rs_l2cap, SO_L2CAP_LM, &mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* rfcomm_dlc_connect(rfcomm_dlc)
|
||||
*
|
||||
@ -225,7 +259,7 @@ rfcomm_dlc_connect(struct rfcomm_dlc *dlc)
|
||||
* If we have not already sent a PN on the session, we must send
|
||||
* a PN to negotiate Credit Flow Control, and this setting will
|
||||
* apply to all future connections for this session. We ask for
|
||||
* this every time.
|
||||
* this every time, in order to establish initial credits.
|
||||
*/
|
||||
memset(&pn, 0, sizeof(pn));
|
||||
pn.dlci = dlc->rd_dlci;
|
||||
@ -248,6 +282,38 @@ rfcomm_dlc_connect(struct rfcomm_dlc *dlc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* rfcomm_dlc_open(rfcomm_dlc)
|
||||
*
|
||||
* send "Modem Status Command" and mark DLC as open.
|
||||
*/
|
||||
int
|
||||
rfcomm_dlc_open(struct rfcomm_dlc *dlc)
|
||||
{
|
||||
struct rfcomm_mcc_msc msc;
|
||||
int err;
|
||||
|
||||
KASSERT(dlc->rd_session != NULL);
|
||||
KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
|
||||
|
||||
memset(&msc, 0, sizeof(msc));
|
||||
msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
|
||||
msc.modem = dlc->rd_lmodem & 0xfe; /* EA = 0 */
|
||||
msc.brk = 0x00 | 0x01; /* EA = 1 */
|
||||
|
||||
err = rfcomm_session_send_mcc(dlc->rd_session, 1,
|
||||
RFCOMM_MCC_MSC, &msc, sizeof(msc));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
callout_schedule(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
|
||||
|
||||
dlc->rd_state = RFCOMM_DLC_OPEN;
|
||||
(*dlc->rd_proto->connected)(dlc->rd_upper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* rfcomm_dlc_start(rfcomm_dlc)
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rfcomm_session.c,v 1.8 2007/04/06 16:27:52 plunky Exp $ */
|
||||
/* $NetBSD: rfcomm_session.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.8 2007/04/06 16:27:52 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.9 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -75,6 +75,7 @@ static void rfcomm_session_connected(void *);
|
||||
static void rfcomm_session_disconnected(void *, int);
|
||||
static void *rfcomm_session_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void rfcomm_session_complete(void *, int);
|
||||
static void rfcomm_session_linkmode(void *, int);
|
||||
static void rfcomm_session_input(void *, struct mbuf *);
|
||||
|
||||
static const struct btproto rfcomm_session_proto = {
|
||||
@ -83,7 +84,8 @@ static const struct btproto rfcomm_session_proto = {
|
||||
rfcomm_session_disconnected,
|
||||
rfcomm_session_newconn,
|
||||
rfcomm_session_complete,
|
||||
rfcomm_session_input
|
||||
rfcomm_session_linkmode,
|
||||
rfcomm_session_input,
|
||||
};
|
||||
|
||||
struct rfcomm_session_list
|
||||
@ -479,6 +481,104 @@ rfcomm_session_complete(void *arg, int count)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Link Mode changed
|
||||
*
|
||||
* This is called when a mode change is complete. Proceed with connections
|
||||
* where appropriate, or pass the new mode to any active DLCs.
|
||||
*/
|
||||
static void
|
||||
rfcomm_session_linkmode(void *arg, int new)
|
||||
{
|
||||
struct rfcomm_session *rs = arg;
|
||||
struct rfcomm_dlc *dlc, *next;
|
||||
int err, mode = 0;
|
||||
|
||||
DPRINTF("auth %s, encrypt %s, secure %s\n",
|
||||
(new & L2CAP_LM_AUTH ? "on" : "off"),
|
||||
(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
|
||||
(new & L2CAP_LM_SECURE ? "on" : "off"));
|
||||
|
||||
if (new & L2CAP_LM_AUTH)
|
||||
mode |= RFCOMM_LM_AUTH;
|
||||
|
||||
if (new & L2CAP_LM_ENCRYPT)
|
||||
mode |= RFCOMM_LM_ENCRYPT;
|
||||
|
||||
if (new & L2CAP_LM_SECURE)
|
||||
mode |= RFCOMM_LM_SECURE;
|
||||
|
||||
next = LIST_FIRST(&rs->rs_dlcs);
|
||||
while ((dlc = next) != NULL) {
|
||||
next = LIST_NEXT(dlc, rd_next);
|
||||
|
||||
switch (dlc->rd_state) {
|
||||
case RFCOMM_DLC_WAIT_SEND_SABM: /* we are connecting */
|
||||
if ((mode & dlc->rd_mode) != dlc->rd_mode) {
|
||||
rfcomm_dlc_close(dlc, ECONNABORTED);
|
||||
} else {
|
||||
err = rfcomm_session_send_frame(rs,
|
||||
RFCOMM_FRAME_SABM, dlc->rd_dlci);
|
||||
if (err) {
|
||||
rfcomm_dlc_close(dlc, err);
|
||||
} else {
|
||||
dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
|
||||
callout_schedule(&dlc->rd_timeout,
|
||||
rfcomm_ack_timeout * hz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we aborted the connection and there are no more DLCs
|
||||
* on the session, it is our responsibility to disconnect.
|
||||
*/
|
||||
if (!LIST_EMPTY(&rs->rs_dlcs))
|
||||
break;
|
||||
|
||||
rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
|
||||
rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
|
||||
callout_schedule(&rs->rs_timeout, rfcomm_ack_timeout * hz);
|
||||
break;
|
||||
|
||||
case RFCOMM_DLC_WAIT_SEND_UA: /* they are connecting */
|
||||
if ((mode & dlc->rd_mode) != dlc->rd_mode) {
|
||||
rfcomm_session_send_frame(rs,
|
||||
RFCOMM_FRAME_DM, dlc->rd_dlci);
|
||||
rfcomm_dlc_close(dlc, ECONNABORTED);
|
||||
break;
|
||||
}
|
||||
|
||||
err = rfcomm_session_send_frame(rs,
|
||||
RFCOMM_FRAME_UA, dlc->rd_dlci);
|
||||
if (err) {
|
||||
rfcomm_session_send_frame(rs,
|
||||
RFCOMM_FRAME_DM, dlc->rd_dlci);
|
||||
rfcomm_dlc_close(dlc, err);
|
||||
break;
|
||||
}
|
||||
|
||||
err = rfcomm_dlc_open(dlc);
|
||||
if (err) {
|
||||
rfcomm_session_send_frame(rs,
|
||||
RFCOMM_FRAME_DM, dlc->rd_dlci);
|
||||
rfcomm_dlc_close(dlc, err);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RFCOMM_DLC_WAIT_RECV_UA:
|
||||
case RFCOMM_DLC_OPEN: /* already established */
|
||||
(*dlc->rd_proto->linkmode)(dlc->rd_upper, mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive data from L2CAP layer for session. There is always exactly one
|
||||
* RFCOMM frame contained in each L2CAP frame.
|
||||
@ -598,7 +698,6 @@ done:
|
||||
static void
|
||||
rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci)
|
||||
{
|
||||
struct rfcomm_mcc_msc msc;
|
||||
struct rfcomm_dlc *dlc;
|
||||
int err;
|
||||
|
||||
@ -637,29 +736,36 @@ rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci)
|
||||
return; /* (DM is sent) */
|
||||
}
|
||||
|
||||
DPRINTFN(2, "send UA(%d) state = %d\n", dlci, dlc->rd_state);
|
||||
|
||||
err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
|
||||
if (err) {
|
||||
rfcomm_dlc_close(dlc, err);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this was some kind of spurious SABM then lets
|
||||
* not do anything, heh.
|
||||
* ..but if this DLC is not waiting to connect, they did
|
||||
* something wrong, ignore it.
|
||||
*/
|
||||
if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
|
||||
return;
|
||||
|
||||
msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
|
||||
msc.modem = dlc->rd_lmodem & 0xfe; /* EA = 0 */
|
||||
msc.brk = 0x00 | 0x01; /* EA = 1 */
|
||||
rfcomm_session_send_mcc(rs, 1, RFCOMM_MCC_MSC, &msc, sizeof(msc));
|
||||
callout_schedule(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
|
||||
/* set link mode */
|
||||
err = rfcomm_dlc_setmode(dlc);
|
||||
if (err == EINPROGRESS) {
|
||||
dlc->rd_state = RFCOMM_DLC_WAIT_SEND_UA;
|
||||
(*dlc->rd_proto->connecting)(dlc->rd_upper);
|
||||
return;
|
||||
}
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
dlc->rd_state = RFCOMM_DLC_OPEN;
|
||||
(*dlc->rd_proto->connected)(dlc->rd_upper);
|
||||
err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
/* and mark it open */
|
||||
err = rfcomm_dlc_open(dlc);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
return;
|
||||
|
||||
close:
|
||||
rfcomm_dlc_close(dlc, err);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -707,7 +813,6 @@ rfcomm_session_recv_disc(struct rfcomm_session *rs, int dlci)
|
||||
static void
|
||||
rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci)
|
||||
{
|
||||
struct rfcomm_mcc_msc msc;
|
||||
struct rfcomm_dlc *dlc;
|
||||
|
||||
DPRINTFN(5, "UA(%d)\n", dlci);
|
||||
@ -747,16 +852,8 @@ rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci)
|
||||
goto check;
|
||||
|
||||
switch (dlc->rd_state) {
|
||||
case RFCOMM_DLC_WAIT_CONNECT: /* We sent SABM */
|
||||
msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
|
||||
msc.modem = dlc->rd_lmodem & 0xfe; /* EA = 0 */
|
||||
msc.brk = 0x00 | 0x01; /* EA = 1 */
|
||||
rfcomm_session_send_mcc(rs, 1, RFCOMM_MCC_MSC,
|
||||
&msc, sizeof(msc));
|
||||
callout_schedule(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
|
||||
|
||||
dlc->rd_state = RFCOMM_DLC_OPEN;
|
||||
(*dlc->rd_proto->connected)(dlc->rd_upper);
|
||||
case RFCOMM_DLC_WAIT_RECV_UA: /* We sent SABM */
|
||||
rfcomm_dlc_open(dlc);
|
||||
return;
|
||||
|
||||
case RFCOMM_DLC_WAIT_DISCONNECT: /* We sent DISC */
|
||||
@ -904,7 +1001,7 @@ rfcomm_session_recv_mcc(struct rfcomm_session *rs, struct mbuf *m)
|
||||
m_adj(m, sizeof(b));
|
||||
|
||||
if (RFCOMM_EA(b) == 0) { /* verify no extensions */
|
||||
DPRINTF("MCC type EA = 1, discarded\n");
|
||||
DPRINTF("MCC type EA = 0, discarded\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
@ -1272,19 +1369,34 @@ rfcomm_session_recv_mcc_pn(struct rfcomm_session *rs, int cr, struct mbuf *m)
|
||||
}
|
||||
dlc->rd_mtu = pn.mtu;
|
||||
|
||||
/* initial credits can only be set before DLC is open */
|
||||
if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT
|
||||
&& (pn.flow_control & 0xf0) == 0xe0) {
|
||||
/* if DLC is not waiting to connect, we are done */
|
||||
if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
|
||||
return;
|
||||
|
||||
/* set initial credits according to RFCOMM spec */
|
||||
if ((pn.flow_control & 0xf0) == 0xe0) {
|
||||
rs->rs_flags |= RFCOMM_SESSION_CFC;
|
||||
dlc->rd_txcred = (pn.credits & 0x07);
|
||||
}
|
||||
|
||||
/* Ok, lets go with it */
|
||||
callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
|
||||
|
||||
/* set link mode */
|
||||
err = rfcomm_dlc_setmode(dlc);
|
||||
if (err == EINPROGRESS) {
|
||||
dlc->rd_state = RFCOMM_DLC_WAIT_SEND_SABM;
|
||||
(*dlc->rd_proto->connecting)(dlc->rd_upper);
|
||||
return;
|
||||
}
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
/* we can proceed now */
|
||||
err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, pn.dlci);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
|
||||
dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rfcomm_socket.c,v 1.6 2007/03/31 18:17:13 plunky Exp $ */
|
||||
/* $NetBSD: rfcomm_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.6 2007/03/31 18:17:13 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
/* load symbolic names */
|
||||
#ifdef BLUETOOTH_DEBUG
|
||||
@ -64,6 +64,7 @@ static void rfcomm_connected(void *);
|
||||
static void rfcomm_disconnected(void *, int);
|
||||
static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void rfcomm_complete(void *, int);
|
||||
static void rfcomm_linkmode(void *, int);
|
||||
static void rfcomm_input(void *, struct mbuf *);
|
||||
|
||||
static const struct btproto rfcomm_proto = {
|
||||
@ -72,6 +73,7 @@ static const struct btproto rfcomm_proto = {
|
||||
rfcomm_disconnected,
|
||||
rfcomm_newconn,
|
||||
rfcomm_complete,
|
||||
rfcomm_linkmode,
|
||||
rfcomm_input,
|
||||
};
|
||||
|
||||
@ -364,6 +366,29 @@ rfcomm_complete(void *arg, int length)
|
||||
sowwakeup(so);
|
||||
}
|
||||
|
||||
/*
|
||||
* rfcomm_linkmode(rfcomm_dlc, new)
|
||||
*
|
||||
* link mode change notification.
|
||||
*/
|
||||
static void
|
||||
rfcomm_linkmode(void *arg, int new)
|
||||
{
|
||||
struct socket *so = arg;
|
||||
int mode;
|
||||
|
||||
DPRINTF("auth %s, encrypt %s, secure %s\n",
|
||||
(new & RFCOMM_LM_AUTH ? "on" : "off"),
|
||||
(new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
|
||||
(new & RFCOMM_LM_SECURE ? "on" : "off"));
|
||||
|
||||
(void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
|
||||
if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
|
||||
|| ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
|
||||
|| ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
|
||||
rfcomm_disconnect(so->so_pcb, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* rfcomm_input(rfcomm_dlc, mbuf)
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rfcomm_upper.c,v 1.5 2007/04/06 17:09:00 plunky Exp $ */
|
||||
/* $NetBSD: rfcomm_upper.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.5 2007/04/06 17:09:00 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.6 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -228,7 +228,14 @@ rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
|
||||
case RFCOMM_DLC_LISTEN:
|
||||
return EINVAL;
|
||||
|
||||
case RFCOMM_DLC_WAIT_SEND_UA:
|
||||
err = rfcomm_session_send_frame(rs,
|
||||
RFCOMM_FRAME_DM, dlc->rd_dlci);
|
||||
|
||||
/* fall through */
|
||||
case RFCOMM_DLC_WAIT_SESSION:
|
||||
case RFCOMM_DLC_WAIT_CONNECT:
|
||||
case RFCOMM_DLC_WAIT_SEND_SABM:
|
||||
rfcomm_dlc_close(dlc, 0);
|
||||
break;
|
||||
|
||||
@ -239,7 +246,7 @@ rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
|
||||
}
|
||||
|
||||
/* else fall through */
|
||||
case RFCOMM_DLC_WAIT_CONNECT:
|
||||
case RFCOMM_DLC_WAIT_RECV_UA:
|
||||
dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
|
||||
err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
|
||||
dlc->rd_dlci);
|
||||
@ -416,7 +423,7 @@ rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
|
||||
int
|
||||
rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
|
||||
{
|
||||
int err = 0;
|
||||
int mode, err = 0;
|
||||
uint16_t mtu;
|
||||
|
||||
switch (opt) {
|
||||
@ -431,6 +438,23 @@ rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
|
||||
|
||||
break;
|
||||
|
||||
case SO_RFCOMM_LM:
|
||||
mode = *(int *)addr;
|
||||
mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
|
||||
|
||||
if (mode & RFCOMM_LM_SECURE)
|
||||
mode |= RFCOMM_LM_ENCRYPT;
|
||||
|
||||
if (mode & RFCOMM_LM_ENCRYPT)
|
||||
mode |= RFCOMM_LM_AUTH;
|
||||
|
||||
dlc->rd_mode = mode;
|
||||
|
||||
if (dlc->rd_state == RFCOMM_DLC_OPEN)
|
||||
err = rfcomm_dlc_setmode(dlc);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
err = ENOPROTOOPT;
|
||||
break;
|
||||
@ -466,6 +490,10 @@ rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
|
||||
|
||||
return sizeof(*fc);
|
||||
|
||||
case SO_RFCOMM_LM:
|
||||
*(int *)addr = dlc->rd_mode;
|
||||
return sizeof(int);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: sco_socket.c,v 1.8 2007/03/31 18:17:13 plunky Exp $ */
|
||||
/* $NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.8 2007/03/31 18:17:13 plunky Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $");
|
||||
|
||||
/* load symbolic names */
|
||||
#ifdef BLUETOOTH_DEBUG
|
||||
@ -62,6 +62,7 @@ static void sco_connected(void *);
|
||||
static void sco_disconnected(void *, int);
|
||||
static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
|
||||
static void sco_complete(void *, int);
|
||||
static void sco_linkmode(void *, int);
|
||||
static void sco_input(void *, struct mbuf *);
|
||||
|
||||
static const struct btproto sco_proto = {
|
||||
@ -70,6 +71,7 @@ static const struct btproto sco_proto = {
|
||||
sco_disconnected,
|
||||
sco_newconn,
|
||||
sco_complete,
|
||||
sco_linkmode,
|
||||
sco_input,
|
||||
};
|
||||
|
||||
@ -346,6 +348,11 @@ sco_complete(void *arg, int num)
|
||||
sowwakeup(so);
|
||||
}
|
||||
|
||||
static void
|
||||
sco_linkmode(void *arg, int mode)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
sco_input(void *arg, struct mbuf *m)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: rfcomm_sppd.1,v 1.4 2007/03/01 21:44:30 plunky Exp $
|
||||
.\" $NetBSD: rfcomm_sppd.1,v 1.5 2007/04/21 06:15:23 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006 Itronix Inc.
|
||||
.\" All rights reserved.
|
||||
@ -52,7 +52,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd February 28, 2007
|
||||
.Dd April 10, 2007
|
||||
.Dt RFCOMM_SPPD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -61,9 +61,10 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d Ar device
|
||||
.Op Fl m Ar mode
|
||||
.Op Fl s Ar service
|
||||
.Op Fl t Ar tty
|
||||
.Fl a Ar address | Fl c Ar channel
|
||||
.Brq Fl a Ar address | Fl c Ar channel
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
@ -116,6 +117,18 @@ for a list of available devices.
|
||||
If no
|
||||
.Ar device
|
||||
is specified, the connection will be set up on a system determined device.
|
||||
.It Fl m Ar mode
|
||||
Set connection link mode.
|
||||
Supported modes are:
|
||||
.Pp
|
||||
.Bl -tag -compact -offset indent
|
||||
.It auth
|
||||
require devices be paired.
|
||||
.It encrypt
|
||||
auth, plus enable encryption.
|
||||
.It secure
|
||||
encryption, plus change of link key.
|
||||
.El
|
||||
.It Fl s Ar service
|
||||
This is the service class that will be searched for on the remote device.
|
||||
If no
|
||||
@ -173,10 +186,10 @@ server, e.g. with the use of
|
||||
.Pp
|
||||
In order to use
|
||||
.Nm
|
||||
to automatically create a link for
|
||||
to automatically create a secured link for
|
||||
.Xr pppd 8 ,
|
||||
use
|
||||
.Dl pty Qo rfcomm_sppd -a 00:01:02:03:04:05 -s DUN Qc
|
||||
.Dl pty Qo rfcomm_sppd -a 00:01:02:03:04:05 -s DUN -m secure Qc
|
||||
.Pp
|
||||
in your
|
||||
.Xr pppd 8
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rfcomm_sppd.c,v 1.6 2007/03/31 07:14:44 plunky Exp $ */
|
||||
/* $NetBSD: rfcomm_sppd.c,v 1.7 2007/04/21 06:15:24 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -62,7 +62,7 @@ __COPYRIGHT("@(#) Copyright (c) 2007 Iain Hibbert\n"
|
||||
"@(#) Copyright (c) 2006 Itronix, Inc.\n"
|
||||
"@(#) Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>\n"
|
||||
"All rights reserved.\n");
|
||||
__RCSID("$NetBSD: rfcomm_sppd.c,v 1.6 2007/03/31 07:14:44 plunky Exp $");
|
||||
__RCSID("$NetBSD: rfcomm_sppd.c,v 1.7 2007/04/21 06:15:24 plunky Exp $");
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <ctype.h>
|
||||
@ -82,13 +82,15 @@ __RCSID("$NetBSD: rfcomm_sppd.c,v 1.6 2007/03/31 07:14:44 plunky Exp $");
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netbt/rfcomm.h>
|
||||
|
||||
#include "rfcomm_sdp.h"
|
||||
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
int open_tty(const char *);
|
||||
int open_client(bdaddr_t *, bdaddr_t *, const char *);
|
||||
int open_server(bdaddr_t *, uint8_t, const char *);
|
||||
int open_client(bdaddr_t *, bdaddr_t *, int, const char *);
|
||||
int open_server(bdaddr_t *, uint8_t, int, const char *);
|
||||
void copy_data(int, int);
|
||||
void sighandler(int);
|
||||
void usage(void);
|
||||
@ -129,7 +131,7 @@ main(int argc, char *argv[])
|
||||
fd_set rdset;
|
||||
const char *service;
|
||||
char *ep, *tty;
|
||||
int n, rfcomm, tty_in, tty_out;
|
||||
int lm, n, rfcomm, tty_in, tty_out;
|
||||
uint8_t channel;
|
||||
|
||||
bdaddr_copy(&laddr, BDADDR_ANY);
|
||||
@ -137,9 +139,10 @@ main(int argc, char *argv[])
|
||||
service = "SP";
|
||||
tty = NULL;
|
||||
channel = 0;
|
||||
lm = 0;
|
||||
|
||||
/* Parse command line options */
|
||||
while ((n = getopt(argc, argv, "a:c:d:hs:t:")) != -1) {
|
||||
while ((n = getopt(argc, argv, "a:c:d:hm:s:t:")) != -1) {
|
||||
switch (n) {
|
||||
case 'a': /* remote device address */
|
||||
if (!bt_aton(optarg, &raddr)) {
|
||||
@ -166,6 +169,18 @@ main(int argc, char *argv[])
|
||||
|
||||
break;
|
||||
|
||||
case 'm': /* Link Mode */
|
||||
if (strcasecmp(optarg, "auth") == 0)
|
||||
lm = RFCOMM_LM_AUTH;
|
||||
else if (strcasecmp(optarg, "encrypt") == 0)
|
||||
lm = RFCOMM_LM_ENCRYPT;
|
||||
else if (strcasecmp(optarg, "secure") == 0)
|
||||
lm = RFCOMM_LM_SECURE;
|
||||
else
|
||||
errx(EXIT_FAILURE, "%s: unknown mode", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case 's': /* service class */
|
||||
service = optarg;
|
||||
break;
|
||||
@ -206,9 +221,9 @@ main(int argc, char *argv[])
|
||||
|
||||
/* open RFCOMM */
|
||||
if (channel == 0)
|
||||
rfcomm = open_client(&laddr, &raddr, service);
|
||||
rfcomm = open_client(&laddr, &raddr, lm, service);
|
||||
else
|
||||
rfcomm = open_server(&laddr, channel, service);
|
||||
rfcomm = open_server(&laddr, channel, lm, service);
|
||||
|
||||
/*
|
||||
* now we are ready to go, so either detach or maybe turn
|
||||
@ -314,7 +329,7 @@ open_tty(const char *tty)
|
||||
}
|
||||
|
||||
int
|
||||
open_client(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
|
||||
open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, const char *service)
|
||||
{
|
||||
struct sockaddr_bt sa;
|
||||
struct service *s;
|
||||
@ -358,6 +373,9 @@ open_client(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
|
||||
err(EXIT_FAILURE, "linger()");
|
||||
|
||||
if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
|
||||
err(EXIT_FAILURE, "link mode");
|
||||
|
||||
sa.bt_channel = channel;
|
||||
bdaddr_copy(&sa.bt_bdaddr, raddr);
|
||||
|
||||
@ -377,7 +395,7 @@ open_client(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
|
||||
#define pdu_len sizeof(struct sdp_lan_profile)
|
||||
|
||||
int
|
||||
open_server(bdaddr_t *laddr, uint8_t channel, const char *service)
|
||||
open_server(bdaddr_t *laddr, uint8_t channel, int lm, const char *service)
|
||||
{
|
||||
struct sockaddr_bt sa;
|
||||
struct linger l;
|
||||
@ -400,6 +418,9 @@ open_server(bdaddr_t *laddr, uint8_t channel, const char *service)
|
||||
err(EXIT_FAILURE, "bind(%s, %d)", bt_ntoa(laddr, NULL),
|
||||
channel);
|
||||
|
||||
if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
|
||||
err(EXIT_FAILURE, "link mode");
|
||||
|
||||
if (listen(sv, 1) < 0)
|
||||
err(EXIT_FAILURE, "listen()");
|
||||
|
||||
@ -481,17 +502,20 @@ reset_tio(void)
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
const char *cmd = getprogname();
|
||||
struct service *s;
|
||||
|
||||
fprintf(stderr, "Usage: %s [-d device] [-s service] [-t tty] -a bdaddr | -c channel\n"
|
||||
fprintf(stderr, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
|
||||
" %*s {-a bdaddr | -c channel}\n"
|
||||
"\n"
|
||||
"Where:\n"
|
||||
"\t-a bdaddr remote device address\n"
|
||||
"\t-c channel local RFCOMM channel\n"
|
||||
"\t-d device local device address\n"
|
||||
"\t-m mode link mode\n"
|
||||
"\t-s service service class\n"
|
||||
"\t-t tty run in background using pty\n"
|
||||
"\n", getprogname());
|
||||
"\n", cmd, strlen(cmd), "");
|
||||
|
||||
fprintf(stderr, "Known service classes:\n");
|
||||
for (s = services ; s->name != NULL ; s++)
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: btdevctl.8,v 1.3 2006/09/10 15:45:56 plunky Exp $
|
||||
.\" $NetBSD: btdevctl.8,v 1.4 2007/04/21 06:15:24 plunky Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006 Itronix Inc.
|
||||
.\" All rights reserved.
|
||||
@ -51,10 +51,10 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: btdevctl.8,v 1.3 2006/09/10 15:45:56 plunky Exp $
|
||||
.\" $Id: btdevctl.8,v 1.4 2007/04/21 06:15:24 plunky Exp $
|
||||
.\" $FreeBSD: src/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.8,v 1.3 2005/01/18 20:02:30 ru Exp $
|
||||
.\"
|
||||
.Dd September 9, 2006
|
||||
.Dd April 10, 2007
|
||||
.Dt BTDEVCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -64,6 +64,7 @@
|
||||
.Nm
|
||||
.Op Fl A | Fl D
|
||||
.Op Fl qv
|
||||
.Op Fl m Ar mode
|
||||
.Fl a Ar address
|
||||
.Fl d Ar device
|
||||
.Fl s Ar service
|
||||
@ -99,6 +100,29 @@ Detach device
|
||||
.It Fl d Ar device
|
||||
Local device address.
|
||||
May be given as BDADDR or device name.
|
||||
.It Fl m Ar mode
|
||||
Connection link mode.
|
||||
The following modes are supported:
|
||||
.Pp
|
||||
.Bl -tag -compact
|
||||
.It none
|
||||
clear previously set mode.
|
||||
.It auth
|
||||
require devices be paired, see
|
||||
.Xr btpin 1 .
|
||||
.It encrypt
|
||||
auth, plus enable encryption.
|
||||
.It secure
|
||||
encryption, plus change of link key.
|
||||
.El
|
||||
.Pp
|
||||
When configuring the HID service,
|
||||
.Nm
|
||||
will set
|
||||
.Sq auth
|
||||
by default, or
|
||||
.Sq encrypt
|
||||
for keyboard devices.
|
||||
.It Fl q
|
||||
Ignore any cached data and perform a SDP query for the given
|
||||
.Ar service .
|
||||
@ -136,6 +160,7 @@ to YES.
|
||||
.It Pa /var/db/btdevctl.plist
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr btpin 1 ,
|
||||
.Xr bthidev 4 ,
|
||||
.Xr bthub 4 ,
|
||||
.Xr btsco 4 ,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: btdevctl.c,v 1.3 2006/09/11 18:30:27 plunky Exp $ */
|
||||
/* $NetBSD: btdevctl.c,v 1.4 2007/04/21 06:15:24 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
#include <sys/cdefs.h>
|
||||
__COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc.\n"
|
||||
"All rights reserved.\n");
|
||||
__RCSID("$NetBSD: btdevctl.c,v 1.3 2006/09/11 18:30:27 plunky Exp $");
|
||||
__RCSID("$NetBSD: btdevctl.c,v 1.4 2007/04/21 06:15:24 plunky Exp $");
|
||||
|
||||
#include <prop/proplib.h>
|
||||
#include <sys/ioctl.h>
|
||||
@ -64,18 +64,21 @@ main(int argc, char *argv[])
|
||||
prop_dictionary_t dev;
|
||||
prop_object_t obj;
|
||||
bdaddr_t laddr, raddr;
|
||||
const char *service;
|
||||
int ch, query, verbose, attach, detach;
|
||||
const char *service, *mode;
|
||||
int ch, query, verbose, attach, detach, set, none;
|
||||
|
||||
bdaddr_copy(&laddr, BDADDR_ANY);
|
||||
bdaddr_copy(&raddr, BDADDR_ANY);
|
||||
service = NULL;
|
||||
mode = NULL;
|
||||
query = FALSE;
|
||||
verbose = FALSE;
|
||||
attach = FALSE;
|
||||
detach = FALSE;
|
||||
set = FALSE;
|
||||
none = FALSE;
|
||||
|
||||
while ((ch = getopt(argc, argv, "Aa:Dd:hqs:v")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "Aa:Dd:hm:qs:v")) != -1) {
|
||||
switch (ch) {
|
||||
case 'A': /* Attach device */
|
||||
attach = TRUE;
|
||||
@ -103,6 +106,20 @@ main(int argc, char *argv[])
|
||||
|
||||
break;
|
||||
|
||||
case 'm': /* link mode */
|
||||
if (strcasecmp(optarg, "none") == 0)
|
||||
none = TRUE;
|
||||
else if (strcasecmp(optarg, BTDEVauth) == 0)
|
||||
mode = BTDEVauth;
|
||||
else if (strcasecmp(optarg, BTDEVencrypt) == 0)
|
||||
mode = BTDEVencrypt;
|
||||
else if (strcasecmp(optarg, BTDEVsecure) == 0)
|
||||
mode = BTDEVsecure;
|
||||
else
|
||||
errx(EXIT_FAILURE, "%s: unknown mode", mode);
|
||||
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
query = TRUE;
|
||||
break;
|
||||
@ -143,10 +160,26 @@ main(int argc, char *argv[])
|
||||
if (dev == NULL)
|
||||
errx(EXIT_FAILURE, "%s/%s not found", bt_ntoa(&raddr, NULL), service);
|
||||
|
||||
if (!db_set(dev, &laddr, &raddr, service))
|
||||
errx(EXIT_FAILURE, "service store failed");
|
||||
set = TRUE;
|
||||
}
|
||||
|
||||
if (mode != NULL) {
|
||||
obj = prop_string_create_cstring_nocopy(mode);
|
||||
if (obj == NULL || !prop_dictionary_set(dev, BTDEVmode, obj))
|
||||
errx(EXIT_FAILURE, "proplib failure (%s)", BTDEVmode);
|
||||
|
||||
prop_object_release(obj);
|
||||
set = TRUE;
|
||||
}
|
||||
|
||||
if (none == TRUE) {
|
||||
prop_dictionary_remove(dev, BTDEVmode);
|
||||
set = TRUE;
|
||||
}
|
||||
|
||||
if (set == TRUE && !db_set(dev, &laddr, &raddr, service))
|
||||
errx(EXIT_FAILURE, "service store failed");
|
||||
|
||||
/* add binary local-bdaddr */
|
||||
obj = prop_data_create_data(&laddr, sizeof(laddr));
|
||||
if (obj == NULL || !prop_dictionary_set(dev, BTDEVladdr, obj))
|
||||
@ -185,12 +218,13 @@ usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr,
|
||||
"usage: %s [-A | -D] [-qv] -a address -d device -s service\n"
|
||||
"usage: %s [-A | -D] [-qv] [-m mode] -a address -d device -s service\n"
|
||||
"Where:\n"
|
||||
"\t-A attach device\n"
|
||||
"\t-a address remote device address\n"
|
||||
"\t-D detach device\n"
|
||||
"\t-d device local device address\n"
|
||||
"\t-m mode link mode\n"
|
||||
"\t-q force SDP query\n"
|
||||
"\t-s service remote service\n"
|
||||
"\t-v verbose\n"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: btdevctl.h,v 1.2 2006/09/10 15:45:56 plunky Exp $ */
|
||||
/* $NetBSD: btdevctl.h,v 1.3 2007/04/21 06:15:24 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -43,5 +43,6 @@ void cfg_print(prop_dictionary_t);
|
||||
|
||||
/* sdp.c */
|
||||
prop_dictionary_t cfg_query(bdaddr_t *, bdaddr_t *, const char *);
|
||||
const char *hid_mode(prop_data_t);
|
||||
|
||||
#endif /* __BTDEVCTL_H__ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: db.c,v 1.2 2007/04/11 19:59:02 plunky Exp $ */
|
||||
/* $NetBSD: db.c,v 1.3 2007/04/21 06:15:24 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: db.c,v 1.2 2007/04/11 19:59:02 plunky Exp $");
|
||||
__RCSID("$NetBSD: db.c,v 1.3 2007/04/21 06:15:24 plunky Exp $");
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <err.h>
|
||||
@ -41,17 +41,19 @@ __RCSID("$NetBSD: db.c,v 1.2 2007/04/11 19:59:02 plunky Exp $");
|
||||
#include <prop/proplib.h>
|
||||
|
||||
#include <dev/bluetooth/btdev.h>
|
||||
#include <dev/bluetooth/bthidev.h>
|
||||
#include <dev/bluetooth/btsco.h>
|
||||
|
||||
#include "btdevctl.h"
|
||||
|
||||
#define BTDEVCTL_PLIST "/var/db/btdevctl.plist"
|
||||
#define BTDEVCTL_VERSION 1
|
||||
#define BTDEVCTL_VERSION 2
|
||||
|
||||
static prop_dictionary_t db = NULL;
|
||||
static int db_flush = TRUE; /* write db on set */
|
||||
|
||||
static void db_update0(void);
|
||||
static void db_update1(void);
|
||||
|
||||
/*
|
||||
* lookup laddr/raddr/service in database and return dictionary
|
||||
@ -73,10 +75,8 @@ db_get(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
|
||||
} else {
|
||||
obj = prop_dictionary_get(db, "btdevctl-version");
|
||||
switch(prop_number_integer_value(obj)) {
|
||||
case 0:
|
||||
db_update0();
|
||||
break;
|
||||
|
||||
case 0: db_update0();
|
||||
case 1: db_update1();
|
||||
case BTDEVCTL_VERSION:
|
||||
break;
|
||||
|
||||
@ -222,3 +222,58 @@ db_update0(void)
|
||||
|
||||
db_flush = TRUE; /* write on set */
|
||||
}
|
||||
|
||||
/*
|
||||
* update database from version 1. Link Mode capability was added.
|
||||
* By default, we request authentication for HIDs, and encryption
|
||||
* is enabled for keyboards.
|
||||
*/
|
||||
static void
|
||||
db_update1(void)
|
||||
{
|
||||
prop_dictionary_t ldev, rdev, srv;
|
||||
prop_object_iterator_t iter0, iter1;
|
||||
prop_dictionary_keysym_t key;
|
||||
prop_object_t obj;
|
||||
bdaddr_t bdaddr;
|
||||
|
||||
iter0 = prop_dictionary_iterator(db);
|
||||
if (iter0 == NULL)
|
||||
err(EXIT_FAILURE, "prop_dictionary_iterator");
|
||||
|
||||
while ((key = prop_object_iterator_next(iter0)) != NULL) {
|
||||
ldev = prop_dictionary_get_keysym(db, key);
|
||||
if (prop_object_type(ldev) != PROP_TYPE_DICTIONARY
|
||||
|| !bt_aton(prop_dictionary_keysym_cstring_nocopy(key), &bdaddr))
|
||||
continue;
|
||||
|
||||
iter1 = prop_dictionary_iterator(ldev);
|
||||
if (iter1 == NULL)
|
||||
err(EXIT_FAILURE, "prop_dictionary_iterator");
|
||||
|
||||
while ((key = prop_object_iterator_next(iter1)) != NULL) {
|
||||
rdev = prop_dictionary_get_keysym(ldev, key);
|
||||
if (prop_object_type(rdev) != PROP_TYPE_DICTIONARY
|
||||
|| !bt_aton(prop_dictionary_keysym_cstring_nocopy(key), &bdaddr))
|
||||
continue;
|
||||
|
||||
srv = prop_dictionary_get(rdev, "HID");
|
||||
if (prop_object_type(srv) != PROP_TYPE_DICTIONARY)
|
||||
continue;
|
||||
|
||||
obj = prop_dictionary_get(srv, BTHIDEVdescriptor);
|
||||
if (prop_object_type(obj) != PROP_TYPE_DATA)
|
||||
continue;
|
||||
|
||||
obj = prop_string_create_cstring_nocopy(hid_mode(obj));
|
||||
if (obj == NULL || !prop_dictionary_set(srv, BTDEVmode, obj))
|
||||
err(EXIT_FAILURE, "Cannot set %s", BTDEVmode);
|
||||
|
||||
prop_object_release(obj);
|
||||
}
|
||||
|
||||
prop_object_iterator_release(iter1);
|
||||
}
|
||||
|
||||
prop_object_iterator_release(iter0);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: print.c,v 1.7 2006/09/29 18:48:17 plunky Exp $ */
|
||||
/* $NetBSD: print.c,v 1.8 2007/04/21 06:15:24 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -58,7 +58,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: print.c,v 1.7 2006/09/29 18:48:17 plunky Exp $");
|
||||
__RCSID("$NetBSD: print.c,v 1.8 2007/04/21 06:15:24 plunky Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -99,6 +99,10 @@ cfg_print(prop_dictionary_t dict)
|
||||
}
|
||||
printf("remote bdaddr: %s\n", bt_ntoa(prop_data_data_nocopy(obj), NULL));
|
||||
|
||||
obj = prop_dictionary_get(dict, BTDEVmode);
|
||||
if (prop_object_type(obj) == PROP_TYPE_STRING)
|
||||
printf("link mode: %s\n", prop_string_cstring_nocopy(obj));
|
||||
|
||||
obj = prop_dictionary_get(dict, BTDEVtype);
|
||||
if (prop_object_type(obj) != PROP_TYPE_STRING) {
|
||||
printf("No device type!\n");
|
||||
@ -166,7 +170,7 @@ hid_parse(prop_data_t desc)
|
||||
|
||||
hid_init(NULL);
|
||||
|
||||
r = hid_use_report_desc((unsigned char *)prop_data_data_nocopy(desc),
|
||||
r = hid_use_report_desc(prop_data_data_nocopy(desc),
|
||||
prop_data_size(desc));
|
||||
if (r == NULL)
|
||||
return;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: sdp.c,v 1.2 2007/04/11 20:01:01 plunky Exp $ */
|
||||
/* $NetBSD: sdp.c,v 1.3 2007/04/21 06:15:24 plunky Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Itronix Inc.
|
||||
@ -55,7 +55,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: sdp.c,v 1.2 2007/04/11 20:01:01 plunky Exp $");
|
||||
__RCSID("$NetBSD: sdp.c,v 1.3 2007/04/21 06:15:24 plunky Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -213,6 +213,7 @@ config_hid(prop_dictionary_t dict)
|
||||
reconnect_initiate, battery_power,
|
||||
normally_connectable, hid_length;
|
||||
uint8_t *hid_descriptor;
|
||||
const char *mode;
|
||||
int i;
|
||||
|
||||
control_psm = -1;
|
||||
@ -286,6 +287,13 @@ config_hid(prop_dictionary_t dict)
|
||||
if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVdescriptor, obj))
|
||||
return errno;
|
||||
|
||||
mode = hid_mode(obj);
|
||||
prop_object_release(obj);
|
||||
|
||||
obj = prop_string_create_cstring_nocopy(mode);
|
||||
if (obj == NULL || !prop_dictionary_set(dict, BTDEVmode, obj))
|
||||
return errno;
|
||||
|
||||
prop_object_release(obj);
|
||||
|
||||
if (!reconnect_initiate) {
|
||||
@ -764,3 +772,37 @@ parse_rfcomm_channel(sdp_attr_t *a)
|
||||
|
||||
return (channel);
|
||||
}
|
||||
|
||||
/*
|
||||
* return appropriate mode for HID descriptor
|
||||
*/
|
||||
const char *
|
||||
hid_mode(prop_data_t desc)
|
||||
{
|
||||
report_desc_t r;
|
||||
hid_data_t d;
|
||||
struct hid_item h;
|
||||
const char *mode;
|
||||
|
||||
hid_init(NULL);
|
||||
|
||||
mode = BTDEVauth; /* default */
|
||||
|
||||
r = hid_use_report_desc(prop_data_data_nocopy(desc),
|
||||
prop_data_size(desc));
|
||||
if (r == NULL)
|
||||
err(EXIT_FAILURE, "hid_use_report_desc");
|
||||
|
||||
d = hid_start_parse(r, ~0, -1);
|
||||
while (hid_get_item(d, &h) > 0) {
|
||||
if (h.kind == hid_collection
|
||||
&& HID_PAGE(h.usage) == HUP_GENERIC_DESKTOP
|
||||
&& HID_USAGE(h.usage) == HUG_KEYBOARD)
|
||||
mode = BTDEVencrypt;
|
||||
}
|
||||
|
||||
hid_end_parse(d);
|
||||
hid_dispose_report_desc(r);
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user