那么netif具體該如何使用呢?其實使用還是非常簡單的。首先我們需要根據我們的網卡定義一個netif結構體變量struct netif gnetif,我們首先要把網卡掛載到netif\_list鏈表上才能使用,因為LwIP是通過鏈表來管理所有的網卡,所有第一步是通過netif\_add()函數將我們的網卡掛載到netif\_list鏈表上,netif\_add()函數具體見代碼清單 4?2。
```
1 struct netif *
2 netif_add(struct netif *netif,const ip4_addr_t *ipaddr,
3 const ip4_addr_t *netmask, const ip4_addr_t *gw,
4 void *state, netif_init_fn init, netif_input_fn input)
5 {
6 LWIP_ASSERT_CORE_LOCKED();
7
8 if (ipaddr == NULL)
9 {
10 ipaddr = ip_2_ip4(IP4_ADDR_ANY);
11 }
12 if (netmask == NULL)
13 {
14 netmask = ip_2_ip4(IP4_ADDR_ANY);
15 }
16 if (gw == NULL)
17 {
18 gw = ip_2_ip4(IP4_ADDR_ANY);
19 }
20
21 /* reset new interface configuration state */
22 ip_addr_set_zero_ip4(&netif->ip_addr); (1)
23 ip_addr_set_zero_ip4(&netif->netmask);
24 ip_addr_set_zero_ip4(&netif->gw);
25 netif->output = netif_null_output_ip4;
26
27 NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL);
28 netif->mtu = 0;
29 netif->flags = 0;
30
31 memset(netif->client_data, 0, sizeof(netif->client_data));
32
33 /* remember netif specific state information data */
34 netif->state = state;
35 netif->num = netif_num;
36 netif->input = input; (2)
37
38 NETIF_RESET_HINTS(netif);
39
40
41 netif_set_addr(netif, ipaddr, netmask, gw); (3)
42
43
44 /* call user specified initialization function for netif */
45 if (init(netif) != ERR_OK) (4)
46 {
47 return NULL;
48 }
49
50 {
51 struct netif *netif2;
52 int num_netifs;
53 do
54 {
55 if (netif->num == 255)
56 {
57 netif->num = 0;
58 }
59 num_netifs = 0;
60 for(netif2 = netif_list; netif2 != NULL; netif2 = netif2->next)
61 {
62 num_netifs++;
63 if (netif2->num == netif->num)
64 {
65 netif->num++;
66 break;
67 }
68 }
69 }
70 while (netif2 != NULL);
71 }
72 if (netif->num == 254)
73 {
74 netif_num = 0;
75 }
76 else
77 {
78 netif_num = (u8_t)(netif->num + 1); (5)
79 }
80
81 /* add this netif to the list */
82 netif->next = netif_list;
83 netif_list = netif; (6)
84
85 mib2_netif_added(netif);
86
87
88 ip4_addr_debug_print(NETIF_DEBUG, ipaddr);
89
90 ip4_addr_debug_print(NETIF_DEBUG, netmask);
91
92 ip4_addr_debug_print(NETIF_DEBUG, gw);
93
94
95 netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL);
96
97 return netif;
98 }
```
* (1):清空主機IP地址、子網掩碼、網關等字段信息。
* (2):根據傳遞進來的參數填寫網卡state、input等字段的相關信息。
* (3):調用網卡設置函數netif_set_addr()設置網卡IP地址、子網掩碼、網關等信息。
* (4):通過傳遞進來的回調函數init()進行網卡真正的初始化操作,所以該函數是由用戶實現的,對于不同網卡就使用不一樣的初始化,而此處是以太網,則該回調函數一般為ethernetif_init(),該函數在后文想想講解。
* (5):初始化網卡成功,則遍歷當前設備擁有多少個網卡,并為當前網卡分配唯一標識num。
* (6):將當前網卡插入netif_list鏈表中。
在使用之前需要進行初始化主機IP地址、子網掩碼、網關等,并且在調用netif_add()函數之后會觸發netif_init_fn的回調函數。
總之一句話,在開始使用LwIP協議棧的時候,我們就需要將網卡底層移植完成,才能開始使用,而移植的第一步,就是將網絡進行初始化,并且設置該網卡為默認網卡,讓LwIP能通過網卡進行收發數據,具體見代碼清單 4 3加粗部分
```
1 /*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
2 #define IP_ADDR0 192
3 #define IP_ADDR1 168
4 #define IP_ADDR2 1
5 #define IP_ADDR3 122
6
7 /*NETMASK*/
8 #define NETMASK_ADDR0 255
9 #define NETMASK_ADDR1 255
10 #define NETMASK_ADDR2 255
11 #define NETMASK_ADDR3 0
12
13 /*Gateway Address*/
14 #define GW_ADDR0 192
15 #define GW_ADDR1 168
16 #define GW_ADDR2 1
17 #define GW_ADDR3 1
18
19 struct netif gnetif;
20 ip4_addr_t ipaddr;
21 ip4_addr_t netmask;
22 ip4_addr_t gw;
23 uint8_t IP_ADDRESS[4];
24 uint8_t NETMASK_ADDRESS[4];
25 uint8_t GATEWAY_ADDRESS[4];
26
27 void TCPIP_Init(void)
28 {
29
30 tcpip_init(NULL, NULL);
31
32 /* IP addresses initialization */
33 /* USER CODE BEGIN 0 */
34 #ifdef USE_DHCP
35 ip_addr_set_zero_ip4(&ipaddr);
36 ip_addr_set_zero_ip4(&netmask);
37 ip_addr_set_zero_ip4(&gw);
38 #else
39 IP4_ADDR(&ipaddr,IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR3);
40 IP4_ADDR(&netmask,NETMASK_ADDR0,NETMASK_ADDR1,NETMASK_ADDR2,NETMASK_ADDR3);
41 IP4_ADDR(&gw,GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_ADDR3);
42 #endif /* USE_DHCP */
43 /* USER CODE END 0 */
44 /* Initilialize the LwIP stack without RTOS */
45 /* add the network interface (IPv4/IPv6) without RTOS */
46 netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init,
47 &tcpip_input);
48 /* Registers the default network interface */
49 netif_set_default(&gnetif);
50
51 if (netif_is_link_up(&gnetif))
52 {
53 /* When the netif is fully configured this function must be called */
54 netif_set_up(&gnetif);
55 }
56 else
57 {
58 /* When the netif link is down this function must be called */
59 netif_set_down(&gnetif);
60 }
61 }
```
掛載網卡的過程是非常簡單的,如果一個設備當前是還沒有網卡的,當調用netif\_add()函數掛載網卡后,其過程如圖 4?1所示,當設備需要掛載多個網卡的時候,就多次調用netif\_add()函數即可,新掛載的網卡會在鏈表的最前面,具體見圖 4?2。


- 說明
- 第1章:網絡協議簡介
- 1.1:常用網絡協議
- 1.2:網絡協議的分層模型
- 1.3:協議層報文間的封裝與拆封
- 第2章:LwIP簡介
- 2.1:LwIP的優缺點
- 2.2:LwIP的文件說明
- 2.2.1:如何獲取LwIP源碼文件
- 2.2.2:LwIP文件說明
- 2.3:查看LwIP的說明文檔
- 2.4:使用vscode查看源碼
- 2.4.1:查看文件中的符號列表(函數列表)
- 2.4.2:函數定義跳轉
- 2.5:LwIP源碼里的example
- 2.6:LwIP的三種編程接口
- 2.6.1:RAW/Callback API
- 2.6.2:NETCONN API
- 2.6.3:SOCKET API
- 第3章:開發平臺介紹
- 3.1:以太網簡介
- 3.1.1:PHY層
- 3.1.2:MAC子層
- 3.2:STM32的ETH外設
- 3.3:MII 和 RMII 接口
- 3.4:PHY:LAN8720A
- 3.5:硬件設計
- 3.6:軟件設計
- 3.6.1:獲取STM32的裸機工程模板
- 3.6.2:添加bsp_eth.c與bsp_eth.h
- 3.6.3:修改stm32f4xx_hal_conf.h文件
- 第4章:LwIP的網絡接口管理
- 4.1:netif結構體
- 4.2:netif使用
- 4.3:與netif相關的底層函數
- 4.4:ethernetif.c文件內容
- 4.4.1:ethernetif數據結構
- 4.4.2:ethernetif_init()
- 4.4.3:low_level_init()
- 第5章:LwIP的內存管理
- 5.1:幾種內存分配策略
- 5.1.1:固定大小的內存塊
- 5.1.2:可變長度分配
- 5.2:動態內存池(POOL)
- 5.2.1:內存池的預處理
- 5.2.2:內存池的初始化
- 5.2.3:內存分配
- 5.2.4:內存釋放
- 5.3:動態內存堆
- 5.3.1:內存堆的組織結構
- 5.3.2:內存堆初始化
- 5.3.3:內存分配
- 5.3.4:內存釋放
- 5.4:使用C庫的malloc和free來管理內存
- 5.5:LwIP中的配置
- 第6章:網絡數據包
- 6.1:TCP/IP協議的分層思想
- 6.2:LwIP的線程模型
- 6.3:pbuf結構體說明
- 6.4:pbuf的類型
- 6.4.1:PBUF_RAM類型的pbuf
- 6.4.2:PBUF_POOL類型的pbuf
- 6.4.3:PBUF_ROM和PBUF_REF類型pbuf
- 6.5:pbuf_alloc()
- 6.6:pbuf_free()
- 6.7:其它pbuf操作函數
- 6.7.1:pbuf_realloc()
- 6.7.2:pbuf_header()
- 6.7.3:pbuf_take()
- 6.8:網卡中使用的pbuf
- 6.8.1:low_level_output()
- 6.8.2:low_level_input()
- 6.8.3:ethernetif_input()
- 第7章:無操作系統移植LwIP
- 7.1:將LwIP添加到裸機工程
- 7.2:移植頭文件
- 7.3:移植網卡驅動
- 7.4:LwIP時基
- 7.5:協議棧初始化
- 7.6:獲取數據包
- 7.6.1:查詢方式
- 7.6.2:ping命令詳解
- 7.6.3:中斷方式
- 第8章:有操作系統移植LwIP
- 8.1:LwIP中添加操作系統
- 8.1.1:拷貝FreeRTOS源碼到工程文件夾
- 8.1.2:添加FreeRTOS源碼到工程組文件夾
- 8.1.3:指定FreeRTOS頭文件的路徑
- 8.1.4:修改stm32f10x_it.c
- 8.2:lwipopts.h文件需要加入的配置
- 8.3:sys_arch.c/h文件的編寫
- 8.4:網卡底層的編寫
- 8.5:協議棧初始化
- 8.6:移植后使用ping測試基本響應
- 第9章:LwIP一探究竟
- 9.1:網卡接收數據的流程
- 9.2:內核超時處理
- 9.2.1:sys_timeo結構體與超時鏈表
- 9.2.2:注冊超時事件
- 9.2.3:超時檢查
- 9.3:tcpip_thread線程
- 9.4:LwIP中的消息
- 9.4.1:消息結構
- 9.4.2:數據包消息
- 9.4.3:API消息
- 9.5:揭開LwIP神秘的面紗
- 第10章:ARP協議
- 10.1:鏈路層概述
- 10.2:MAC地址的基本概念
- 10.3:初識ARP
- 10.4:以太網幀結構
- 10.5:IP地址映射為物理地址
- 10.6:ARP緩存表
- 10.7:ARP緩存表的超時處理
- 10.8:ARP報文
- 10.9:發送ARP請求包
- 10.10:數據包接收流程
- 10.10.1:以太網之數據包接收
- 10.10.2:ARP數據包處理
- 10.10.3:更新ARP緩存表
- 10.11:數據包發送流程
- 10.11.1:etharp_output()函數
- 10.11.2:etharp_output_to_arp_index()函數
- 10.11.3:etharp_query()函數
- 第11章:IP協議
- 11.1:IP地址.md
- 11.1.1:概述
- 11.1.2:IP地址編址
- 11.1.3:特殊IP地址