lwip网络接口
lwip协议栈支持多种不同的网络接口,比如WiFi、以太网、4G等等,由于网卡是直接和硬件平台打交道,硬件不同则处理也是不同的,所以由用户提供最底层的接口函数,lwip提供统一的接口,但是底层的实现需要用户自己去完成,比如以太网的MAC接口,WiFi的RF接口等。
lwip的网络接口结构
lwip中的每一个网卡都由一个netif结构体表示,netif声明多个成员变量,这些变量是对网卡进行抽象,可以有多个网卡,多个网卡的存储为单向链表形式。用户需要实现网络的底层接口,例如数据input以及output等。
/** 以下是netif结构体的部分说明
* 成员变量需要根据网卡特性,针对赋值 */
struct netif {
#if !LWIP_SINGLE_NETIF
/** 指向下一个网卡的指针 */
struct netif *next;
#endif
#if LWIP_IPV4
/** IPv4的地址设置 */
ip_addr_t ip_addr;
ip_addr_t netmask;
ip_addr_t gw;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
/** IPv6的地址设置 */
ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#if LWIP_IPV6_ADDRESS_LIFETIMES
u32_t ip6_addr_valid_life[LWIP_IPV6_NUM_ADDRESSES];
u32_t ip6_addr_pref_life[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
#endif /* LWIP_IPV6 */
/** 网络数据的输入函数,由网络设备驱动调用并上传到TCP/IP堆栈 */
netif_input_fn input;
#if LWIP_IPV4
/** 网络数据待发送函数,由TCP/IP调用,包含检测目标IP地址的MAC地址等操作*/
netif_output_fn output;
#endif /* LWIP_IPV4 */
/** 网络数据的输出函数*/
netif_linkoutput_fn linkoutput;
#if LWIP_IPV6
/** 针对IPv6地址的网络数据待发送函数*/
netif_output_ip6_fn output_ip6;
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_STATUS_CALLBACK
/** 网络状态回调函数 */
netif_status_callback_fn status_callback;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
/** 网卡链接状态回调函数 */
netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
/** 网卡移除回调函数 */
netif_status_callback_fn remove_callback;
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
/** 网卡状态 */
void *state;
#if LWIP_NETIF_HOSTNAME
/* 网卡主机名称,不能为NULL */
const char* hostname;
#endif /* LWIP_NETIF_HOSTNAME */
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/
/** 最大传输单元,最大为1500*/
u16_t mtu;
#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES
/** IPv6最大传输单元,最大为1500 */
u16_t mtu6;
#endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */
/** 网卡的MAC地址 */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
/** 网卡的MAC地址长度 */
u8_t hwaddr_len;
/**网卡标志符 */
u8_t flags;
/** 网卡名称 */
char name[2];
........
};
lwip的网络接口相关函数
函数 | 功能 |
---|---|
netif_init(void) | 虚拟网卡初始化 ,调用netif_add添加默认网卡 |
netif_add() | 添加一个虚拟网卡,配置netif结构体成员变量,将网卡加入到网卡链表 |
netif_remove() | 移除一个虚拟网卡,将网卡从网卡链表中删除 |
netif_set_default() | 设置默认虚拟网卡 |
具体函数源码可以参考lwip中的netif.c
源码下载可以点击文章底部链接
lwip网络数据包
TCP/IP协议栈的实现本质上就是对网络数据包进行封装,解析。在lwip中,使用pbuf结构进行数据包的管理。
lwip网络数据包结构
lwip网络数据包是由一个个pbuf组成的单向链表。pbuf在TCP/IP各层之间传递数据,每经过一层,都会增加响应的头部,因此在申请pbuf时会把头部的空间也一起申请。但是初始化时指针是指向payload的,在调用pbuf_header()添加头部信息时,指针会向上偏移。图中offset即是预留的头部空间
struct pbuf {
/** 指向下一个pbuf */
struct pbuf *next;
/** 数据buffer */
void *payload;
/** 所有pubuf总长度*/
u16_t tot_len;
/** 当前pbuf的长度 */
u16_t len;
/** pbuf类型,4个*/
u8_t type_internal;
/** 引用计数 */
LWIP_PBUF_REF_T ref;
...
};
lwip网络数据包函数
函数 | 功能 |
---|---|
pbuf_alloc() | 根据类型申请pbuf内存 |
pbuf_free() | 释放pbuf内存 |
pbuf_header() | 添加协议包头,本质上是调整payload指针向上偏移 |
具体函数源码可以参考lwip中的pbuf.c
源码下载可以点击文章底部链接
学习笔记,有问题欢迎指出
lwip官方源码:http://git.savannah.gnu.org/cgit/lwip.git