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 
41 #include "net/mac/ble/ble-l2cap.h"
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 */
60 static uint8_t ble_addr[BLE_ADDR_SIZE];
61 /*---------------------------------------------------------------------------*/
62 /* L2CAP fragmentation buffers and utilities */
63 typedef 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 /*---------------------------------------------------------------------------*/
72 typedef struct {
73  uint16_t cid;
74  uint16_t mtu;
75  uint16_t mps;
76  uint16_t credits;
77 } ble_mac_l2cap_channel_t;
78 /*---------------------------------------------------------------------------*/
79 typedef 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 
87 static uint8_t l2cap_channel_count;
88 static l2cap_channel_t l2cap_channels[L2CAP_CHANNELS];
89 static process_event_t l2cap_tx_event;
90 /*---------------------------------------------------------------------------*/
91 static l2cap_channel_t *
92 get_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 /*---------------------------------------------------------------------------*/
105 static l2cap_channel_t *
106 get_channel_for_cid(uint16_t own_cid)
107 {
108  uint8_t i = own_cid - L2CAP_FLOW_CHANNEL;
109  if(i >= 0 && i < l2cap_channel_count) {
110  return &l2cap_channels[own_cid - L2CAP_FLOW_CHANNEL];
111  } else {
112  return NULL;
113  }
114 }
115 /*---------------------------------------------------------------------------*/
116 PROCESS(ble_l2cap_tx_process, "BLE L2CAP TX process");
117 /*---------------------------------------------------------------------------*/
118 static uint8_t
119 init_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 /*---------------------------------------------------------------------------*/
145 static uint8_t
146 init_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 /*---------------------------------------------------------------------------*/
167 void
168 input_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 /*---------------------------------------------------------------------------*/
232 static void
233 init(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 /*---------------------------------------------------------------------------*/
272 static uint16_t
273 check_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 /*---------------------------------------------------------------------------*/
286 static void
287 send_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 /*---------------------------------------------------------------------------*/
318 static void
319 send(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 /*---------------------------------------------------------------------------*/
353 void
354 input_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 /*---------------------------------------------------------------------------*/
373 void
374 input_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 /* uint8_t identifier = data[0]; */
382  memcpy(&len, &data[1], 2);
383 
384  if(len != 4) {
385  LOG_WARN("process_l2cap_credit: invalid len: %d\n", len);
386  return;
387  }
388 
389  /* parse L2CAP credit data */
390  memcpy(&cid, &data[3], 2);
391  memcpy(&credits, &data[5], 2);
392 
393  channel->channel_peer.credits += credits;
394 }
395 /*---------------------------------------------------------------------------*/
396 static void
397 input_l2cap_frame_signal_channel(uint8_t *data, uint8_t data_len)
398 {
399  if(data[4] == L2CAP_CODE_CREDIT) {
400  input_l2cap_credit(&data[5]);
401  } else if(data[4] == L2CAP_CODE_CONN_REQ) {
402  input_l2cap_conn_req(&data[5]);
403  } else if(data[4] == L2CAP_CODE_CONN_UPDATE_RSP) {
404  input_l2cap_connection_udate_resp(&data[5]);
405  } else {
406  LOG_WARN("l2cap_frame_signal_channel: unknown signal channel code: %d\n", data[4]);
407  }
408 }
409 /*---------------------------------------------------------------------------*/
410 static void
411 input_l2cap_frame_flow_channel(l2cap_channel_t *channel, uint8_t *data, uint16_t data_len)
412 {
413  uint16_t frame_len;
414  uint16_t payload_len;
415 
416  if(data_len < 4) {
417  LOG_WARN("l2cap_frame: illegal L2CAP frame data_len: %d\n", data_len);
418  /* a L2CAP frame has a minimum length of 4 */
419  return;
420  }
421 
422  if(channel->rx_buffer.sdu_length == 0) {
423  /* handle first fragment */
424  memcpy(&frame_len, &data[0], 2);
425  memcpy(&channel->rx_buffer.sdu_length, &data[4], 2);
426  payload_len = frame_len - 2;
427 
428  memcpy(channel->rx_buffer.sdu, &data[6], payload_len);
429  channel->rx_buffer.current_index = payload_len;
430  } else {
431  /* subsequent fragment */
432  memcpy(&frame_len, &data[0], 2);
433  payload_len = frame_len;
434 
435  memcpy(&channel->rx_buffer.sdu[channel->rx_buffer.current_index], &data[4], payload_len);
436  channel->rx_buffer.current_index += payload_len;
437  }
438 
439  if((channel->rx_buffer.sdu_length > 0) &&
440  (channel->rx_buffer.sdu_length == channel->rx_buffer.current_index)) {
441  /* do not use packetbuf_copyfrom here because the packetbuf_attr
442  * must not be cleared */
443  memcpy(packetbuf_dataptr(), channel->rx_buffer.sdu, channel->rx_buffer.sdu_length);
444  packetbuf_set_datalen(channel->rx_buffer.sdu_length);
445  NETSTACK_NETWORK.input();
446 
447  /* reset counters */
448  channel->rx_buffer.sdu_length = 0;
449  channel->rx_buffer.current_index = 0;
450  }
451 }
452 /*---------------------------------------------------------------------------*/
453 static void
454 input(void)
455 {
456  uint8_t *data = (uint8_t *)packetbuf_dataptr();
457  uint16_t len = packetbuf_datalen();
458  uint8_t frame_type = packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE);
459  uint16_t channel_id;
460  l2cap_channel_t *channel;
461  uint16_t credits;
462 
463  if(frame_type == FRAME_BLE_RX_EVENT) {
464  memcpy(&channel_id, &data[2], 2);
465  channel = get_channel_for_cid(channel_id);
466  LOG_DBG("input %d bytes\n", len);
467  if(channel_id == L2CAP_SIGNAL_CHANNEL) {
468  input_l2cap_frame_signal_channel(data, len);
469  } else if(channel == NULL) {
470  LOG_WARN("input (RX_EVENT): no channel found for CID: %d\n", channel_id);
471  return;
472  } else {
473  input_l2cap_frame_flow_channel(channel, data, len);
474  channel->channel_own.credits--;
475  credits = check_own_l2cap_credits(channel);
476  if(credits > 0) {
477  send_l2cap_credit(channel, credits);
478  }
479  }
480  }
481  /* check if there are still fragments left to be transmitted */
482  if(frame_type == FRAME_BLE_TX_EVENT) {
483  channel = get_channel_for_addr(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
484  if(channel == NULL) {
485  LOG_WARN("input (TX_EVENT): no channel found for CID: %d\n", channel_id);
486  } else if(channel->tx_buffer.sdu_length > 0) {
487  process_post(&ble_l2cap_tx_process, l2cap_tx_event, (void *)channel);
488  }
489  }
490 }
491 /*---------------------------------------------------------------------------*/
492 static int
493 on(void)
494 {
495  LOG_DBG("on()\n");
496  process_start(&ble_l2cap_tx_process, NULL);
497  return 0;
498 }
499 /*---------------------------------------------------------------------------*/
500 static int
501 off(void)
502 {
503  LOG_DBG("off()\n");
504  process_exit(&ble_l2cap_tx_process);
505  return 0;
506 }
507 /*---------------------------------------------------------------------------*/
508 static int
509 max_payload(void)
510 {
511  return BLE_L2CAP_NODE_MTU;
512 }
513 /*---------------------------------------------------------------------------*/
514 const struct mac_driver ble_l2cap_driver = {
515  "ble-l2cap",
516  init,
517  send,
518  input,
519  on,
520  off,
521  max_payload,
522 };
523 /*---------------------------------------------------------------------------*/
524 PROCESS_THREAD(ble_l2cap_tx_process, ev, data)
525 {
526  uint16_t data_len;
527  uint16_t frame_len;
528  uint16_t num_buffer;
529  l2cap_channel_t *channel = (l2cap_channel_t *)data;
530  uint8_t first_fragment;
531  uint16_t used_mps;
532  uint16_t credits;
533 
534  PROCESS_BEGIN();
535  LOG_DBG("starting ble_mac_tx_process\n");
536 
537  while(1) {
538  PROCESS_YIELD_UNTIL(ev == l2cap_tx_event);
539  if(channel != NULL) {
540  NETSTACK_RADIO.get_value(RADIO_CONST_BLE_BUFFER_AMOUNT, (radio_value_t *)&num_buffer);
541  first_fragment = (channel->tx_buffer.current_index == 0);
542  used_mps = MIN(channel->channel_own.mps, channel->channel_peer.mps);
543  credits = channel->channel_peer.credits;
544 
545  LOG_DBG("process: sending - first: %d, used_mps: %3d, num_buffers: %2d, credits: %2d\n",
546  first_fragment, used_mps, num_buffer, credits);
547  if((channel->tx_buffer.sdu_length > 0) && (num_buffer > 0) && (credits > 0)) {
548  packetbuf_clear();
549  if(first_fragment) {
550  packetbuf_hdralloc(L2CAP_FIRST_HEADER_SIZE);
551  used_mps -= L2CAP_FIRST_HEADER_SIZE;
552  data_len = MIN(channel->tx_buffer.sdu_length, used_mps);
553  frame_len = data_len + 2;
554 
555  /* set L2CAP header fields */
556  memcpy(packetbuf_hdrptr(), &frame_len, 2); /* fragment size */
557  memcpy(packetbuf_hdrptr() + 2, &channel->channel_peer.cid, 2); /* L2CAP channel id*/
558  memcpy(packetbuf_hdrptr() + 4, &channel->tx_buffer.sdu_length, 2); /* overall packet size */
559  } else {
560  packetbuf_hdralloc(L2CAP_SUBSEQ_HEADER_SIZE);
561  used_mps -= L2CAP_SUBSEQ_HEADER_SIZE;
562  data_len = MIN((channel->tx_buffer.sdu_length - channel->tx_buffer.current_index), used_mps);
563  frame_len = data_len;
564 
565  /* set L2CAP header fields */
566  memcpy(packetbuf_hdrptr(), &frame_len, 2); /* fragment size */
567  memcpy(packetbuf_hdrptr() + 2, &channel->channel_peer.cid, 2); /* L2CAP channel id*/
568  }
569 
570  /* copy payload */
571  memcpy(packetbuf_dataptr(),
572  &channel->tx_buffer.sdu[channel->tx_buffer.current_index],
573  data_len);
574  packetbuf_set_datalen(data_len);
575  channel->tx_buffer.current_index += data_len;
576 
577  /* send the fragment */
578  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr);
579  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
580  NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
581  channel->channel_peer.credits--;
582 
583  /* reset the L2CAP TX buffer if packet is finished */
584  if(channel->tx_buffer.current_index == channel->tx_buffer.sdu_length) {
585  channel->tx_buffer.current_index = 0;
586  channel->tx_buffer.sdu_length = 0;
587  }
588  }
589  } else {
590  LOG_WARN("process. channel is NULL\n");
591  }
592  }
593 
594  PROCESS_END();
595  LOG_DBG("stopped ble_mac_tx_process\n");
596 }
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:91
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:75
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
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:62
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
#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
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
const linkaddr_t linkaddr_null
The null link-layer address.
int(* off)(void)
Turn the MAC layer off.
Definition: mac.h:78
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:97
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
Linked list manipulation routines.
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition: packetbuf.c:84
MAC layer that implements BLE L2CAP credit-based flow control channels to support IPv6 over BLE (RFC ...
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:101
Memory block allocation routines.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:149
void(* send)(mac_callback_t sent_callback, void *ptr)
Send a packet from the packetbuf.
Definition: mac.h:69
void(* init)(void)
Initialize the MAC driver.
Definition: mac.h:66
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
Definition: mac.h:81
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1107
Header file for the logging system
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1802
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99