OpenHarmony NetDev网络设备
文章目录
-
- NetDev
-
- 一、前提
- 二、NetDevice
- 三、NetBuf
- 四、适配器 NetDeviceImpl
-
- NetDeviceImplOp
- 五、netif
-
- 网口发送数据到lwip
- 网口从lwip接收数据
NetDev
WIFI 芯片属于网络设备,自然也要归OpenHarmony的网络框架管理,本文用于了解 网络数据如何在协议栈和网络驱动之间传输。
网络设备的使用需要配合网络协议栈,OpenHarmony的网络协议栈有两种,一种是liteos-a内核使用的lwip协议栈,一种是标准系统linux内核网络协议栈。
本文以lwip协议栈为例来了解。
一、前提
网络数据的通路:(这里的网口驱动是具体wifi芯片的驱动程序,由厂商实现。)
发送数据:应用程序->lwip->网口驱动
接受数据:网口驱动->lwip->应用程序
二、NetDevice
openharmony使用NetDevice结构体来描述所有的网络设备(网口)
typedef struct NetDevice { NetIfCategory netifCateg; //内核类型 char name[IFNAMSIZ]; //设备名称 NetLinkType LinkLayerType; //链路层类型:以太网或wifi IfType funType; //网络端口类型 including AP, STA, and P2P uint8_t macAddr[MAC_ADDR_SIZE]; //mac地址 .... struct NetDeviceInterFace *netDeviceIf; //提供给驱动厂商的接口 struct NetDevice *owner; /< Network device */ struct NetDevStats stats; /< Network statistics */} NetDevice;
其中 NetDeviceInterFace 对象的作用是初始化、打开、关闭一个网络设备等以下功能,必须由驱动开发厂商根据具体的wifi芯片编写的驱动来实现其中的函数:
struct NetDeviceInterFace { int32_t (*init)(struct NetDevice *netDev); //初始化网络设备 void (*deInit)(struct NetDevice *netDev);int32_t (*open)(struct NetDevice *netDev); //打开数据链路层 int32_t (*stop)(struct NetDevice *netDev); NetDevTxResult (*xmit)(struct NetDevice *netDev, NetBuf *netBuff); //发送数据 int32_t (*ioctl)(struct NetDevice *netDev, IfReq *req, int32_t cmd); /< Used for the control command word. */ int32_t (*setMacAddr)(struct NetDevice *netDev, void *addr);//设置mac地址 struct NetDevStats *(*getStats)(struct NetDevice *netDev); //获取设备状态 void (*setNetIfStatus)(struct NetDevice *netDev, NetIfStatus status); //设置状态 uint16_t (*selectQueue)(struct NetDevice *netDev, NetBuf *netBuff);//选择一个队列 uint32_t (*netifNotify)(struct NetDevice *netDev, NetDevNotify *notify); /< Notifies the network port status. */ int32_t (*changeMtu)(struct NetDevice *netDev, int32_t newMtu); //改变mtu void (*linkStatusChanged)(struct NetDevice *netDev); //检查以太网连接状态 ProcessingResult (*specialEtherTypeProcess)(const struct NetDevice *netDev, NetBuf *buff); /< Performs private processing without * involving network-layer data. */};
根据HdfWlanDevice 创建NetDevice:
struct NetDevice *AllocPlatformNetDevice(struct HdfWlanDevice *device){ struct NetDevice *result = NULL; char ifName[IFNAMSIZ] = {0}; struct HdfWifiNetDeviceData *data = NULL; data = (struct HdfWifiNetDeviceData *)OsalMemCalloc(sizeof(struct HdfWifiNetDeviceData)); do { //分配网卡编号 for (i = 0; i < MAX_IF_COUNT; i++) { if (((g_allocatedIfMap >> i) & 0x1) != 0x1) { id = i; break; } }//生成网卡名称:wlan0 ret = GetPlatformIfName(id, ifName, IFNAMSIZ);#ifdef _PRE_HDF_LINUX result = NetDeviceInit(ifName, strlen(ifName), WIFI_LINK, FULL_OS);#else //获取netdev result = NetDeviceInit(ifName, strlen(ifName), WIFI_LINK, LITE_OS);#endif } while (false); result->classDriverName = HDF_WIFI_PLATFORM_DRIVER_NAME; result->classDriverPriv = data; data->netInterfaceId = id; SET_BIT(device->netIfMap, id); SET_BIT(g_allocatedIfMap, id); return result;}
三、NetBuf
NetBuf用于描述网络数据,以在网络协议栈和网络驱动之间传输数据。
//记录一段网络数据的偏移和长度struct BufField { uint32_t offset; /< Offset of the buffer segment */ uint32_t len; /< Length of the buffer segment */};typedef struct NetBuf { struct DListHead dlist; //双链表 struct BufField bufs[MAX_BUF_NUM]; uint8_t *mem; //内存地址 uint32_t len; //内存长度 uint32_t dataLen; //真实数据长度 void *dev; //接受到该数据的netdev uint32_t qmap; /< Queue mappings of the network data buffer */ uint8_t rsv[MAX_NETBUF_RESEVER_SIZE]; /< Reserved field. For details, see {@link MAX_NETBUF_RESEVER_SIZE}. */} NetBuf;
四、适配器 NetDeviceImpl
这里有一个问题,就是openharmony使用NetDev来描述网口,用NetBuf来描述网口数据,但是在lwip协议栈中,有他自己的一套机制来描述网口和网络数据。
这里就存在一个适配(adapt)的问题,需要一个适配器(adapter)来适配这两套机制,使得数据能在这两者之间顺利传递。
NetDev ------> netifNetBuf ------> pbuf
NetDeviceImpl结构体应运而生,该部分的代码在bearpi_micro/drivers/adapter/khdf/liteos/network/src/net_device_adapter.c,net_device_adapter顾名思义就是把net_device适配到lwip的netif。同理netbuf_adapter.c实现的就是把netbuf适配到lwip的pbuf。
struct NetDeviceImpl { struct NetDevice *netDevice;//可通过netDevice->NetDeviceInterFace 调用芯片驱动程序 struct NetDeviceImplOp *interFace;//调用lwip的接口 void *osPrivate;//指向 lwip的netif对象};
所以NetDeviceImpl 就是芯片驱动程序 和 lwip协议栈沟通的中介,其成员的作用很明显:
- NetDevice:可通过netDevice->NetDeviceInterFace 调用芯片驱动程序
- NetDeviceImplOp:提供给开发者的接口
- osPrivate:指向 lwip的netif对象
NetDeviceImplOp
NetDeviceImplOp结构体就是提供给开发者的接口,使得网口驱动程序能与lwip协议栈交互。在net_device_adapter.c中的g_liteNdImplOps就是NetDeviceImplOp。我们将通过这个结构体,看lwip协议栈如何收发数据。
struct NetDeviceImplOp { //初始化netdev int32_t (*init)(struct NetDeviceImpl *netDevice); int32_t (*deInit)(struct NetDeviceImpl *netDevice); int32_t (*add)(struct NetDeviceImpl *netDevice); int32_t (*delete)(struct NetDeviceImpl *netDevice); int32_t (*setStatus)(struct NetDeviceImpl *netDevice, NetIfStatus status); int32_t (*setLinkStatus)(struct NetDeviceImpl *netDevice, NetIfLinkStatus status); int32_t (*getLinkStatus)(struct NetDeviceImpl *netDevice, NetIfLinkStatus *status); int32_t (*receive)(struct NetDeviceImpl *netDevice, NetBuf *buff, ReceiveFlag flag); int32_t (*setIpAddr)(struct NetDeviceImpl *netDevice, const IpV4Addr *ipAddr, const IpV4Addr *netMask, const IpV4Addr *gw); int32_t (*dhcpsStart)(struct NetDeviceImpl *netDevice, char *ip, uint16_t ipNum); int32_t (*dhcpsStop)(struct NetDeviceImpl *netDevice); int32_t (*dhcpStart)(struct NetDeviceImpl *netDevice); int32_t (*dhcpStop)(struct NetDeviceImpl *netDevice); int32_t (*dhcpIsBound)(struct NetDeviceImpl *netDevice); int32_t (*changeMacAddr)(struct NetDeviceImpl *netDevice);};static struct NetDeviceImplOp g_liteNdImplOps = { .init = LiteNetDevInit,//创建netif .deInit = LiteNetDevDeInit, .add = LiteNetDevAdd,//创建netif并添加到协议栈 .delete = LiteNetDevDelete, .setStatus = LiteNetDevSetStatus, .setLinkStatus = LiteNetDevSetLinkStatus, .getLinkStatus = LiteNetDevGetLinkStatus, .receive = LiteNetDevReceive,//将数据上传到协议栈 .setIpAddr = LiteNetSetIpAddr,//设置ip .dhcpsStart = LiteNetDhcpsStart,//开始dhcp .dhcpsStop = LiteNetDhcpsStop, .dhcpStart = LiteNetDhcpStart, .dhcpStop = LiteNetDhcpStop, .dhcpIsBound = LiteNetDhcpIsBound, .changeMacAddr = LiteNetChangeMacAddr,};
五、netif
要使用lwip协议栈,就需要创建一个netif来描述所使用的wifi 网口。NetDeviceImplOp结构体提供给开发者创建netif的接口:
创建初始化lwip netif的接口:
- g_liteNdImplOps.init()
- g_liteNdImplOps.add()
struct NetDeviceAdapterLite { struct netif *lwipNetif;};//创建netifstatic int32_t LiteNetDevInit(struct NetDeviceImpl *netDeviceImpl){ struct NetDeviceAdapterLite *liteNdPri = NULL; liteNdPri = (struct NetDeviceAdapterLite *)OsalMemCalloc(sizeof(struct NetDeviceAdapterLite)); (void)memset_s(liteNdPri, sizeof(struct NetDeviceAdapterLite), 0, sizeof(struct NetDeviceAdapterLite)); netDeviceImpl->osPrivate = (void *)liteNdPri;}//创建netif并添加到协议栈static int32_t LiteNetDevAdd(struct NetDeviceImpl *netDeviceImpl){ struct NetDeviceAdapterLite *liteNdPri = (struct NetDeviceAdapterLite *)netDeviceImpl->osPrivate; struct NetDevice *lwipNd = netDeviceImpl->netDevice;//根据lwipNd创建netif lwipNf = CreateLwipNetIf(netDeviceImpl, lwipNd创建netif); if ((ret = netifapi_netif_add(lwipNf, &ipaddr, &netmask, &gw)) != ERR_OK) { return HDF_FAILURE; } //复制mac地址 if (memcpy_s(lwipNf->hwaddr, NETIF_MAX_HWADDR_LEN, lwipNd->macAddr, MAC_ADDR_SIZE) != EOK) { return HDF_FAILURE; } liteNdPri->lwipNetif = lwipNf; IpV6SpecialProc(lwipNd, lwipNf); /* set netif default status */ netifapi_netif_set_default(lwipNf); netif_set_link_callback(lwipNf, LiteNetifLinkChangeCallback); return HDF_SUCCESS;}
创建netif的同时实现了netif的一些函数如drv_send、drv_set_hwaddr,这些函数需要调用芯片驱动。
static struct netif *CreateLwipNetIf(const struct NetDeviceImpl *netDeviceImpl, const struct NetDevice *netDev){ lwipNf = (struct netif *)OsalMemCalloc(sizeof(struct netif)); (void)memset_s(lwipNf, sizeof(struct netif), 0, sizeof(struct netif)); /* register netif to lwip */ lwipNf->state = (void *)netDeviceImpl; lwipNf->drv_send = LwipSend; lwipNf->drv_set_hwaddr = LwipSetHwaddr; lwipNf->link_layer_type = netDev->LinkLayerType; lwipNf->hwaddr_len = MAC_ADDR_SIZE; lwipNf->drv_config = LwipDrvConfig; return lwipNf;}
网口发送数据到lwip
在网口的驱动程序收到数据后,需要传递给lwip协议栈,这时调用NetDeviceImplOp->reveive()函数来传递数据:
首先把netdev转换成netif,把netbuf转换成pbuf,再调用driverif_input()传递pbuf给lwip协议栈。
static int32_t LiteNetDevReceive(struct NetDeviceImpl *netDeviceImpl, struct NetBuf *buff, ReceiveFlag flag){ //get lwip netif struct netif *lwipNf = GetNetIfFromDevImpl(netDeviceImpl); ProcessingResult ret = LiteNetDevDataFilter(netDeviceImpl, buff); if (ret == PROCESSING_CONTINUE) { //call LiteNetDevDataReceive to send pbuf return LiteNetDevDataReceive(netDeviceImpl, buff); } else if (ret == PROCESSING_COMPLETE) { return HDF_SUCCESS; } else { return HDF_FAILURE; }}static int32_t LiteNetDevDataReceive(struct NetDeviceImpl *netDeviceImpl, struct NetBuf *buff){ struct netif *lwipNf = GetNetIfFromDevImpl(netDeviceImpl); //Conver NetBuf To PBuf struct pbuf *pBuff = ConverNetBufToPBuf(buff);//post pbuff to lwip driverif_input(lwipNf, pBuff); NetBufFree(buff); return HDF_SUCCESS;}
driverif_input()是由lwip提供的接口,定义如下:
/* * This function should be called by network driver to pass the input packet to LwIP. * Before calling this API, driver has to keep the packet in pbuf structure. Driver has to * call pbuf_alloc() with type as PBUF_RAM to create pbuf structure. Then driver * has to pass the pbuf structure to this API. This will add the pbuf into the TCPIP thread. * Once this packet is processed by TCPIP thread, pbuf will be freed. Driver is not required to * free the pbuf. * * @param netif the lwip network interface structure for this driverif * @param p packet in pbuf structure format */void driverif_input(struct netif *netif, struct pbuf *p)
网口从lwip接收数据
lwip协议栈的数据会传递到netif结构体,而我们在创建netif结构体时,设置了drv_send()等函数,lwip协议栈就会调用该函数,在这个函数中我们就需要实现netif和netdev,pbuf和netbuf的转换,调用NetDeviceInterFace 里的函数发送数据。
void LwipSend(struct netif *netif, struct pbuf *lwipBuf){ struct NetDeviceImpl *ndImpl = (struct NetDeviceImpl *)netif->state; //get netdev struct NetDevice *netDev = ndImpl->netDevice; struct NetDeviceInterFace *netDevIf = NULL;//get netbuf struct NetBuf *netBuff = ConverPbuffToNetBuf(netDev, lwipBuf);//get NetDeviceInterFace netDevIf = netDev->netDeviceIf; //send netbuf netDevIf->xmit(netDev, netBuff); return;}