mirror of
				https://github.com/espressif/ESP8266_RTOS_SDK.git
				synced 2025-10-31 18:57:14 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			609 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			609 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| 
 | |
| //     http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include "lwip/pbuf.h"
 | |
| #include "lwip/ethip6.h"
 | |
| #include "netif/etharp.h"
 | |
| #include "esp_libc.h"
 | |
| #include "esp_wifi.h"
 | |
| #include "esp_aio.h"
 | |
| #include "tcpip_adapter.h"
 | |
| #include "freertos/semphr.h"
 | |
| #include "lwip/tcpip.h"
 | |
| #include "stdlib.h"
 | |
| 
 | |
| #include "esp8266/eagle_soc.h"
 | |
| 
 | |
| int ieee80211_output_pbuf(esp_aio_t *aio);
 | |
| int8_t wifi_get_netif(uint8_t fd);
 | |
| void wifi_station_set_default_hostname(uint8_t* hwaddr);
 | |
| 
 | |
| #define IFNAME0 'e'
 | |
| #define IFNAME1 'n'
 | |
| 
 | |
| #if ESP_TCP
 | |
| typedef struct pbuf_send_list {
 | |
|     struct pbuf_send_list* next;
 | |
|     struct pbuf* p;
 | |
|     int aiofd;
 | |
|     int err_cnt;
 | |
| } pbuf_send_list_t;
 | |
| 
 | |
| static pbuf_send_list_t* pbuf_list_head = NULL;
 | |
| static int pbuf_send_list_num = 0;
 | |
| #endif
 | |
| static int low_level_send_cb(esp_aio_t* aio);
 | |
| 
 | |
| #if ESP_TCP_TXRX_PBUF_DEBUG
 | |
| void tcp_print_status(int status, void* buf, uint32_t tmp1, uint32_t tmp2, uint32_t tmp3)
 | |
| {
 | |
|     struct pbuf* p = (struct pbuf*)buf;
 | |
|     if (p->tot_len < 50) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     uint32_t i;
 | |
| 
 | |
|     i = *((unsigned char*)p->payload + 12);
 | |
| 
 | |
|     if (i == 0x08) { /*ipv4*/
 | |
|         i = *((unsigned char*)p->payload + 13);
 | |
| 
 | |
|         if (i == 0) {
 | |
|             i = *((unsigned char*)p->payload + 23);
 | |
| 
 | |
|             if (i == 0x06) { /*tcp*/
 | |
|                 i = *((unsigned char*)p->payload + 16);
 | |
|                 i <<= 8;
 | |
|                 i += *((unsigned char*)p->payload + 17);
 | |
| 
 | |
|                 if (i >= 40) { /*tcp data*/
 | |
|                     uint32_t len, seq, ack, srcport, destport, flags;
 | |
|                     wifi_tx_status_t *tx_result = (wifi_tx_status_t *)(&tmp1);
 | |
|                     len = i;
 | |
|                     i = *((unsigned char*)p->payload + 38);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 39);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 40);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 41);
 | |
|                     seq = i;
 | |
|                     i = *((unsigned char*)p->payload + 42);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 43);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 44);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 45);
 | |
|                     ack = i;
 | |
|                     i = *((unsigned char*)p->payload + 34);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 35);
 | |
|                     srcport = i;
 | |
|                     i = *((unsigned char*)p->payload + 36);
 | |
|                     i <<= 8;
 | |
|                     i += *((unsigned char*)p->payload + 37);
 | |
|                     destport = i;
 | |
|                     flags = *((unsigned char *)p->payload+47);
 | |
| 
 | |
|                     switch (status) {
 | |
|                         case LWIP_SEND_DATA_TO_WIFI:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ Tx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
 | |
|                             break;
 | |
| 
 | |
|                         case LWIP_RESEND_DATA_TO_WIFI_WHEN_WIFI_SEND_FAILED:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ Cache Tx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
 | |
|                             break;
 | |
| 
 | |
|                         case LWIP_RECV_DATA_FROM_WIFI:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ WiFi Rx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
 | |
|                             break;
 | |
| 
 | |
|                         case LWIP_RETRY_DATA_WHEN_RECV_ACK_TIMEOUT:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ TCP RTY - rtime:%d, rto:%d, L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", tmp1, tmp2, len, seq, ack, srcport, destport, flags));
 | |
|                             return;
 | |
| 
 | |
|                         case LWIP_FETCH_DATA_AT_TCPIP_THREAD:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ eth Rx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
 | |
|                             break;
 | |
| 
 | |
|                         case WIFI_SEND_DATA_FAILED:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ WiFi Tx Fail - result:%d, src:%d, lrc:%d, rate:%d, L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n",\
 | |
|                             tx_result->wifi_tx_result, tx_result->wifi_tx_src, tx_result->wifi_tx_lrc, tx_result->wifi_tx_rate, len, seq, ack, srcport, destport, flags));
 | |
|                             break;
 | |
| 
 | |
|                         default:
 | |
|                             LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ status:%d, L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x, tmp1:%d, tmp2:%d, tmp3:%d\n",\
 | |
|                             status, len, seq, ack, srcport, destport, flags, tmp1, tmp2, tmp3));
 | |
|                             break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if ESP_TCP
 | |
| static inline bool check_pbuf_to_insert(struct pbuf* p)
 | |
| {
 | |
|     uint8_t* buf = (uint8_t*)p->payload;
 | |
| 
 | |
|     /*Check if pbuf is tcp ip*/
 | |
|     if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x06) {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static void insert_to_list(int fd, struct pbuf* p)
 | |
| {
 | |
|     pbuf_send_list_t* tmp_pbuf_list1;
 | |
|     pbuf_send_list_t* tmp_pbuf_list2;
 | |
| 
 | |
|     if (pbuf_send_list_num > (TCP_SND_QUEUELEN * MEMP_NUM_TCP_PCB + MEMP_NUM_TCP_PCB)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!check_pbuf_to_insert(p)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Insert %p,%d\n", p, pbuf_send_list_num));
 | |
| 
 | |
|     if (pbuf_list_head == NULL) {
 | |
|         tmp_pbuf_list1 = (pbuf_send_list_t*)malloc(sizeof(pbuf_send_list_t));
 | |
| 
 | |
|         if (!tmp_pbuf_list1) {
 | |
|             LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("no memory malloc pbuf list error\n"));
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         pbuf_ref(p);
 | |
|         tmp_pbuf_list1->aiofd = fd;
 | |
|         tmp_pbuf_list1->p = p;
 | |
|         tmp_pbuf_list1->next = NULL;
 | |
|         tmp_pbuf_list1->err_cnt = 0;
 | |
|         pbuf_list_head = tmp_pbuf_list1;
 | |
|         pbuf_send_list_num++;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     tmp_pbuf_list1 = pbuf_list_head;
 | |
|     tmp_pbuf_list2 = tmp_pbuf_list1;
 | |
| 
 | |
|     while (tmp_pbuf_list1 != NULL) {
 | |
|         if (tmp_pbuf_list1->p == p) {
 | |
|             tmp_pbuf_list1->err_cnt ++;
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         tmp_pbuf_list2 = tmp_pbuf_list1;
 | |
|         tmp_pbuf_list1 = tmp_pbuf_list2->next;
 | |
|     }
 | |
| 
 | |
|     tmp_pbuf_list1 = (pbuf_send_list_t*)malloc(sizeof(pbuf_send_list_t));
 | |
| 
 | |
|     if (!tmp_pbuf_list1) {
 | |
|         LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("no memory malloc pbuf list error\n"));
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     pbuf_ref(p);
 | |
|     tmp_pbuf_list1->aiofd = fd;
 | |
|     tmp_pbuf_list1->p = p;
 | |
|     tmp_pbuf_list1->next = NULL;
 | |
|     tmp_pbuf_list1->err_cnt = 0;
 | |
|     tmp_pbuf_list2->next = tmp_pbuf_list1;
 | |
|     pbuf_send_list_num++;
 | |
| }
 | |
| 
 | |
| void send_from_list()
 | |
| {
 | |
|     pbuf_send_list_t* tmp_pbuf_list1;
 | |
| 
 | |
|     while (pbuf_list_head != NULL) {
 | |
|         if (pbuf_list_head->p->ref == 1) {
 | |
|             tmp_pbuf_list1 = pbuf_list_head->next;
 | |
|             LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
 | |
|             pbuf_free(pbuf_list_head->p);
 | |
|             free(pbuf_list_head);
 | |
|             pbuf_send_list_num--;
 | |
|             pbuf_list_head = tmp_pbuf_list1;
 | |
|         } else {
 | |
|             esp_aio_t aio;
 | |
|             esp_err_t err;
 | |
|             aio.fd = (int)pbuf_list_head->aiofd;
 | |
|             aio.pbuf = pbuf_list_head->p->payload;
 | |
|             aio.len = pbuf_list_head->p->len;
 | |
|             aio.cb = low_level_send_cb;
 | |
|             aio.arg = pbuf_list_head->p;
 | |
|             aio.ret = 0;
 | |
| 
 | |
|             err = ieee80211_output_pbuf(aio);
 | |
| 
 | |
| #if ESP_TCP_TXRX_PBUF_DEBUG
 | |
|             tcp_print_status(LWIP_RESEND_DATA_TO_WIFI_WHEN_WIFI_SEND_FAILED, (void*)pbuf_list_head->p, 0 ,0, 0);
 | |
| #endif
 | |
|             tmp_pbuf_list1 = pbuf_list_head->next;
 | |
| 
 | |
|             if (err == ERR_MEM) {
 | |
|                 pbuf_list_head->err_cnt++;
 | |
| 
 | |
|                 if (pbuf_list_head->err_cnt >= 3) {
 | |
|                     LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
 | |
|                     pbuf_free(pbuf_list_head->p);
 | |
|                     free(pbuf_list_head);
 | |
|                     pbuf_send_list_num--;
 | |
|                     pbuf_list_head = tmp_pbuf_list1;
 | |
|                 }
 | |
| 
 | |
|                 return;
 | |
|             } else if (err == ERR_OK) {
 | |
|                 LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
 | |
|                 free(pbuf_list_head);
 | |
|                 pbuf_send_list_num--;
 | |
|                 pbuf_list_head = tmp_pbuf_list1;
 | |
|             } else {
 | |
|                 LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
 | |
|                 pbuf_free(pbuf_list_head->p);
 | |
|                 free(pbuf_list_head);
 | |
|                 pbuf_send_list_num--;
 | |
|                 pbuf_list_head = tmp_pbuf_list1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /**
 | |
|  * In this function, the hardware should be initialized.
 | |
|  * Called from ethernetif_init().
 | |
|  *
 | |
|  * @param netif the already initialized lwip network interface structure
 | |
|  *        for this ethernetif
 | |
|  */
 | |
| static void low_level_init(struct netif* netif)
 | |
| {
 | |
|     if (netif == NULL) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("low_level_init: netif is NULL\n"));
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     /* set MAC hardware address length */
 | |
|     netif->hwaddr_len = ETHARP_HWADDR_LEN;
 | |
| 
 | |
|     /* maximum transfer unit */
 | |
|     netif->mtu = 1500;
 | |
| 
 | |
|     /* device capabilities */
 | |
|     /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
 | |
|     netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
 | |
| 
 | |
| #if LWIP_IGMP
 | |
|     netif->flags |= NETIF_FLAG_IGMP;
 | |
| #endif
 | |
|     /* Do whatever else is needed to initialize interface. */
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * @brief LWIP low-level AI/O sending callback function, it is to free pbuf
 | |
|  *
 | |
|  * @param aio AI/O control block pointer
 | |
|  *
 | |
|  * @return 0 meaning successs
 | |
|  */
 | |
| static int low_level_send_cb(esp_aio_t* aio)
 | |
| {
 | |
|     struct pbuf* pbuf = aio->arg;
 | |
| 
 | |
| #if ESP_TCP_TXRX_PBUF_DEBUG
 | |
|     wifi_tx_status_t* status = (wifi_tx_status_t*) & (aio->ret);
 | |
|     if (TX_STATUS_SUCCESS != status->wifi_tx_result) {
 | |
|         uint8_t* buf = (uint8_t*)pbuf->payload;
 | |
| 
 | |
|         /*Check if pbuf is tcp ip*/
 | |
|         if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x06) {
 | |
|             tcp_print_status(WIFI_SEND_DATA_FAILED, (void*)pbuf, aio->ret ,0, 0);
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #if ESP_TCP
 | |
|     wifi_tx_status_t* status = (wifi_tx_status_t*) & (aio->ret);
 | |
| 
 | |
|     if ((TX_STATUS_SUCCESS != status->wifi_tx_result) && check_pbuf_to_insert(pbuf)) {
 | |
|         uint8_t* buf = (uint8_t*)pbuf->payload;
 | |
|         struct eth_hdr ethhdr;
 | |
| 
 | |
|         if (*(buf - 17) & 0x01) { //From DS
 | |
|             memcpy(ðhdr.dest, buf - 2, ETH_HWADDR_LEN);
 | |
|             memcpy(ðhdr.src, buf - 2 - ETH_HWADDR_LEN, ETH_HWADDR_LEN);
 | |
|         } else if (*(buf - 17) & 0x02) { //To DS
 | |
|             memcpy(ðhdr.dest, buf - 2 - ETH_HWADDR_LEN - ETH_HWADDR_LEN, ETH_HWADDR_LEN);
 | |
|             memcpy(ðhdr.src, buf - 2, 6);
 | |
|         } else {
 | |
|             pbuf_free(pbuf);
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         memcpy(buf, ðhdr, (ETH_HWADDR_LEN + ETH_HWADDR_LEN));
 | |
|         LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Send packet fail: result:%d, LRC:%d, SRC:%d, RATE:%d",
 | |
|                                        status->wifi_tx_result, status->wifi_tx_lrc, status->wifi_tx_src, status->wifi_tx_rate));
 | |
|         insert_to_list(aio->fd, aio->arg);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     pbuf_free(pbuf);
 | |
| 
 | |
| #if ESP_UDP
 | |
|     udp_sync_trigger();
 | |
| #endif
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * @brief transform custom pbuf to LWIP core pbuf, LWIP may use input custom pbuf
 | |
|  *        to send ARP data directly
 | |
|  *
 | |
|  * @param pbuf LWIP pbuf pointer
 | |
|  *
 | |
|  * @return LWIP pbuf pointer which it not "PBUF_FLAG_IS_CUSTOM" attribute
 | |
|  */
 | |
| static inline struct pbuf* ethernetif_transform_pbuf(struct pbuf* pbuf)
 | |
| {
 | |
|     struct pbuf* p;
 | |
| 
 | |
|     if (!(pbuf->flags & PBUF_FLAG_IS_CUSTOM) && IS_DRAM(pbuf->payload)) {
 | |
|         /*
 | |
|          * Add ref to pbuf to avoid it to be freed by upper layer.
 | |
|          */
 | |
|         pbuf_ref(pbuf);
 | |
|         return pbuf;
 | |
|     }
 | |
| 
 | |
|     p = pbuf_alloc(PBUF_RAW, pbuf->len, PBUF_RAM);
 | |
| 
 | |
|     if (!p) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (IS_IRAM(p->payload)) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: data in IRAM\n"));
 | |
|         pbuf_free(p);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     memcpy(p->payload, pbuf->payload, pbuf->len);
 | |
| 
 | |
|     /*
 | |
|      * The input pbuf(named "pbuf") should not be freed, becasue it will be
 | |
|      * freed by upper layer.
 | |
|      *
 | |
|      * The output pbuf(named "p") should not be freed either, becasue it will
 | |
|      * be freed at callback function "low_level_send_cb".
 | |
|      */
 | |
| 
 | |
|     return p;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * This function should do the actual transmission of the packet. The packet is
 | |
|  * contained in the pbuf that is passed to the function. This pbuf
 | |
|  * might be chained.
 | |
|  *
 | |
|  * @param netif the lwip network interface structure for this ethernetif
 | |
|  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
 | |
|  * @return ERR_OK if the packet could be sent
 | |
|  *         an int8_t value if the packet couldn't be sent
 | |
|  *
 | |
|  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
 | |
|  *       strange results. You might consider waiting for space in the DMA queue
 | |
|  *       to become availale since the stack doesn't retry to send a packet
 | |
|  *       dropped because of memory failure (except for the TCP timers).
 | |
|  */
 | |
| 
 | |
| static int8_t low_level_output(struct netif* netif, struct pbuf* p)
 | |
| {
 | |
|     esp_aio_t aio;
 | |
|     int8_t err = ERR_OK;
 | |
| 
 | |
|     if (netif == NULL) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: netif is NULL\n"));
 | |
|         return ERR_ARG;
 | |
|     }
 | |
| 
 | |
|     if (!netif_is_up(netif)) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: netif is not up\n"));
 | |
|         return ERR_RTE;
 | |
|     }
 | |
| 
 | |
| #if ETH_PAD_SIZE
 | |
|     pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
 | |
| #endif
 | |
| 
 | |
|     p = ethernetif_transform_pbuf(p);
 | |
| 
 | |
|     if (!p) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: lack memory\n"));
 | |
|         return ERR_OK;
 | |
|     }
 | |
| 
 | |
|     aio.fd = (int)netif->state;
 | |
|     aio.pbuf = p->payload;
 | |
|     aio.len = p->len;
 | |
|     aio.cb = low_level_send_cb;
 | |
|     aio.arg = p;
 | |
|     aio.ret = 0;
 | |
| 
 | |
| #if ESP_TCP_TXRX_PBUF_DEBUG
 | |
|     tcp_print_status(LWIP_SEND_DATA_TO_WIFI, (void*)p, 0 ,0, 0);
 | |
| #endif
 | |
| 
 | |
|     /*
 | |
|      * we use "SOCK_RAW" to create socket, so all input/output datas include full ethernet
 | |
|      * header, meaning we should not pass target low-level address here.
 | |
|      */
 | |
|     err = ieee80211_output_pbuf(&aio);
 | |
| #if ESP_UDP
 | |
|     udp_sync_set_ret(netif, p, err);
 | |
| #endif
 | |
| 
 | |
|     if (err != ERR_OK) {
 | |
|         if (err == ERR_MEM) {
 | |
| #if ESP_TCP
 | |
|             insert_to_list(aio.fd, p);
 | |
| #endif
 | |
|             err = ERR_OK;
 | |
|         }
 | |
| 
 | |
|         pbuf_free(p);
 | |
|     }
 | |
| 
 | |
| //  signal that packet should be sent();
 | |
| 
 | |
| #if ETH_PAD_SIZE
 | |
|     pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
 | |
| #endif
 | |
| 
 | |
| #if LWIP_STATS
 | |
|     LINK_STATS_INC(link.xmit);
 | |
| #endif
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * This function should be called when a packet is ready to be read
 | |
|  * from the interface. It uses the function low_level_input() that
 | |
|  * should handle the actual reception of bytes from the network
 | |
|  * interface. Then the type of the received packet is determined and
 | |
|  * the appropriate input function is called.
 | |
|  *
 | |
|  * @param netif the lwip network interface structure for this ethernetif
 | |
|  */
 | |
| void ethernetif_input(struct netif* netif, struct pbuf* p)
 | |
| {
 | |
|     struct eth_hdr* ethhdr;
 | |
| 
 | |
|     if (p == NULL) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: pbuf is NULL\n"));
 | |
|         goto _exit;
 | |
|     }
 | |
| 
 | |
|     if (p->payload == NULL) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: payload is NULL\n"));
 | |
|         pbuf_free(p);
 | |
|         goto _exit;
 | |
|     }
 | |
| 
 | |
|     if (netif == NULL) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: netif is NULL\n"));
 | |
|         pbuf_free(p);
 | |
|         goto _exit;
 | |
|     }
 | |
| 
 | |
|     if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: netif is not up\n"));
 | |
|         pbuf_free(p);
 | |
|         p = NULL;
 | |
|         goto _exit;
 | |
|     }
 | |
| 
 | |
|     /* points to packet payload, which starts with an Ethernet header */
 | |
|     ethhdr = p->payload;
 | |
| 
 | |
|     switch (htons(ethhdr->type)) {
 | |
|         /* IP or ARP packet? */
 | |
|         case ETHTYPE_IP:
 | |
|         case ETHTYPE_IPV6:
 | |
|         case ETHTYPE_ARP:
 | |
| #if PPPOE_SUPPORT
 | |
| 
 | |
|         /* PPPoE packet? */
 | |
|         case ETHTYPE_PPPOEDISC:
 | |
|         case ETHTYPE_PPPOE:
 | |
| #endif /* PPPOE_SUPPORT */
 | |
| 
 | |
|             /* full packet send to tcpip_thread to process */
 | |
|             if (netif->input(p, netif) != ERR_OK) {
 | |
|                 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
 | |
|                 pbuf_free(p);
 | |
|                 p = NULL;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             pbuf_free(p);
 | |
|             p = NULL;
 | |
|             break;
 | |
|     }
 | |
| 
 | |
| _exit:
 | |
|     ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Should be called at the beginning of the program to set up the
 | |
|  * network interface. It calls the function low_level_init() to do the
 | |
|  * actual setup of the hardware.
 | |
|  *
 | |
|  * This function should be passed as a parameter to netif_add().
 | |
|  *
 | |
|  * @param netif the lwip network interface structure for this ethernetif
 | |
|  * @return ERR_OK if the loopif is initialized
 | |
|  *         ERR_MEM if private data couldn't be allocated
 | |
|  *         any other int8_t on error
 | |
|  */
 | |
| int8_t ethernetif_init(struct netif* netif)
 | |
| {
 | |
|     if (netif == NULL) {
 | |
|         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: netif is NULL\n"));
 | |
|     }
 | |
| 
 | |
| #if LWIP_NETIF_HOSTNAME
 | |
| 
 | |
|     netif->hostname = "LWIP";
 | |
| 
 | |
| #endif /* LWIP_NETIF_HOSTNAME */
 | |
| 
 | |
|     /*
 | |
|      * Initialize the snmp variables and counters inside the struct netif.
 | |
|      * The last argument should be replaced with your link speed, in units
 | |
|      * of bits per second.
 | |
|      */
 | |
| 
 | |
|     netif->name[0] = IFNAME0;
 | |
|     netif->name[1] = IFNAME1;
 | |
|     /* We directly use etharp_output() here to save a function call.
 | |
|      * You can instead declare your own function an call etharp_output()
 | |
|      * from it if you have to do some checks before sending (e.g. if link
 | |
|      * is available...) */
 | |
|     netif->output = etharp_output;
 | |
| #if LWIP_IPV6
 | |
|     netif->output_ip6 = ethip6_output;
 | |
| #endif /* LWIP_IPV6 */
 | |
|     netif->linkoutput = low_level_output;
 | |
| 
 | |
|     /* initialize the hardware */
 | |
|     low_level_init(netif);
 | |
| 
 | |
|     return ERR_OK;
 | |
| }
 | 
