Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/padovan/bluetooth-next-2.6
  • Loading branch information
John W. Linville committed Apr 29, 2011
2 parents ce6cac8 + 7cbc9bd commit dee04ca
Show file tree
Hide file tree
Showing 15 changed files with 907 additions and 504 deletions.
9 changes: 9 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ enum {
#define HCI_AT_GENERAL_BONDING 0x04
#define HCI_AT_GENERAL_BONDING_MITM 0x05

/* Link Key types */
#define HCI_LK_COMBINATION 0x00
#define HCI_LK_LOCAL_UNIT 0x01
#define HCI_LK_REMOTE_UNIT 0x02
#define HCI_LK_DEBUG_COMBINATION 0x03
#define HCI_LK_UNAUTH_COMBINATION 0x04
#define HCI_LK_AUTH_COMBINATION 0x05
#define HCI_LK_CHANGED_COMBINATION 0x06

/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000

Expand Down
16 changes: 11 additions & 5 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ struct hci_dev {
__u16 sniff_min_interval;
__u16 sniff_max_interval;

unsigned int auto_accept_delay;

unsigned long quirks;

atomic_t cmd_cnt;
Expand Down Expand Up @@ -226,6 +228,7 @@ struct hci_conn {
__u16 pkt_type;
__u16 link_policy;
__u32 link_mode;
__u8 key_type;
__u8 auth_type;
__u8 sec_level;
__u8 pending_sec_level;
Expand All @@ -245,6 +248,7 @@ struct hci_conn {

struct timer_list disc_timer;
struct timer_list idle_timer;
struct timer_list auto_accept_timer;

struct work_struct work_add;
struct work_struct work_del;
Expand Down Expand Up @@ -511,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev);

int hci_link_keys_clear(struct hci_dev *hdev);
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);

int hci_remote_oob_data_clear(struct hci_dev *hdev);
Expand Down Expand Up @@ -771,15 +775,16 @@ int mgmt_index_removed(u16 index);
int mgmt_powered(u16 index, u8 powered);
int mgmt_discoverable(u16 index, u8 discoverable);
int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type);
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
int mgmt_connected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value);
int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
u8 confirm_hint);
int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
u8 status);
Expand All @@ -790,6 +795,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir);
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
int mgmt_discovering(u16 index, u8 discovering);

/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
Expand Down
69 changes: 36 additions & 33 deletions include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,41 @@ struct srej_list {

struct l2cap_chan {
struct sock *sk;

struct l2cap_conn *conn;

__le16 psm;
__u16 dcid;
__u16 scid;

__u16 imtu;
__u16 omtu;
__u16 flush_to;
__u8 mode;

__le16 sport;

__u8 sec_level;
__u8 role_switch;
__u8 force_reliable;
__u8 flushable;

__u8 ident;

__u8 conf_req[64];
__u8 conf_len;
__u8 num_conf_req;
__u8 num_conf_rsp;

__u8 fcs;

__u8 tx_win;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
__u16 mps;

__u8 conf_state;
__u16 conn_state;

__u8 next_tx_seq;
Expand Down Expand Up @@ -360,32 +388,6 @@ struct l2cap_conn {

struct l2cap_pinfo {
struct bt_sock bt;
__le16 psm;
__u16 dcid;
__u16 scid;

__u16 imtu;
__u16 omtu;
__u16 flush_to;
__u8 mode;

__u8 fcs;
__u8 sec_level;
__u8 role_switch;
__u8 force_reliable;
__u8 flushable;

__u8 conf_state;

__u8 tx_win;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
__u16 mps;

__le16 sport;

struct l2cap_conn *conn;
struct l2cap_chan *chan;
};

Expand Down Expand Up @@ -439,21 +441,20 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)

extern int disable_ertm;
extern const struct proto_ops l2cap_sock_ops;
extern struct bt_sock_list l2cap_sk_list;

int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void);

void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
void __l2cap_connect_rsp_defer(struct sock *sk);
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
int __l2cap_wait_ack(struct sock *sk);

struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb);
void l2cap_streaming_send(struct l2cap_chan *chan);
int l2cap_ertm_send(struct l2cap_chan *chan);

Expand All @@ -465,7 +466,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent);
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio);
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
struct l2cap_chan *l2cap_chan_alloc(struct sock *sk);
void l2cap_chan_del(struct l2cap_chan *chan, int err);
int l2cap_do_connect(struct sock *sk);
void l2cap_chan_free(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan);

#endif /* __L2CAP_H */
10 changes: 9 additions & 1 deletion include/net/bluetooth/mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data {
bdaddr_t bdaddr;
} __packed;

#define MGMT_OP_START_DISCOVERY 0x001B

#define MGMT_OP_STOP_DISCOVERY 0x001C

#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
Expand Down Expand Up @@ -226,8 +230,8 @@ struct mgmt_ev_controller_error {

#define MGMT_EV_NEW_KEY 0x000A
struct mgmt_ev_new_key {
__u8 store_hint;
struct mgmt_key_info key;
__u8 old_key_type;
} __packed;

#define MGMT_EV_CONNECTED 0x000B
Expand All @@ -249,11 +253,13 @@ struct mgmt_ev_connect_failed {
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
struct mgmt_ev_pin_code_request {
bdaddr_t bdaddr;
__u8 secure;
} __packed;

#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
struct mgmt_ev_user_confirm_request {
bdaddr_t bdaddr;
__u8 confirm_hint;
__le32 value;
} __packed;

Expand Down Expand Up @@ -281,3 +287,5 @@ struct mgmt_ev_remote_name {
bdaddr_t bdaddr;
__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;

#define MGMT_EV_DISCOVERING 0x0014
3 changes: 2 additions & 1 deletion net/bluetooth/cmtp/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)

bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);

session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
l2cap_pi(sock->sk)->chan->imtu);

BT_DBG("mtu %d", session->mtu);

Expand Down
78 changes: 68 additions & 10 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg)
hci_conn_enter_sniff_mode(conn);
}

static void hci_conn_auto_accept(unsigned long arg)
{
struct hci_conn *conn = (void *) arg;
struct hci_dev *hdev = conn->hdev;

hci_dev_lock(hdev);

hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
&conn->dst);

hci_dev_unlock(hdev);
}

struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
{
struct hci_conn *conn;
Expand All @@ -287,6 +300,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->auth_type = HCI_AT_GENERAL_BONDING;
conn->io_capability = hdev->io_capability;
conn->remote_auth = 0xff;
conn->key_type = 0xff;

conn->power_save = 1;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
Expand All @@ -311,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)

setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
(unsigned long) conn);

atomic_set(&conn->refcnt, 0);

Expand Down Expand Up @@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn)

del_timer(&conn->disc_timer);

del_timer(&conn->auto_accept_timer);

if (conn->type == ACL_LINK) {
struct hci_conn *sco = conn->link;
if (sco)
Expand Down Expand Up @@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
return 0;
}

/* Encrypt the the link */
static void hci_conn_encrypt(struct hci_conn *conn)
{
BT_DBG("conn %p", conn);

if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 0x01;
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
&cp);
}
}

/* Enable security */
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);

/* For sdp we don't need the link key. */
if (sec_level == BT_SECURITY_SDP)
return 1;

/* For non 2.1 devices and low security level we don't need the link
key. */
if (sec_level == BT_SECURITY_LOW &&
(!conn->ssp_mode || !conn->hdev->ssp_mode))
return 1;

if (conn->link_mode & HCI_LM_ENCRYPT)
return hci_conn_auth(conn, sec_level, auth_type);

/* For other security levels we need the link key. */
if (!(conn->link_mode & HCI_LM_AUTH))
goto auth;

/* An authenticated combination key has sufficient security for any
security level. */
if (conn->key_type == HCI_LK_AUTH_COMBINATION)
goto encrypt;

/* An unauthenticated combination key has sufficient security for
security level 1 and 2. */
if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
(sec_level == BT_SECURITY_MEDIUM ||
sec_level == BT_SECURITY_LOW))
goto encrypt;

/* A combination key has always sufficient security for the security
levels 1 or 2. High security level requires the combination key
is generated using maximum PIN code length (16).
For pre 2.1 units. */
if (conn->key_type == HCI_LK_COMBINATION &&
(sec_level != BT_SECURITY_HIGH ||
conn->pin_length == 16))
goto encrypt;

auth:
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;

if (hci_conn_auth(conn, sec_level, auth_type)) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1;
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
sizeof(cp), &cp);
}
hci_conn_auth(conn, sec_level, auth_type);
return 0;

encrypt:
if (conn->link_mode & HCI_LM_ENCRYPT)
return 1;

hci_conn_encrypt(conn);
return 0;
}
EXPORT_SYMBOL(hci_conn_security);
Expand Down
Loading

0 comments on commit dee04ca

Please sign in to comment.