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