40
40
#include <linux/signal.h>
41
41
#include <linux/ioctl.h>
42
42
#include <linux/skbuff.h>
43
+ #include <asm/unaligned.h>
43
44
44
45
#include <net/bluetooth/bluetooth.h>
45
46
#include <net/bluetooth/hci_core.h>
@@ -113,6 +114,12 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
113
114
return 0 ;
114
115
}
115
116
117
+ static const struct h4_recv_pkt h4_recv_pkts [] = {
118
+ { H4_RECV_ACL , .recv = hci_recv_frame },
119
+ { H4_RECV_SCO , .recv = hci_recv_frame },
120
+ { H4_RECV_EVENT , .recv = hci_recv_frame },
121
+ };
122
+
116
123
/* Recv data */
117
124
static int h4_recv (struct hci_uart * hu , const void * data , int count )
118
125
{
@@ -121,7 +128,8 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
121
128
if (!test_bit (HCI_UART_REGISTERED , & hu -> flags ))
122
129
return - EUNATCH ;
123
130
124
- h4 -> rx_skb = h4_recv_buf (hu -> hdev , h4 -> rx_skb , data , count );
131
+ h4 -> rx_skb = h4_recv_buf (hu -> hdev , h4 -> rx_skb , data , count ,
132
+ h4_recv_pkts , ARRAY_SIZE (h4_recv_pkts ));
125
133
if (IS_ERR (h4 -> rx_skb )) {
126
134
int err = PTR_ERR (h4 -> rx_skb );
127
135
BT_ERR ("%s: Frame reassembly failed (%d)" , hu -> hdev -> name , err );
@@ -159,96 +167,93 @@ int __exit h4_deinit(void)
159
167
}
160
168
161
169
struct sk_buff * h4_recv_buf (struct hci_dev * hdev , struct sk_buff * skb ,
162
- const unsigned char * buffer , int count )
170
+ const unsigned char * buffer , int count ,
171
+ const struct h4_recv_pkt * pkts , int pkts_count )
163
172
{
164
173
while (count ) {
165
- int len ;
174
+ int i , len ;
166
175
167
176
if (!skb ) {
168
- switch (buffer [0 ]) {
169
- case HCI_ACLDATA_PKT :
170
- skb = bt_skb_alloc (HCI_MAX_FRAME_SIZE ,
171
- GFP_ATOMIC );
172
- if (!skb )
173
- return ERR_PTR (- ENOMEM );
177
+ for (i = 0 ; i < pkts_count ; i ++ ) {
178
+ if (buffer [0 ] != (& pkts [i ])-> type )
179
+ continue ;
174
180
175
- bt_cb (skb )-> pkt_type = HCI_ACLDATA_PKT ;
176
- bt_cb (skb )-> expect = HCI_ACL_HDR_SIZE ;
177
- break ;
178
- case HCI_SCODATA_PKT :
179
- skb = bt_skb_alloc (HCI_MAX_SCO_SIZE ,
181
+ skb = bt_skb_alloc ((& pkts [i ])-> maxlen ,
180
182
GFP_ATOMIC );
181
183
if (!skb )
182
184
return ERR_PTR (- ENOMEM );
183
185
184
- bt_cb (skb )-> pkt_type = HCI_SCODATA_PKT ;
185
- bt_cb (skb )-> expect = HCI_SCO_HDR_SIZE ;
186
+ bt_cb (skb )-> pkt_type = ( & pkts [ i ]) -> type ;
187
+ bt_cb (skb )-> expect = ( & pkts [ i ]) -> hlen ;
186
188
break ;
187
- case HCI_EVENT_PKT :
188
- skb = bt_skb_alloc (HCI_MAX_EVENT_SIZE ,
189
- GFP_ATOMIC );
190
- if (!skb )
191
- return ERR_PTR (- ENOMEM );
189
+ }
192
190
193
- bt_cb (skb )-> pkt_type = HCI_EVENT_PKT ;
194
- bt_cb (skb )-> expect = HCI_EVENT_HDR_SIZE ;
195
- break ;
196
- default :
191
+ /* Check for invalid packet type */
192
+ if (!skb )
197
193
return ERR_PTR (- EILSEQ );
198
- }
199
194
200
195
count -= 1 ;
201
196
buffer += 1 ;
202
197
}
203
198
204
- len = min_t (uint , bt_cb (skb )-> expect , count );
199
+ len = min_t (uint , bt_cb (skb )-> expect - skb -> len , count );
205
200
memcpy (skb_put (skb , len ), buffer , len );
206
201
207
202
count -= len ;
208
203
buffer += len ;
209
- bt_cb (skb )-> expect -= len ;
210
204
211
- switch (bt_cb (skb )-> pkt_type ) {
212
- case HCI_ACLDATA_PKT :
213
- if (skb -> len == HCI_ACL_HDR_SIZE ) {
214
- __le16 dlen = hci_acl_hdr (skb )-> dlen ;
205
+ /* Check for partial packet */
206
+ if (skb -> len < bt_cb (skb )-> expect )
207
+ continue ;
208
+
209
+ for (i = 0 ; i < pkts_count ; i ++ ) {
210
+ if (bt_cb (skb )-> pkt_type == (& pkts [i ])-> type )
211
+ break ;
212
+ }
213
+
214
+ if (i >= pkts_count ) {
215
+ kfree_skb (skb );
216
+ return ERR_PTR (- EILSEQ );
217
+ }
215
218
216
- /* Complete ACL header */
217
- bt_cb ( skb ) -> expect = __le16_to_cpu ( dlen ) ;
219
+ if ( skb -> len == ( & pkts [ i ]) -> hlen ) {
220
+ u16 dlen ;
218
221
219
- if ( skb_tailroom ( skb ) < bt_cb ( skb ) -> expect ) {
220
- kfree_skb ( skb );
221
- return ERR_PTR ( - EMSGSIZE );
222
- }
223
- }
224
- break ;
225
- case HCI_SCODATA_PKT :
226
- if ( skb -> len == HCI_SCO_HDR_SIZE ) {
227
- /* Complete SCO header */
228
- bt_cb (skb )-> expect = hci_sco_hdr ( skb ) -> dlen ;
222
+ switch (( & pkts [ i ]) -> lsize ) {
223
+ case 0 :
224
+ /* No variable data length */
225
+ ( & pkts [ i ]) -> recv ( hdev , skb );
226
+ skb = NULL ;
227
+ break ;
228
+ case 1 :
229
+ /* Single octet variable length */
230
+ dlen = skb -> data [( & pkts [ i ]) -> loff ];
231
+ bt_cb (skb )-> expect += dlen ;
229
232
230
- if (skb_tailroom (skb ) < bt_cb ( skb ) -> expect ) {
233
+ if (skb_tailroom (skb ) < dlen ) {
231
234
kfree_skb (skb );
232
235
return ERR_PTR (- EMSGSIZE );
233
236
}
234
- }
235
- break ;
236
- case HCI_EVENT_PKT :
237
- if (skb -> len == HCI_EVENT_HDR_SIZE ) {
238
- /* Complete event header */
239
- bt_cb (skb )-> expect = hci_event_hdr ( skb ) -> plen ;
237
+ break ;
238
+ case 2 :
239
+ /* Double octet variable length */
240
+ dlen = get_unaligned_le16 (skb -> data +
241
+ ( & pkts [ i ]) -> loff );
242
+ bt_cb (skb )-> expect += dlen ;
240
243
241
- if (skb_tailroom (skb ) < bt_cb ( skb ) -> expect ) {
244
+ if (skb_tailroom (skb ) < dlen ) {
242
245
kfree_skb (skb );
243
246
return ERR_PTR (- EMSGSIZE );
244
247
}
248
+ break ;
249
+ default :
250
+ /* Unsupported variable length */
251
+ kfree_skb (skb );
252
+ return ERR_PTR (- EILSEQ );
245
253
}
246
- break ;
247
- }
248
-
249
- if (bt_cb (skb )-> expect == 0 ) {
254
+ } else {
250
255
/* Complete frame */
251
- hci_recv_frame (hdev , skb );
256
+ ( & pkts [ i ]) -> recv (hdev , skb );
252
257
skb = NULL ;
253
258
}
254
259
}
0 commit comments