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