1 // Copyright 2021 Espressif Systems (Shanghai) CO LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License
13 
14 #include <string.h>
15 
16 #include "esp_netif.h"
17 #include "esp_netif_net_stack.h"
18 #include "lwip/netif.h"
19 #include "lwip/pbuf.h"
20 #include "netif/openthreadif.h"
21 #include "openthread/error.h"
22 #include "openthread/ip6.h"
23 #include "openthread/link.h"
24 #include "openthread/message.h"
25 
26 #define OPENTHREAD_IP6_MTU 1280
27 
openthread_output_ip6(struct netif * netif,struct pbuf * p,const struct ip6_addr * peer_addr)28 static err_t openthread_output_ip6(struct netif *netif, struct pbuf *p, const struct ip6_addr *peer_addr)
29 {
30     struct pbuf *q = p;
31     esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(netif);
32     esp_err_t ret = ESP_FAIL;
33     if (!esp_netif) {
34         LWIP_DEBUGF(NETIF_DEBUG, ("corresponding esp-netif is NULL: netif=%p pbuf=%p len=%d\n", netif, p, p->len));
35         return ERR_IF;
36     }
37 
38     if (q->next == NULL) {
39         ret = esp_netif_transmit(esp_netif, q->payload, q->len);
40     } else {
41         LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
42         q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
43         if (q != NULL) {
44 #if ESP_LWIP
45             /* This pbuf RAM was not allocated on layer2, no extra free operation needed in pbuf_free */
46             q->l2_owner = NULL;
47             q->l2_buf = NULL;
48 #endif
49             pbuf_copy(q, p);
50         } else {
51             return ERR_MEM;
52         }
53         ret = esp_netif_transmit(esp_netif, q->payload, q->len);
54         /* content in payload has been copied to OpenThread queue, it's safe to free pbuf now */
55         pbuf_free(q);
56     }
57     /* Check error */
58     if (unlikely(ret != ESP_OK)) {
59         return ERR_ABRT;
60     } else {
61         return ERR_OK;
62     }
63 }
64 
openthread_netif_input(void * h,void * buffer,size_t len,void * eb)65 void openthread_netif_input(void *h, void *buffer, size_t len, void *eb)
66 {
67     struct netif *netif = h;
68     struct pbuf *p;
69     otMessage *message = (otMessage *)buffer;
70 
71     if (unlikely(buffer == NULL || !netif_is_up(netif))) {
72         return;
73     }
74 
75     /* Allocate LINK buffer in case it's forwarded to WiFi/ETH */
76     p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
77     if (p == NULL) {
78         LWIP_DEBUGF(NETIF_DEBUG, ("Failed to allocate input pbuf for OpenThread netif\n"));
79         return;
80     }
81 
82     if (unlikely(otMessageRead(message, 0, p->payload, len) != OT_ERROR_NONE)) {
83         LWIP_DEBUGF(NETIF_DEBUG, ("Failed to read OpenThread message\n"));
84     }
85 
86 #if ESP_LWIP
87     p->l2_owner = NULL;
88     p->l2_buf = NULL;
89 #endif
90     /* full packet send to tcpip_thread to process */
91     if (unlikely(netif->input(p, netif) != ERR_OK)) {
92         LWIP_DEBUGF(NETIF_DEBUG, ("openthread_netif_input: IP input error\n"));
93         pbuf_free(p);
94     }
95     /* the pbuf will be free in upper layer, eg: tcpip_input */
96 }
97 
openthread_netif_init(struct netif * netif)98 err_t openthread_netif_init(struct netif *netif)
99 {
100     netif->name[0] = 'o';
101     netif->name[1] = 't';
102     netif->hwaddr_len = sizeof(otExtAddress);
103     memset(netif->hwaddr, 0, sizeof(netif->hwaddr));
104     netif->mtu = OPENTHREAD_IP6_MTU;
105     netif->flags = NETIF_FLAG_BROADCAST;
106     netif->output = NULL;
107     netif->output_ip6 = openthread_output_ip6;
108     netif->l2_buffer_free_notify = NULL;
109     netif_set_link_up(netif);
110 
111     return ERR_OK;
112 }
113