1 /* Copyright 2018 Espressif Systems (Shanghai) PTE 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 /* */
7 /* http://www.apache.org/licenses/LICENSE-2.0 */
8 /* */
9 /* Unless required by applicable law or agreed to in writing, software */
10 /* distributed under the License is distributed on an "AS IS" BASIS, */
11 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
12 /* See the License for the specific language governing permissions and */
13 /* limitations under the License. */
14
15 /* Standard includes. */
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 /* FreeRTOS includes. */
21 #include "FreeRTOS.h"
22 #include "task.h"
23 #include "queue.h"
24 #include "semphr.h"
25
26 /* FreeRTOS+TCP includes. */
27 #include "FreeRTOS_IP.h"
28 #include "FreeRTOS_Sockets.h"
29 #include "FreeRTOS_IP_Private.h"
30 #include "FreeRTOS_DNS.h"
31 #include "NetworkBufferManagement.h"
32 #include "NetworkInterface.h"
33
34 #include "esp_log.h"
35 #include "esp_wifi.h"
36 #include "esp_wifi_internal.h"
37 #include "tcpip_adapter.h"
38
39 enum if_state_t
40 {
41 INTERFACE_DOWN = 0,
42 INTERFACE_UP,
43 };
44
45 static const char * TAG = "NetInterface";
46 volatile static uint32_t xInterfaceState = INTERFACE_DOWN;
47
48 static NetworkInterface_t * pxMyInterface;
49
50 static BaseType_t xESP32_Eth_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
51
52 static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
53 NetworkBufferDescriptor_t * const pxDescriptor,
54 BaseType_t xReleaseAfterSend );
55
56 static BaseType_t xESP32_Eth_GetPhyLinkStatus( NetworkInterface_t * pxInterface );
57
58 NetworkInterface_t * pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex,
59 NetworkInterface_t * pxInterface );
60
61 /*-----------------------------------------------------------*/
62
63 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
64
65 /* Do not call the following function directly. It is there for downward compatibility.
66 * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
67 * objects. See the description in FreeRTOS_Routing.h. */
pxFillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)68 NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
69 NetworkInterface_t * pxInterface )
70 {
71 pxESP32_Eth_FillInterfaceDescriptor( xEMACIndex, pxInterface );
72 }
73
74 #endif
75 /*-----------------------------------------------------------*/
76
77
pxESP32_Eth_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)78 NetworkInterface_t * pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex,
79 NetworkInterface_t * pxInterface )
80 {
81 static char pcName[ 8 ];
82
83 /* This function pxESP32_Eth_FillInterfaceDescriptor() adds a network-interface.
84 * Make sure that the object pointed to by 'pxInterface'
85 * is declared static or global, and that it will remain to exist. */
86
87 snprintf( pcName, sizeof( pcName ), "eth%ld", xEMACIndex );
88
89 memset( pxInterface, '\0', sizeof( *pxInterface ) );
90 pxInterface->pcName = pcName; /* Just for logging, debugging. */
91 pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
92 pxInterface->pfInitialise = xESP32_Eth_NetworkInterfaceInitialise;
93 pxInterface->pfOutput = xESP32_Eth_NetworkInterfaceOutput;
94 pxInterface->pfGetPhyLinkStatus = xESP32_Eth_GetPhyLinkStatus;
95
96 FreeRTOS_AddNetworkInterface( pxInterface );
97 pxMyInterface = pxInterface;
98
99 return pxInterface;
100 }
101 /*-----------------------------------------------------------*/
102
xESP32_Eth_NetworkInterfaceInitialise(NetworkInterface_t * pxInterface)103 static BaseType_t xESP32_Eth_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
104 {
105 static BaseType_t xMACAdrInitialized = pdFALSE;
106 uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ];
107
108 if( xInterfaceState == INTERFACE_UP )
109 {
110 if( xMACAdrInitialized == pdFALSE )
111 {
112 esp_wifi_get_mac( ESP_IF_WIFI_STA, ucMACAddress );
113 FreeRTOS_UpdateMACAddress( ucMACAddress );
114 xMACAdrInitialized = pdTRUE;
115 }
116
117 return pdTRUE;
118 }
119
120 return pdFALSE;
121 }
122
xESP32_Eth_GetPhyLinkStatus(NetworkInterface_t * pxInterface)123 static BaseType_t xESP32_Eth_GetPhyLinkStatus( NetworkInterface_t * pxInterface )
124 {
125 BaseType_t xResult = pdFALSE;
126
127 if( xInterfaceState == INTERFACE_UP )
128 {
129 xResult = pdTRUE;
130 }
131
132 return xResult;
133 }
134
xESP32_Eth_NetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t xReleaseAfterSend)135 static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
136 NetworkBufferDescriptor_t * const pxDescriptor,
137 BaseType_t xReleaseAfterSend )
138 {
139 if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->pucEthernetBuffer == NULL ) || ( pxNetworkBuffer->xDataLength == 0 ) )
140 {
141 ESP_LOGE( TAG, "Invalid params" );
142 return pdFALSE;
143 }
144
145 esp_err_t ret;
146
147 if( xInterfaceState == INTERFACE_DOWN )
148 {
149 ESP_LOGD( TAG, "Interface down" );
150 ret = ESP_FAIL;
151 }
152 else
153 {
154 ret = esp_wifi_internal_tx( ESP_IF_WIFI_STA, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
155
156 if( ret != ESP_OK )
157 {
158 ESP_LOGE( TAG, "Failed to tx buffer %p, len %d, err %d", pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, ret );
159 }
160 }
161
162 #if ( ipconfigHAS_PRINTF != 0 )
163 {
164 /* Call a function that monitors resources: the amount of free network
165 * buffers and the amount of free space on the heap. See FreeRTOS_IP.c
166 * for more detailed comments. */
167 vPrintResourceStats();
168 }
169 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
170
171 if( xReleaseAfterSend == pdTRUE )
172 {
173 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
174 }
175
176 return ret == ESP_OK ? pdTRUE : pdFALSE;
177 }
178
vNetworkNotifyIFDown()179 void vNetworkNotifyIFDown()
180 {
181 IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL };
182
183 if( xInterfaceState != INTERFACE_DOWN )
184 {
185 xInterfaceState = INTERFACE_DOWN;
186 xSendEventStructToIPTask( &xRxEvent, 0 );
187 }
188 }
189
vNetworkNotifyIFUp()190 void vNetworkNotifyIFUp()
191 {
192 xInterfaceState = INTERFACE_UP;
193 }
194
wlanif_input(void * netif,void * buffer,uint16_t len,void * eb)195 esp_err_t wlanif_input( void * netif,
196 void * buffer,
197 uint16_t len,
198 void * eb )
199 {
200 NetworkBufferDescriptor_t * pxNetworkBuffer;
201 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
202 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
203
204 #if ( ipconfigHAS_PRINTF != 0 )
205 {
206 vPrintResourceStats();
207 }
208 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
209
210 if( eConsiderFrameForProcessing( buffer ) != eProcessBuffer )
211 {
212 ESP_LOGD( TAG, "Dropping packet" );
213 esp_wifi_internal_free_rx_buffer( eb );
214 return ESP_OK;
215 }
216
217 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( len, xDescriptorWaitTime );
218
219 if( pxNetworkBuffer != NULL )
220 {
221 /* Set the packet size, in case a larger buffer was returned. */
222 pxNetworkBuffer->xDataLength = len;
223 pxNetworkBuffer->pxInterface = pxMyInterface;
224 pxNetworkBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pcBuffer );
225
226 /* Copy the packet data. */
227 memcpy( pxNetworkBuffer->pucEthernetBuffer, buffer, len );
228 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
229
230 if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFAIL )
231 {
232 ESP_LOGE( TAG, "Failed to enqueue packet to network stack %p, len %d", buffer, len );
233 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
234 return ESP_FAIL;
235 }
236
237 esp_wifi_internal_free_rx_buffer( eb );
238 return ESP_OK;
239 }
240 else
241 {
242 ESP_LOGE( TAG, "Failed to get buffer descriptor" );
243 return ESP_FAIL;
244 }
245 }
246