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:
plunky 2007-04-21 06:15:22 +00:00
parent c4ec0fc4f8
commit f5db72e7b7
30 changed files with 1257 additions and 192 deletions

View File

@ -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

View File

@ -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

View File

@ -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 .

View File

@ -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 {

View File

@ -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.
*/

View File

@ -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)
{

View File

@ -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 *);
};

View File

@ -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 *);

View File

@ -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
*/

View File

@ -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)

View File

@ -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 *);

View File

@ -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)

View File

@ -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
*/

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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 */

View File

@ -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)
*

View File

@ -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;

View File

@ -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)
*/

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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

View File

@ -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++)

View File

@ -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 ,

View File

@ -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"

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}