Contiki-NG
ble-l2cap.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017, Graz University of Technology
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * \file
33 * MAC layer that implements BLE L2CAP credit-based flow control
34 * channels to support IPv6 over BLE (RFC 7668)
35 *
36 * \author
37 * Michael Spoerk <michael.spoerk@tugraz.at>
38 */
39/*---------------------------------------------------------------------------*/
40
42
43#include "net/packetbuf.h"
44#include "net/netstack.h"
45#include "lib/memb.h"
46#include "lib/list.h"
47
48#include <string.h>
49
50#include "../../../dev/ble-hal.h"
51/*---------------------------------------------------------------------------*/
52#include "sys/log.h"
53#define LOG_MODULE "L2CAP"
54#define LOG_LEVEL LOG_LEVEL_MAC
55/*---------------------------------------------------------------------------*/
56#define MS_TO_CLOCK_SECONDS(X) ((int)(((double)((X)*CLOCK_SECOND)) / 1000.0))
57/*---------------------------------------------------------------------------*/
58/* BLE controller */
59/* public device address of BLE controller */
60static uint8_t ble_addr[BLE_ADDR_SIZE];
61/*---------------------------------------------------------------------------*/
62/* L2CAP fragmentation buffers and utilities */
63typedef struct {
64 /* L2CAP Service Data Unit (SDU) (= packet data)*/
65 uint8_t sdu[BLE_L2CAP_NODE_MTU];
66 /* length of the L2CAP SDU */
67 uint16_t sdu_length;
68 /* index of the first byte not sent yet */
69 uint16_t current_index;
70} l2cap_buffer_t;
71/*---------------------------------------------------------------------------*/
72typedef struct {
73 uint16_t cid;
74 uint16_t mtu;
75 uint16_t mps;
76 uint16_t credits;
77} ble_mac_l2cap_channel_t;
78/*---------------------------------------------------------------------------*/
79typedef struct {
80 ble_mac_l2cap_channel_t channel_own;
81 ble_mac_l2cap_channel_t channel_peer;
82 l2cap_buffer_t tx_buffer;
83 l2cap_buffer_t rx_buffer;
84 linkaddr_t peer_addr;
85} l2cap_channel_t;
86
87static uint8_t l2cap_channel_count;
88static l2cap_channel_t l2cap_channels[L2CAP_CHANNELS];
89static process_event_t l2cap_tx_event;
90/*---------------------------------------------------------------------------*/
91static l2cap_channel_t *
92get_channel_for_addr(const linkaddr_t *peer_addr)
93{
94 uint8_t i;
95 l2cap_channel_t *channel;
96 for(i = 0; i < l2cap_channel_count; i++) {
97 channel = &l2cap_channels[i];
98 if(linkaddr_cmp(peer_addr, &channel->peer_addr) != 0) {
99 return channel;
100 }
101 }
102 return NULL;
103}
104/*---------------------------------------------------------------------------*/
105static l2cap_channel_t *
106get_channel_for_cid(uint16_t own_cid)
107{
108 int16_t i = own_cid - L2CAP_FLOW_CHANNEL;
109 if(i >= 0 && i < l2cap_channel_count) {
110 return &l2cap_channels[i];
111 } else {
112 return NULL;
113 }
114}
115/*---------------------------------------------------------------------------*/
116PROCESS(ble_l2cap_tx_process, "BLE L2CAP TX process");
117/*---------------------------------------------------------------------------*/
118static uint8_t
119init_adv_data(char *adv_data)
120{
121 uint8_t adv_data_len = 0;
122 memset(adv_data, 0x00, BLE_ADV_DATA_LEN);
123 /* BLE flags */
124 adv_data[adv_data_len++] = 2;
125 adv_data[adv_data_len++] = 0x01;
126 adv_data[adv_data_len++] = 0x05; /* LE limited (no BR/EDR support) */
127 /* TX power level */
128 adv_data[adv_data_len++] = 2;
129 adv_data[adv_data_len++] = 0x0A;
130 adv_data[adv_data_len++] = 0; /* 0 dBm */
131 /* service UUIDs (16-bit identifiers) */
132 adv_data[adv_data_len++] = 3;
133 adv_data[adv_data_len++] = 0x03;
134 adv_data[adv_data_len++] = 0x20;
135 adv_data[adv_data_len++] = 0x18; /* only IP support service exposed */
136 /* service UUIDs (32-bit identifiers) */
137 adv_data[adv_data_len++] = 1;
138 adv_data[adv_data_len++] = 0x05; /* empty list */
139 /* service UUIDs (128-bit identifiers) */
140 adv_data[adv_data_len++] = 1;
141 adv_data[adv_data_len++] = 0x07; /* empty list */
142 return adv_data_len;
143}
144/*---------------------------------------------------------------------------*/
145static uint8_t
146init_scan_resp_data(char *scan_resp_data)
147{
148 uint8_t scan_resp_data_len = 0;
149 memset(scan_resp_data, 0x00, BLE_SCAN_RESP_DATA_LEN);
150 /* complete device name */
151 scan_resp_data[scan_resp_data_len++] = 1 + strlen(BLE_DEVICE_NAME);
152 scan_resp_data[scan_resp_data_len++] = 0x09;
153 memcpy(&scan_resp_data[scan_resp_data_len],
154 BLE_DEVICE_NAME, strlen(BLE_DEVICE_NAME));
155 scan_resp_data_len += strlen(BLE_DEVICE_NAME);
156 /* slave connection interval range */
157 scan_resp_data[scan_resp_data_len++] = 5;
158 scan_resp_data[scan_resp_data_len++] = 0x12;
159 scan_resp_data[scan_resp_data_len++] = (BLE_SLAVE_CONN_INTERVAL_MIN & 0xFF);
160 scan_resp_data[scan_resp_data_len++] = ((BLE_SLAVE_CONN_INTERVAL_MIN >> 8) & 0xFF);
161 scan_resp_data[scan_resp_data_len++] = (BLE_SLAVE_CONN_INTERVAL_MAX & 0xFF);
162 scan_resp_data[scan_resp_data_len++] = ((BLE_SLAVE_CONN_INTERVAL_MAX >> 8) & 0xFF);
163
164 return scan_resp_data_len;
165}
166/*---------------------------------------------------------------------------*/
167void
168input_l2cap_conn_req(uint8_t *data)
169{
170 uint8_t identifier = data[0];
171 uint16_t len;
172 uint16_t le_psm;
173 uint8_t resp_data[18];
174 l2cap_channel_t *channel;
175
176 memcpy(&len, &data[1], 2);
177
178 if(len != 10) {
179 LOG_WARN("l2cap_conn_req: invalid len: %d\n", len);
180 return;
181 }
182
183 /* create a new L2CAP connection because of this request */
184 if(l2cap_channel_count >= L2CAP_CHANNELS) {
185 LOG_WARN("l2cap_conn_req: maximum supported L2CAP channels reached\n");
186 return;
187 }
188
189 channel = &l2cap_channels[l2cap_channel_count];
190 /* parse L2CAP connection data */
191 memcpy(&le_psm, &data[3], 2);
192 memset(&channel->channel_peer, 0x00, sizeof(ble_mac_l2cap_channel_t));
193 memcpy(&channel->channel_peer.cid, &data[5], 2);
194 memcpy(&channel->channel_peer.mtu, &data[7], 2);
195 memcpy(&channel->channel_peer.mps, &data[9], 2);
196 memcpy(&channel->channel_peer.credits, &data[11], 2);
197 linkaddr_copy(&channel->peer_addr, packetbuf_addr(PACKETBUF_ADDR_SENDER));
198
199 LOG_INFO("recv CONN_REQ (MTU: %4d, MPS: %4d, credits: %4d)\n",
200 channel->channel_peer.mtu, channel->channel_peer.mps, channel->channel_peer.credits);
201
202 l2cap_channel_count++;
203
204 /* create L2CAP connection response */
205 /* length */
206 resp_data[0] = 0x0E;
207 resp_data[1] = 0x00;
208 /* channel ID */
209 resp_data[2] = 0x05;
210 resp_data[3] = 0x00;
211 /* code */
212 resp_data[4] = L2CAP_CODE_CONN_RSP;
213 /* identifier */
214 resp_data[5] = identifier;
215 /* cmd length */
216 resp_data[6] = 0x0A;
217 resp_data[7] = 0x00;
218 /* node channel information */
219 memcpy(&resp_data[8], &channel->channel_own.cid, 2);
220 memcpy(&resp_data[10], &channel->channel_own.mtu, 2);
221 memcpy(&resp_data[12], &channel->channel_own.mps, 2);
222 memcpy(&resp_data[14], &channel->channel_own.credits, 2);
223 /* result */
224 memset(&resp_data[16], 0x00, 2);
225
226 packetbuf_copyfrom((void *)resp_data, 18);
227 packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
228 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr);
229 NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
230}
231/*---------------------------------------------------------------------------*/
232static void
233init(void)
234{
235 uint8_t i;
236 l2cap_tx_event = process_alloc_event();
237 LOG_DBG("init()\n");
238 /* initialize the L2CAP connection parameter */
239 for(i = 0; i < L2CAP_CHANNELS; i++) {
240 l2cap_channels[i].channel_own.cid = L2CAP_FLOW_CHANNEL + i;
241 l2cap_channels[i].channel_own.credits = L2CAP_CREDIT_NEW;
242 l2cap_channels[i].channel_own.mps = (BLE_L2CAP_NODE_FRAG_LEN - L2CAP_SUBSEQ_HEADER_SIZE);
243 l2cap_channels[i].channel_own.mtu = BLE_L2CAP_NODE_MTU;
244 }
245
246 /* Initialize the BLE controller */
247 NETSTACK_RADIO.init();
248 NETSTACK_RADIO.get_object(RADIO_CONST_BLE_BD_ADDR, &ble_addr, BLE_ADDR_SIZE);
249
250 uint8_t adv_data_len, scan_resp_data_len;
251 char adv_data[BLE_ADV_DATA_LEN];
252 char scan_resp_data[BLE_SCAN_RESP_DATA_LEN];
253 /* set the advertisement parameter */
254 NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_INTERVAL, BLE_ADV_INTERVAL);
255 NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_TYPE, BLE_ADV_DIR_IND_LDC);
256 NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_OWN_ADDR_TYPE, BLE_ADDR_TYPE_PUBLIC);
257 NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_CHANNEL_MAP, 0x01);
258
259 adv_data_len = init_adv_data(adv_data);
260 scan_resp_data_len = init_scan_resp_data(scan_resp_data);
261
262 /* set advertisement payload & scan response */
263 NETSTACK_RADIO.set_object(RADIO_PARAM_BLE_ADV_PAYLOAD, adv_data, adv_data_len);
264 NETSTACK_RADIO.set_object(RADIO_PARAM_BLE_ADV_SCAN_RESPONSE, scan_resp_data, scan_resp_data_len);
265
266 /* enable advertisement */
267 NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_ENABLE, 1);
268
269 NETSTACK_MAC.on();
270}
271/*---------------------------------------------------------------------------*/
272static uint16_t
273check_own_l2cap_credits(l2cap_channel_t *channel)
274{
275 uint16_t credits_new = 0;
276 uint16_t credits_current;
277
278 credits_current = channel->channel_own.credits;
279 if(credits_current < L2CAP_CREDIT_THRESHOLD) {
280 credits_new = L2CAP_CREDIT_NEW;
281 }
282 LOG_DBG("check for new credits: current credits: %2d, new credits: %2d\n", credits_current, credits_new);
283 return credits_new;
284}
285/*---------------------------------------------------------------------------*/
286static void
287send_l2cap_credit(l2cap_channel_t *channel, uint16_t credits)
288{
289 uint8_t len = 4;
290 uint8_t data[12];
291 /* create L2CAP credit */
292 /* length */
293 data[0] = len + 4;
294 data[1] = 0x00;
295 /* channel ID */
296 data[2] = 0x05;
297 data[3] = 0x00;
298 /* code */
299 data[4] = L2CAP_CODE_CREDIT;
300 /* identifier */
301 data[5] = 0xFF;
302 /* cmd length */
303 data[6] = len;
304 data[7] = 0x00;
305
306 memcpy(&data[8], &channel->channel_own.cid, 2);
307 data[10] = credits & 0xFF;
308 data[11] = credits >> 8;
309
310 channel->channel_own.credits += credits;
311
312 packetbuf_copyfrom((void *)data, len + 8);
313 packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
314 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr);
315 NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
316}
317/*---------------------------------------------------------------------------*/
318static void
319send(mac_callback_t sent_callback, void *ptr)
320{
321 uint8_t i;
322 l2cap_channel_t *channel;
323 uint16_t data_len = packetbuf_datalen();
324 LOG_DBG("send %d\n", data_len);
325
326 /* packet is too long */
327 if(data_len > BLE_L2CAP_NODE_MTU) {
328 LOG_WARN("send message is too long\n");
329 mac_call_sent_callback(sent_callback, ptr, MAC_TX_ERR, 0);
330 return;
331 }
332
333 for(i = 0; i < l2cap_channel_count; i++) {
334 channel = &l2cap_channels[i];
335 if((linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null) != 0)
336 || (linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &channel->peer_addr) != 0)) {
337 if(channel->tx_buffer.sdu_length > 0) {
338 LOG_WARN("send() another L2CAP message active (trying to send %4d bytes)\n", data_len);
339 mac_call_sent_callback(sent_callback, ptr, MAC_TX_COLLISION, 0);
340 return;
341 }
342 LOG_DBG("send() adding to L2CAP CID: %2d\n", channel->channel_own.cid);
343 channel->tx_buffer.sdu_length = data_len;
344 if(channel->tx_buffer.sdu_length > 0) {
345 memcpy(&channel->tx_buffer.sdu, packetbuf_dataptr(), data_len);
346 mac_call_sent_callback(sent_callback, ptr, MAC_TX_DEFERRED, 1);
347 process_post(&ble_l2cap_tx_process, l2cap_tx_event, (void *)channel);
348 }
349 }
350 }
351}
352/*---------------------------------------------------------------------------*/
353void
354input_l2cap_connection_udate_resp(uint8_t *data)
355{
356 uint16_t len;
357 uint16_t result;
358
359 memcpy(&len, &data[1], 2);
360
361 if(len != 2) {
362 LOG_WARN("input_l2cap_connection_update_resp: invalid len: %d\n", len);
363 return;
364 }
365
366 memcpy(&result, &data[3], 2);
367 if(result != 0x0000) {
368 LOG_WARN("input_l2cap_connection_update_resp: result: 0x%04X\n", result);
369 return;
370 }
371}
372/*---------------------------------------------------------------------------*/
373void
374input_l2cap_credit(uint8_t *data)
375{
376 uint16_t len;
377 uint16_t cid;
378 uint16_t credits;
379 l2cap_channel_t *channel = get_channel_for_addr(packetbuf_addr(PACKETBUF_ADDR_SENDER));
380
381 if(channel == NULL) {
382 LOG_WARN("input_l2cap_credit: no channel found for sender address\n");
383 return;
384 }
385
386/* uint8_t identifier = data[0]; */
387 memcpy(&len, &data[1], 2);
388
389 if(len != 4) {
390 LOG_WARN("input_l2cap_credit: invalid len: %d\n", len);
391 return;
392 }
393
394 /* parse L2CAP credit data */
395 memcpy(&cid, &data[3], 2);
396 memcpy(&credits, &data[5], 2);
397
398 channel->channel_peer.credits += credits;
399}
400/*---------------------------------------------------------------------------*/
401static void
402input_l2cap_frame_signal_channel(uint8_t *data, uint8_t data_len)
403{
404 if(data[4] == L2CAP_CODE_CREDIT) {
405 input_l2cap_credit(&data[5]);
406 } else if(data[4] == L2CAP_CODE_CONN_REQ) {
407 input_l2cap_conn_req(&data[5]);
408 } else if(data[4] == L2CAP_CODE_CONN_UPDATE_RSP) {
409 input_l2cap_connection_udate_resp(&data[5]);
410 } else {
411 LOG_WARN("l2cap_frame_signal_channel: unknown signal channel code: %d\n", data[4]);
412 }
413}
414/*---------------------------------------------------------------------------*/
415static void
416input_l2cap_frame_flow_channel(l2cap_channel_t *channel, uint8_t *data, uint16_t data_len)
417{
418 uint16_t frame_len;
419 uint16_t payload_len;
420
421 if(data_len < 4) {
422 LOG_WARN("l2cap_frame: illegal L2CAP frame data_len: %d\n", data_len);
423 /* a L2CAP frame has a minimum length of 4 */
424 return;
425 }
426
427 if(channel->rx_buffer.sdu_length == 0) {
428 /* handle first fragment */
429 memcpy(&frame_len, &data[0], 2);
430 payload_len = frame_len - 2;
431
432 if(payload_len > BLE_L2CAP_NODE_MTU) {
433 LOG_WARN("l2cap_frame: illegal L2CAP frame payload_len: %d\n", payload_len);
434 /* the payload length may not be larger than the destination buffer */
435 return;
436 }
437
438 memcpy(&channel->rx_buffer.sdu_length, &data[4], 2);
439
440 memcpy(channel->rx_buffer.sdu, &data[6], payload_len);
441 channel->rx_buffer.current_index = payload_len;
442 } else {
443 /* subsequent fragment */
444 memcpy(&frame_len, &data[0], 2);
445 payload_len = frame_len;
446
447 if(payload_len > BLE_L2CAP_NODE_MTU - channel->rx_buffer.current_index) {
448 LOG_WARN("l2cap_frame: illegal L2CAP frame payload_len: %d\n", payload_len);
449 /* the current index plus the payload length may not be larger than
450 * the destination buffer */
451 return;
452 }
453
454 memcpy(&channel->rx_buffer.sdu[channel->rx_buffer.current_index], &data[4], payload_len);
455 channel->rx_buffer.current_index += payload_len;
456 }
457
458 if((channel->rx_buffer.sdu_length > 0) &&
459 (channel->rx_buffer.sdu_length == channel->rx_buffer.current_index)) {
460 if(channel->rx_buffer.sdu_length > packetbuf_remaininglen()) {
461 LOG_WARN("l2cap_frame: illegal L2CAP frame sdu_length: %"PRIu16"\n",
462 channel->rx_buffer.sdu_length);
463 return;
464 }
465
466 /* do not use packetbuf_copyfrom here because the packetbuf_attr
467 * must not be cleared */
468 memcpy(packetbuf_dataptr(), channel->rx_buffer.sdu, channel->rx_buffer.sdu_length);
469 packetbuf_set_datalen(channel->rx_buffer.sdu_length);
470 NETSTACK_NETWORK.input();
471
472 /* reset counters */
473 channel->rx_buffer.sdu_length = 0;
474 channel->rx_buffer.current_index = 0;
475 }
476}
477/*---------------------------------------------------------------------------*/
478static void
479input(void)
480{
481 uint8_t *data = (uint8_t *)packetbuf_dataptr();
482 uint16_t len = packetbuf_datalen();
483 uint8_t frame_type = packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE);
484 uint16_t channel_id;
485 l2cap_channel_t *channel;
486 uint16_t credits;
487
488 if(frame_type == FRAME_BLE_RX_EVENT) {
489 memcpy(&channel_id, &data[2], 2);
490 channel = get_channel_for_cid(channel_id);
491 LOG_DBG("input %d bytes\n", len);
492 if(channel_id == L2CAP_SIGNAL_CHANNEL) {
493 input_l2cap_frame_signal_channel(data, len);
494 } else if(channel == NULL) {
495 LOG_WARN("input (RX_EVENT): no channel found for CID: %d\n", channel_id);
496 return;
497 } else {
498 input_l2cap_frame_flow_channel(channel, data, len);
499 channel->channel_own.credits--;
500 credits = check_own_l2cap_credits(channel);
501 if(credits > 0) {
502 send_l2cap_credit(channel, credits);
503 }
504 }
505 }
506 /* check if there are still fragments left to be transmitted */
507 if(frame_type == FRAME_BLE_TX_EVENT) {
508 channel = get_channel_for_addr(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
509 if(channel == NULL) {
510 LOG_WARN("input (TX_EVENT): no channel found for CID: %d\n", channel_id);
511 } else if(channel->tx_buffer.sdu_length > 0) {
512 process_post(&ble_l2cap_tx_process, l2cap_tx_event, (void *)channel);
513 }
514 }
515}
516/*---------------------------------------------------------------------------*/
517static int
518on(void)
519{
520 LOG_DBG("on()\n");
521 process_start(&ble_l2cap_tx_process, NULL);
522 return 0;
523}
524/*---------------------------------------------------------------------------*/
525static int
526off(void)
527{
528 LOG_DBG("off()\n");
529 process_exit(&ble_l2cap_tx_process);
530 return 0;
531}
532/*---------------------------------------------------------------------------*/
533static int
534max_payload(void)
535{
536 return BLE_L2CAP_NODE_MTU;
537}
538/*---------------------------------------------------------------------------*/
539const struct mac_driver ble_l2cap_driver = {
540 "ble-l2cap",
541 init,
542 send,
543 input,
544 on,
545 off,
547};
548/*---------------------------------------------------------------------------*/
549PROCESS_THREAD(ble_l2cap_tx_process, ev, data)
550{
551 uint16_t data_len;
552 uint16_t frame_len;
553 uint16_t num_buffer;
554 l2cap_channel_t *channel = (l2cap_channel_t *)data;
555 uint8_t first_fragment;
556 uint16_t used_mps;
557 uint16_t credits;
558
560 LOG_DBG("starting ble_mac_tx_process\n");
561
562 while(1) {
563 PROCESS_YIELD_UNTIL(ev == l2cap_tx_event);
564 if(channel != NULL) {
565 NETSTACK_RADIO.get_value(RADIO_CONST_BLE_BUFFER_AMOUNT, (radio_value_t *)&num_buffer);
566 first_fragment = (channel->tx_buffer.current_index == 0);
567 used_mps = MIN(channel->channel_own.mps, channel->channel_peer.mps);
568 credits = channel->channel_peer.credits;
569
570 LOG_DBG("process: sending - first: %d, used_mps: %3d, num_buffers: %2d, credits: %2d\n",
571 first_fragment, used_mps, num_buffer, credits);
572 if((channel->tx_buffer.sdu_length > 0) && (num_buffer > 0) && (credits > 0)) {
574 if(first_fragment) {
575 packetbuf_hdralloc(L2CAP_FIRST_HEADER_SIZE);
576 used_mps -= L2CAP_FIRST_HEADER_SIZE;
577 data_len = MIN(channel->tx_buffer.sdu_length, used_mps);
578 frame_len = data_len + 2;
579
580 /* set L2CAP header fields */
581 memcpy(packetbuf_hdrptr(), &frame_len, 2); /* fragment size */
582 memcpy(packetbuf_hdrptr() + 2, &channel->channel_peer.cid, 2); /* L2CAP channel id*/
583 memcpy(packetbuf_hdrptr() + 4, &channel->tx_buffer.sdu_length, 2); /* overall packet size */
584 } else {
585 packetbuf_hdralloc(L2CAP_SUBSEQ_HEADER_SIZE);
586 used_mps -= L2CAP_SUBSEQ_HEADER_SIZE;
587 data_len = MIN((channel->tx_buffer.sdu_length - channel->tx_buffer.current_index), used_mps);
588 frame_len = data_len;
589
590 /* set L2CAP header fields */
591 memcpy(packetbuf_hdrptr(), &frame_len, 2); /* fragment size */
592 memcpy(packetbuf_hdrptr() + 2, &channel->channel_peer.cid, 2); /* L2CAP channel id*/
593 }
594
595 /* copy payload */
596 if(data_len > PACKETBUF_SIZE - packetbuf_hdrlen()) {
597 LOG_WARN("Not enough packetbuf space to copy buffer\n");
598 continue;
599 }
600 memcpy(packetbuf_dataptr(),
601 &channel->tx_buffer.sdu[channel->tx_buffer.current_index],
602 data_len);
603 packetbuf_set_datalen(data_len);
604 channel->tx_buffer.current_index += data_len;
605
606 /* send the fragment */
607 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr);
608 packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
609 NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
610 channel->channel_peer.credits--;
611
612 /* reset the L2CAP TX buffer if packet is finished */
613 if(channel->tx_buffer.current_index == channel->tx_buffer.sdu_length) {
614 channel->tx_buffer.current_index = 0;
615 channel->tx_buffer.sdu_length = 0;
616 }
617 }
618 } else {
619 LOG_WARN("process. channel is NULL\n");
620 }
621 }
622
623 PROCESS_END();
624 LOG_DBG("stopped ble_mac_tx_process\n");
625}
MAC layer that implements BLE L2CAP credit-based flow control channels to support IPv6 over BLE (RFC ...
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
const linkaddr_t linkaddr_null
The null link-layer address.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
uint8_t packetbuf_hdrlen(void)
Get the length of the header in the packetbuf.
Definition: packetbuf.c:161
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition: packetbuf.c:84
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:149
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
Definition: packetbuf.c:107
uint16_t packetbuf_remaininglen(void)
Get the total length of the remaining space in the packetbuf.
Definition: packetbuf.c:173
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
Definition: radio.h:88
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1833
Linked list manipulation routines.
Header file for the logging system.
@ MAC_TX_COLLISION
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:91
@ MAC_TX_DEFERRED
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:97
@ MAC_TX_ERR
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:101
Memory block allocation routines.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:62
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:75
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
Definition: mac.h:81
int(* off)(void)
Turn the MAC layer off.
Definition: mac.h:78
void(* init)(void)
Initialize the MAC driver.
Definition: mac.h:66
void(* send)(mac_callback_t sent_callback, void *ptr)
Send a packet from the packetbuf
Definition: mac.h:69