In a project, I want to use Raspberry Pi Zero W as an USB wifi dongle to my USB Host(PC). Currently only station mode needed, but I would like it has AP mode either, just like a real Wifi Dongle. Is there anyway to do that through a few configuration steps? Or I have to write up a real linux usb gadget driver in C code to emulate a wifi card on RPi Zero W？
I do not have a Raspberry Pi Zero W so I cannot test it with this hardware. But when you have established an OTG Gadget ether emulation with the USB connection then you have a virtual but regular interface that should be usable like any other ethernet interface. Afaik it has the name usb0 but to be a bit more generic for others I will name it eth0.
You want to use the RasPi as station. Then in principle you can use either routing or bridging. The problem is that the on-board wifi device does not support bridging a wifi client connection. For further information look at Raspberry Pi WiFi to Ethernet Bridge for a server?.
I will show how I would use routing to connect a wired ethernet connection to a remote hotspot via wifi with systemd-networkd. The disadvantage of routing is that the subnet for eth0 must be different from that for wlan0. If not then the connection will not work. To reduce matching subnets I will make that for eth0 as small as possible from a pool as big as possible. That's from the class A private subnet 10.0.0.0/8.
For reference I use Raspbian Stretch Lite 2019-04-08 updated with
sudo apt update && sudo apt full-upgrade && sudo reboot on 2019-04-28.
Example for this setup:
wired wifi wan
laptop <───────> (eth0)RPi(wlan0) <.~.~.~> hotspot <───> INTERNET
\ / \
(dhcp 10.148.238.125 (dhcp
from RPi) from hotspot)
Switch over to systemd-networkd:
# disable classic networking
rpi ~$ sudo -Es
rpi ~# systemctl mask networking.service
rpi ~# systemctl mask dhcpcd.service
rpi ~# mv /etc/network/interfaces /etc/network/interfaces~
rpi ~# sed -i '1i resolvconf=NO' /etc/resolvconf.conf
# enable systemd-networkd
rpi ~# systemctl enable systemd-networkd.service
rpi ~# systemctl enable systemd-resolved.service
rpi ~# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
Configure wpa_supplicant with your settings for
rpi ~# cat > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf <<EOF
rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
rpi ~# systemctl disable wpa_supplicant.service
rpi ~# systemctl enable [email protected]
Configure interfaces with this files:
rpi ~# cat > /etc/systemd/network/04-eth0.network <<EOF
rpi ~# cat > /etc/systemd/network/08-wlan0.network <<EOF
With the used netmask
/30 for eth0 we have selected a very small subnet just for two devices:
Hosts/Net: 2 (Private Internet)
We have to use NAT because it is not practicable to configure the hostspot for routing. To configure NAT we have to extend the wpa_supplicant service with:
rpi ~# systemctl edit [email protected]
In the empty editor insert these statements, save them and quit the editor:
ExecStartPre=/sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
ExecStopPost=/sbin/iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE
Use proxy arp
If you want a workaround for bridging the two interfaces wlan0 and eth0 you can use proxy arp. The setup is a bit more complex and need some additional helpers. How to setup this you can look at the Workaround for a wifi bridge on a Raspberry Pi with proxy arp.
Use an access point
If you also want to use an access point I suggest to configure a routed client connection together with it and a bridge for the access point with the wired connection to the laptop. This would be a general solution for your question. You can connect to any remote hostspot as station and use the local access point from the RasPi as repeater for other wifi devices. The laptop is connected by wire to the same subnet (broadcast domain) spawned by the access point. If the remote hotspot provides an internet access then all local devices incl. the laptop can use this resource. How to setup it you can look at Access point as WiFi repeater, optional with bridge, section Setup bridge.