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;
IfType funType;
uint8_t macAddr[MAC_ADDR_SIZE];
....
struct NetDeviceInterFace *netDeviceIf;
struct NetDevice *owner;
struct NetDevStats stats;
} 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);
int32_t (*setMacAddr)(struct NetDevice *netDev, void *addr);
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);
int32_t (*changeMtu)(struct NetDevice *netDev, int32_t newMtu);
void (*linkStatusChanged)(struct NetDevice *netDev);
ProcessingResult (*specialEtherTypeProcess)(const struct NetDevice *netDev, NetBuf *buff);
};
根据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;
}
}
ret = GetPlatformIfName(id, ifName, IFNAMSIZ);
#ifdef _PRE_HDF_LINUX
result = NetDeviceInit(ifName, strlen(ifName), WIFI_LINK, FULL_OS);
#else
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;
uint32_t len;
};
typedef struct NetBuf {
struct DListHead dlist;
struct BufField bufs[MAX_BUF_NUM];
uint8_t *mem;
uint32_t len;
uint32_t dataLen;
void *dev;
uint32_t qmap;
uint8_t rsv[MAX_NETBUF_RESEVER_SIZE];
} NetBuf;
四、适配器 NetDeviceImpl
这里有一个问题,就是openharmony使用NetDev来描述网口,用NetBuf来描述网口数据,但是在lwip协议栈中,有他自己的一套机制来描述网口和网络数据。
这里就存在一个适配(adapt)的问题,需要一个适配器(adapter)来适配这两套机制,使得数据能在这两者之间顺利传递。
NetDev ------> netif
NetBuf ------> 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;
struct NetDeviceImplOp *interFace;
void *osPrivate;
};
所以NetDeviceImpl 就是芯片驱动程序 和 lwip协议栈沟通的中介,其成员的作用很明显:
- NetDevice:可通过netDevice->NetDeviceInterFace 调用芯片驱动程序
- NetDeviceImplOp:提供给开发者的接口
- osPrivate:指向 lwip的netif对象
NetDeviceImplOp
NetDeviceImplOp结构体就是提供给开发者的接口,使得网口驱动程序能与lwip协议栈交互。在net_device_adapter.c中的g_liteNdImplOps就是NetDeviceImplOp。我们将通过这个结构体,看lwip协议栈如何收发数据。
struct NetDeviceImplOp {
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,
.deInit = LiteNetDevDeInit,
.add = LiteNetDevAdd,
.delete = LiteNetDevDelete,
.setStatus = LiteNetDevSetStatus,
.setLinkStatus = LiteNetDevSetLinkStatus,
.getLinkStatus = LiteNetDevGetLinkStatus,
.receive = LiteNetDevReceive,
.setIpAddr = LiteNetSetIpAddr,
.dhcpsStart = LiteNetDhcpsStart,
.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;
};
static 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;
}
static int32_t LiteNetDevAdd(struct NetDeviceImpl *netDeviceImpl)
{
struct NetDeviceAdapterLite *liteNdPri = (struct NetDeviceAdapterLite *)netDeviceImpl->osPrivate;
struct NetDevice *lwipNd = netDeviceImpl->netDevice;
lwipNf = CreateLwipNetIf(netDeviceImpl, lwipNd创建netif);
if ((ret = netifapi_netif_add(lwipNf, &ipaddr, &netmask, &gw)) != ERR_OK) {
return HDF_FAILURE;
}
if (memcpy_s(lwipNf->hwaddr, NETIF_MAX_HWADDR_LEN, lwipNd->macAddr, MAC_ADDR_SIZE) != EOK) {
return HDF_FAILURE;
}
liteNdPri->lwipNetif = lwipNf;
IpV6SpecialProc(lwipNd, lwipNf);
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));
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)
{
struct netif *lwipNf = GetNetIfFromDevImpl(netDeviceImpl);
ProcessingResult ret = LiteNetDevDataFilter(netDeviceImpl, buff);
if (ret == PROCESSING_CONTINUE) {
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);
struct pbuf *pBuff = ConverNetBufToPBuf(buff);
driverif_input(lwipNf, pBuff);
NetBufFree(buff);
return HDF_SUCCESS;
}
driverif_input()是由lwip提供的接口,定义如下:
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;
struct NetDevice *netDev = ndImpl->netDevice;
struct NetDeviceInterFace *netDevIf = NULL;
struct NetBuf *netBuff = ConverPbuffToNetBuf(netDev, lwipBuf);
netDevIf = netDev->netDeviceIf;
netDevIf->xmit(netDev, netBuff);
return;
}
|