xref: /device/qemu/drivers/virtio/virtnet.c (revision d6aed566)
1/*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/*
17 * Simple virtio-net driver using HDF WIFI framework without real WIFI functions.
18 */
19
20#include "los_hw_cpu.h"
21#include "los_vm_iomap.h"
22#include "los_vm_zone.h"
23#include "netinet/if_ether.h"
24#include "arpa/inet.h"
25#include "hdf_device_desc.h"
26#include "wifi/hdf_wlan_chipdriver_manager.h"
27#include "wifi/wifi_mac80211_ops.h"
28#include "osal.h"
29#include "osal_io.h"
30#include "eapol.h"
31#include "virtmmio.h"
32
33#define HDF_LOG_TAG HDF_VIRTIO_NET
34
35#define VIRTIO_NET_F_MTU                    (1 << 3)
36#define VIRTIO_NET_F_MAC                    (1 << 5)
37struct VirtnetConfig {
38    uint8_t mac[6];
39    uint16_t status;
40    uint16_t maxVirtqPairs;
41    uint16_t mtu;
42};
43
44#define VIRTMMIO_NETIF_NAME                 "virtnet"
45#define VIRTMMIO_NETIF_DFT_GW               "10.0.2.2"
46#define VIRTMMIO_NETIF_DFT_MASK             "255.255.255.0"
47
48/* This struct is actually ignored by this simple driver */
49struct VirtnetHdr {
50    uint8_t flag;
51    uint8_t gsoType;
52    uint16_t hdrLen;
53    uint16_t gsoSize;
54    uint16_t csumStart;
55    uint16_t csumOffset;
56    uint16_t numBuffers;
57};
58
59/*
60 * We use two queues for Tx/Rx respectively. When Tx, we record outgoing NetBuf
61 * and free it when QEMU done. When Rx, we use fixed buffers, then allocate &
62 * copy to a NetBuf, and then HDF will consume & free the NetBuf.
63 * Every NetBuf is a solo packet, no chaining like LWIP pbuf. So every outgoing
64 * packet always occupy two desc items: one for VirtnetHdr, the other for NetBuf.
65 * Tx/Rx queues memory layout:
66 *                         Rx queue                                Tx queue
67 * +-----------------+------------------+------------------++------+-------+------+
68 * | desc: 16B align | avail: 2B align  | used: 4B align   || desc | avail | used |
69 * | 16∗(Queue Size) | 4+2∗(Queue Size) | 4+8∗(Queue Size) ||      |       |      |
70 * +-----------------+------------------+------------------++------+-------+------+
71 */
72#define VIRTQ_RX_QSZ        16
73#define VIRTQ_TX_QSZ        32
74#define PER_TX_ENTRIES      2
75#define PER_RXBUF_SIZE      (sizeof(struct VirtnetHdr) + ETH_FRAME_LEN)
76
77struct VirtNetif {
78    struct VirtmmioDev  dev;
79
80    uint16_t            tFreeHdr;   /* head of Tx free desc entries list */
81    uint16_t            tFreeNum;
82    NetBuf*             tbufRec[VIRTQ_TX_QSZ];
83    OSAL_DECLARE_SPINLOCK(transLock);
84
85    uint8_t             rbuf[VIRTQ_RX_QSZ][PER_RXBUF_SIZE];
86
87    struct VirtnetHdr   vnHdr;
88};
89
90static inline struct VirtNetif *GetVirtnetIf(const NetDevice *netDev)
91{
92    return (struct VirtNetif *)GET_NET_DEV_PRIV(netDev);
93}
94
95static bool Feature0(uint32_t features, uint32_t *supported, void *dev)
96{
97    NetDevice *netDev = dev;
98    struct VirtNetif *nic = GetVirtnetIf(netDev);
99    struct VirtnetConfig *conf = (struct VirtnetConfig *)(nic->dev.base + VIRTMMIO_REG_CONFIG);
100    int i;
101
102    if (features & VIRTIO_NET_F_MTU) {
103        if (conf->mtu > WLAN_MAX_MTU || conf->mtu < WLAN_MIN_MTU) {
104            HDF_LOGE("[%s]unsupported backend net MTU: %u", __func__, conf->mtu);
105            return false;
106        }
107        netDev->mtu = conf->mtu;
108        *supported |= VIRTIO_NET_F_MTU;
109    } else {
110        netDev->mtu = DEFAULT_MTU;
111    }
112
113    if ((features & VIRTIO_NET_F_MAC) == 0) {
114        HDF_LOGE("[%s]no MAC feature found", __func__);
115        return false;
116    }
117    for (i = 0; i < MAC_ADDR_SIZE; i++) {
118        netDev->macAddr[i] = conf->mac[i];
119    }
120    netDev->addrLen = MAC_ADDR_SIZE;
121    *supported |= VIRTIO_NET_F_MAC;
122
123    return true;
124}
125
126static bool Feature1(uint32_t features, uint32_t *supported, void *dev)
127{
128    (void)dev;
129    if (features & VIRTIO_F_VERSION_1) {
130        *supported |= VIRTIO_F_VERSION_1;
131    } else {
132        HDF_LOGE("[%s]net device has no VERSION_1 feature", __func__);
133        return false;
134    }
135
136    return true;
137}
138
139static int32_t InitTxFreelist(struct VirtNetif *nic)
140{
141    int i;
142
143    for (i = 0; i < nic->dev.vq[1].qsz - 1; i++) {
144        nic->dev.vq[1].desc[i].flag = VIRTQ_DESC_F_NEXT;
145        nic->dev.vq[1].desc[i].next = i + 1;
146    }
147    nic->tFreeHdr = 0;
148    nic->tFreeNum = nic->dev.vq[1].qsz;
149
150    return OsalSpinInit(&nic->transLock);
151}
152
153static void FreeTxEntry(struct VirtNetif *nic, uint16_t head)
154{
155    struct Virtq *q = &nic->dev.vq[1];
156    uint16_t idx = q->desc[head].next;
157    NetBuf *nb = NULL;
158
159    /* keep track of virt queue free entries */
160    OsalSpinLock(&nic->transLock);
161    if (nic->tFreeNum > 0) {
162        q->desc[idx].next = nic->tFreeHdr;
163        q->desc[idx].flag = VIRTQ_DESC_F_NEXT;
164    }
165    nic->tFreeNum += PER_TX_ENTRIES;
166    nic->tFreeHdr = head;
167    nb = nic->tbufRec[idx];
168    OsalSpinUnlock(&nic->transLock);
169
170    /* We free upstream Tx NetBuf! */
171    NetBufFree(nb);
172}
173
174static void PopulateRxBuffer(struct VirtNetif *nic)
175{
176    uint32_t i;
177    PADDR_T paddr;
178    struct Virtq *q = &nic->dev.vq[0];
179
180    for (i = 0; i < q->qsz; i++) {
181        paddr = VMM_TO_DMA_ADDR((VADDR_T)nic->rbuf[i]);
182
183        q->desc[i].pAddr = paddr;
184        q->desc[i].len = PER_RXBUF_SIZE;
185        q->desc[i].flag = VIRTQ_DESC_F_WRITE;
186
187        q->avail->ring[i] = i;
188    }
189}
190
191static int32_t ConfigQueue(struct VirtNetif *nic)
192{
193    VADDR_T base;
194    uint16_t qsz[VIRTQ_NUM];
195
196    base = ALIGN((VADDR_T)nic + sizeof(struct VirtNetif), VIRTQ_ALIGN_DESC);
197    qsz[0] = VIRTQ_RX_QSZ;
198    qsz[1] = VIRTQ_TX_QSZ;
199    if (VirtmmioConfigQueue(&nic->dev, base, qsz, VIRTQ_NUM) == 0) {
200        return HDF_DEV_ERR_DEV_INIT_FAIL;
201    }
202
203    PopulateRxBuffer(nic);
204
205    return InitTxFreelist(nic);
206}
207
208static uint16_t GetTxFreeEntry(struct VirtNetif *nic)
209{
210    uint32_t intSave;
211    uint16_t head, idx;
212    bool logged = false;
213
214RETRY:
215    OsalSpinLockIrqSave(&nic->transLock, &intSave);
216    if (PER_TX_ENTRIES > nic->tFreeNum) {
217        OsalSpinUnlockIrqRestore(&nic->transLock, &intSave);
218        if (!logged) {
219            HDF_LOGW("[%s]transmit queue is full", __func__);
220            logged = true;
221        }
222        LOS_TaskYield();
223        goto RETRY;
224    }
225
226    nic->tFreeNum -= PER_TX_ENTRIES;
227    head = nic->tFreeHdr;
228    idx = nic->dev.vq[1].desc[head].next;
229    /* new tFreeHdr may be invalid if list is empty, but tFreeNum must be valid: 0 */
230    nic->tFreeHdr = nic->dev.vq[1].desc[idx].next;
231    OsalSpinUnlockIrqRestore(&nic->transLock, &intSave);
232    nic->dev.vq[1].desc[idx].flag &= ~VIRTQ_DESC_F_NEXT;
233
234    return head;
235}
236
237static NetDevTxResult LowLevelOutput(NetDevice *netDev, NetBuf *p)
238{
239    uint16_t idx, head;
240    struct VirtNetif *nic = GetVirtnetIf(netDev);
241    struct Virtq *trans = &nic->dev.vq[1];
242
243    head = GetTxFreeEntry(nic);
244    trans->desc[head].pAddr = VMM_TO_DMA_ADDR((PADDR_T)&nic->vnHdr);
245    trans->desc[head].len = sizeof(struct VirtnetHdr);
246    idx = trans->desc[head].next;
247    trans->desc[idx].pAddr = LOS_PaddrQuery(NetBufGetAddress(p, E_DATA_BUF));
248    trans->desc[idx].len = NetBufGetDataLen(p);
249
250    nic->tbufRec[idx] = p;
251
252    trans->avail->ring[trans->avail->index % trans->qsz] = head;
253    DSB;
254    trans->avail->index++;
255    if (trans->used->flag != VIRTQ_USED_F_NO_NOTIFY) {
256        OSAL_WRITEL(1, nic->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
257    }
258
259    return NETDEV_TX_OK;
260}
261
262static NetBuf *LowLevelInput(const NetDevice *netDev, const struct VirtqUsedElem *e)
263{
264    struct VirtNetif *nic = GetVirtnetIf(netDev);
265    uint16_t len;
266    uint8_t *payload = NULL;
267    NetBuf *nb = NULL;
268
269    /* we allocate Rx NetBuf & fill in received packet */
270    len = e->len - sizeof(struct VirtnetHdr);
271    nb = NetBufDevAlloc(netDev, len);
272    if (nb == NULL) {
273        HDF_LOGE("[%s]allocate NetBuf failed, drop 1 packet", __func__);
274        return NULL;
275    }
276    payload = NetBufPush(nb, E_DATA_BUF, len);  /* here always succeed */
277    (void)memcpy_s(payload, len, nic->rbuf[e->id] + sizeof(struct VirtnetHdr), len);
278
279    return nb;
280}
281
282static void VirtnetRxHandle(NetDevice *netDev)
283{
284    struct VirtNetif *nic = GetVirtnetIf(netDev);
285    struct Virtq *q = &nic->dev.vq[0];
286    NetBuf *nb = NULL;
287    struct VirtqUsedElem *e = NULL;
288    uint16_t add = 0;
289
290    q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT;
291    while (1) {
292        if (q->last == q->used->index) {
293            q->avail->flag = 0;
294            /* recheck if new one come in between empty ring and enable interrupt */
295            DSB;
296            if (q->last == q->used->index) {
297                break;
298            }
299            q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT;
300        }
301
302        DSB;
303        e = &q->used->ring[q->last % q->qsz];
304        nb = LowLevelInput(netDev, e);
305        if (nb && NetIfRx(netDev, nb) != 0) {   /* Upstream free Rx NetBuf! */
306            HDF_LOGE("[%s]NetIfRx failed, drop 1 packet", __func__);
307            NetBufFree(nb);
308        }
309
310        /*
311         * Our fixed receive buffers always sit in the appropriate desc[].
312         * We only need to update the available ring to QEMU.
313         */
314        q->avail->ring[(q->avail->index + add++) % q->qsz] = e->id;
315        q->last++;
316    }
317    DSB;
318    q->avail->index += add;
319
320    if (q->used->flag != VIRTQ_USED_F_NO_NOTIFY) {
321        OSAL_WRITEL(0, nic->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
322    }
323}
324
325static void VirtnetTxHandle(struct VirtNetif *nic)
326{
327    struct Virtq *q = &nic->dev.vq[1];
328    struct VirtqUsedElem *e = NULL;
329
330    /* Bypass recheck as VirtnetRxHandle */
331    q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT;
332    while (q->last != q->used->index) {
333        DSB;
334        e = &q->used->ring[q->last % q->qsz];
335        FreeTxEntry(nic, e->id);
336        q->last++;
337    }
338    q->avail->flag = 0;
339}
340
341static void VirtnetIRQhandle(int swIrq, void *pDevId)
342{
343    (void)swIrq;
344    NetDevice *netDev = pDevId;
345    struct VirtNetif *nic = GetVirtnetIf(netDev);
346
347    if (!(OSAL_READL(nic->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) {
348        return;
349    }
350
351    VirtnetRxHandle(netDev);
352
353    VirtnetTxHandle(nic);
354
355    OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, nic->dev.base + VIRTMMIO_REG_INTERRUPTACK);
356}
357
358/*
359 * The whole initialization is complex, here is the main point.
360 *  -factory-    FakeWifiInit/Release: alloc, set & register HdfChipDriverFactory
361 *  -chip-       FakeFactoryInitChip/Release: alloc & set HdfChipDriver
362 *  -NetDevice-  VirtNetDeviceInit/DeInit: set & add NetDevice
363 *  -virtnet-    VirtnetInit/DeInit: virtio-net driver
364 */
365
366static int32_t VirtnetInit(NetDevice *netDev)
367{
368    int32_t ret, len;
369    struct VirtNetif *nic = NULL;
370
371    /* NOTE: For simplicity, alloc all these data from physical continuous memory. */
372    len = sizeof(struct VirtNetif) + VirtqSize(VIRTQ_RX_QSZ) + VirtqSize(VIRTQ_TX_QSZ);
373    nic = LOS_DmaMemAlloc(NULL, len, sizeof(void *), DMA_CACHE);
374    if (nic == NULL) {
375        HDF_LOGE("[%s]alloc nic memory failed", __func__);
376        return HDF_ERR_MALLOC_FAIL;
377    }
378    memset_s(nic, len, 0, len);
379    GET_NET_DEV_PRIV(netDev) = nic;
380
381    if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_NET, &nic->dev)) {
382        return HDF_DEV_ERR_NO_DEVICE;
383    }
384
385    VirtmmioInitBegin(&nic->dev);
386
387    if (!VirtmmioNegotiate(&nic->dev, Feature0, Feature1, netDev)) {
388        ret = HDF_DEV_ERR_DEV_INIT_FAIL;
389        goto ERR_OUT;
390    }
391
392    if ((ret = ConfigQueue(nic)) != HDF_SUCCESS) {
393        goto ERR_OUT;
394    }
395
396    ret = OsalRegisterIrq(nic->dev.irq, OSAL_IRQF_TRIGGER_NONE, (OsalIRQHandle)VirtnetIRQhandle,
397                          VIRTMMIO_NETIF_NAME, netDev);
398    if (ret != HDF_SUCCESS) {
399        HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret);
400        goto ERR_OUT;
401    }
402    nic->dev.irq |= ~_IRQ_MASK;
403
404    VritmmioInitEnd(&nic->dev);
405    return HDF_SUCCESS;
406
407ERR_OUT:
408    VirtmmioInitFailed(&nic->dev);
409    return ret;
410}
411
412static void VirtnetDeInit(NetDevice *netDev)
413{
414    struct VirtNetif *nic = GetVirtnetIf(netDev);
415
416    if (nic && (nic->dev.irq & ~_IRQ_MASK)) {
417        OsalUnregisterIrq(nic->dev.irq & _IRQ_MASK, netDev);
418    }
419    if (nic) {
420        LOS_DmaMemFree(nic);
421    }
422    GET_NET_DEV_PRIV(netDev) = NULL;
423}
424
425static int32_t VirtNetDeviceSetMacAddr(NetDevice *netDev, void *addr)
426{
427    uint8_t *p = addr;
428    for (int i = 0; i < netDev->addrLen; i++) {
429        netDev->macAddr[i] = p[i];
430    }
431    return HDF_SUCCESS;
432}
433
434static struct NetDeviceInterFace g_netDevOps = {
435    .setMacAddr = VirtNetDeviceSetMacAddr,
436    /*
437     * Link layer packet transmission chain:
438     *   LWIP netif->linkoutput = driverif_output, in kernel, pbuf
439     *       KHDF netif->drv_send = LwipSend, in HDF adapter, NetBuf
440     *           NetDevice .xmit = our driver, NetBuf
441     */
442    .xmit = LowLevelOutput,
443};
444
445#define VN_RANDOM_IP_MASK   0xFF    /* 255.255.255.0 subnet */
446#define VN_RANDOM_IP_SHF    24      /* network byte order */
447
448/* fake WIFI have to UP interface, assign IP by hand */
449static int32_t VirtNetDeviceInitDone(NetDevice *netDev)
450{
451    IpV4Addr ip, mask, gw;
452    uint32_t h, l;
453    int32_t ret;
454
455    if ((ret = NetIfSetStatus(netDev, NETIF_UP)) != HDF_SUCCESS) {
456        return ret;
457    }
458
459    /* odd way hope to get ~distinct~ IP for different guests */
460    LOS_GetCpuCycle(&h, &l);
461    l &= VN_RANDOM_IP_MASK;
462    if (l == 0 || l == (1 << 1)) {          /* avoid 10.0.2.0, 10.0.2.2 */
463        l++;
464    } else if (l == VN_RANDOM_IP_MASK) {    /* avoid 10.0.2.255 */
465        l--;
466    }
467    l <<= VN_RANDOM_IP_SHF;
468    ip.addr = (inet_addr(VIRTMMIO_NETIF_DFT_MASK) & inet_addr(VIRTMMIO_NETIF_DFT_GW)) | l;
469    mask.addr = inet_addr(VIRTMMIO_NETIF_DFT_MASK);
470    gw.addr = inet_addr(VIRTMMIO_NETIF_DFT_GW);
471    return NetIfSetAddr(netDev, &ip, &mask, &gw);
472}
473
474static int32_t VirtNetDeviceInit(struct HdfChipDriver *chipDriver, NetDevice *netDev)
475{
476    (void)chipDriver;
477    int32_t ret;
478
479    /* VirtnetInit also set netDev->macAddr, mtu, addrLen */
480    if ((ret = VirtnetInit(netDev)) != HDF_SUCCESS) {
481        return ret;
482    }
483    netDev->flags = NET_DEVICE_IFF_RUNNING;
484    netDev->neededHeadRoom = 0;
485    netDev->neededTailRoom = 0;
486    netDev->funType.wlanType = PROTOCOL_80211_IFTYPE_STATION;
487    netDev->netDeviceIf = &g_netDevOps;
488    if ((ret = NetDeviceAdd(netDev)) != HDF_SUCCESS) {
489        goto ERR_OUT;
490    }
491    if ((ret = CreateEapolData(netDev)) != HDF_SUCCESS) {
492        goto ERR_OUT;
493    }
494
495    /* everything is ready, now notify device the receive buffers */
496    struct VirtNetif *nic = GetVirtnetIf(netDev);
497    nic->dev.vq[0].avail->index = nic->dev.vq[0].qsz;
498    OSAL_WRITEL(0, nic->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
499
500    return VirtNetDeviceInitDone(netDev);
501
502ERR_OUT:
503    VirtnetDeInit(netDev);
504    return ret;
505}
506
507static int32_t VirtNetDeviceDeInit(struct HdfChipDriver *chipDriver, NetDevice *netDev)
508{
509    (void)chipDriver;
510
511    DestroyEapolData(netDev);
512
513    if (GetVirtnetIf(netDev)) {
514        VirtnetDeInit(netDev);
515    }
516
517    return NetDeviceDelete(netDev);
518}
519
520
521/*
522 * Followings are mainly fake data & funcs to mimic a wireless card.
523 *
524 * Here is fake MAC80211 base operations.
525 */
526static int32_t FakeWalSetMode(NetDevice *netDev, enum WlanWorkMode mode)
527{
528    (void)netDev;
529    if (mode != WLAN_WORKMODE_STA) {
530        HDF_LOGE("[%s]unsupported WLAN mode: %u", __func__, mode);
531        return HDF_ERR_NOT_SUPPORT;
532    }
533    return HDF_SUCCESS;
534}
535static int32_t FakeWalAddKey(NetDevice *netDev, uint8_t keyIndex, bool pairwise, const uint8_t *macAddr,
536                             struct KeyParams *params)
537{
538    (void)netDev;
539    (void)keyIndex;
540    (void)pairwise;
541    (void)macAddr;
542    (void)params;
543    return HDF_SUCCESS;
544}
545static int32_t FakeWalDelKey(NetDevice *netDev, uint8_t keyIndex, bool pairwise, const uint8_t *macAddr)
546{
547    (void)netDev;
548    (void)keyIndex;
549    (void)pairwise;
550    (void)macAddr;
551    return HDF_SUCCESS;
552}
553static int32_t FakeWalSetDefaultKey(NetDevice *netDev, uint8_t keyIndex, bool unicast, bool multicas)
554{
555    (void)netDev;
556    (void)keyIndex;
557    (void)unicast;
558    (void)multicas;
559    return HDF_SUCCESS;
560}
561static int32_t FakeWalGetDeviceMacAddr(NetDevice *netDev, int32_t type, uint8_t *mac, uint8_t len)
562{
563    (void)netDev;
564    (void)type;
565
566    for (int i = 0; i < len && i < netDev->addrLen; i++) {
567        mac[i] = netDev->macAddr[i];
568    }
569
570    return HDF_SUCCESS;
571}
572static int32_t FakeWalSetMacAddr(NetDevice *netDev, uint8_t *mac, uint8_t len)
573{
574    (void)netDev;
575
576    for (int i = 0; i < len && i < netDev->addrLen; i++) {
577        netDev->macAddr[i] = mac[i];
578    }
579
580    return HDF_SUCCESS;
581}
582static int32_t FakeWalSetTxPower(NetDevice *netDev, int32_t power)
583{
584    (void)netDev;
585    (void)power;
586    return HDF_SUCCESS;
587}
588#define FAKE_MAGIC_BAND     20
589#define FAKE_MAGIC_FREQ     2412
590#define FAKE_MAGIC_CAPS     20
591#define FAKE_MAGIC_RATE     100
592static int32_t FakeWalGetValidFreqsWithBand(NetDevice *netDev, int32_t band, int32_t *freqs, uint32_t *num)
593{
594    (void)netDev;
595
596    if (band != FAKE_MAGIC_BAND) {
597        HDF_LOGE("[%s]unsupported WLAN band: %dMHz", __func__, band);
598        return HDF_ERR_NOT_SUPPORT;
599    }
600
601    *freqs = FAKE_MAGIC_FREQ; /* MHz, channel 1 */
602    *num = 1;
603    return HDF_SUCCESS;
604}
605struct MemAllocForWlanHwCapability {
606    struct WlanHwCapability cap;
607    struct WlanBand band;
608    struct WlanChannel ch;
609    uint16_t rate;
610};
611static void FakeWalHwCapabilityRelease(struct WlanHwCapability *self)
612{
613    OsalMemFree(self);
614}
615static int32_t FakeWalGetHwCapability(NetDevice *netDev, struct WlanHwCapability **capability)
616{
617    (void)netDev;
618
619    struct MemAllocForWlanHwCapability *p = OsalMemCalloc(sizeof(struct MemAllocForWlanHwCapability));
620    if (p == NULL) {
621        HDF_LOGE("[%s]alloc memory failed", __func__);
622        return HDF_ERR_MALLOC_FAIL;
623    }
624    p->cap.Release = FakeWalHwCapabilityRelease;
625    p->cap.bands[0] = &p->band;
626    p->cap.htCapability = FAKE_MAGIC_CAPS;
627    p->cap.supportedRateCount = 1;
628    p->cap.supportedRates = &p->rate;
629    p->band.channelCount = 1;
630    p->ch.channelId = 1;
631    p->ch.centerFreq = FAKE_MAGIC_FREQ;
632    p->ch.flags = WLAN_CHANNEL_FLAG_NO_IR | WLAN_CHANNEL_FLAG_DFS_UNAVAILABLE;
633    p->rate = FAKE_MAGIC_RATE;
634
635    *capability = &p->cap;
636    return HDF_SUCCESS;
637}
638static struct HdfMac80211BaseOps g_fakeBaseOps = {
639    .SetMode = FakeWalSetMode,
640    .AddKey = FakeWalAddKey,
641    .DelKey = FakeWalDelKey,
642    .SetDefaultKey = FakeWalSetDefaultKey,
643    .GetDeviceMacAddr = FakeWalGetDeviceMacAddr,
644    .SetMacAddr = FakeWalSetMacAddr,
645    .SetTxPower = FakeWalSetTxPower,
646    .GetValidFreqsWithBand = FakeWalGetValidFreqsWithBand,
647    .GetHwCapability = FakeWalGetHwCapability
648};
649
650
651/*
652 * Fake STA operations.
653 */
654static int32_t FakeStaConnect(NetDevice *netDev, WlanConnectParams *param)
655{
656    (void)netDev;
657    (void)param;
658    return HDF_SUCCESS;
659}
660static int32_t FakeStaDisonnect(NetDevice *netDev, uint16_t reasonCode)
661{
662    (void)netDev;
663    (void)reasonCode;
664    return HDF_SUCCESS;
665}
666static int32_t FakeStaStartScan(NetDevice *netDev, struct WlanScanRequest *param)
667{
668    (void)netDev;
669    (void)param;
670    return HDF_SUCCESS;
671}
672static int32_t FakeStaAbortScan(NetDevice *netDev)
673{
674    (void)netDev;
675    return HDF_SUCCESS;
676}
677static int32_t FakeStaSetScanningMacAddress(NetDevice *netDev, unsigned char *mac, uint32_t len)
678{
679    (void)netDev;
680    (void)mac;
681    (void)len;
682    return HDF_SUCCESS;
683}
684static struct HdfMac80211STAOps g_fakeStaOps = {
685    .Connect = FakeStaConnect,
686    .Disconnect = FakeStaDisonnect,
687    .StartScan = FakeStaStartScan,
688    .AbortScan = FakeStaAbortScan,
689    .SetScanningMacAddress = FakeStaSetScanningMacAddress,
690};
691
692
693/*
694 * Fake factory & chip functions.
695 */
696static struct HdfChipDriver *FakeFactoryInitChip(struct HdfWlanDevice *device, uint8_t ifIndex)
697{
698    struct HdfChipDriver *chipDriver = NULL;
699    if (device == NULL || ifIndex > 0) {
700        HDF_LOGE("[%s]HdfWlanDevice is NULL or ifIndex>0", __func__);
701        return NULL;
702    }
703    chipDriver = OsalMemCalloc(sizeof(struct HdfChipDriver));
704    if (chipDriver == NULL) {
705        HDF_LOGE("[%s]alloc memory failed", __func__);
706        return NULL;
707    }
708
709    if (strcpy_s(chipDriver->name, MAX_WIFI_COMPONENT_NAME_LEN, VIRTMMIO_NETIF_NAME) != EOK) {
710        HDF_LOGE("[%s]strcpy_s failed", __func__);
711        OsalMemFree(chipDriver);
712        return NULL;
713    }
714    chipDriver->init = VirtNetDeviceInit;
715    chipDriver->deinit = VirtNetDeviceDeInit;
716    chipDriver->ops = &g_fakeBaseOps;
717    chipDriver->staOps = &g_fakeStaOps;
718
719    return chipDriver;
720}
721static void FakeFactoryReleaseChip(struct HdfChipDriver *chipDriver)
722{
723    if (chipDriver == NULL) {
724        return;
725    }
726    if (strcmp(chipDriver->name, VIRTMMIO_NETIF_NAME) != 0) {
727        HDF_LOGE("[%s]not my driver: %s", __func__, chipDriver->name);
728        return;
729    }
730    OsalMemFree(chipDriver);
731}
732static uint8_t FakeFactoryGetMaxIFCount(struct HdfChipDriverFactory *factory)
733{
734    (void)factory;
735    return 1;
736}
737static void FakeFactoryRelease(struct HdfChipDriverFactory *factory)
738{
739    OsalMemFree(factory);
740}
741static int32_t FakeFactoryInit(void)
742{
743    struct HdfChipDriverManager *driverMgr = NULL;
744    struct HdfChipDriverFactory *tmpFactory = NULL;
745    int32_t ret;
746
747    tmpFactory = OsalMemCalloc(sizeof(struct HdfChipDriverFactory));
748    if (tmpFactory == NULL) {
749        HDF_LOGE("[%s]alloc memory failed", __func__);
750        return HDF_ERR_MALLOC_FAIL;
751    }
752
753    driverMgr = HdfWlanGetChipDriverMgr();
754    if (driverMgr == NULL || driverMgr->RegChipDriver == NULL) {
755        HDF_LOGE("[%s]driverMgr or its RegChipDriver is NULL!", __func__);
756        OsalMemFree(tmpFactory);
757        return HDF_FAILURE;
758    }
759
760#define VIRTMMIO_WIFI_NAME  "fakewifi"  /* must match wlan_chip_virtnet.hcs::driverName */
761    tmpFactory->driverName = VIRTMMIO_WIFI_NAME;
762    tmpFactory->ReleaseFactory = FakeFactoryRelease;
763    tmpFactory->Build = FakeFactoryInitChip;
764    tmpFactory->Release = FakeFactoryReleaseChip;
765    tmpFactory->GetMaxIFCount = FakeFactoryGetMaxIFCount;
766    if ((ret = driverMgr->RegChipDriver(tmpFactory)) != HDF_SUCCESS) {
767        HDF_LOGE("[%s]register chip driver failed: %d", __func__, ret);
768        OsalMemFree(tmpFactory);
769        return ret;
770    }
771
772    return HDF_SUCCESS;
773}
774
775
776/*
777 * HDF entry.
778 */
779
780static int32_t FakeWifiInit(struct HdfDeviceObject *device)
781{
782    struct VirtmmioDev dev;
783
784    if (device == NULL) {
785        HDF_LOGE("[%s]device is null", __func__);
786        return HDF_ERR_INVALID_PARAM;
787    }
788
789    /* only when virtio-net do exist, we go on the other lots of work */
790    if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_NET, &dev)) {
791        return HDF_ERR_INVALID_OBJECT;
792    }
793
794    return FakeFactoryInit();
795}
796
797static void FakeWifiRelease(struct HdfDeviceObject *deviceObject)
798{
799    if (deviceObject) {
800        (void)ChipDriverMgrDeInit();
801    }
802}
803
804struct HdfDriverEntry g_fakeWifiEntry = {
805    .moduleVersion = 1,
806    .Init = FakeWifiInit,
807    .Release = FakeWifiRelease,
808    .moduleName = "HDF_FAKE_WIFI"
809};
810
811HDF_INIT(g_fakeWifiEntry);
812