xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_l2cap.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <string.h>
21 #include <errno.h>
22 #include "syscfg/syscfg.h"
23 #include "os/os.h"
24 #include "nimble/ble.h"
25 #include "nimble/hci_common.h"
26 #include "ble_hs_priv.h"
27 #include "ble_l2cap_coc_priv.h"
28 
29 _Static_assert(sizeof (struct ble_l2cap_hdr) == BLE_L2CAP_HDR_SZ,
30                "struct ble_l2cap_hdr must be 4 bytes");
31 
32 struct os_mempool ble_l2cap_chan_pool;
33 
34 static os_membuf_t ble_l2cap_chan_mem[
35     OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_MAX_CHANS) +
36                     MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM),
37                     sizeof (struct ble_l2cap_chan))
38 ];
39 
40 STATS_SECT_DECL(ble_l2cap_stats) ble_l2cap_stats;
41 STATS_NAME_START(ble_l2cap_stats)
STATS_NAME(ble_l2cap_stats,chan_create)42     STATS_NAME(ble_l2cap_stats, chan_create)
43     STATS_NAME(ble_l2cap_stats, chan_delete)
44     STATS_NAME(ble_l2cap_stats, update_init)
45     STATS_NAME(ble_l2cap_stats, update_rx)
46     STATS_NAME(ble_l2cap_stats, update_fail)
47     STATS_NAME(ble_l2cap_stats, proc_timeout)
48     STATS_NAME(ble_l2cap_stats, sig_tx)
49     STATS_NAME(ble_l2cap_stats, sig_rx)
50     STATS_NAME(ble_l2cap_stats, sm_tx)
51     STATS_NAME(ble_l2cap_stats, sm_rx)
52 STATS_NAME_END(ble_l2cap_stats)
53 
54 struct ble_l2cap_chan *
55 ble_l2cap_chan_alloc(uint16_t conn_handle)
56 {
57     struct ble_l2cap_chan *chan;
58 
59     chan = os_memblock_get(&ble_l2cap_chan_pool);
60     if (chan == NULL) {
61         return NULL;
62     }
63 
64     memset(chan, 0, sizeof *chan);
65     chan->conn_handle = conn_handle;
66 
67     STATS_INC(ble_l2cap_stats, chan_create);
68 
69     return chan;
70 }
71 
72 void
ble_l2cap_chan_free(struct ble_l2cap_chan * chan)73 ble_l2cap_chan_free(struct ble_l2cap_chan *chan)
74 {
75     int rc;
76 
77     if (chan == NULL) {
78         return;
79     }
80 
81     os_mbuf_free_chain(chan->rx_buf);
82     ble_l2cap_coc_cleanup_chan(chan);
83 
84 #if MYNEWT_VAL(BLE_HS_DEBUG)
85     memset(chan, 0xff, sizeof *chan);
86 #endif
87     rc = os_memblock_put(&ble_l2cap_chan_pool, chan);
88     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
89 
90     STATS_INC(ble_l2cap_stats, chan_delete);
91 }
92 
93 bool
ble_l2cap_is_mtu_req_sent(const struct ble_l2cap_chan * chan)94 ble_l2cap_is_mtu_req_sent(const struct ble_l2cap_chan *chan)
95 {
96     return (chan->flags & BLE_L2CAP_CHAN_F_TXED_MTU);
97 }
98 
99 int
ble_l2cap_parse_hdr(struct os_mbuf * om,int off,struct ble_l2cap_hdr * l2cap_hdr)100 ble_l2cap_parse_hdr(struct os_mbuf *om, int off,
101                     struct ble_l2cap_hdr *l2cap_hdr)
102 {
103     int rc;
104 
105     rc = os_mbuf_copydata(om, off, sizeof *l2cap_hdr, l2cap_hdr);
106     if (rc != 0) {
107         return BLE_HS_EMSGSIZE;
108     }
109 
110     l2cap_hdr->len = get_le16(&l2cap_hdr->len);
111     l2cap_hdr->cid = get_le16(&l2cap_hdr->cid);
112 
113     return 0;
114 }
115 
116 struct os_mbuf *
ble_l2cap_prepend_hdr(struct os_mbuf * om,uint16_t cid,uint16_t len)117 ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid, uint16_t len)
118 {
119     struct ble_l2cap_hdr hdr;
120 
121     put_le16(&hdr.len, len);
122     put_le16(&hdr.cid, cid);
123 
124     om = os_mbuf_prepend_pullup(om, sizeof hdr);
125     if (om == NULL) {
126         return NULL;
127     }
128 
129     memcpy(om->om_data, &hdr, sizeof hdr);
130 
131     return om;
132 }
133 
134 uint16_t
ble_l2cap_get_conn_handle(struct ble_l2cap_chan * chan)135 ble_l2cap_get_conn_handle(struct ble_l2cap_chan *chan)
136 {
137     if (!chan) {
138         return BLE_HS_CONN_HANDLE_NONE;
139     }
140 
141     return chan->conn_handle;
142 }
143 
144 int
ble_l2cap_create_server(uint16_t psm,uint16_t mtu,ble_l2cap_event_fn * cb,void * cb_arg)145 ble_l2cap_create_server(uint16_t psm, uint16_t mtu,
146                         ble_l2cap_event_fn *cb, void *cb_arg)
147 {
148     return ble_l2cap_coc_create_server(psm, mtu, cb, cb_arg);
149 }
150 
151 int
ble_l2cap_connect(uint16_t conn_handle,uint16_t psm,uint16_t mtu,struct os_mbuf * sdu_rx,ble_l2cap_event_fn * cb,void * cb_arg)152 ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
153                   struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb, void *cb_arg)
154 {
155     return ble_l2cap_sig_coc_connect(conn_handle, psm, mtu, sdu_rx, cb, cb_arg);
156 }
157 
ble_l2cap_disconnect(struct ble_l2cap_chan * chan)158 int ble_l2cap_disconnect(struct ble_l2cap_chan *chan)
159 {
160     return ble_l2cap_sig_disconnect(chan);
161 }
162 
163 /**
164  * Transmits a packet over an L2CAP channel.  This function only consumes the
165  * supplied mbuf on success.
166  */
167 int
ble_l2cap_send(struct ble_l2cap_chan * chan,struct os_mbuf * sdu)168 ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu)
169 {
170     return ble_l2cap_coc_send(chan, sdu);
171 }
172 
173 void
ble_l2cap_recv_ready(struct ble_l2cap_chan * chan,struct os_mbuf * sdu_rx)174 ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx)
175 {
176     ble_l2cap_coc_recv_ready(chan, sdu_rx);
177 }
178 
179 void
ble_l2cap_remove_rx(struct ble_hs_conn * conn,struct ble_l2cap_chan * chan)180 ble_l2cap_remove_rx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan)
181 {
182     conn->bhc_rx_chan = NULL;
183     os_mbuf_free_chain(chan->rx_buf);
184     chan->rx_buf = NULL;
185     chan->rx_len = 0;
186 }
187 
188 static void
ble_l2cap_append_rx(struct ble_l2cap_chan * chan,struct os_mbuf * frag)189 ble_l2cap_append_rx(struct ble_l2cap_chan *chan, struct os_mbuf *frag)
190 {
191     int rc;
192 
193     (void)rc;
194 
195 #if MYNEWT_VAL(BLE_L2CAP_JOIN_RX_FRAGS)
196     /* Copy the data from the incoming fragment into the packet in progress. */
197     rc = os_mbuf_appendfrom(chan->rx_buf, frag, 0, OS_MBUF_PKTLEN(frag));
198     if (rc == 0) {
199         os_mbuf_free_chain(frag);
200         return;
201     }
202 #endif
203 
204     /* Join disabled or append failed due to mbuf shortage.  Just attach the
205      * mbuf to the end of the packet.
206      */
207     os_mbuf_concat(chan->rx_buf, frag);
208 }
209 
210 static int
ble_l2cap_rx_payload(struct ble_hs_conn * conn,struct ble_l2cap_chan * chan,struct os_mbuf * om,ble_l2cap_rx_fn ** out_rx_cb)211 ble_l2cap_rx_payload(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
212                      struct os_mbuf *om,
213                      ble_l2cap_rx_fn **out_rx_cb)
214 {
215     int len_diff;
216     int rc;
217 
218     if (chan->rx_buf == NULL) {
219         /* First fragment in packet. */
220         chan->rx_buf = om;
221     } else {
222         /* Continuation of packet in progress. */
223         ble_l2cap_append_rx(chan, om);
224     }
225 
226     /* Determine if packet is fully reassembled. */
227     len_diff = OS_MBUF_PKTLEN(chan->rx_buf) - chan->rx_len;
228     if (len_diff > 0) {
229         /* More data than expected; data corruption. */
230         ble_l2cap_remove_rx(conn, chan);
231         rc = BLE_HS_EBADDATA;
232     } else if (len_diff == 0) {
233         /* All fragments received. */
234         *out_rx_cb = chan->rx_fn;
235         rc = 0;
236     } else {
237         /* More fragments remain. */
238 #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0
239         conn->bhc_rx_timeout =
240             ble_npl_time_get() + MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT);
241 
242         ble_hs_timer_resched();
243 #endif
244         rc = BLE_HS_EAGAIN;
245     }
246 
247     return rc;
248 }
249 
250 static uint16_t
ble_l2cap_get_mtu(struct ble_l2cap_chan * chan)251 ble_l2cap_get_mtu(struct ble_l2cap_chan *chan)
252 {
253     if (chan->scid == BLE_L2CAP_CID_ATT) {
254         /* In case of ATT chan->my_mtu keeps preferred MTU which is later
255          * used during exchange MTU procedure. Helper below will gives us actual
256          * MTU on the channel, which is 23 or higher if exchange MTU has been
257          * done
258          */
259         return ble_att_chan_mtu(chan);
260     }
261 
262     return chan->my_mtu;
263 }
264 
265 /**
266  * Processes an incoming L2CAP fragment.
267  *
268  * @param conn                  The connection the L2CAP fragment was sent
269  *                                  over.
270  * @param hci_hdr               The ACL data header that was at the start of
271  *                                  the L2CAP fragment.  This header has been
272  *                                  stripped from the mbuf parameter.
273  * @param om                    An mbuf containing the L2CAP data.  If this is
274  *                                  the first fragment, the L2CAP header is at
275  *                                  the start of the mbuf.  For subsequent
276  *                                  fragments, the mbuf starts with L2CAP
277  *                                  payload data.
278  * @param out_rx_cb             If a full L2CAP packet has been received, a
279  *                                  pointer to the appropriate handler gets
280  *                                  written here.  The caller should pass the
281  *                                  receive buffer to this callback.
282  * @param out_rx_buf            If a full L2CAP packet has been received, this
283  *                                  will point to the entire L2CAP packet.  To
284  *                                  process the packet, pass this buffer to the
285  *                                  receive handler (out_rx_cb).
286  * @param out_reject_cid        Indicates whether an L2CAP Command Reject
287  *                                  command should be sent.  If this equals -1,
288  *                                  no reject should get sent.  Otherwise, the
289  *                                  value indicates the CID that the outgoing
290  *                                  reject should specify.
291  *
292  * @return                      0 if a complete L2CAP packet has been received.
293  *                              BLE_HS_EAGAIN if a partial L2CAP packet has
294  *                                  been received; more fragments are expected.
295  *                              Other value on error.
296  */
297 int
ble_l2cap_rx(struct ble_hs_conn * conn,struct hci_data_hdr * hci_hdr,struct os_mbuf * om,ble_l2cap_rx_fn ** out_rx_cb,int * out_reject_cid)298 ble_l2cap_rx(struct ble_hs_conn *conn,
299              struct hci_data_hdr *hci_hdr,
300              struct os_mbuf *om,
301              ble_l2cap_rx_fn **out_rx_cb,
302              int *out_reject_cid)
303 {
304     struct ble_l2cap_chan *chan;
305     struct ble_l2cap_hdr l2cap_hdr;
306     uint8_t pb;
307     int rc;
308 
309     *out_reject_cid = -1;
310 
311     pb = BLE_HCI_DATA_PB(hci_hdr->hdh_handle_pb_bc);
312     switch (pb) {
313     case BLE_HCI_PB_FIRST_FLUSH:
314         /* First fragment. */
315         rc = ble_l2cap_parse_hdr(om, 0, &l2cap_hdr);
316         if (rc != 0) {
317             goto err;
318         }
319 
320         /* Strip L2CAP header from the front of the mbuf. */
321         os_mbuf_adj(om, BLE_L2CAP_HDR_SZ);
322 
323         chan = ble_hs_conn_chan_find_by_scid(conn, l2cap_hdr.cid);
324         if (chan == NULL) {
325             rc = BLE_HS_ENOENT;
326 
327             /* Unsupported channel. If the target CID is the black hole
328              * channel, quietly drop the packet.  Otherwise, send an invalid
329              * CID response.
330              */
331             if (l2cap_hdr.cid != BLE_L2CAP_CID_BLACK_HOLE) {
332                 BLE_HS_LOG(DEBUG, "rx on unknown L2CAP channel: %d\n",
333                            l2cap_hdr.cid);
334                 *out_reject_cid = l2cap_hdr.cid;
335             }
336             goto err;
337         }
338 
339         if (chan->rx_buf != NULL) {
340             /* Previous data packet never completed.  Discard old packet. */
341             ble_l2cap_remove_rx(conn, chan);
342         }
343 
344         if (l2cap_hdr.len > ble_l2cap_get_mtu(chan)) {
345             /* More data then we expected on the channel */
346             rc = BLE_HS_EBADDATA;
347             goto err;
348         }
349 
350         /* Remember channel and length of L2CAP data for reassembly. */
351         conn->bhc_rx_chan = chan;
352         chan->rx_len = l2cap_hdr.len;
353         break;
354 
355     case BLE_HCI_PB_MIDDLE:
356         chan = conn->bhc_rx_chan;
357         if (chan == NULL || chan->rx_buf == NULL) {
358             /* Middle fragment without the start.  Discard new packet. */
359             rc = BLE_HS_EBADDATA;
360             goto err;
361         }
362         break;
363 
364     default:
365         rc = BLE_HS_EBADDATA;
366         goto err;
367     }
368 
369     rc = ble_l2cap_rx_payload(conn, chan, om, out_rx_cb);
370     om = NULL;
371     if (rc != 0) {
372         goto err;
373     }
374 
375     return 0;
376 
377 err:
378     os_mbuf_free_chain(om);
379     return rc;
380 }
381 
382 /**
383  * Transmits the L2CAP payload contained in the specified mbuf.  The supplied
384  * mbuf is consumed, regardless of the outcome of the function call.
385  *
386  * @param chan                  The L2CAP channel to transmit over.
387  * @param txom                  The data to transmit.
388  *
389  * @return                      0 on success; nonzero on error.
390  */
391 int
ble_l2cap_tx(struct ble_hs_conn * conn,struct ble_l2cap_chan * chan,struct os_mbuf * txom)392 ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
393              struct os_mbuf *txom)
394 {
395     int rc;
396 
397     txom = ble_l2cap_prepend_hdr(txom, chan->dcid, OS_MBUF_PKTLEN(txom));
398     if (txom == NULL) {
399         return BLE_HS_ENOMEM;
400     }
401 
402     rc = ble_hs_hci_acl_tx(conn, &txom);
403     switch (rc) {
404     case 0:
405         /* Success. */
406         return 0;
407 
408     case BLE_HS_EAGAIN:
409         /* Controller could not accommodate full packet.  Enqueue remainder. */
410         STAILQ_INSERT_TAIL(&conn->bhc_tx_q, OS_MBUF_PKTHDR(txom), omp_next);
411         return 0;
412 
413     default:
414         /* Error. */
415         return rc;
416     }
417 }
418 
419 int
ble_l2cap_init(void)420 ble_l2cap_init(void)
421 {
422     int rc;
423 
424     rc = os_mempool_init(&ble_l2cap_chan_pool,
425                          MYNEWT_VAL(BLE_L2CAP_MAX_CHANS) +
426                          MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM),
427                          sizeof (struct ble_l2cap_chan),
428                          ble_l2cap_chan_mem, "ble_l2cap_chan_pool");
429     if (rc != 0) {
430         return BLE_HS_EOS;
431     }
432 
433     rc = ble_l2cap_sig_init();
434     if (rc != 0) {
435         return rc;
436     }
437 
438     rc = ble_l2cap_coc_init();
439     if (rc != 0) {
440         return rc;
441     }
442 
443     rc = ble_sm_init();
444     if (rc != 0) {
445         return rc;
446     }
447 
448     rc = stats_init_and_reg(
449         STATS_HDR(ble_l2cap_stats), STATS_SIZE_INIT_PARMS(ble_l2cap_stats,
450         STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_l2cap_stats), "ble_l2cap");
451     if (rc != 0) {
452         return BLE_HS_EOS;
453     }
454 
455     return 0;
456 }
457