[LWIP学习]--SylixOS AF_PACKET socket套接字分析
2017-08-31 20:25
781 查看
之前我们学习了原始套接字(SOCK_RAW),通过原始套接字可以越过传输层,直接在IP层进行数据的发送和接收。
通过原始套接字,可以构建自定义的IP包。
其实,还有一种套接字比它更厉害,可以构建自定义以太网包–AF_PACKET套接字
在SylixOS中,
使用socket(AF_PACKET, SOCK_RAW, ETHTYPE_*)创建的套接字可以接收链路层报文。
那为什么AF_PACKET协议域的套接字可以接收链路层报文呢?
今日追踪了一下:
1.首先在socket函数中,对不同的协议域设置了不同入口。
本文进入的是packet_socket函数。
在packet_socket->__packetCreate函数中,创建AF_PACKET控制块,并加入AF_PACKET链表。
2.通过recvfrom函数接收数据。
选择AF_PACKET协议域,进入packet_recvfrom函数。
在packet_recvfrom 函数中判断AF_PACKET控制块是否获取到数据,并读取。
3.获取到数据的源头在tcpip.c文件中,tcpip_input函数是LWIP协议栈的入口,在tcpip_input函数中添加了一个回调函数,用于AF_PACKET获取链路层报文。
4.通过sendto函数发送数据。
和之前一样,选择AF_PACKET协议域,进入packet_sendto函数。
在packet_sendto->__packetEthRawSendto函数中,组装一个以太网报文,并通过netif->linkoutput函数将数据通过网卡驱动发送出去。
至此,AF_PACKET套接字的创建即使用介绍完毕。
AF_PACKET套接字工作流程图如下:
通过原始套接字,可以构建自定义的IP包。
其实,还有一种套接字比它更厉害,可以构建自定义以太网包–AF_PACKET套接字
在SylixOS中,
使用socket(AF_PACKET, SOCK_RAW, ETHTYPE_*)创建的套接字可以接收链路层报文。
那为什么AF_PACKET协议域的套接字可以接收链路层报文呢?
今日追踪了一下:
1.首先在socket函数中,对不同的协议域设置了不同入口。
本文进入的是packet_socket函数。
/* 选择协议域 */ switch (domain) { case AF_UNIX: /* UNIX 域协议 */ pafunix = unix_socket(domain, type, protocol); ... case AF_PACKET: /* PACKET */ pafpacket = packet_socket(domain, type, protocol); ... case AF_INET: case AF_INET6: /* IPv4 / v6 */ iLwipFd = lwip_socket(domain, type, protocol); ... default: }
在packet_socket->__packetCreate函数中,创建AF_PACKET控制块,并加入AF_PACKET链表。
static AF_PACKET_T *__packetCreate (INT iType, INT iProtocol) { AF_PACKET_T *pafpacket; pafpacket = (AF_PACKET_T *)__SHEAP_ALLOC(sizeof(AF_PACKET_T)); ... pafpacket->PACKET_iType = iType; pafpacket->PACKET_iProtocol = iProtocol; ... /* 将AF_PACKET控制块加入全局链表 */ _List_Line_Add_Ahead(&pafpacket->PACKET_lineManage, &_G_plineAfPacket); ... return (pafpacket); }
2.通过recvfrom函数接收数据。
选择AF_PACKET协议域,进入packet_recvfrom函数。
ssize_t recvfrom (int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { ... switch (psock->SOCK_iFamily) { case AF_UNIX: /* UNIX 域协议 */ sstRet = (ssize_t)unix_recvfrom(psock->SOCK_pafunix, mem, len, flags, from, fromlen); break; case AF_PACKET: /* PACKET */ sstRet = (ssize_t)packet_recvfrom(psock->SOCK_pafpacket, mem, len, flags, from, fromlen); break; default: sstRet = (ssize_t)lwip_recvfrom(psock->SOCK_iLwipFd, mem, len, flags, from, fromlen); break; } ... }
在packet_recvfrom 函数中判断AF_PACKET控制块是否获取到数据,并读取。
ssize_t packet_recvfrom (AF_PACKET_T *pafpacket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { ... /* 当前节点是否有数据 */ if (__packetCanRead(pafpacket, flags, len)) { /* 接收一个数据包 */ sstTotal = __packetBufRecv(pafpacket, mem, len, (struct sockaddr_ll *)from, flags); } ... }
3.获取到数据的源头在tcpip.c文件中,tcpip_input函数是LWIP协议栈的入口,在tcpip_input函数中添加了一个回调函数,用于AF_PACKET获取链路层报文。
tcpip_input(struct pbuf *p, struct netif *inp) { #if defined(SYLIXOS) && defined(LWIP_HOOK_LINK_INPUT) /* SylixOS 添加的回调函数(AF_PACKET获取链路层报文) */ if (LWIP_HOOK_LINK_INPUT(p, inp)) { pbuf_free(p); return ERR_OK; } ... }
4.通过sendto函数发送数据。
和之前一样,选择AF_PACKET协议域,进入packet_sendto函数。
在packet_sendto->__packetEthRawSendto函数中,组装一个以太网报文,并通过netif->linkoutput函数将数据通过网卡驱动发送出去。
errno_t __packetEthRawSendto (CPVOID pvPacket, size_t stBytes, struct sockaddr_ll *psockaddrll) { ... /* 获取网络接口 */ pnetif = (struct netif *)netif_get_by_index((UINT)psockaddrll->sll_ifindex); ... /* 分配带有 PAD 的以太网报头 pbuf */ pbuf_hdr = pbuf_alloc(PBUF_RAW, ETH_HLEN + ETH_PAD_SIZE, PBUF_RAM); ... /* 拷贝数据至pbuf */ lib_memcpy(((u8_t *)pbuf_hdr->payload) + ETH_PAD_SIZE, pvPacket, ETH_HLEN); ... /* 通过网卡驱动发送函数,将数据发送出去 */ err = pnetif->linkoutput(pnetif, pbuf_hdr); ... }
至此,AF_PACKET套接字的创建即使用介绍完毕。
AF_PACKET套接字工作流程图如下:
相关文章推荐
- [LWIP学习]--SylixOS AF_UNIX socket套接字分析
- UNIX环境编程--------原始套接字学习笔记-----Linux原始套接字实现分析
- [LWIP学习]--LWIP网络通信流程(物理层,链路层,网络层,传输层,socket套接字,应用层通信流程汇总)
- [LWIP学习]--netconn结构体及其接口分析
- [LWIP学习]--pbuf_realloc函数分析
- [LWIP学习]--bind函数分析
- [LWIP学习]--accept函数分析
- [LWIP学习]--recv,recvfrom,recvmsg函数分析
- [LWIP学习]--socket函数分析
- [LWIP学习]--connect函数分析
- [LWIP学习]--send,sendto,sendmsg函数分析
- [LWIP学习]--原始套接字(SOCK_RAW)
- [LWIP学习]--listen函数分析
- [LWIP学习]--udp_input函数分析
- [LWIP学习]--tcpip_input,tcpip_inpkt,tcpip_thread函数分析(协议栈入口)
- input子系统学习笔记九 evdev输入事件驱动分析
- 北美18名校的数据挖掘,数据分析,人工智能及机器学习课程汇总
- 机器学习、大数据、深度学习、数据挖掘、统计、决策和风险分析、概率和模糊逻辑的常见问题解答
- scikit-learn学习之回归分析
- 北美18名校的数据挖掘,数据分析,人工智能及机器学习课程汇总