diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/a2mp.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 188b42120074..1cc920a62b0f 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, | |||
63 | kfree(cmd); | 63 | kfree(cmd); |
64 | } | 64 | } |
65 | 65 | ||
66 | static inline void __a2mp_cl_bredr(struct a2mp_cl *cl) | ||
67 | { | ||
68 | cl->id = 0; | ||
69 | cl->type = 0; | ||
70 | cl->status = 1; | ||
71 | } | ||
72 | |||
73 | /* hci_dev_list shall be locked */ | ||
74 | static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl) | ||
75 | { | ||
76 | int i = 0; | ||
77 | struct hci_dev *hdev; | ||
78 | |||
79 | __a2mp_cl_bredr(cl); | ||
80 | |||
81 | list_for_each_entry(hdev, &hci_dev_list, list) { | ||
82 | /* Iterate through AMP controllers */ | ||
83 | if (hdev->id == HCI_BREDR_ID) | ||
84 | continue; | ||
85 | |||
86 | /* Starting from second entry */ | ||
87 | if (++i >= num_ctrl) | ||
88 | return; | ||
89 | |||
90 | cl[i].id = hdev->id; | ||
91 | cl[i].type = hdev->amp_type; | ||
92 | cl[i].status = hdev->amp_status; | ||
93 | } | ||
94 | } | ||
95 | |||
66 | /* Processing A2MP messages */ | 96 | /* Processing A2MP messages */ |
67 | static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, | 97 | static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, |
68 | struct a2mp_cmd *hdr) | 98 | struct a2mp_cmd *hdr) |
@@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, | |||
79 | return 0; | 109 | return 0; |
80 | } | 110 | } |
81 | 111 | ||
112 | static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, | ||
113 | struct a2mp_cmd *hdr) | ||
114 | { | ||
115 | struct a2mp_discov_req *req = (void *) skb->data; | ||
116 | u16 len = le16_to_cpu(hdr->len); | ||
117 | struct a2mp_discov_rsp *rsp; | ||
118 | u16 ext_feat; | ||
119 | u8 num_ctrl; | ||
120 | |||
121 | if (len < sizeof(*req)) | ||
122 | return -EINVAL; | ||
123 | |||
124 | skb_pull(skb, sizeof(*req)); | ||
125 | |||
126 | ext_feat = le16_to_cpu(req->ext_feat); | ||
127 | |||
128 | BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat); | ||
129 | |||
130 | /* check that packet is not broken for now */ | ||
131 | while (ext_feat & A2MP_FEAT_EXT) { | ||
132 | if (len < sizeof(ext_feat)) | ||
133 | return -EINVAL; | ||
134 | |||
135 | ext_feat = get_unaligned_le16(skb->data); | ||
136 | BT_DBG("efm 0x%4.4x", ext_feat); | ||
137 | len -= sizeof(ext_feat); | ||
138 | skb_pull(skb, sizeof(ext_feat)); | ||
139 | } | ||
140 | |||
141 | read_lock(&hci_dev_list_lock); | ||
142 | |||
143 | num_ctrl = __hci_num_ctrl(); | ||
144 | len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp); | ||
145 | rsp = kmalloc(len, GFP_ATOMIC); | ||
146 | if (!rsp) { | ||
147 | read_unlock(&hci_dev_list_lock); | ||
148 | return -ENOMEM; | ||
149 | } | ||
150 | |||
151 | rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); | ||
152 | rsp->ext_feat = 0; | ||
153 | |||
154 | __a2mp_add_cl(mgr, rsp->cl, num_ctrl); | ||
155 | |||
156 | read_unlock(&hci_dev_list_lock); | ||
157 | |||
158 | a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp); | ||
159 | |||
160 | kfree(rsp); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
82 | /* Handle A2MP signalling */ | 164 | /* Handle A2MP signalling */ |
83 | static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) | 165 | static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) |
84 | { | 166 | { |
@@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) | |||
109 | break; | 191 | break; |
110 | 192 | ||
111 | case A2MP_DISCOVER_REQ: | 193 | case A2MP_DISCOVER_REQ: |
194 | err = a2mp_discover_req(mgr, skb, hdr); | ||
195 | break; | ||
196 | |||
112 | case A2MP_CHANGE_NOTIFY: | 197 | case A2MP_CHANGE_NOTIFY: |
113 | case A2MP_GETINFO_REQ: | 198 | case A2MP_GETINFO_REQ: |
114 | case A2MP_GETAMPASSOC_REQ: | 199 | case A2MP_GETAMPASSOC_REQ: |