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