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