tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/rtl8720dn/rtl8720dn.go (about)

     1  // Package rtl8720dn implements TCP wireless communication over UART
     2  // talking to a RealTek rtl8720dn module.
     3  //
     4  // 01/2023    sfeldma@gmail.com    Heavily modified to use netdev interface
     5  
     6  package rtl8720dn // import "tinygo.org/x/drivers/rtl8720dn"
     7  
     8  import (
     9  	"encoding/hex"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"machine"
    14  	"net"
    15  	"net/netip"
    16  	"strings"
    17  	"sync"
    18  	"time"
    19  
    20  	"tinygo.org/x/drivers"
    21  	"tinygo.org/x/drivers/netdev"
    22  	"tinygo.org/x/drivers/netlink"
    23  )
    24  
    25  var _debug debug = debugBasic
    26  
    27  //var _debug debug = debugBasic | debugNetdev
    28  //var _debug debug = debugBasic | debugNetdev | debugRpc
    29  
    30  var (
    31  	driverName = "Realtek rtl8720dn Wifi network device driver (rtl8720dn)"
    32  )
    33  
    34  const (
    35  	O_NONBLOCK     = 1 // note: different value than syscall.O_NONBLOCK (0x800)
    36  	RTW_MODE_STA   = 0x00000001
    37  	defaultChannel = 6
    38  )
    39  
    40  type sock int32
    41  
    42  type socket struct {
    43  	protocol int
    44  	inuse    bool
    45  }
    46  
    47  type Config struct {
    48  	// Enable
    49  	En machine.Pin
    50  
    51  	// UART config
    52  	Uart     *machine.UART
    53  	Tx       machine.Pin
    54  	Rx       machine.Pin
    55  	Baudrate uint32
    56  }
    57  
    58  type rtl8720dn struct {
    59  	cfg      *Config
    60  	notifyCb func(netlink.Event)
    61  	mu       sync.Mutex
    62  
    63  	uart *machine.UART
    64  	seq  uint64
    65  
    66  	debug bool
    67  
    68  	params *netlink.ConnectParams
    69  
    70  	netConnected bool
    71  	driverShown  bool
    72  	deviceShown  bool
    73  
    74  	killWatchdog chan bool
    75  
    76  	// keyed by sock as returned by rpc_lwip_socket()
    77  	sockets map[sock]*socket
    78  }
    79  
    80  func newSocket(protocol int) *socket {
    81  	return &socket{protocol: protocol, inuse: true}
    82  }
    83  
    84  func New(cfg *Config) *rtl8720dn {
    85  	return &rtl8720dn{
    86  		debug:        (_debug & debugRpc) != 0,
    87  		cfg:          cfg,
    88  		sockets:      make(map[sock]*socket),
    89  		killWatchdog: make(chan bool),
    90  	}
    91  }
    92  
    93  func (r *rtl8720dn) startDhcpc() error {
    94  	if result := r.rpc_tcpip_adapter_dhcpc_start(0); result == -1 {
    95  		return netdev.ErrStartingDHCPClient
    96  	}
    97  	return nil
    98  }
    99  
   100  func (r *rtl8720dn) connectToAP() error {
   101  
   102  	if len(r.params.Ssid) == 0 {
   103  		return netlink.ErrMissingSSID
   104  	}
   105  
   106  	if len(r.params.Passphrase) != 0 && len(r.params.Passphrase) < 8 {
   107  		return netlink.ErrShortPassphrase
   108  	}
   109  
   110  	if debugging(debugBasic) {
   111  		fmt.Printf("Connecting to Wifi SSID '%s'...", r.params.Ssid)
   112  	}
   113  
   114  	// Start the connection process
   115  	securityType := uint32(0) // RTW_SECURITY_OPEN
   116  	if len(r.params.Passphrase) != 0 {
   117  		securityType = 0x00400004 // RTW_SECURITY_WPA2_AES_PSK
   118  	}
   119  
   120  	result := r.rpc_wifi_connect(r.params.Ssid, r.params.Passphrase, securityType, -1, 0)
   121  	if result != 0 {
   122  		if debugging(debugBasic) {
   123  			fmt.Printf("FAILED\r\n")
   124  		}
   125  		return netlink.ErrConnectFailed
   126  	}
   127  
   128  	if debugging(debugBasic) {
   129  		fmt.Printf("CONNECTED\r\n")
   130  	}
   131  
   132  	if r.notifyCb != nil {
   133  		r.notifyCb(netlink.EventNetUp)
   134  	}
   135  
   136  	return r.startDhcpc()
   137  }
   138  
   139  func (r *rtl8720dn) startDhcps() error {
   140  	if result := r.rpc_tcpip_adapter_dhcps_start(0); result == -1 {
   141  		return netdev.ErrStartingDHCPServer
   142  	}
   143  	return nil
   144  }
   145  
   146  func (r *rtl8720dn) startAP() error {
   147  	if len(r.params.Ssid) == 0 {
   148  		return netlink.ErrMissingSSID
   149  	}
   150  
   151  	if len(r.params.Passphrase) != 0 && len(r.params.Passphrase) < 8 {
   152  		return netlink.ErrShortPassphrase
   153  	}
   154  
   155  	if debugging(debugBasic) {
   156  		fmt.Printf("Starting Wifi AP as SSID '%s'...", r.params.Ssid)
   157  	}
   158  
   159  	// Start the connection process
   160  	securityType := uint32(0) // RTW_SECURITY_OPEN
   161  	if len(r.params.Passphrase) != 0 {
   162  		securityType = 0x00400004 // RTW_SECURITY_WPA2_AES_PSK
   163  	}
   164  
   165  	result := r.rpc_wifi_start_ap(r.params.Ssid, r.params.Passphrase, securityType, defaultChannel)
   166  	if result != 0 {
   167  		if debugging(debugBasic) {
   168  			fmt.Printf("FAILED\r\n")
   169  		}
   170  		return netlink.ErrConnectFailed
   171  	}
   172  
   173  	if debugging(debugBasic) {
   174  		fmt.Printf("LISTENING\r\n")
   175  	}
   176  
   177  	if r.notifyCb != nil {
   178  		r.notifyCb(netlink.EventNetUp)
   179  	}
   180  
   181  	return r.startDhcps()
   182  }
   183  
   184  func (r *rtl8720dn) showDriver() {
   185  	if r.driverShown {
   186  		return
   187  	}
   188  	if debugging(debugBasic) {
   189  		fmt.Printf("\r\n")
   190  		fmt.Printf("%s\r\n\r\n", driverName)
   191  		fmt.Printf("Driver version           : %s\r\n", drivers.Version)
   192  	}
   193  	r.driverShown = true
   194  }
   195  
   196  func (r *rtl8720dn) initWifi() error {
   197  	if result := r.rpc_tcpip_adapter_init(); result == -1 {
   198  		return fmt.Errorf("TCP/IP adapter init failed")
   199  	}
   200  	if result := r.rpc_wifi_off(); result == -1 {
   201  		return errors.New("Error turning off WiFi")
   202  	}
   203  	if result := r.rpc_wifi_on(RTW_MODE_STA); result == -1 {
   204  		return errors.New("Error turning on WiFi")
   205  	}
   206  	if result := r.rpc_wifi_disconnect(); result == -1 {
   207  		return errors.New("Error disconnecting WiFi")
   208  	}
   209  	return nil
   210  }
   211  
   212  func (r *rtl8720dn) setupUART() {
   213  	r.uart = r.cfg.Uart
   214  	r.uart.Configure(machine.UARTConfig{TX: r.cfg.Tx,
   215  		RX: r.cfg.Rx, BaudRate: r.cfg.Baudrate})
   216  }
   217  
   218  func (r *rtl8720dn) start() error {
   219  	en := r.cfg.En
   220  	if en == 0 {
   221  		return fmt.Errorf("Must set Config.En")
   222  	}
   223  	en.Configure(machine.PinConfig{Mode: machine.PinOutput})
   224  	en.Low()
   225  	time.Sleep(100 * time.Millisecond)
   226  	en.High()
   227  	time.Sleep(1000 * time.Millisecond)
   228  	r.setupUART()
   229  	return r.initWifi()
   230  }
   231  
   232  func (r *rtl8720dn) stop() {
   233  	r.rpc_tcpip_adapter_stop(0)
   234  	r.cfg.En.Low()
   235  }
   236  
   237  func (r *rtl8720dn) showDevice() {
   238  	if r.deviceShown {
   239  		return
   240  	}
   241  	if debugging(debugBasic) {
   242  		fmt.Printf("RTL8720 firmware version : %s\r\n", r.getFwVersion())
   243  		fmt.Printf("MAC address              : %s\r\n", r.getMACAddr())
   244  		fmt.Printf("\r\n")
   245  	}
   246  	r.deviceShown = true
   247  }
   248  
   249  func (r *rtl8720dn) showIP() {
   250  	if debugging(debugBasic) {
   251  		ip, subnet, gateway, _ := r.getIP()
   252  		fmt.Printf("\r\n")
   253  		fmt.Printf("DHCP-assigned IP         : %s\r\n", ip)
   254  		fmt.Printf("DHCP-assigned subnet     : %s\r\n", subnet)
   255  		fmt.Printf("DHCP-assigned gateway    : %s\r\n", gateway)
   256  		fmt.Printf("\r\n")
   257  	}
   258  }
   259  
   260  func (r *rtl8720dn) networkDown() bool {
   261  	result := r.rpc_wifi_is_connected_to_ap()
   262  	return result != 0
   263  }
   264  
   265  func (r *rtl8720dn) watchdog() {
   266  	ticker := time.NewTicker(r.params.WatchdogTimeout)
   267  	for {
   268  		select {
   269  		case <-r.killWatchdog:
   270  			return
   271  		case <-ticker.C:
   272  			r.mu.Lock()
   273  			if r.networkDown() {
   274  				if debugging(debugBasic) {
   275  					fmt.Printf("Watchdog: Wifi NOT CONNECTED, trying again...\r\n")
   276  				}
   277  				if r.notifyCb != nil {
   278  					r.notifyCb(netlink.EventNetDown)
   279  				}
   280  				r.netConnect(false)
   281  			}
   282  			r.mu.Unlock()
   283  		}
   284  	}
   285  }
   286  
   287  func (r *rtl8720dn) netConnect(reset bool) error {
   288  	if reset {
   289  		if err := r.start(); err != nil {
   290  			return err
   291  		}
   292  	}
   293  	r.showDevice()
   294  
   295  retry:
   296  	for i := 0; r.params.Retries == 0 || i < r.params.Retries; i++ {
   297  		switch r.params.ConnectMode {
   298  		case netlink.ConnectModeAP:
   299  			if err := r.startAP(); err != nil {
   300  				if err == netlink.ErrConnectFailed {
   301  					continue
   302  				}
   303  				return err
   304  			}
   305  			break retry
   306  
   307  		default:
   308  			if err := r.connectToAP(); err != nil {
   309  				if err == netlink.ErrConnectFailed {
   310  					continue
   311  				}
   312  				return err
   313  			}
   314  			break retry
   315  		}
   316  	}
   317  
   318  	if r.networkDown() {
   319  		return netlink.ErrConnectFailed
   320  	}
   321  
   322  	r.showIP()
   323  	return nil
   324  }
   325  
   326  func (r *rtl8720dn) NetConnect(params *netlink.ConnectParams) error {
   327  
   328  	r.mu.Lock()
   329  	defer r.mu.Unlock()
   330  
   331  	if r.netConnected {
   332  		return netlink.ErrConnected
   333  	}
   334  
   335  	r.params = params
   336  
   337  	r.showDriver()
   338  
   339  	if err := r.netConnect(true); err != nil {
   340  		return err
   341  	}
   342  
   343  	r.netConnected = true
   344  
   345  	if r.params.WatchdogTimeout != 0 {
   346  		go r.watchdog()
   347  	}
   348  
   349  	return nil
   350  }
   351  
   352  func (r *rtl8720dn) netDisconnect() {
   353  	r.disconnect()
   354  }
   355  
   356  func (r *rtl8720dn) NetDisconnect() {
   357  
   358  	r.mu.Lock()
   359  	defer r.mu.Unlock()
   360  
   361  	if !r.netConnected {
   362  		return
   363  	}
   364  
   365  	if r.params.WatchdogTimeout != 0 {
   366  		r.killWatchdog <- true
   367  	}
   368  	r.netDisconnect()
   369  	r.stop()
   370  
   371  	r.netConnected = false
   372  
   373  	if debugging(debugBasic) {
   374  		fmt.Printf("\r\nDisconnected from Wifi SSID '%s'\r\n\r\n", r.params.Ssid)
   375  	}
   376  
   377  	if r.notifyCb != nil {
   378  		r.notifyCb(netlink.EventNetDown)
   379  	}
   380  }
   381  
   382  func (r *rtl8720dn) NetNotify(cb func(netlink.Event)) {
   383  	r.notifyCb = cb
   384  }
   385  
   386  func (r *rtl8720dn) GetHostByName(name string) (netip.Addr, error) {
   387  
   388  	if debugging(debugNetdev) {
   389  		fmt.Printf("[GetHostByName] name: %s\r\n", name)
   390  	}
   391  
   392  	r.mu.Lock()
   393  	defer r.mu.Unlock()
   394  
   395  	var ip [4]byte
   396  	result := r.rpc_netconn_gethostbyname(name, ip[:])
   397  	if result == -1 {
   398  		return netip.Addr{}, netdev.ErrHostUnknown
   399  	}
   400  
   401  	addr, ok := netip.AddrFromSlice(ip[:])
   402  	if !ok {
   403  		return netip.Addr{}, netdev.ErrMalAddr
   404  	}
   405  
   406  	return addr, nil
   407  }
   408  
   409  func (r *rtl8720dn) GetHardwareAddr() (net.HardwareAddr, error) {
   410  
   411  	if debugging(debugNetdev) {
   412  		fmt.Printf("[GetHardwareAddr]\r\n")
   413  	}
   414  
   415  	r.mu.Lock()
   416  	defer r.mu.Unlock()
   417  
   418  	mac := strings.ReplaceAll(r.getMACAddr(), ":", "")
   419  	addr, err := hex.DecodeString(mac)
   420  
   421  	return net.HardwareAddr(addr), err
   422  }
   423  
   424  func (r *rtl8720dn) Addr() (netip.Addr, error) {
   425  
   426  	if debugging(debugNetdev) {
   427  		fmt.Printf("[GetIPAddr]\r\n")
   428  	}
   429  
   430  	r.mu.Lock()
   431  	defer r.mu.Unlock()
   432  
   433  	ip, _, _, err := r.getIP()
   434  
   435  	return ip, err
   436  }
   437  
   438  func (r *rtl8720dn) clientTLS() uint32 {
   439  	client := r.rpc_wifi_ssl_client_create()
   440  	r.rpc_wifi_ssl_init(client)
   441  	r.rpc_wifi_ssl_set_timeout(client, 120*1000 /* usec? */)
   442  	return client
   443  }
   444  
   445  // See man socket(2) for standard Berkely sockets for Socket, Bind, etc.
   446  // The driver strives to meet the function and semantics of socket(2).
   447  
   448  func (r *rtl8720dn) Socket(domain int, stype int, protocol int) (int, error) {
   449  
   450  	if debugging(debugNetdev) {
   451  		fmt.Printf("[Socket] domain: %d, type: %d, protocol: %d\r\n",
   452  			domain, stype, protocol)
   453  	}
   454  
   455  	switch domain {
   456  	case netdev.AF_INET:
   457  	default:
   458  		return -1, netdev.ErrFamilyNotSupported
   459  	}
   460  
   461  	var newSock int32
   462  
   463  	r.mu.Lock()
   464  	defer r.mu.Unlock()
   465  
   466  	switch {
   467  	case protocol == netdev.IPPROTO_TCP && stype == netdev.SOCK_STREAM:
   468  		newSock = r.rpc_lwip_socket(netdev.AF_INET, netdev.SOCK_STREAM,
   469  			netdev.IPPROTO_TCP)
   470  	case protocol == netdev.IPPROTO_TLS && stype == netdev.SOCK_STREAM:
   471  		// TODO Investigate: using client number as socket number;
   472  		// TODO this may cause a problem if mixing TLS and non-TLS sockets?
   473  		newSock = int32(r.clientTLS())
   474  	case protocol == netdev.IPPROTO_UDP && stype == netdev.SOCK_DGRAM:
   475  		newSock = r.rpc_lwip_socket(netdev.AF_INET, netdev.SOCK_DGRAM,
   476  			netdev.IPPROTO_UDP)
   477  	default:
   478  		return -1, netdev.ErrProtocolNotSupported
   479  	}
   480  
   481  	if newSock == -1 {
   482  		return -1, netdev.ErrNoMoreSockets
   483  	}
   484  
   485  	socket := newSocket(protocol)
   486  	r.sockets[sock(newSock)] = socket
   487  
   488  	return int(newSock), nil
   489  }
   490  
   491  func ipToName(ip netip.AddrPort) []byte {
   492  	name := make([]byte, 16)
   493  	name[0] = 0x00
   494  	name[1] = netdev.AF_INET
   495  	name[2] = byte(ip.Port() >> 8)
   496  	name[3] = byte(ip.Port())
   497  	if ip.Addr().Is4() {
   498  		addr := ip.Addr().As4()
   499  		name[4] = byte(addr[0])
   500  		name[5] = byte(addr[1])
   501  		name[6] = byte(addr[2])
   502  		name[7] = byte(addr[3])
   503  	}
   504  	return name
   505  }
   506  
   507  func nameToIp(name []byte) netip.AddrPort {
   508  	port := uint16(name[2])<<8 | uint16(name[3])
   509  	addr, _ := netip.AddrFromSlice(name[4:8])
   510  	return netip.AddrPortFrom(addr, port)
   511  }
   512  
   513  func (r *rtl8720dn) Bind(sockfd int, ip netip.AddrPort) error {
   514  
   515  	if debugging(debugNetdev) {
   516  		fmt.Printf("[Bind] sockfd: %d, addr: %s\r\n", sockfd, ip)
   517  	}
   518  
   519  	r.mu.Lock()
   520  	defer r.mu.Unlock()
   521  
   522  	var sock = sock(sockfd)
   523  	var socket = r.sockets[sock]
   524  	var name = ipToName(ip)
   525  
   526  	switch socket.protocol {
   527  	case netdev.IPPROTO_TCP, netdev.IPPROTO_UDP:
   528  		result := r.rpc_lwip_bind(int32(sock), name, uint32(len(name)))
   529  		if result == -1 {
   530  			return fmt.Errorf("Bind to %s failed", ip)
   531  		}
   532  	default:
   533  		return netdev.ErrProtocolNotSupported
   534  	}
   535  
   536  	return nil
   537  }
   538  
   539  func (r *rtl8720dn) Connect(sockfd int, host string, ip netip.AddrPort) error {
   540  
   541  	port := ip.Port()
   542  
   543  	if debugging(debugNetdev) {
   544  		if host == "" {
   545  			fmt.Printf("[Connect] sockfd: %d, addr: %s\r\n", sockfd, ip)
   546  		} else {
   547  			fmt.Printf("[Connect] sockfd: %d, host: %s:%d\r\n", sockfd, host, port)
   548  		}
   549  	}
   550  
   551  	r.mu.Lock()
   552  	defer r.mu.Unlock()
   553  
   554  	var sock = sock(sockfd)
   555  	var socket = r.sockets[sock]
   556  	var name = ipToName(ip)
   557  
   558  	// Start the connection
   559  	switch socket.protocol {
   560  	case netdev.IPPROTO_TCP, netdev.IPPROTO_UDP:
   561  		result := r.rpc_lwip_connect(int32(sock), name, uint32(len(name)))
   562  		if result == -1 {
   563  			return fmt.Errorf("Connect to %s failed", ip)
   564  		}
   565  	case netdev.IPPROTO_TLS:
   566  		result := r.rpc_wifi_start_ssl_client(uint32(sock),
   567  			host, uint32(port), 0)
   568  		if result == -1 {
   569  			return fmt.Errorf("Connect to %s:%d failed", host, port)
   570  		}
   571  	}
   572  
   573  	return nil
   574  }
   575  
   576  func (r *rtl8720dn) Listen(sockfd int, backlog int) error {
   577  
   578  	if debugging(debugNetdev) {
   579  		fmt.Printf("[Listen] sockfd: %d\r\n", sockfd)
   580  	}
   581  
   582  	r.mu.Lock()
   583  	defer r.mu.Unlock()
   584  
   585  	var sock = sock(sockfd)
   586  	var socket = r.sockets[sock]
   587  
   588  	switch socket.protocol {
   589  	case netdev.IPPROTO_TCP:
   590  		result := r.rpc_lwip_listen(int32(sock), int32(backlog))
   591  		if result == -1 {
   592  			return fmt.Errorf("Listen failed")
   593  		}
   594  		result = r.rpc_lwip_fcntl(int32(sock), netdev.F_SETFL, O_NONBLOCK)
   595  		if result == -1 {
   596  			return fmt.Errorf("Fcntl failed")
   597  		}
   598  	case netdev.IPPROTO_UDP:
   599  		result := r.rpc_lwip_listen(int32(sock), int32(backlog))
   600  		if result == -1 {
   601  			return fmt.Errorf("Listen failed")
   602  		}
   603  	default:
   604  		return netdev.ErrProtocolNotSupported
   605  	}
   606  
   607  	return nil
   608  }
   609  
   610  func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
   611  
   612  	if debugging(debugNetdev) {
   613  		fmt.Printf("[Accept] sockfd: %d\r\n", sockfd)
   614  	}
   615  
   616  	r.mu.Lock()
   617  	defer r.mu.Unlock()
   618  
   619  	var newSock int32
   620  	var lsock = sock(sockfd)
   621  	var socket = r.sockets[lsock]
   622  	var name = ipToName(netip.AddrPort{})
   623  
   624  	switch socket.protocol {
   625  	case netdev.IPPROTO_TCP:
   626  	default:
   627  		return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
   628  	}
   629  
   630  	for {
   631  		// Accept() will be sleeping most of the time, checking for a
   632  		// new clients every 1/10 sec.
   633  		r.mu.Unlock()
   634  		time.Sleep(100 * time.Millisecond)
   635  		r.mu.Lock()
   636  
   637  		// Check if a client connected.  O_NONBLOCK is set on lsock.
   638  		namelen := uint32(len(name))
   639  		newSock = r.rpc_lwip_accept(int32(lsock), name, &namelen)
   640  		if newSock == -1 {
   641  			// No new client
   642  			time.Sleep(100 * time.Millisecond)
   643  			continue
   644  		}
   645  
   646  		// Get remote peer ip:port
   647  		namelen = uint32(len(name))
   648  		result := r.rpc_lwip_getpeername(int32(newSock), name, &namelen)
   649  		if result == -1 {
   650  			return -1, netip.AddrPort{}, fmt.Errorf("Getpeername failed")
   651  		}
   652  		raddr := nameToIp(name)
   653  
   654  		// If we've already seen this socket, we can re-use
   655  		// the socket and return it.  But, only if the socket
   656  		// is closed.  If it's not closed, we'll just come back
   657  		// later to reuse it.
   658  
   659  		clientSocket, ok := r.sockets[sock(newSock)]
   660  		if ok {
   661  			// Wait for client to Close
   662  			if clientSocket.inuse {
   663  				continue
   664  			}
   665  			// Reuse client socket
   666  			return int(newSock), raddr, nil
   667  		}
   668  
   669  		// Create new socket for client and return fd
   670  		r.sockets[sock(newSock)] = newSocket(socket.protocol)
   671  		return int(newSock), raddr, nil
   672  	}
   673  }
   674  
   675  func (r *rtl8720dn) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
   676  	var sock = sock(sockfd)
   677  	var socket = r.sockets[sock]
   678  
   679  	// Check if we've timed out
   680  	if !deadline.IsZero() {
   681  		if time.Now().After(deadline) {
   682  			return -1, netdev.ErrTimeout
   683  		}
   684  	}
   685  
   686  	switch socket.protocol {
   687  	case netdev.IPPROTO_TCP, netdev.IPPROTO_UDP:
   688  		result := r.rpc_lwip_send(int32(sock), buf, 0x00000008)
   689  		if result == -1 {
   690  			return -1, fmt.Errorf("Send error")
   691  		}
   692  		return int(result), nil
   693  	case netdev.IPPROTO_TLS:
   694  		result := r.rpc_wifi_send_ssl_data(uint32(sock), buf, uint16(len(buf)))
   695  		if result == -1 {
   696  			return -1, fmt.Errorf("TLS Send error")
   697  		}
   698  		return int(result), nil
   699  	}
   700  
   701  	return -1, netdev.ErrProtocolNotSupported
   702  }
   703  
   704  func (r *rtl8720dn) Send(sockfd int, buf []byte, flags int,
   705  	deadline time.Time) (int, error) {
   706  
   707  	if debugging(debugNetdev) {
   708  		fmt.Printf("[Send] sockfd: %d, len(buf): %d, flags: %d\r\n",
   709  			sockfd, len(buf), flags)
   710  	}
   711  
   712  	r.mu.Lock()
   713  	defer r.mu.Unlock()
   714  
   715  	// Break large bufs into chunks
   716  
   717  	chunkSize := 1436
   718  	for i := 0; i < len(buf); i += chunkSize {
   719  		end := i + chunkSize
   720  		if end > len(buf) {
   721  			end = len(buf)
   722  		}
   723  		_, err := r.sendChunk(sockfd, buf[i:end], deadline)
   724  		if err != nil {
   725  			return -1, err
   726  		}
   727  	}
   728  
   729  	return len(buf), nil
   730  }
   731  
   732  func (r *rtl8720dn) Recv(sockfd int, buf []byte, flags int,
   733  	deadline time.Time) (int, error) {
   734  
   735  	if debugging(debugNetdev) {
   736  		fmt.Printf("[Recv] sockfd: %d, len(buf): %d, flags: %d\r\n",
   737  			sockfd, len(buf), flags)
   738  	}
   739  
   740  	r.mu.Lock()
   741  	defer r.mu.Unlock()
   742  
   743  	var sock = sock(sockfd)
   744  	var socket = r.sockets[sock]
   745  	var length = len(buf)
   746  	var n int32
   747  
   748  	// Limit length read size to chunk large read requests
   749  	if length > 1436 {
   750  		length = 1436
   751  	}
   752  
   753  	for {
   754  		// Check if we've timed out
   755  		if !deadline.IsZero() {
   756  			if time.Now().After(deadline) {
   757  				return -1, netdev.ErrTimeout
   758  			}
   759  		}
   760  
   761  		switch socket.protocol {
   762  		case netdev.IPPROTO_TCP, netdev.IPPROTO_UDP:
   763  			n = r.rpc_lwip_recv(int32(sock), buf[:length],
   764  				uint32(length), 0x00000008, 0)
   765  		case netdev.IPPROTO_TLS:
   766  			n = r.rpc_wifi_get_ssl_receive(uint32(sock),
   767  				buf[:length], int32(length))
   768  		}
   769  
   770  		if n < 0 {
   771  			r.mu.Unlock()
   772  			time.Sleep(100 * time.Millisecond)
   773  			r.mu.Lock()
   774  			continue
   775  		} else if n == 0 {
   776  			if debugging(debugNetdev) {
   777  				fmt.Printf("[<--Recv] sockfd: %d, n: %d EOF\r\n",
   778  					sock, n)
   779  			}
   780  			return -1, io.EOF
   781  		}
   782  
   783  		if debugging(debugNetdev) {
   784  			fmt.Printf("[<--Recv] sockfd: %d, n: %d\r\n",
   785  				sock, n)
   786  		}
   787  
   788  		return int(n), nil
   789  	}
   790  }
   791  
   792  func (r *rtl8720dn) Close(sockfd int) error {
   793  
   794  	if debugging(debugNetdev) {
   795  		fmt.Printf("[Close] sockfd: %d\r\n", sockfd)
   796  	}
   797  
   798  	r.mu.Lock()
   799  	defer r.mu.Unlock()
   800  
   801  	var sock = sock(sockfd)
   802  	var socket = r.sockets[sock]
   803  	var result int32
   804  
   805  	if !socket.inuse {
   806  		return nil
   807  	}
   808  
   809  	switch socket.protocol {
   810  	case netdev.IPPROTO_TCP, netdev.IPPROTO_UDP:
   811  		result = r.rpc_lwip_close(int32(sock))
   812  	case netdev.IPPROTO_TLS:
   813  		r.rpc_wifi_stop_ssl_socket(uint32(sock))
   814  		r.rpc_wifi_ssl_client_destroy(uint32(sock))
   815  	}
   816  
   817  	if result == -1 {
   818  		return netdev.ErrClosingSocket
   819  	}
   820  
   821  	socket.inuse = false
   822  
   823  	return nil
   824  }
   825  
   826  func (r *rtl8720dn) SetSockOpt(sockfd int, level int, opt int, value interface{}) error {
   827  
   828  	if debugging(debugNetdev) {
   829  		fmt.Printf("[SetSockOpt] sockfd: %d\r\n", sockfd)
   830  	}
   831  
   832  	return netdev.ErrNotSupported
   833  }
   834  
   835  func (r *rtl8720dn) disconnect() error {
   836  	result := r.rpc_wifi_disconnect()
   837  	if result == -1 {
   838  		return fmt.Errorf("Error disconnecting Wifi")
   839  	}
   840  	return nil
   841  }
   842  
   843  func (r *rtl8720dn) getFwVersion() string {
   844  	return r.rpc_system_version()
   845  }
   846  
   847  func (r *rtl8720dn) getMACAddr() string {
   848  	var mac [18]uint8
   849  	r.rpc_wifi_get_mac_address(mac[:])
   850  	return string(mac[:])
   851  }
   852  
   853  func (r *rtl8720dn) getIP() (ip, subnet, gateway netip.Addr, err error) {
   854  	var ip_info [12]byte
   855  	result := r.rpc_tcpip_adapter_get_ip_info(0, ip_info[:])
   856  	if result == -1 {
   857  		err = fmt.Errorf("Get IP info failed")
   858  		return
   859  	}
   860  	ip, _ = netip.AddrFromSlice(ip_info[0:4])
   861  	subnet, _ = netip.AddrFromSlice(ip_info[4:8])
   862  	gateway, _ = netip.AddrFromSlice(ip_info[8:12])
   863  	return
   864  }