xref: /btstack/platform/lwip/bnep_lwip.c (revision abb61bc22a5228e9b178c541f7c9a87dcafdb1f0)
1 /*
2  * Copyright (C) 2017 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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 holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "bnep_lwip_lwip.c"
39 
40 /*
41  * bnep_lwip_lwip_.c
42  */
43 
44 #include "lwip/sys.h"
45 #include "lwip/arch.h"
46 #include "lwip/api.h"
47 #include "lwip/netifapi.h"
48 #include "lwip/tcpip.h"
49 #include "lwip/ip.h"
50 #include "lwip/dhcp.h"
51 #include "lwip/sockets.h"
52 #include "lwip/prot/dhcp.h"
53 #include "netif/etharp.h"
54 
55 #include "btstack_bool.h"
56 
57 #if LWIP_IPV6
58 #include "lwip/ethip6.h"
59 #endif
60 
61 #include "bnep_lwip.h"
62 
63 #include "btstack_config.h"
64 #include "btstack_debug.h"
65 #include "btstack_util.h"
66 #include "btstack_event.h"
67 #include "classic/bnep.h"
68 
69 #if NO_SYS
70 #include "btstack_ring_buffer.h"
71 #include "btstack_run_loop.h"
72 #include "lwip/timeouts.h"
73 #else
74 #ifdef HAVE_FREERTOS_INCLUDE_PREFIX
75 #include "freertos/FreeRTOS.h"
76 #include "freertos/queue.h"
77 #else
78 #include "FreeRTOS.h"
79 #include "queue.h"
80 #endif
81 #endif
82 
83 /* Short name used for netif in lwIP */
84 #define IFNAME0 'b'
85 #define IFNAME1 't'
86 
87 #define LWIP_TIMER_INTERVAL_MS 25
88 
89 static void bnep_lwip_outgoing_process(void * arg);
90 static bool bnep_lwip_outgoing_packets_empty(void);
91 
92 // lwip data
93 static struct netif btstack_netif;
94 
95 // outgoing queue
96 #if NO_SYS
97 static uint8_t bnep_lwip_outgoing_queue_storage[ (TCP_SND_QUEUELEN+1) * sizeof(struct pbuf *)];
98 static btstack_ring_buffer_t bnep_lwip_outgoing_queue;
99 #else
100 static QueueHandle_t bnep_lwip_outgoing_queue;
101 #endif
102 btstack_context_callback_registration_t bnep_lwip_outgoing_callback_registration;
103 
104 #if NO_SYS
105 static btstack_timer_source_t   bnep_lwip_timer;
106 #endif
107 
108 // bnep data
109 static uint16_t  bnep_cid;
110 static btstack_packet_handler_t client_handler;
111 
112 // next packet only modified from btstack context
113 static struct pbuf * bnep_lwip_outgoing_next_packet;
114 
115 // temp buffer to unchain buffer
116 static uint8_t btstack_network_outgoing_buffer[HCI_ACL_PAYLOAD_SIZE];
117 
118 // helper functions to hide NO_SYS vs. FreeRTOS implementations
119 
bnep_lwip_outgoing_init_queue(void)120 static int bnep_lwip_outgoing_init_queue(void){
121 #if NO_SYS
122     btstack_ring_buffer_init(&bnep_lwip_outgoing_queue, bnep_lwip_outgoing_queue_storage, sizeof(bnep_lwip_outgoing_queue_storage));
123 #else
124     bnep_lwip_outgoing_queue = xQueueCreate(TCP_SND_QUEUELEN, sizeof(struct pbuf *));
125     if (bnep_lwip_outgoing_queue == NULL){
126         log_error("cannot allocate outgoing queue");
127         return 1;
128     }
129 #endif
130     return 0;
131 }
132 
bnep_lwip_outgoing_reset_queue(void)133 static void bnep_lwip_outgoing_reset_queue(void){
134 #if NO_SYS
135     btstack_ring_buffer_init(&bnep_lwip_outgoing_queue, bnep_lwip_outgoing_queue_storage, sizeof(bnep_lwip_outgoing_queue_storage));
136 #else
137     xQueueReset(bnep_lwip_outgoing_queue);
138 #endif
139 }
140 
bnep_lwip_outgoing_queue_packet(struct pbuf * p)141 static void bnep_lwip_outgoing_queue_packet(struct pbuf *p){
142 #if NO_SYS
143     // queue up
144     btstack_ring_buffer_write(&bnep_lwip_outgoing_queue, (uint8_t *) &p, sizeof(struct pbuf *));
145 #else
146     // queue up
147     xQueueSendToBack(bnep_lwip_outgoing_queue, &p, portMAX_DELAY);
148 #endif
149 }
150 
bnep_lwip_outgoing_pop_packet(void)151 static struct pbuf * bnep_lwip_outgoing_pop_packet(void){
152     struct pbuf * p = NULL;
153 #if NO_SYS
154     uint32_t bytes_read = 0;
155     btstack_ring_buffer_read(&bnep_lwip_outgoing_queue, (uint8_t *) &p, sizeof(struct pbuf *), &bytes_read);
156     (void) bytes_read;
157 #else
158     xQueueReceive(bnep_lwip_outgoing_queue, &p, portMAX_DELAY);
159 #endif
160     return p;
161 }
162 
bnep_lwip_outgoing_packets_empty(void)163 static bool bnep_lwip_outgoing_packets_empty(void){
164 #if NO_SYS
165     return btstack_ring_buffer_empty(&bnep_lwip_outgoing_queue) != 0;
166  #else
167     return uxQueueMessagesWaiting(bnep_lwip_outgoing_queue) == 0;
168 #endif
169 }
170 
bnep_lwip_free_pbuf(struct pbuf * p)171 static void bnep_lwip_free_pbuf(struct pbuf * p){
172 #if NO_SYS
173     // release buffer / decrease refcount
174     pbuf_free(p);
175  #else
176     // release buffer / decrease refcount
177     pbuf_free_callback(p);
178 #endif
179 }
180 
bnep_lwip_outgoing_packet_processed(void)181 static void bnep_lwip_outgoing_packet_processed(void){
182     // free pbuf
183     bnep_lwip_free_pbuf(bnep_lwip_outgoing_next_packet);
184     // mark as done
185     bnep_lwip_outgoing_next_packet = NULL;
186 }
187 
bnep_lwip_trigger_outgoing_process(void)188 static void bnep_lwip_trigger_outgoing_process(void){
189 #if NO_SYS
190     bnep_lwip_outgoing_process(NULL);
191 #else
192     bnep_lwip_outgoing_callback_registration.callback = &bnep_lwip_outgoing_process;
193     btstack_run_loop_execute_on_main_thread(&bnep_lwip_outgoing_callback_registration);
194 #endif
195 }
196 
197 /// lwIP functions
198 
199 /**
200  * This function should do the actual transmission of the packet. The packet is
201  * contained in the pbuf that is passed to the function. This pbuf
202  * might be chained.
203  *
204  * @param netif the lwip network interface structure
205  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
206  * @return ERR_OK if the packet could be sent
207  *         an err_t value if the packet couldn't be sent
208  *
209  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
210  *       strange results. You might consider waiting for space in the DMA queue
211  *       to become availale since the stack doesn't retry to send a packet
212  *       dropped because of memory failure (except for the TCP timers).
213  */
214 
low_level_output(struct netif * netif,struct pbuf * p)215 static err_t low_level_output( struct netif *netif, struct pbuf *p ){
216     UNUSED(netif);
217 
218     log_info("low_level_output: packet %p, len %u, total len %u ", p, p->len, p->tot_len);
219 
220     // bnep up?
221     if (bnep_cid == 0) return ERR_OK;
222 
223     // inc refcount
224     pbuf_ref( p );
225 
226     // queue empty now?
227     int queue_empty = bnep_lwip_outgoing_packets_empty();
228 
229     // queue up
230     bnep_lwip_outgoing_queue_packet(p);
231 
232     // trigger processing if queue was empty (might be new packet)
233     if (queue_empty){
234         bnep_lwip_trigger_outgoing_process();
235     }
236 
237     return ERR_OK;
238 }
239 
240 /**
241  * Should be called at the beginning of the program to set up the
242  * network interface. It calls the function low_level_init() to do the
243  * actual setup of the hardware.
244  *
245  * This function should be passed as a parameter to netif_add().
246  *
247  * @param netif the lwip network interface structure for this ethernetif
248  * @return ERR_OK if the loopif is initialized
249  *         ERR_MEM if private data couldn't be allocated
250  *         any other err_t on error
251  */
252 
bnep_lwip_netif_init(struct netif * netif)253 static err_t bnep_lwip_netif_init(struct netif *netif){
254 
255     // interface short name
256     netif->name[0] = IFNAME0;
257     netif->name[1] = IFNAME1;
258 
259     // mtu
260     netif->mtu = 1600;
261 
262     /* device capabilities */
263     netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
264 
265     /* We directly use etharp_output() here to save a function call.
266      * You can instead declare your own function an call etharp_output()
267      * from it if you have to do some checks before sending (e.g. if link
268      * is available...)
269      */
270     netif->output = etharp_output;
271 #if LWIP_IPV6
272     netif->output_ip6 = ethip6_output;
273 #endif
274     netif->linkoutput = low_level_output;
275 
276     return ERR_OK;
277 }
278 
bnep_lwip_netif_up(bd_addr_t network_address)279 static int bnep_lwip_netif_up(bd_addr_t network_address){
280     log_info("bnep_lwip_netif_up start addr %s", bd_addr_to_str(network_address));
281 
282     // set mac address
283     btstack_netif.hwaddr_len = 6;
284     memcpy(btstack_netif.hwaddr, network_address, 6);
285 
286     // link is up
287     btstack_netif.flags |= NETIF_FLAG_LINK_UP;
288 
289     // if up
290     netif_set_up(&btstack_netif);
291 
292     return 0;
293 }
294 
295 /**
296  * @brief Bring up network interfacd
297  * @param network_address
298  * @return 0 if ok
299  */
bnep_lwip_netif_down(void)300 static int bnep_lwip_netif_down(void){
301     log_info("bnep_lwip_netif_down");
302 
303     // link is down
304     btstack_netif.flags &= ~NETIF_FLAG_LINK_UP;
305 
306     netif_set_down(&btstack_netif);
307     return 0;
308 }
309 
310 /**
311  * @brief Forward packet to TCP/IP stack
312  * @param packet
313  * @param size
314  */
bnep_lwip_netif_process_packet(const uint8_t * packet,uint16_t size)315 static void bnep_lwip_netif_process_packet(const uint8_t * packet, uint16_t size){
316 
317     /* We allocate a pbuf chain of pbufs from the pool. */
318     struct pbuf * p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
319     log_debug("bnep_lwip_netif_process_packet, pbuf_alloc = %p", p);
320 
321     if (!p) return;
322 
323     /* store packet in pbuf chain */
324     struct pbuf * q = p;
325     while (q != NULL && size){
326         memcpy(q->payload, packet, q->len);
327         packet += q->len;
328         size   -= q->len;
329         q = q->next;
330     }
331 
332     if (size != 0){
333         log_error("failed to copy data into pbuf");
334         bnep_lwip_free_pbuf(p);
335         return;
336     }
337 
338     /* pass all packets to ethernet_input, which decides what packets it supports */
339     int res = btstack_netif.input(p, &btstack_netif);
340     if (res != ERR_OK){
341         log_error("bnep_lwip_netif_process_packet: IP input error\n");
342         bnep_lwip_free_pbuf(p);
343         p = NULL;
344     }
345 }
346 
347 
348 // BNEP Functions & Handler
349 
350 #if NO_SYS
bnep_lwip_timeout_handler(btstack_timer_source_t * ts)351 static void bnep_lwip_timeout_handler(btstack_timer_source_t * ts){
352 
353     // process lwIP timers
354     sys_check_timeouts();
355 
356     // check if link is still up
357     if ((btstack_netif.flags & NETIF_FLAG_LINK_UP) == 0) return;
358 
359     // restart timer
360     btstack_run_loop_set_timer(ts, LWIP_TIMER_INTERVAL_MS);
361     btstack_run_loop_add_timer(ts);
362 }
363 #endif
364 
bnep_lwip_outgoing_process(void * arg)365 static void bnep_lwip_outgoing_process(void * arg){
366     UNUSED(arg);
367 
368     // previous packet not sent yet
369     if (bnep_lwip_outgoing_next_packet) return;
370 
371     bnep_lwip_outgoing_next_packet = bnep_lwip_outgoing_pop_packet();
372 
373     // request can send now
374     bnep_request_can_send_now_event(bnep_cid);
375 }
376 
bnep_lwip_send_packet(void)377 static void bnep_lwip_send_packet(void){
378     if (bnep_lwip_outgoing_next_packet == NULL){
379         log_error("CAN SEND NOW, but now packet queued");
380         return;
381     }
382 
383     // flatten into our buffer
384     uint32_t len = btstack_min(sizeof(btstack_network_outgoing_buffer), bnep_lwip_outgoing_next_packet->tot_len);
385     pbuf_copy_partial(bnep_lwip_outgoing_next_packet, btstack_network_outgoing_buffer, len, 0);
386     bnep_send(bnep_cid, (uint8_t*) btstack_network_outgoing_buffer, len);
387 }
388 
bnep_lwip_packet_sent(void)389 static void bnep_lwip_packet_sent(void){
390     log_debug("bnep_lwip_packet_sent: %p", bnep_lwip_outgoing_next_packet);
391 
392     // release current packet
393     bnep_lwip_outgoing_packet_processed();
394 
395     // more ?
396     if (bnep_lwip_outgoing_packets_empty()) return;
397     bnep_lwip_trigger_outgoing_process();
398 }
399 
bnep_lwip_discard_packets(void)400 static void bnep_lwip_discard_packets(void){
401     // discard current packet
402     if (bnep_lwip_outgoing_next_packet){
403         bnep_lwip_outgoing_packet_processed();
404     }
405 
406     // reset queue
407     bnep_lwip_outgoing_reset_queue();
408 }
409 
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)410 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
411 {
412 /* LISTING_PAUSE */
413     UNUSED(channel);
414 
415     bd_addr_t local_addr;
416 
417     switch (packet_type) {
418         case HCI_EVENT_PACKET:
419             switch (hci_event_packet_get_type(packet)) {
420 
421                 /* @text BNEP_EVENT_CHANNEL_OPENED is received after a BNEP connection was established or
422                  * or when the connection fails. The status field returns the error code.
423                  *
424                  * The TAP network interface is then configured. A data source is set up and registered with the
425                  * run loop to receive Ethernet packets from the TAP interface.
426                  *
427                  * The event contains both the source and destination UUIDs, as well as the MTU for this connection and
428                  * the BNEP Channel ID, which is used for sending Ethernet packets over BNEP.
429                  */
430                 case BNEP_EVENT_CHANNEL_OPENED:
431                     if (bnep_event_channel_opened_get_status(packet) != 0) break;
432 
433                     bnep_cid = bnep_event_channel_opened_get_bnep_cid(packet);
434 
435                     /* Setup network interface */
436                     gap_local_bd_addr(local_addr);
437                     bnep_lwip_netif_up(local_addr);
438 
439 #if NO_SYS
440                     // start timer
441                     btstack_run_loop_set_timer_handler(&bnep_lwip_timer, bnep_lwip_timeout_handler);
442                     btstack_run_loop_set_timer(&bnep_lwip_timer, LWIP_TIMER_INTERVAL_MS);
443                     btstack_run_loop_add_timer(&bnep_lwip_timer);
444 #endif
445                     break;
446 
447                 /* @text BNEP_EVENT_CHANNEL_CLOSED is received when the connection gets closed.
448                  */
449                 case BNEP_EVENT_CHANNEL_CLOSED:
450                     bnep_cid = 0;
451                     bnep_lwip_discard_packets();
452 
453                     // Mark Link as Down
454                     bnep_lwip_netif_down();
455                     break;
456 
457                 /* @text BNEP_EVENT_CAN_SEND_NOW indicates that a new packet can be send. This triggers the send of a
458                  * stored network packet. The tap datas source can be enabled again
459                  */
460                 case BNEP_EVENT_CAN_SEND_NOW:
461                     bnep_lwip_send_packet();
462                     bnep_lwip_packet_sent();
463                     break;
464 
465                 default:
466                     break;
467             }
468             break;
469 
470         /* @text Ethernet packets from the remote device are received in the packet handler with type BNEP_DATA_PACKET.
471          * It is forwarded to the TAP interface.
472          */
473         case BNEP_DATA_PACKET:
474             if (bnep_cid == 0) break;
475             // Write out the ethernet frame to the network interface
476             bnep_lwip_netif_process_packet(packet, size);
477             break;
478 
479         default:
480             break;
481     }
482 
483     // forward to app
484     if (!client_handler) return;
485     (*client_handler)(packet_type, channel, packet, size);
486 }
487 
488 /// API
489 
490 /**
491  * @brief Initialize network interface
492  * @param send_packet_callback
493  */
bnep_lwip_init(void)494 void bnep_lwip_init(void){
495 
496     // set up outgoing queue
497     int error = bnep_lwip_outgoing_init_queue();
498     if (error) return;
499 
500     ip4_addr_t fsl_netif0_ipaddr, fsl_netif0_netmask, fsl_netif0_gw;
501 #if 0
502     // when using DHCP Client, no address
503     IP4_ADDR(&fsl_netif0_ipaddr, 0U, 0U, 0U, 0U);
504     IP4_ADDR(&fsl_netif0_netmask, 0U, 0U, 0U, 0U);
505 #else
506     // when playing DHCP Server, set address
507     IP4_ADDR(&fsl_netif0_ipaddr, 192U, 168U, 7U, 1U);
508     IP4_ADDR(&fsl_netif0_netmask, 255U, 255U, 255U, 0U);
509 #endif
510     IP4_ADDR(&fsl_netif0_gw, 0U, 0U, 0U, 0U);
511 
512     // input function differs for sys vs nosys
513     netif_input_fn input_function;
514 #if NO_SYS
515     input_function = ethernet_input;
516 #else
517     input_function = tcpip_input;
518 #endif
519 
520     netif_add(&btstack_netif, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, NULL, bnep_lwip_netif_init, input_function);
521     netif_set_default(&btstack_netif);
522 }
523 
524 /**
525  * @brief Register packet handler for BNEP events
526  */
bnep_lwip_register_packet_handler(btstack_packet_handler_t handler)527 void bnep_lwip_register_packet_handler(btstack_packet_handler_t handler){
528     client_handler = handler;
529 }
530 
531 /**
532  * @brief Register BNEP service
533  * @brief Same as benp_register_service, but bnep lwip adapter handles all events
534  * @param service_uuid
535  * @Param max_frame_size
536  */
bnep_lwip_register_service(uint16_t service_uuid,uint16_t max_frame_size)537 uint8_t bnep_lwip_register_service(uint16_t service_uuid, uint16_t max_frame_size){
538     return bnep_register_service(packet_handler, service_uuid, max_frame_size);
539 }
540 
541 /**
542  * @brief Creates BNEP connection (channel) to a given server on a remote device with baseband address. A new baseband connection will be initiated if necessary.
543  * @note: uses our packet handler to manage lwIP network interface
544  * @param addr
545  * @param l2cap_psm
546  * @param uuid_src
547  * @param uuid_dest
548  * @return status
549  */
bnep_lwip_connect(bd_addr_t addr,uint16_t l2cap_psm,uint16_t uuid_src,uint16_t uuid_dest)550 uint8_t bnep_lwip_connect(bd_addr_t addr, uint16_t l2cap_psm, uint16_t uuid_src, uint16_t uuid_dest){
551     int status = bnep_connect(packet_handler, addr, l2cap_psm, uuid_src, uuid_dest);
552     if (status != 0){
553         return ERROR_CODE_UNSPECIFIED_ERROR;
554     } else {
555         return ERROR_CODE_SUCCESS;
556     }
557 }
558 
bnep_lwip_get_interface(void)559 struct netif *bnep_lwip_get_interface(void){
560     return &btstack_netif;
561 }
562