> 文档中心 > OpenHarmony NetDev网络设备

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;}