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