xref: /btstack/platform/lwip/bnep_lwip.c (revision 917f809a5141e8fec42e053a605d398a475f9ed3)
197dc5e69SMatthias Ringwald /*
297dc5e69SMatthias Ringwald  * Copyright (C) 2017 BlueKitchen GmbH
397dc5e69SMatthias Ringwald  *
497dc5e69SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
597dc5e69SMatthias Ringwald  * modification, are permitted provided that the following conditions
697dc5e69SMatthias Ringwald  * are met:
797dc5e69SMatthias Ringwald  *
897dc5e69SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
997dc5e69SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
1097dc5e69SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1197dc5e69SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
1297dc5e69SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
1397dc5e69SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
1497dc5e69SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
1597dc5e69SMatthias Ringwald  *    from this software without specific prior written permission.
1697dc5e69SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
1797dc5e69SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
1897dc5e69SMatthias Ringwald  *    monetary gain.
1997dc5e69SMatthias Ringwald  *
2097dc5e69SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2197dc5e69SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2297dc5e69SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2397dc5e69SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
2497dc5e69SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2597dc5e69SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2697dc5e69SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2797dc5e69SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2897dc5e69SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2997dc5e69SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3097dc5e69SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3197dc5e69SMatthias Ringwald  * SUCH DAMAGE.
3297dc5e69SMatthias Ringwald  *
3397dc5e69SMatthias Ringwald  * Please inquire about commercial licensing options at
3497dc5e69SMatthias Ringwald  * [email protected]
3597dc5e69SMatthias Ringwald  *
3697dc5e69SMatthias Ringwald  */
3797dc5e69SMatthias Ringwald 
3897dc5e69SMatthias Ringwald #define BTSTACK_FILE__ "bnep_lwip_lwip.c"
3997dc5e69SMatthias Ringwald 
4097dc5e69SMatthias Ringwald /*
4197dc5e69SMatthias Ringwald  * bnep_lwip_lwip_.c
4297dc5e69SMatthias Ringwald  */
4397dc5e69SMatthias Ringwald 
4497dc5e69SMatthias Ringwald #include "lwip/netif.h"
4597dc5e69SMatthias Ringwald #include "lwip/sys.h"
4697dc5e69SMatthias Ringwald #include "lwip/arch.h"
4797dc5e69SMatthias Ringwald #include "lwip/api.h"
4897dc5e69SMatthias Ringwald #include "lwip/netifapi.h"
4997dc5e69SMatthias Ringwald #include "lwip/tcpip.h"
5097dc5e69SMatthias Ringwald #include "lwip/ip.h"
5197dc5e69SMatthias Ringwald #include "lwip/dhcp.h"
5297dc5e69SMatthias Ringwald #include "lwip/sockets.h"
5397dc5e69SMatthias Ringwald #include "lwip/prot/dhcp.h"
540be141aeSMatthias Ringwald #include "netif/etharp.h"
550be141aeSMatthias Ringwald 
560be141aeSMatthias Ringwald #if LWIP_IPV6
570be141aeSMatthias Ringwald #include "lwip/ethip6.h"
580be141aeSMatthias Ringwald #endif
5997dc5e69SMatthias Ringwald 
6097dc5e69SMatthias Ringwald #include "bnep_lwip.h"
6197dc5e69SMatthias Ringwald 
6297dc5e69SMatthias Ringwald #include "btstack_config.h"
6397dc5e69SMatthias Ringwald #include "btstack_debug.h"
6497dc5e69SMatthias Ringwald #include "btstack_util.h"
6597dc5e69SMatthias Ringwald #include "btstack_event.h"
6697dc5e69SMatthias Ringwald #include "classic/bnep.h"
6797dc5e69SMatthias Ringwald 
6897dc5e69SMatthias Ringwald #if NO_SYS
6997dc5e69SMatthias Ringwald #include "btstack_ring_buffer.h"
7097dc5e69SMatthias Ringwald #include "btstack_run_loop.h"
7197dc5e69SMatthias Ringwald #include "lwip/timeouts.h"
7297dc5e69SMatthias Ringwald #else
7397dc5e69SMatthias Ringwald #include "btstack_run_loop_freertos.h"
7497dc5e69SMatthias Ringwald #endif
7597dc5e69SMatthias Ringwald 
7697dc5e69SMatthias Ringwald /* Short name used for netif in lwIP */
7797dc5e69SMatthias Ringwald #define IFNAME0 'b'
7897dc5e69SMatthias Ringwald #define IFNAME1 't'
7997dc5e69SMatthias Ringwald 
8097dc5e69SMatthias Ringwald #define LWIP_TIMER_INTERVAL_MS 25
8197dc5e69SMatthias Ringwald 
8297dc5e69SMatthias Ringwald static void bnep_lwip_outgoing_process(void * arg);
83*917f809aSMatthias Ringwald static int bnep_lwip_outgoing_packets_empty(void);
8497dc5e69SMatthias Ringwald 
8597dc5e69SMatthias Ringwald // lwip data
8697dc5e69SMatthias Ringwald static struct netif btstack_netif;
8797dc5e69SMatthias Ringwald 
8897dc5e69SMatthias Ringwald // outgoing queue
8997dc5e69SMatthias Ringwald #if NO_SYS
9097dc5e69SMatthias Ringwald static uint8_t bnep_lwip_outgoing_queue_storage[ (TCP_SND_QUEUELEN+1) * sizeof(struct pbuf *)];
9197dc5e69SMatthias Ringwald static btstack_ring_buffer_t bnep_lwip_outgoing_queue;
9297dc5e69SMatthias Ringwald #else
9397dc5e69SMatthias Ringwald static QueueHandle_t bnep_lwip_outgoing_queue;
9497dc5e69SMatthias Ringwald #endif
9597dc5e69SMatthias Ringwald 
960be141aeSMatthias Ringwald #if NO_SYS
970be141aeSMatthias Ringwald static btstack_timer_source_t   bnep_lwip_timer;
980be141aeSMatthias Ringwald #endif
9997dc5e69SMatthias Ringwald 
10097dc5e69SMatthias Ringwald // bnep data
10197dc5e69SMatthias Ringwald static uint16_t  bnep_cid;
10297dc5e69SMatthias Ringwald static btstack_packet_handler_t client_handler;
10397dc5e69SMatthias Ringwald 
10497dc5e69SMatthias Ringwald // next packet only modified from btstack context
10597dc5e69SMatthias Ringwald static struct pbuf * bnep_lwip_outgoing_next_packet;
10697dc5e69SMatthias Ringwald 
10797dc5e69SMatthias Ringwald // temp buffer to unchain buffer
10897dc5e69SMatthias Ringwald static uint8_t btstack_network_outgoing_buffer[HCI_ACL_PAYLOAD_SIZE];
10997dc5e69SMatthias Ringwald 
110*917f809aSMatthias Ringwald // helper functions to hide NO_SYS vs. FreeRTOS implementations
111*917f809aSMatthias Ringwald 
112*917f809aSMatthias Ringwald static int bnep_lwip_outgoing_init_queue(void){
113*917f809aSMatthias Ringwald #if NO_SYS
114*917f809aSMatthias Ringwald     btstack_ring_buffer_init(&bnep_lwip_outgoing_queue, bnep_lwip_outgoing_queue_storage, sizeof(bnep_lwip_outgoing_queue_storage));
115*917f809aSMatthias Ringwald #else
116*917f809aSMatthias Ringwald     bnep_lwip_outgoing_queue = xQueueCreate(TCP_SND_QUEUELEN, sizeof(struct pbuf *));
117*917f809aSMatthias Ringwald     if (bnep_lwip_outgoing_queue == NULL){
118*917f809aSMatthias Ringwald         log_error("cannot allocate outgoing queue");
119*917f809aSMatthias Ringwald         return 1;
120*917f809aSMatthias Ringwald     }
121*917f809aSMatthias Ringwald #endif
122*917f809aSMatthias Ringwald     return 0;
123*917f809aSMatthias Ringwald }
124*917f809aSMatthias Ringwald 
125*917f809aSMatthias Ringwald static void bnep_lwip_outgoing_reset_queue(void){
126*917f809aSMatthias Ringwald #if NO_SYS
127*917f809aSMatthias Ringwald     btstack_ring_buffer_init(&bnep_lwip_outgoing_queue, bnep_lwip_outgoing_queue_storage, sizeof(bnep_lwip_outgoing_queue_storage));
128*917f809aSMatthias Ringwald #else
129*917f809aSMatthias Ringwald     xQueueReset(bnep_lwip_outgoing_queue);
130*917f809aSMatthias Ringwald #endif
131*917f809aSMatthias Ringwald }
132*917f809aSMatthias Ringwald 
133*917f809aSMatthias Ringwald static void bnep_lwip_outgoing_queue_packet(struct pbuf *p){
134*917f809aSMatthias Ringwald #if NO_SYS
135*917f809aSMatthias Ringwald     // queue up
136*917f809aSMatthias Ringwald     void * pointer = (void * ) p;
137*917f809aSMatthias Ringwald     btstack_ring_buffer_write(&bnep_lwip_outgoing_queue, (uint8_t *) &pointer, sizeof(struct pbuf *));
138*917f809aSMatthias Ringwald #else
139*917f809aSMatthias Ringwald     // queue up
140*917f809aSMatthias Ringwald     xQueueSendToBack(bnep_lwip_outgoing_queue, &p, portMAX_DELAY);
141*917f809aSMatthias Ringwald #endif
142*917f809aSMatthias Ringwald }
143*917f809aSMatthias Ringwald 
144*917f809aSMatthias Ringwald static struct pbuf * bnep_lwip_outgoing_pop_packet(void){
145*917f809aSMatthias Ringwald     struct pbuf * p = NULL;
146*917f809aSMatthias Ringwald #if NO_SYS
147*917f809aSMatthias Ringwald     uint32_t bytes_read = 0;
148*917f809aSMatthias Ringwald     btstack_ring_buffer_read(&bnep_lwip_outgoing_queue, (uint8_t *) &pointer, sizeof(struct pbuf *), &bytes_read);
149*917f809aSMatthias Ringwald     (void) bytes_read;
150*917f809aSMatthias Ringwald #else
151*917f809aSMatthias Ringwald     xQueueReceive(bnep_lwip_outgoing_queue, &p, portMAX_DELAY);
152*917f809aSMatthias Ringwald #endif
153*917f809aSMatthias Ringwald     return p;
154*917f809aSMatthias Ringwald }
155*917f809aSMatthias Ringwald 
156*917f809aSMatthias Ringwald static int bnep_lwip_outgoing_packets_empty(void){
157*917f809aSMatthias Ringwald #if NO_SYS
158*917f809aSMatthias Ringwald     return btstack_ring_buffer_empty(&bnep_lwip_outgoing_queue);
159*917f809aSMatthias Ringwald  #else
160*917f809aSMatthias Ringwald     return uxQueueMessagesWaiting(bnep_lwip_outgoing_queue) == 0;
161*917f809aSMatthias Ringwald #endif
162*917f809aSMatthias Ringwald }
163*917f809aSMatthias Ringwald 
164*917f809aSMatthias Ringwald static void bnep_lwip_free_pbuf(struct pbuf * p){
165*917f809aSMatthias Ringwald #if NO_SYS
166*917f809aSMatthias Ringwald     // release buffer / decrease refcount
167*917f809aSMatthias Ringwald     pbuf_free(p);
168*917f809aSMatthias Ringwald  #else
169*917f809aSMatthias Ringwald     // release buffer / decrease refcount
170*917f809aSMatthias Ringwald     pbuf_free_callback(p);
171*917f809aSMatthias Ringwald #endif
172*917f809aSMatthias Ringwald }
173*917f809aSMatthias Ringwald 
174*917f809aSMatthias Ringwald static void bnep_lwip_outgoing_packet_processed(void){
175*917f809aSMatthias Ringwald     // free pbuf
176*917f809aSMatthias Ringwald     bnep_lwip_free_pbuf(bnep_lwip_outgoing_next_packet);
177*917f809aSMatthias Ringwald     // mark as done
178*917f809aSMatthias Ringwald     bnep_lwip_outgoing_next_packet = NULL;
179*917f809aSMatthias Ringwald }
180*917f809aSMatthias Ringwald 
181*917f809aSMatthias Ringwald static void bnep_lwip_trigger_outgoing_process(void){
182*917f809aSMatthias Ringwald #if NO_SYS
183*917f809aSMatthias Ringwald     bnep_lwip_outgoing_process(NULL);
184*917f809aSMatthias Ringwald #else
185*917f809aSMatthias Ringwald     btstack_run_loop_freertos_execute_code_on_main_thread(&bnep_lwip_outgoing_process, NULL);
186*917f809aSMatthias Ringwald #endif
187*917f809aSMatthias Ringwald }
188*917f809aSMatthias Ringwald 
18997dc5e69SMatthias Ringwald /// lwIP functions
19097dc5e69SMatthias Ringwald 
19197dc5e69SMatthias Ringwald /**
19297dc5e69SMatthias Ringwald  * This function should do the actual transmission of the packet. The packet is
19397dc5e69SMatthias Ringwald  * contained in the pbuf that is passed to the function. This pbuf
19497dc5e69SMatthias Ringwald  * might be chained.
19597dc5e69SMatthias Ringwald  *
19697dc5e69SMatthias Ringwald  * @param netif the lwip network interface structure
19797dc5e69SMatthias Ringwald  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
19897dc5e69SMatthias Ringwald  * @return ERR_OK if the packet could be sent
19997dc5e69SMatthias Ringwald  *         an err_t value if the packet couldn't be sent
20097dc5e69SMatthias Ringwald  *
20197dc5e69SMatthias Ringwald  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
20297dc5e69SMatthias Ringwald  *       strange results. You might consider waiting for space in the DMA queue
20397dc5e69SMatthias Ringwald  *       to become availale since the stack doesn't retry to send a packet
20497dc5e69SMatthias Ringwald  *       dropped because of memory failure (except for the TCP timers).
20597dc5e69SMatthias Ringwald  */
206*917f809aSMatthias Ringwald 
20797dc5e69SMatthias Ringwald static err_t low_level_output( struct netif *netif, struct pbuf *p ){
20897dc5e69SMatthias Ringwald     UNUSED(netif);
20997dc5e69SMatthias Ringwald 
210*917f809aSMatthias Ringwald     log_info("low_level_output: packet %p, len %u, total len %u ", p, p->len, p->tot_len);
21197dc5e69SMatthias Ringwald 
21297dc5e69SMatthias Ringwald     // bnep up?
21397dc5e69SMatthias Ringwald     if (bnep_cid == 0) return ERR_OK;
21497dc5e69SMatthias Ringwald 
21597dc5e69SMatthias Ringwald     // inc refcount
21697dc5e69SMatthias Ringwald     pbuf_ref( p );
21797dc5e69SMatthias Ringwald 
218*917f809aSMatthias Ringwald     // queue empty now?
219*917f809aSMatthias Ringwald     int queue_empty = bnep_lwip_outgoing_packets_empty();
220*917f809aSMatthias Ringwald 
22197dc5e69SMatthias Ringwald     // queue up
222*917f809aSMatthias Ringwald     bnep_lwip_outgoing_queue_packet(p);
22397dc5e69SMatthias Ringwald 
224*917f809aSMatthias Ringwald     // trigger processing if queue was empty (might be new packet)
225*917f809aSMatthias Ringwald     if (queue_empty){
226*917f809aSMatthias Ringwald         bnep_lwip_trigger_outgoing_process();
227*917f809aSMatthias Ringwald     }
22897dc5e69SMatthias Ringwald 
229*917f809aSMatthias Ringwald     return ERR_OK;
23097dc5e69SMatthias Ringwald }
23197dc5e69SMatthias Ringwald 
23297dc5e69SMatthias Ringwald /**
23397dc5e69SMatthias Ringwald  * Should be called at the beginning of the program to set up the
23497dc5e69SMatthias Ringwald  * network interface. It calls the function low_level_init() to do the
23597dc5e69SMatthias Ringwald  * actual setup of the hardware.
23697dc5e69SMatthias Ringwald  *
23797dc5e69SMatthias Ringwald  * This function should be passed as a parameter to netif_add().
23897dc5e69SMatthias Ringwald  *
23997dc5e69SMatthias Ringwald  * @param netif the lwip network interface structure for this ethernetif
24097dc5e69SMatthias Ringwald  * @return ERR_OK if the loopif is initialized
24197dc5e69SMatthias Ringwald  *         ERR_MEM if private data couldn't be allocated
24297dc5e69SMatthias Ringwald  *         any other err_t on error
24397dc5e69SMatthias Ringwald  */
24497dc5e69SMatthias Ringwald 
24597dc5e69SMatthias Ringwald static err_t bnep_lwip_netif_init(struct netif *netif){
24697dc5e69SMatthias Ringwald 
24797dc5e69SMatthias Ringwald     // interface short name
24897dc5e69SMatthias Ringwald     netif->name[0] = IFNAME0;
24997dc5e69SMatthias Ringwald     netif->name[1] = IFNAME1;
25097dc5e69SMatthias Ringwald 
25197dc5e69SMatthias Ringwald     // mtu
25297dc5e69SMatthias Ringwald     netif->mtu = 1600;
25397dc5e69SMatthias Ringwald 
25497dc5e69SMatthias Ringwald     /* device capabilities */
25597dc5e69SMatthias Ringwald     netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
25697dc5e69SMatthias Ringwald 
25797dc5e69SMatthias Ringwald     /* We directly use etharp_output() here to save a function call.
25897dc5e69SMatthias Ringwald      * You can instead declare your own function an call etharp_output()
25997dc5e69SMatthias Ringwald      * from it if you have to do some checks before sending (e.g. if link
26097dc5e69SMatthias Ringwald      * is available...)
26197dc5e69SMatthias Ringwald      */
26297dc5e69SMatthias Ringwald     netif->output = etharp_output;
26397dc5e69SMatthias Ringwald #if LWIP_IPV6
26497dc5e69SMatthias Ringwald     netif->output_ip6 = ethip6_output;
26597dc5e69SMatthias Ringwald #endif
26697dc5e69SMatthias Ringwald     netif->linkoutput = low_level_output;
26797dc5e69SMatthias Ringwald 
26897dc5e69SMatthias Ringwald     return ERR_OK;
26997dc5e69SMatthias Ringwald }
27097dc5e69SMatthias Ringwald 
27197dc5e69SMatthias Ringwald static int bnep_lwip_netif_up(bd_addr_t network_address){
27297dc5e69SMatthias Ringwald     log_info("bnep_lwip_netif_up start addr %s", bd_addr_to_str(network_address));
27397dc5e69SMatthias Ringwald 
27497dc5e69SMatthias Ringwald     // set mac address
27597dc5e69SMatthias Ringwald     btstack_netif.hwaddr_len = 6;
27697dc5e69SMatthias Ringwald     memcpy(btstack_netif.hwaddr, network_address, 6);
27797dc5e69SMatthias Ringwald 
27897dc5e69SMatthias Ringwald     // link is up
27997dc5e69SMatthias Ringwald     btstack_netif.flags |= NETIF_FLAG_LINK_UP;
28097dc5e69SMatthias Ringwald 
28197dc5e69SMatthias Ringwald     // if up
28297dc5e69SMatthias Ringwald     netif_set_up(&btstack_netif);
28397dc5e69SMatthias Ringwald 
28497dc5e69SMatthias Ringwald     return 0;
28597dc5e69SMatthias Ringwald }
28697dc5e69SMatthias Ringwald 
28797dc5e69SMatthias Ringwald /**
28897dc5e69SMatthias Ringwald  * @brief Bring up network interfacd
28997dc5e69SMatthias Ringwald  * @param network_address
29097dc5e69SMatthias Ringwald  * @return 0 if ok
29197dc5e69SMatthias Ringwald  */
29297dc5e69SMatthias Ringwald static int bnep_lwip_netif_down(void){
29397dc5e69SMatthias Ringwald     log_info("bnep_lwip_netif_down");
29497dc5e69SMatthias Ringwald 
29597dc5e69SMatthias Ringwald     // link is down
29697dc5e69SMatthias Ringwald     btstack_netif.flags &= ~NETIF_FLAG_LINK_UP;
29797dc5e69SMatthias Ringwald 
29897dc5e69SMatthias Ringwald     netif_set_down(&btstack_netif);
29997dc5e69SMatthias Ringwald     return 0;
30097dc5e69SMatthias Ringwald }
30197dc5e69SMatthias Ringwald 
30297dc5e69SMatthias Ringwald /**
30397dc5e69SMatthias Ringwald  * @brief Forward packet to TCP/IP stack
30497dc5e69SMatthias Ringwald  * @param packet
30597dc5e69SMatthias Ringwald  * @param size
30697dc5e69SMatthias Ringwald  */
30797dc5e69SMatthias Ringwald static void bnep_lwip_netif_process_packet(const uint8_t * packet, uint16_t size){
30897dc5e69SMatthias Ringwald 
30997dc5e69SMatthias Ringwald     /* We allocate a pbuf chain of pbufs from the pool. */
31097dc5e69SMatthias Ringwald     struct pbuf * p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
31197dc5e69SMatthias Ringwald     log_debug("bnep_lwip_netif_process_packet, pbuf_alloc = %p", p);
31297dc5e69SMatthias Ringwald 
31397dc5e69SMatthias Ringwald     if (!p) return;
31497dc5e69SMatthias Ringwald 
31597dc5e69SMatthias Ringwald     /* store packet in pbuf chain */
31697dc5e69SMatthias Ringwald     struct pbuf * q = p;
31797dc5e69SMatthias Ringwald     while (q != NULL && size){
31897dc5e69SMatthias Ringwald         memcpy(q->payload, packet, q->len);
31997dc5e69SMatthias Ringwald         packet += q->len;
32097dc5e69SMatthias Ringwald         size   -= q->len;
32197dc5e69SMatthias Ringwald         q = q->next;
32297dc5e69SMatthias Ringwald     }
32397dc5e69SMatthias Ringwald 
32497dc5e69SMatthias Ringwald     if (size != 0){
32597dc5e69SMatthias Ringwald         log_error("failed to copy data into pbuf");
326*917f809aSMatthias Ringwald         bnep_lwip_free_pbuf(p);
32797dc5e69SMatthias Ringwald         return;
32897dc5e69SMatthias Ringwald     }
32997dc5e69SMatthias Ringwald 
33097dc5e69SMatthias Ringwald     /* pass all packets to ethernet_input, which decides what packets it supports */
331*917f809aSMatthias Ringwald     int res = btstack_netif.input(p, &btstack_netif);
332*917f809aSMatthias Ringwald     if (res != ERR_OK){
33397dc5e69SMatthias Ringwald         log_error("bnep_lwip_netif_process_packet: IP input error\n");
334*917f809aSMatthias Ringwald         bnep_lwip_free_pbuf(p);
33597dc5e69SMatthias Ringwald         p = NULL;
33697dc5e69SMatthias Ringwald     }
33797dc5e69SMatthias Ringwald }
33897dc5e69SMatthias Ringwald 
33997dc5e69SMatthias Ringwald 
34097dc5e69SMatthias Ringwald // BNEP Functions & Handler
34197dc5e69SMatthias Ringwald 
3420be141aeSMatthias Ringwald #if NO_SYS
34397dc5e69SMatthias Ringwald static void bnep_lwip_timeout_handler(btstack_timer_source_t * ts){
34497dc5e69SMatthias Ringwald 
34597dc5e69SMatthias Ringwald     // process lwIP timers
34697dc5e69SMatthias Ringwald     sys_check_timeouts();
34797dc5e69SMatthias Ringwald 
34897dc5e69SMatthias Ringwald     // check if link is still up
34997dc5e69SMatthias Ringwald     if ((btstack_netif.flags & NETIF_FLAG_LINK_UP) == 0) return;
35097dc5e69SMatthias Ringwald 
35197dc5e69SMatthias Ringwald     // restart timer
35297dc5e69SMatthias Ringwald     btstack_run_loop_set_timer(ts, LWIP_TIMER_INTERVAL_MS);
35397dc5e69SMatthias Ringwald     btstack_run_loop_add_timer(ts);
35497dc5e69SMatthias Ringwald }
3550be141aeSMatthias Ringwald #endif
35697dc5e69SMatthias Ringwald 
357*917f809aSMatthias Ringwald static void bnep_lwip_outgoing_process(void * arg){
358*917f809aSMatthias Ringwald     UNUSED(arg);
359*917f809aSMatthias Ringwald 
360*917f809aSMatthias Ringwald     // previous packet not sent yet
361*917f809aSMatthias Ringwald     if (bnep_lwip_outgoing_next_packet) return;
362*917f809aSMatthias Ringwald 
363*917f809aSMatthias Ringwald     bnep_lwip_outgoing_next_packet = bnep_lwip_outgoing_pop_packet();
364*917f809aSMatthias Ringwald 
365*917f809aSMatthias Ringwald     // request can send now
366*917f809aSMatthias Ringwald     bnep_request_can_send_now_event(bnep_cid);
367*917f809aSMatthias Ringwald }
368*917f809aSMatthias Ringwald 
36997dc5e69SMatthias Ringwald static void bnep_lwip_send_packet(void){
37097dc5e69SMatthias Ringwald     if (bnep_lwip_outgoing_next_packet == NULL){
37197dc5e69SMatthias Ringwald         log_error("CAN SEND NOW, but now packet queued");
3720be141aeSMatthias Ringwald         return;
37397dc5e69SMatthias Ringwald     }
37497dc5e69SMatthias Ringwald 
37597dc5e69SMatthias Ringwald     // flatten into our buffer
37697dc5e69SMatthias Ringwald     uint32_t len = btstack_min(sizeof(btstack_network_outgoing_buffer), bnep_lwip_outgoing_next_packet->tot_len);
37797dc5e69SMatthias Ringwald     pbuf_copy_partial(bnep_lwip_outgoing_next_packet, btstack_network_outgoing_buffer, len, 0);
37897dc5e69SMatthias Ringwald     bnep_send(bnep_cid, (uint8_t*) btstack_network_outgoing_buffer, len);
37997dc5e69SMatthias Ringwald }
38097dc5e69SMatthias Ringwald 
38197dc5e69SMatthias Ringwald static void bnep_lwip_packet_sent(void){
38297dc5e69SMatthias Ringwald     log_debug("bnep_lwip_packet_sent: %p", bnep_lwip_outgoing_next_packet);
38397dc5e69SMatthias Ringwald 
38497dc5e69SMatthias Ringwald     // release current packet
38597dc5e69SMatthias Ringwald     bnep_lwip_outgoing_packet_processed();
38697dc5e69SMatthias Ringwald 
38797dc5e69SMatthias Ringwald     // more ?
38897dc5e69SMatthias Ringwald     if (bnep_lwip_outgoing_packets_empty()) return;
38997dc5e69SMatthias Ringwald     bnep_lwip_trigger_outgoing_process();
39097dc5e69SMatthias Ringwald }
39197dc5e69SMatthias Ringwald 
39297dc5e69SMatthias Ringwald static void bnep_lwip_discard_packets(void){
39397dc5e69SMatthias Ringwald     // discard current packet
39497dc5e69SMatthias Ringwald     if (bnep_lwip_outgoing_next_packet){
39597dc5e69SMatthias Ringwald         bnep_lwip_outgoing_packet_processed();
39697dc5e69SMatthias Ringwald     }
39797dc5e69SMatthias Ringwald 
39897dc5e69SMatthias Ringwald     // reset queue
399*917f809aSMatthias Ringwald     bnep_lwip_outgoing_reset_queue();
40097dc5e69SMatthias Ringwald }
40197dc5e69SMatthias Ringwald 
40297dc5e69SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
40397dc5e69SMatthias Ringwald {
40497dc5e69SMatthias Ringwald /* LISTING_PAUSE */
40597dc5e69SMatthias Ringwald     UNUSED(channel);
40697dc5e69SMatthias Ringwald 
40797dc5e69SMatthias Ringwald     bd_addr_t local_addr;
40897dc5e69SMatthias Ringwald 
40997dc5e69SMatthias Ringwald     switch (packet_type) {
41097dc5e69SMatthias Ringwald         case HCI_EVENT_PACKET:
41197dc5e69SMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
41297dc5e69SMatthias Ringwald 
41397dc5e69SMatthias Ringwald                 /* @text BNEP_EVENT_CHANNEL_OPENED is received after a BNEP connection was established or
41497dc5e69SMatthias Ringwald                  * or when the connection fails. The status field returns the error code.
41597dc5e69SMatthias Ringwald                  *
41697dc5e69SMatthias Ringwald                  * The TAP network interface is then configured. A data source is set up and registered with the
41797dc5e69SMatthias Ringwald                  * run loop to receive Ethernet packets from the TAP interface.
41897dc5e69SMatthias Ringwald                  *
41997dc5e69SMatthias Ringwald                  * The event contains both the source and destination UUIDs, as well as the MTU for this connection and
42097dc5e69SMatthias Ringwald                  * the BNEP Channel ID, which is used for sending Ethernet packets over BNEP.
42197dc5e69SMatthias Ringwald                  */
42297dc5e69SMatthias Ringwald                 case BNEP_EVENT_CHANNEL_OPENED:
42397dc5e69SMatthias Ringwald                     if (bnep_event_channel_opened_get_status(packet) != 0) break;
42497dc5e69SMatthias Ringwald 
42597dc5e69SMatthias Ringwald                     bnep_cid = bnep_event_channel_opened_get_bnep_cid(packet);
42697dc5e69SMatthias Ringwald 
42797dc5e69SMatthias Ringwald                     /* Setup network interface */
42897dc5e69SMatthias Ringwald                     gap_local_bd_addr(local_addr);
42997dc5e69SMatthias Ringwald                     bnep_lwip_netif_up(local_addr);
43097dc5e69SMatthias Ringwald 
43197dc5e69SMatthias Ringwald #if NO_SYS
43297dc5e69SMatthias Ringwald                     // start timer
43397dc5e69SMatthias Ringwald                     btstack_run_loop_set_timer_handler(&bnep_lwip_timer, bnep_lwip_timeout_handler);
43497dc5e69SMatthias Ringwald                     btstack_run_loop_set_timer(&bnep_lwip_timer, LWIP_TIMER_INTERVAL_MS);
43597dc5e69SMatthias Ringwald                     btstack_run_loop_add_timer(&bnep_lwip_timer);
43697dc5e69SMatthias Ringwald #endif
43797dc5e69SMatthias Ringwald                     break;
43897dc5e69SMatthias Ringwald 
43997dc5e69SMatthias Ringwald                 /* @text BNEP_EVENT_CHANNEL_CLOSED is received when the connection gets closed.
44097dc5e69SMatthias Ringwald                  */
44197dc5e69SMatthias Ringwald                 case BNEP_EVENT_CHANNEL_CLOSED:
44297dc5e69SMatthias Ringwald                     bnep_cid = 0;
44397dc5e69SMatthias Ringwald                     bnep_lwip_discard_packets();
44497dc5e69SMatthias Ringwald 
44597dc5e69SMatthias Ringwald                     // Mark Link as Down
44697dc5e69SMatthias Ringwald                     bnep_lwip_netif_down();
44797dc5e69SMatthias Ringwald                     break;
44897dc5e69SMatthias Ringwald 
44997dc5e69SMatthias Ringwald                 /* @text BNEP_EVENT_CAN_SEND_NOW indicates that a new packet can be send. This triggers the send of a
45097dc5e69SMatthias Ringwald                  * stored network packet. The tap datas source can be enabled again
45197dc5e69SMatthias Ringwald                  */
45297dc5e69SMatthias Ringwald                 case BNEP_EVENT_CAN_SEND_NOW:
45397dc5e69SMatthias Ringwald                     bnep_lwip_send_packet();
45497dc5e69SMatthias Ringwald                     bnep_lwip_packet_sent();
45597dc5e69SMatthias Ringwald                     break;
45697dc5e69SMatthias Ringwald 
45797dc5e69SMatthias Ringwald                 default:
45897dc5e69SMatthias Ringwald                     break;
45997dc5e69SMatthias Ringwald             }
46097dc5e69SMatthias Ringwald             break;
46197dc5e69SMatthias Ringwald 
46297dc5e69SMatthias Ringwald         /* @text Ethernet packets from the remote device are received in the packet handler with type BNEP_DATA_PACKET.
46397dc5e69SMatthias Ringwald          * It is forwarded to the TAP interface.
46497dc5e69SMatthias Ringwald          */
46597dc5e69SMatthias Ringwald         case BNEP_DATA_PACKET:
46697dc5e69SMatthias Ringwald             if (bnep_cid == 0) break;
46797dc5e69SMatthias Ringwald             // Write out the ethernet frame to the network interface
46897dc5e69SMatthias Ringwald             bnep_lwip_netif_process_packet(packet, size);
46997dc5e69SMatthias Ringwald             break;
47097dc5e69SMatthias Ringwald 
47197dc5e69SMatthias Ringwald         default:
47297dc5e69SMatthias Ringwald             break;
47397dc5e69SMatthias Ringwald     }
47497dc5e69SMatthias Ringwald 
47597dc5e69SMatthias Ringwald     // forward to app
47697dc5e69SMatthias Ringwald     if (!client_handler) return;
47797dc5e69SMatthias Ringwald     (*client_handler)(packet_type, channel, packet, size);
47897dc5e69SMatthias Ringwald }
47997dc5e69SMatthias Ringwald 
48097dc5e69SMatthias Ringwald /// API
48197dc5e69SMatthias Ringwald 
48297dc5e69SMatthias Ringwald /**
48397dc5e69SMatthias Ringwald  * @brief Initialize network interface
48497dc5e69SMatthias Ringwald  * @param send_packet_callback
48597dc5e69SMatthias Ringwald  */
48697dc5e69SMatthias Ringwald void bnep_lwip_init(void){
48797dc5e69SMatthias Ringwald 
48897dc5e69SMatthias Ringwald     // set up outgoing queue
489*917f809aSMatthias Ringwald     int error = bnep_lwip_outgoing_init_queue();
490*917f809aSMatthias Ringwald     if (error) return;
49197dc5e69SMatthias Ringwald 
49297dc5e69SMatthias Ringwald     ip4_addr_t fsl_netif0_ipaddr, fsl_netif0_netmask, fsl_netif0_gw;
49397dc5e69SMatthias Ringwald #if 0
49497dc5e69SMatthias Ringwald     // when using DHCP Client, no address
49597dc5e69SMatthias Ringwald     IP4_ADDR(&fsl_netif0_ipaddr, 0U, 0U, 0U, 0U);
49697dc5e69SMatthias Ringwald     IP4_ADDR(&fsl_netif0_netmask, 0U, 0U, 0U, 0U);
49797dc5e69SMatthias Ringwald #else
49897dc5e69SMatthias Ringwald     // when playing DHCP Server, set address
49997dc5e69SMatthias Ringwald     IP4_ADDR(&fsl_netif0_ipaddr, 192U, 168U, 7U, 1U);
50097dc5e69SMatthias Ringwald     IP4_ADDR(&fsl_netif0_netmask, 255U, 255U, 255U, 0U);
50197dc5e69SMatthias Ringwald #endif
50297dc5e69SMatthias Ringwald     IP4_ADDR(&fsl_netif0_gw, 0U, 0U, 0U, 0U);
50397dc5e69SMatthias Ringwald 
50497dc5e69SMatthias Ringwald     // input function differs for sys vs nosys
50597dc5e69SMatthias Ringwald     netif_input_fn input_function;
50697dc5e69SMatthias Ringwald #if NO_SYS
50797dc5e69SMatthias Ringwald     input_function = ethernet_input;
50897dc5e69SMatthias Ringwald #else
50997dc5e69SMatthias Ringwald     input_function = tcpip_input;
51097dc5e69SMatthias Ringwald #endif
51197dc5e69SMatthias Ringwald 
51297dc5e69SMatthias Ringwald     netif_add(&btstack_netif, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, NULL, bnep_lwip_netif_init, input_function);
51397dc5e69SMatthias Ringwald     netif_set_default(&btstack_netif);
51497dc5e69SMatthias Ringwald }
51597dc5e69SMatthias Ringwald 
51697dc5e69SMatthias Ringwald /**
51797dc5e69SMatthias Ringwald  * @brief Register packet handler for BNEP events
51897dc5e69SMatthias Ringwald  */
51997dc5e69SMatthias Ringwald void bnep_lwip_register_packet_handler(btstack_packet_handler_t handler){
52097dc5e69SMatthias Ringwald     client_handler = handler;
52197dc5e69SMatthias Ringwald }
52297dc5e69SMatthias Ringwald 
52397dc5e69SMatthias Ringwald /**
52497dc5e69SMatthias Ringwald  * @brief Register BNEP service
52597dc5e69SMatthias Ringwald  * @brief Same as benp_register_service, but bnep lwip adapter handles all events
52697dc5e69SMatthias Ringwald  * @param service_uuid
52797dc5e69SMatthias Ringwald  * @Param max_frame_size
52897dc5e69SMatthias Ringwald  */
52997dc5e69SMatthias Ringwald uint8_t bnep_lwip_register_service(uint16_t service_uuid, uint16_t max_frame_size){
53097dc5e69SMatthias Ringwald     return bnep_register_service(packet_handler, service_uuid, max_frame_size);
53197dc5e69SMatthias Ringwald }
532