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 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH 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 56a02039edSMatthias Ringwald #include "btstack_bool.h" 57a02039edSMatthias Ringwald 580be141aeSMatthias Ringwald #if LWIP_IPV6 590be141aeSMatthias Ringwald #include "lwip/ethip6.h" 600be141aeSMatthias Ringwald #endif 6197dc5e69SMatthias Ringwald 6297dc5e69SMatthias Ringwald #include "bnep_lwip.h" 6397dc5e69SMatthias Ringwald 6497dc5e69SMatthias Ringwald #include "btstack_config.h" 6597dc5e69SMatthias Ringwald #include "btstack_debug.h" 6697dc5e69SMatthias Ringwald #include "btstack_util.h" 6797dc5e69SMatthias Ringwald #include "btstack_event.h" 6897dc5e69SMatthias Ringwald #include "classic/bnep.h" 6997dc5e69SMatthias Ringwald 7097dc5e69SMatthias Ringwald #if NO_SYS 7197dc5e69SMatthias Ringwald #include "btstack_ring_buffer.h" 7297dc5e69SMatthias Ringwald #include "btstack_run_loop.h" 7397dc5e69SMatthias Ringwald #include "lwip/timeouts.h" 7497dc5e69SMatthias Ringwald #else 75*398f8a18SPeter Harper #ifdef HAVE_FREERTOS_INCLUDE_PREFIX 76*398f8a18SPeter Harper #include "freertos/FreeRTOS.h" 77*398f8a18SPeter Harper #include "freertos/queue.h" 78*398f8a18SPeter Harper #else 79*398f8a18SPeter Harper #include "FreeRTOS.h" 80*398f8a18SPeter Harper #include "queue.h" 81*398f8a18SPeter Harper #endif 8297dc5e69SMatthias Ringwald #endif 8397dc5e69SMatthias Ringwald 8497dc5e69SMatthias Ringwald /* Short name used for netif in lwIP */ 8597dc5e69SMatthias Ringwald #define IFNAME0 'b' 8697dc5e69SMatthias Ringwald #define IFNAME1 't' 8797dc5e69SMatthias Ringwald 8897dc5e69SMatthias Ringwald #define LWIP_TIMER_INTERVAL_MS 25 8997dc5e69SMatthias Ringwald 9097dc5e69SMatthias Ringwald static void bnep_lwip_outgoing_process(void * arg); 91a02039edSMatthias Ringwald static bool bnep_lwip_outgoing_packets_empty(void); 9297dc5e69SMatthias Ringwald 9397dc5e69SMatthias Ringwald // lwip data 9497dc5e69SMatthias Ringwald static struct netif btstack_netif; 9597dc5e69SMatthias Ringwald 9697dc5e69SMatthias Ringwald // outgoing queue 9797dc5e69SMatthias Ringwald #if NO_SYS 9897dc5e69SMatthias Ringwald static uint8_t bnep_lwip_outgoing_queue_storage[ (TCP_SND_QUEUELEN+1) * sizeof(struct pbuf *)]; 9997dc5e69SMatthias Ringwald static btstack_ring_buffer_t bnep_lwip_outgoing_queue; 10097dc5e69SMatthias Ringwald #else 10197dc5e69SMatthias Ringwald static QueueHandle_t bnep_lwip_outgoing_queue; 10297dc5e69SMatthias Ringwald #endif 1035da46df6SMatthias Ringwald btstack_context_callback_registration_t bnep_lwip_outgoing_callback_registration; 10497dc5e69SMatthias Ringwald 1050be141aeSMatthias Ringwald #if NO_SYS 1060be141aeSMatthias Ringwald static btstack_timer_source_t bnep_lwip_timer; 1070be141aeSMatthias Ringwald #endif 10897dc5e69SMatthias Ringwald 10997dc5e69SMatthias Ringwald // bnep data 11097dc5e69SMatthias Ringwald static uint16_t bnep_cid; 11197dc5e69SMatthias Ringwald static btstack_packet_handler_t client_handler; 11297dc5e69SMatthias Ringwald 11397dc5e69SMatthias Ringwald // next packet only modified from btstack context 11497dc5e69SMatthias Ringwald static struct pbuf * bnep_lwip_outgoing_next_packet; 11597dc5e69SMatthias Ringwald 11697dc5e69SMatthias Ringwald // temp buffer to unchain buffer 11797dc5e69SMatthias Ringwald static uint8_t btstack_network_outgoing_buffer[HCI_ACL_PAYLOAD_SIZE]; 11897dc5e69SMatthias Ringwald 119917f809aSMatthias Ringwald // helper functions to hide NO_SYS vs. FreeRTOS implementations 120917f809aSMatthias Ringwald 121917f809aSMatthias Ringwald static int bnep_lwip_outgoing_init_queue(void){ 122917f809aSMatthias Ringwald #if NO_SYS 123917f809aSMatthias Ringwald btstack_ring_buffer_init(&bnep_lwip_outgoing_queue, bnep_lwip_outgoing_queue_storage, sizeof(bnep_lwip_outgoing_queue_storage)); 124917f809aSMatthias Ringwald #else 125917f809aSMatthias Ringwald bnep_lwip_outgoing_queue = xQueueCreate(TCP_SND_QUEUELEN, sizeof(struct pbuf *)); 126917f809aSMatthias Ringwald if (bnep_lwip_outgoing_queue == NULL){ 127917f809aSMatthias Ringwald log_error("cannot allocate outgoing queue"); 128917f809aSMatthias Ringwald return 1; 129917f809aSMatthias Ringwald } 130917f809aSMatthias Ringwald #endif 131917f809aSMatthias Ringwald return 0; 132917f809aSMatthias Ringwald } 133917f809aSMatthias Ringwald 134917f809aSMatthias Ringwald static void bnep_lwip_outgoing_reset_queue(void){ 135917f809aSMatthias Ringwald #if NO_SYS 136917f809aSMatthias Ringwald btstack_ring_buffer_init(&bnep_lwip_outgoing_queue, bnep_lwip_outgoing_queue_storage, sizeof(bnep_lwip_outgoing_queue_storage)); 137917f809aSMatthias Ringwald #else 138917f809aSMatthias Ringwald xQueueReset(bnep_lwip_outgoing_queue); 139917f809aSMatthias Ringwald #endif 140917f809aSMatthias Ringwald } 141917f809aSMatthias Ringwald 142917f809aSMatthias Ringwald static void bnep_lwip_outgoing_queue_packet(struct pbuf *p){ 143917f809aSMatthias Ringwald #if NO_SYS 144917f809aSMatthias Ringwald // queue up 14545e58ddaSMatthias Ringwald btstack_ring_buffer_write(&bnep_lwip_outgoing_queue, (uint8_t *) &p, sizeof(struct pbuf *)); 146917f809aSMatthias Ringwald #else 147917f809aSMatthias Ringwald // queue up 148917f809aSMatthias Ringwald xQueueSendToBack(bnep_lwip_outgoing_queue, &p, portMAX_DELAY); 149917f809aSMatthias Ringwald #endif 150917f809aSMatthias Ringwald } 151917f809aSMatthias Ringwald 152917f809aSMatthias Ringwald static struct pbuf * bnep_lwip_outgoing_pop_packet(void){ 153917f809aSMatthias Ringwald struct pbuf * p = NULL; 154917f809aSMatthias Ringwald #if NO_SYS 155917f809aSMatthias Ringwald uint32_t bytes_read = 0; 15645e58ddaSMatthias Ringwald btstack_ring_buffer_read(&bnep_lwip_outgoing_queue, (uint8_t *) &p, sizeof(struct pbuf *), &bytes_read); 157917f809aSMatthias Ringwald (void) bytes_read; 158917f809aSMatthias Ringwald #else 159917f809aSMatthias Ringwald xQueueReceive(bnep_lwip_outgoing_queue, &p, portMAX_DELAY); 160917f809aSMatthias Ringwald #endif 161917f809aSMatthias Ringwald return p; 162917f809aSMatthias Ringwald } 163917f809aSMatthias Ringwald 164a02039edSMatthias Ringwald static bool bnep_lwip_outgoing_packets_empty(void){ 165917f809aSMatthias Ringwald #if NO_SYS 166a02039edSMatthias Ringwald return btstack_ring_buffer_empty(&bnep_lwip_outgoing_queue) != 0; 167917f809aSMatthias Ringwald #else 168917f809aSMatthias Ringwald return uxQueueMessagesWaiting(bnep_lwip_outgoing_queue) == 0; 169917f809aSMatthias Ringwald #endif 170917f809aSMatthias Ringwald } 171917f809aSMatthias Ringwald 172917f809aSMatthias Ringwald static void bnep_lwip_free_pbuf(struct pbuf * p){ 173917f809aSMatthias Ringwald #if NO_SYS 174917f809aSMatthias Ringwald // release buffer / decrease refcount 175917f809aSMatthias Ringwald pbuf_free(p); 176917f809aSMatthias Ringwald #else 177917f809aSMatthias Ringwald // release buffer / decrease refcount 178917f809aSMatthias Ringwald pbuf_free_callback(p); 179917f809aSMatthias Ringwald #endif 180917f809aSMatthias Ringwald } 181917f809aSMatthias Ringwald 182917f809aSMatthias Ringwald static void bnep_lwip_outgoing_packet_processed(void){ 183917f809aSMatthias Ringwald // free pbuf 184917f809aSMatthias Ringwald bnep_lwip_free_pbuf(bnep_lwip_outgoing_next_packet); 185917f809aSMatthias Ringwald // mark as done 186917f809aSMatthias Ringwald bnep_lwip_outgoing_next_packet = NULL; 187917f809aSMatthias Ringwald } 188917f809aSMatthias Ringwald 189917f809aSMatthias Ringwald static void bnep_lwip_trigger_outgoing_process(void){ 190917f809aSMatthias Ringwald #if NO_SYS 191917f809aSMatthias Ringwald bnep_lwip_outgoing_process(NULL); 192917f809aSMatthias Ringwald #else 1935da46df6SMatthias Ringwald bnep_lwip_outgoing_callback_registration.callback = &bnep_lwip_outgoing_process; 1945da46df6SMatthias Ringwald btstack_run_loop_execute_on_main_thread(&bnep_lwip_outgoing_callback_registration); 195917f809aSMatthias Ringwald #endif 196917f809aSMatthias Ringwald } 197917f809aSMatthias Ringwald 19897dc5e69SMatthias Ringwald /// lwIP functions 19997dc5e69SMatthias Ringwald 20097dc5e69SMatthias Ringwald /** 20197dc5e69SMatthias Ringwald * This function should do the actual transmission of the packet. The packet is 20297dc5e69SMatthias Ringwald * contained in the pbuf that is passed to the function. This pbuf 20397dc5e69SMatthias Ringwald * might be chained. 20497dc5e69SMatthias Ringwald * 20597dc5e69SMatthias Ringwald * @param netif the lwip network interface structure 20697dc5e69SMatthias Ringwald * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) 20797dc5e69SMatthias Ringwald * @return ERR_OK if the packet could be sent 20897dc5e69SMatthias Ringwald * an err_t value if the packet couldn't be sent 20997dc5e69SMatthias Ringwald * 21097dc5e69SMatthias Ringwald * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to 21197dc5e69SMatthias Ringwald * strange results. You might consider waiting for space in the DMA queue 21297dc5e69SMatthias Ringwald * to become availale since the stack doesn't retry to send a packet 21397dc5e69SMatthias Ringwald * dropped because of memory failure (except for the TCP timers). 21497dc5e69SMatthias Ringwald */ 215917f809aSMatthias Ringwald 21697dc5e69SMatthias Ringwald static err_t low_level_output( struct netif *netif, struct pbuf *p ){ 21797dc5e69SMatthias Ringwald UNUSED(netif); 21897dc5e69SMatthias Ringwald 219917f809aSMatthias Ringwald log_info("low_level_output: packet %p, len %u, total len %u ", p, p->len, p->tot_len); 22097dc5e69SMatthias Ringwald 22197dc5e69SMatthias Ringwald // bnep up? 22297dc5e69SMatthias Ringwald if (bnep_cid == 0) return ERR_OK; 22397dc5e69SMatthias Ringwald 22497dc5e69SMatthias Ringwald // inc refcount 22597dc5e69SMatthias Ringwald pbuf_ref( p ); 22697dc5e69SMatthias Ringwald 227917f809aSMatthias Ringwald // queue empty now? 228917f809aSMatthias Ringwald int queue_empty = bnep_lwip_outgoing_packets_empty(); 229917f809aSMatthias Ringwald 23097dc5e69SMatthias Ringwald // queue up 231917f809aSMatthias Ringwald bnep_lwip_outgoing_queue_packet(p); 23297dc5e69SMatthias Ringwald 233917f809aSMatthias Ringwald // trigger processing if queue was empty (might be new packet) 234917f809aSMatthias Ringwald if (queue_empty){ 235917f809aSMatthias Ringwald bnep_lwip_trigger_outgoing_process(); 236917f809aSMatthias Ringwald } 23797dc5e69SMatthias Ringwald 238917f809aSMatthias Ringwald return ERR_OK; 23997dc5e69SMatthias Ringwald } 24097dc5e69SMatthias Ringwald 24197dc5e69SMatthias Ringwald /** 24297dc5e69SMatthias Ringwald * Should be called at the beginning of the program to set up the 24397dc5e69SMatthias Ringwald * network interface. It calls the function low_level_init() to do the 24497dc5e69SMatthias Ringwald * actual setup of the hardware. 24597dc5e69SMatthias Ringwald * 24697dc5e69SMatthias Ringwald * This function should be passed as a parameter to netif_add(). 24797dc5e69SMatthias Ringwald * 24897dc5e69SMatthias Ringwald * @param netif the lwip network interface structure for this ethernetif 24997dc5e69SMatthias Ringwald * @return ERR_OK if the loopif is initialized 25097dc5e69SMatthias Ringwald * ERR_MEM if private data couldn't be allocated 25197dc5e69SMatthias Ringwald * any other err_t on error 25297dc5e69SMatthias Ringwald */ 25397dc5e69SMatthias Ringwald 25497dc5e69SMatthias Ringwald static err_t bnep_lwip_netif_init(struct netif *netif){ 25597dc5e69SMatthias Ringwald 25697dc5e69SMatthias Ringwald // interface short name 25797dc5e69SMatthias Ringwald netif->name[0] = IFNAME0; 25897dc5e69SMatthias Ringwald netif->name[1] = IFNAME1; 25997dc5e69SMatthias Ringwald 26097dc5e69SMatthias Ringwald // mtu 26197dc5e69SMatthias Ringwald netif->mtu = 1600; 26297dc5e69SMatthias Ringwald 26397dc5e69SMatthias Ringwald /* device capabilities */ 26497dc5e69SMatthias Ringwald netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; 26597dc5e69SMatthias Ringwald 26697dc5e69SMatthias Ringwald /* We directly use etharp_output() here to save a function call. 26797dc5e69SMatthias Ringwald * You can instead declare your own function an call etharp_output() 26897dc5e69SMatthias Ringwald * from it if you have to do some checks before sending (e.g. if link 26997dc5e69SMatthias Ringwald * is available...) 27097dc5e69SMatthias Ringwald */ 27197dc5e69SMatthias Ringwald netif->output = etharp_output; 27297dc5e69SMatthias Ringwald #if LWIP_IPV6 27397dc5e69SMatthias Ringwald netif->output_ip6 = ethip6_output; 27497dc5e69SMatthias Ringwald #endif 27597dc5e69SMatthias Ringwald netif->linkoutput = low_level_output; 27697dc5e69SMatthias Ringwald 27797dc5e69SMatthias Ringwald return ERR_OK; 27897dc5e69SMatthias Ringwald } 27997dc5e69SMatthias Ringwald 28097dc5e69SMatthias Ringwald static int bnep_lwip_netif_up(bd_addr_t network_address){ 28197dc5e69SMatthias Ringwald log_info("bnep_lwip_netif_up start addr %s", bd_addr_to_str(network_address)); 28297dc5e69SMatthias Ringwald 28397dc5e69SMatthias Ringwald // set mac address 28497dc5e69SMatthias Ringwald btstack_netif.hwaddr_len = 6; 28597dc5e69SMatthias Ringwald memcpy(btstack_netif.hwaddr, network_address, 6); 28697dc5e69SMatthias Ringwald 28797dc5e69SMatthias Ringwald // link is up 28897dc5e69SMatthias Ringwald btstack_netif.flags |= NETIF_FLAG_LINK_UP; 28997dc5e69SMatthias Ringwald 29097dc5e69SMatthias Ringwald // if up 29197dc5e69SMatthias Ringwald netif_set_up(&btstack_netif); 29297dc5e69SMatthias Ringwald 29397dc5e69SMatthias Ringwald return 0; 29497dc5e69SMatthias Ringwald } 29597dc5e69SMatthias Ringwald 29697dc5e69SMatthias Ringwald /** 29797dc5e69SMatthias Ringwald * @brief Bring up network interfacd 29897dc5e69SMatthias Ringwald * @param network_address 29997dc5e69SMatthias Ringwald * @return 0 if ok 30097dc5e69SMatthias Ringwald */ 30197dc5e69SMatthias Ringwald static int bnep_lwip_netif_down(void){ 30297dc5e69SMatthias Ringwald log_info("bnep_lwip_netif_down"); 30397dc5e69SMatthias Ringwald 30497dc5e69SMatthias Ringwald // link is down 30597dc5e69SMatthias Ringwald btstack_netif.flags &= ~NETIF_FLAG_LINK_UP; 30697dc5e69SMatthias Ringwald 30797dc5e69SMatthias Ringwald netif_set_down(&btstack_netif); 30897dc5e69SMatthias Ringwald return 0; 30997dc5e69SMatthias Ringwald } 31097dc5e69SMatthias Ringwald 31197dc5e69SMatthias Ringwald /** 31297dc5e69SMatthias Ringwald * @brief Forward packet to TCP/IP stack 31397dc5e69SMatthias Ringwald * @param packet 31497dc5e69SMatthias Ringwald * @param size 31597dc5e69SMatthias Ringwald */ 31697dc5e69SMatthias Ringwald static void bnep_lwip_netif_process_packet(const uint8_t * packet, uint16_t size){ 31797dc5e69SMatthias Ringwald 31897dc5e69SMatthias Ringwald /* We allocate a pbuf chain of pbufs from the pool. */ 31997dc5e69SMatthias Ringwald struct pbuf * p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL); 32097dc5e69SMatthias Ringwald log_debug("bnep_lwip_netif_process_packet, pbuf_alloc = %p", p); 32197dc5e69SMatthias Ringwald 32297dc5e69SMatthias Ringwald if (!p) return; 32397dc5e69SMatthias Ringwald 32497dc5e69SMatthias Ringwald /* store packet in pbuf chain */ 32597dc5e69SMatthias Ringwald struct pbuf * q = p; 32697dc5e69SMatthias Ringwald while (q != NULL && size){ 32797dc5e69SMatthias Ringwald memcpy(q->payload, packet, q->len); 32897dc5e69SMatthias Ringwald packet += q->len; 32997dc5e69SMatthias Ringwald size -= q->len; 33097dc5e69SMatthias Ringwald q = q->next; 33197dc5e69SMatthias Ringwald } 33297dc5e69SMatthias Ringwald 33397dc5e69SMatthias Ringwald if (size != 0){ 33497dc5e69SMatthias Ringwald log_error("failed to copy data into pbuf"); 335917f809aSMatthias Ringwald bnep_lwip_free_pbuf(p); 33697dc5e69SMatthias Ringwald return; 33797dc5e69SMatthias Ringwald } 33897dc5e69SMatthias Ringwald 33997dc5e69SMatthias Ringwald /* pass all packets to ethernet_input, which decides what packets it supports */ 340917f809aSMatthias Ringwald int res = btstack_netif.input(p, &btstack_netif); 341917f809aSMatthias Ringwald if (res != ERR_OK){ 34297dc5e69SMatthias Ringwald log_error("bnep_lwip_netif_process_packet: IP input error\n"); 343917f809aSMatthias Ringwald bnep_lwip_free_pbuf(p); 34497dc5e69SMatthias Ringwald p = NULL; 34597dc5e69SMatthias Ringwald } 34697dc5e69SMatthias Ringwald } 34797dc5e69SMatthias Ringwald 34897dc5e69SMatthias Ringwald 34997dc5e69SMatthias Ringwald // BNEP Functions & Handler 35097dc5e69SMatthias Ringwald 3510be141aeSMatthias Ringwald #if NO_SYS 35297dc5e69SMatthias Ringwald static void bnep_lwip_timeout_handler(btstack_timer_source_t * ts){ 35397dc5e69SMatthias Ringwald 35497dc5e69SMatthias Ringwald // process lwIP timers 35597dc5e69SMatthias Ringwald sys_check_timeouts(); 35697dc5e69SMatthias Ringwald 35797dc5e69SMatthias Ringwald // check if link is still up 35897dc5e69SMatthias Ringwald if ((btstack_netif.flags & NETIF_FLAG_LINK_UP) == 0) return; 35997dc5e69SMatthias Ringwald 36097dc5e69SMatthias Ringwald // restart timer 36197dc5e69SMatthias Ringwald btstack_run_loop_set_timer(ts, LWIP_TIMER_INTERVAL_MS); 36297dc5e69SMatthias Ringwald btstack_run_loop_add_timer(ts); 36397dc5e69SMatthias Ringwald } 3640be141aeSMatthias Ringwald #endif 36597dc5e69SMatthias Ringwald 366917f809aSMatthias Ringwald static void bnep_lwip_outgoing_process(void * arg){ 367917f809aSMatthias Ringwald UNUSED(arg); 368917f809aSMatthias Ringwald 369917f809aSMatthias Ringwald // previous packet not sent yet 370917f809aSMatthias Ringwald if (bnep_lwip_outgoing_next_packet) return; 371917f809aSMatthias Ringwald 372917f809aSMatthias Ringwald bnep_lwip_outgoing_next_packet = bnep_lwip_outgoing_pop_packet(); 373917f809aSMatthias Ringwald 374917f809aSMatthias Ringwald // request can send now 375917f809aSMatthias Ringwald bnep_request_can_send_now_event(bnep_cid); 376917f809aSMatthias Ringwald } 377917f809aSMatthias Ringwald 37897dc5e69SMatthias Ringwald static void bnep_lwip_send_packet(void){ 37997dc5e69SMatthias Ringwald if (bnep_lwip_outgoing_next_packet == NULL){ 38097dc5e69SMatthias Ringwald log_error("CAN SEND NOW, but now packet queued"); 3810be141aeSMatthias Ringwald return; 38297dc5e69SMatthias Ringwald } 38397dc5e69SMatthias Ringwald 38497dc5e69SMatthias Ringwald // flatten into our buffer 38597dc5e69SMatthias Ringwald uint32_t len = btstack_min(sizeof(btstack_network_outgoing_buffer), bnep_lwip_outgoing_next_packet->tot_len); 38697dc5e69SMatthias Ringwald pbuf_copy_partial(bnep_lwip_outgoing_next_packet, btstack_network_outgoing_buffer, len, 0); 38797dc5e69SMatthias Ringwald bnep_send(bnep_cid, (uint8_t*) btstack_network_outgoing_buffer, len); 38897dc5e69SMatthias Ringwald } 38997dc5e69SMatthias Ringwald 39097dc5e69SMatthias Ringwald static void bnep_lwip_packet_sent(void){ 39197dc5e69SMatthias Ringwald log_debug("bnep_lwip_packet_sent: %p", bnep_lwip_outgoing_next_packet); 39297dc5e69SMatthias Ringwald 39397dc5e69SMatthias Ringwald // release current packet 39497dc5e69SMatthias Ringwald bnep_lwip_outgoing_packet_processed(); 39597dc5e69SMatthias Ringwald 39697dc5e69SMatthias Ringwald // more ? 39797dc5e69SMatthias Ringwald if (bnep_lwip_outgoing_packets_empty()) return; 39897dc5e69SMatthias Ringwald bnep_lwip_trigger_outgoing_process(); 39997dc5e69SMatthias Ringwald } 40097dc5e69SMatthias Ringwald 40197dc5e69SMatthias Ringwald static void bnep_lwip_discard_packets(void){ 40297dc5e69SMatthias Ringwald // discard current packet 40397dc5e69SMatthias Ringwald if (bnep_lwip_outgoing_next_packet){ 40497dc5e69SMatthias Ringwald bnep_lwip_outgoing_packet_processed(); 40597dc5e69SMatthias Ringwald } 40697dc5e69SMatthias Ringwald 40797dc5e69SMatthias Ringwald // reset queue 408917f809aSMatthias Ringwald bnep_lwip_outgoing_reset_queue(); 40997dc5e69SMatthias Ringwald } 41097dc5e69SMatthias Ringwald 41197dc5e69SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) 41297dc5e69SMatthias Ringwald { 41397dc5e69SMatthias Ringwald /* LISTING_PAUSE */ 41497dc5e69SMatthias Ringwald UNUSED(channel); 41597dc5e69SMatthias Ringwald 41697dc5e69SMatthias Ringwald bd_addr_t local_addr; 41797dc5e69SMatthias Ringwald 41897dc5e69SMatthias Ringwald switch (packet_type) { 41997dc5e69SMatthias Ringwald case HCI_EVENT_PACKET: 42097dc5e69SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 42197dc5e69SMatthias Ringwald 42297dc5e69SMatthias Ringwald /* @text BNEP_EVENT_CHANNEL_OPENED is received after a BNEP connection was established or 42397dc5e69SMatthias Ringwald * or when the connection fails. The status field returns the error code. 42497dc5e69SMatthias Ringwald * 42597dc5e69SMatthias Ringwald * The TAP network interface is then configured. A data source is set up and registered with the 42697dc5e69SMatthias Ringwald * run loop to receive Ethernet packets from the TAP interface. 42797dc5e69SMatthias Ringwald * 42897dc5e69SMatthias Ringwald * The event contains both the source and destination UUIDs, as well as the MTU for this connection and 42997dc5e69SMatthias Ringwald * the BNEP Channel ID, which is used for sending Ethernet packets over BNEP. 43097dc5e69SMatthias Ringwald */ 43197dc5e69SMatthias Ringwald case BNEP_EVENT_CHANNEL_OPENED: 43297dc5e69SMatthias Ringwald if (bnep_event_channel_opened_get_status(packet) != 0) break; 43397dc5e69SMatthias Ringwald 43497dc5e69SMatthias Ringwald bnep_cid = bnep_event_channel_opened_get_bnep_cid(packet); 43597dc5e69SMatthias Ringwald 43697dc5e69SMatthias Ringwald /* Setup network interface */ 43797dc5e69SMatthias Ringwald gap_local_bd_addr(local_addr); 43897dc5e69SMatthias Ringwald bnep_lwip_netif_up(local_addr); 43997dc5e69SMatthias Ringwald 44097dc5e69SMatthias Ringwald #if NO_SYS 44197dc5e69SMatthias Ringwald // start timer 44297dc5e69SMatthias Ringwald btstack_run_loop_set_timer_handler(&bnep_lwip_timer, bnep_lwip_timeout_handler); 44397dc5e69SMatthias Ringwald btstack_run_loop_set_timer(&bnep_lwip_timer, LWIP_TIMER_INTERVAL_MS); 44497dc5e69SMatthias Ringwald btstack_run_loop_add_timer(&bnep_lwip_timer); 44597dc5e69SMatthias Ringwald #endif 44697dc5e69SMatthias Ringwald break; 44797dc5e69SMatthias Ringwald 44897dc5e69SMatthias Ringwald /* @text BNEP_EVENT_CHANNEL_CLOSED is received when the connection gets closed. 44997dc5e69SMatthias Ringwald */ 45097dc5e69SMatthias Ringwald case BNEP_EVENT_CHANNEL_CLOSED: 45197dc5e69SMatthias Ringwald bnep_cid = 0; 45297dc5e69SMatthias Ringwald bnep_lwip_discard_packets(); 45397dc5e69SMatthias Ringwald 45497dc5e69SMatthias Ringwald // Mark Link as Down 45597dc5e69SMatthias Ringwald bnep_lwip_netif_down(); 45697dc5e69SMatthias Ringwald break; 45797dc5e69SMatthias Ringwald 45897dc5e69SMatthias Ringwald /* @text BNEP_EVENT_CAN_SEND_NOW indicates that a new packet can be send. This triggers the send of a 45997dc5e69SMatthias Ringwald * stored network packet. The tap datas source can be enabled again 46097dc5e69SMatthias Ringwald */ 46197dc5e69SMatthias Ringwald case BNEP_EVENT_CAN_SEND_NOW: 46297dc5e69SMatthias Ringwald bnep_lwip_send_packet(); 46397dc5e69SMatthias Ringwald bnep_lwip_packet_sent(); 46497dc5e69SMatthias Ringwald break; 46597dc5e69SMatthias Ringwald 46697dc5e69SMatthias Ringwald default: 46797dc5e69SMatthias Ringwald break; 46897dc5e69SMatthias Ringwald } 46997dc5e69SMatthias Ringwald break; 47097dc5e69SMatthias Ringwald 47197dc5e69SMatthias Ringwald /* @text Ethernet packets from the remote device are received in the packet handler with type BNEP_DATA_PACKET. 47297dc5e69SMatthias Ringwald * It is forwarded to the TAP interface. 47397dc5e69SMatthias Ringwald */ 47497dc5e69SMatthias Ringwald case BNEP_DATA_PACKET: 47597dc5e69SMatthias Ringwald if (bnep_cid == 0) break; 47697dc5e69SMatthias Ringwald // Write out the ethernet frame to the network interface 47797dc5e69SMatthias Ringwald bnep_lwip_netif_process_packet(packet, size); 47897dc5e69SMatthias Ringwald break; 47997dc5e69SMatthias Ringwald 48097dc5e69SMatthias Ringwald default: 48197dc5e69SMatthias Ringwald break; 48297dc5e69SMatthias Ringwald } 48397dc5e69SMatthias Ringwald 48497dc5e69SMatthias Ringwald // forward to app 48597dc5e69SMatthias Ringwald if (!client_handler) return; 48697dc5e69SMatthias Ringwald (*client_handler)(packet_type, channel, packet, size); 48797dc5e69SMatthias Ringwald } 48897dc5e69SMatthias Ringwald 48997dc5e69SMatthias Ringwald /// API 49097dc5e69SMatthias Ringwald 49197dc5e69SMatthias Ringwald /** 49297dc5e69SMatthias Ringwald * @brief Initialize network interface 49397dc5e69SMatthias Ringwald * @param send_packet_callback 49497dc5e69SMatthias Ringwald */ 49597dc5e69SMatthias Ringwald void bnep_lwip_init(void){ 49697dc5e69SMatthias Ringwald 49797dc5e69SMatthias Ringwald // set up outgoing queue 498917f809aSMatthias Ringwald int error = bnep_lwip_outgoing_init_queue(); 499917f809aSMatthias Ringwald if (error) return; 50097dc5e69SMatthias Ringwald 50197dc5e69SMatthias Ringwald ip4_addr_t fsl_netif0_ipaddr, fsl_netif0_netmask, fsl_netif0_gw; 50297dc5e69SMatthias Ringwald #if 0 50397dc5e69SMatthias Ringwald // when using DHCP Client, no address 50497dc5e69SMatthias Ringwald IP4_ADDR(&fsl_netif0_ipaddr, 0U, 0U, 0U, 0U); 50597dc5e69SMatthias Ringwald IP4_ADDR(&fsl_netif0_netmask, 0U, 0U, 0U, 0U); 50697dc5e69SMatthias Ringwald #else 50797dc5e69SMatthias Ringwald // when playing DHCP Server, set address 50897dc5e69SMatthias Ringwald IP4_ADDR(&fsl_netif0_ipaddr, 192U, 168U, 7U, 1U); 50997dc5e69SMatthias Ringwald IP4_ADDR(&fsl_netif0_netmask, 255U, 255U, 255U, 0U); 51097dc5e69SMatthias Ringwald #endif 51197dc5e69SMatthias Ringwald IP4_ADDR(&fsl_netif0_gw, 0U, 0U, 0U, 0U); 51297dc5e69SMatthias Ringwald 51397dc5e69SMatthias Ringwald // input function differs for sys vs nosys 51497dc5e69SMatthias Ringwald netif_input_fn input_function; 51597dc5e69SMatthias Ringwald #if NO_SYS 51697dc5e69SMatthias Ringwald input_function = ethernet_input; 51797dc5e69SMatthias Ringwald #else 51897dc5e69SMatthias Ringwald input_function = tcpip_input; 51997dc5e69SMatthias Ringwald #endif 52097dc5e69SMatthias Ringwald 52197dc5e69SMatthias Ringwald netif_add(&btstack_netif, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, NULL, bnep_lwip_netif_init, input_function); 52297dc5e69SMatthias Ringwald netif_set_default(&btstack_netif); 52397dc5e69SMatthias Ringwald } 52497dc5e69SMatthias Ringwald 52597dc5e69SMatthias Ringwald /** 52697dc5e69SMatthias Ringwald * @brief Register packet handler for BNEP events 52797dc5e69SMatthias Ringwald */ 52897dc5e69SMatthias Ringwald void bnep_lwip_register_packet_handler(btstack_packet_handler_t handler){ 52997dc5e69SMatthias Ringwald client_handler = handler; 53097dc5e69SMatthias Ringwald } 53197dc5e69SMatthias Ringwald 53297dc5e69SMatthias Ringwald /** 53397dc5e69SMatthias Ringwald * @brief Register BNEP service 53497dc5e69SMatthias Ringwald * @brief Same as benp_register_service, but bnep lwip adapter handles all events 53597dc5e69SMatthias Ringwald * @param service_uuid 53697dc5e69SMatthias Ringwald * @Param max_frame_size 53797dc5e69SMatthias Ringwald */ 53897dc5e69SMatthias Ringwald uint8_t bnep_lwip_register_service(uint16_t service_uuid, uint16_t max_frame_size){ 53997dc5e69SMatthias Ringwald return bnep_register_service(packet_handler, service_uuid, max_frame_size); 54097dc5e69SMatthias Ringwald } 5419c30c50aSMatthias Ringwald 5429c30c50aSMatthias Ringwald /** 5439c30c50aSMatthias Ringwald * @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. 5449c30c50aSMatthias Ringwald * @note: uses our packet handler to manage lwIP network interface 5459c30c50aSMatthias Ringwald * @param addr 5469c30c50aSMatthias Ringwald * @param l2cap_psm 5479c30c50aSMatthias Ringwald * @param uuid_src 5489c30c50aSMatthias Ringwald * @param uuid_dest 5499c30c50aSMatthias Ringwald * @return status 5509c30c50aSMatthias Ringwald */ 5519c30c50aSMatthias Ringwald uint8_t bnep_lwip_connect(bd_addr_t addr, uint16_t l2cap_psm, uint16_t uuid_src, uint16_t uuid_dest){ 5529c30c50aSMatthias Ringwald int status = bnep_connect(packet_handler, addr, l2cap_psm, uuid_src, uuid_dest); 5539c30c50aSMatthias Ringwald if (status != 0){ 5549c30c50aSMatthias Ringwald return ERROR_CODE_UNSPECIFIED_ERROR; 5559c30c50aSMatthias Ringwald } else { 5569c30c50aSMatthias Ringwald return ERROR_CODE_SUCCESS; 5579c30c50aSMatthias Ringwald } 5589c30c50aSMatthias Ringwald } 559