mirror of
https://github.com/soypat/lneto.git
synced 2026-08-04 23:17:52 +00:00
813b7b5e57
* good code today * add netdev.Runner * round off APIs more * better interface method documentation * improve DHCP netstack API * add pico w netdev example * remove temp file * keep thinking about this. this is hard :/ * fix ci * small fixer * working dhcp * fix rebase API mismatches * begin adding espradio example * keep working on espradio, icmp not working * fix icmp by fixing dhcp
112 lines
3.7 KiB
Go
112 lines
3.7 KiB
Go
package xnet
|
|
|
|
import (
|
|
"context"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"github.com/soypat/lneto"
|
|
"github.com/soypat/lneto/x/netdev"
|
|
)
|
|
|
|
// Netstack is a more modern outward facing API wrapper on StackAsync.
|
|
type Netstack struct {
|
|
stack StackAsync
|
|
//gstack references stack above.
|
|
gstack StackGo
|
|
awaitDHCP bool
|
|
}
|
|
|
|
var _ netdev.Stack = (*Netstack)(nil)
|
|
|
|
// Configure configures this Stack with the argument mac, ip and gateway addresses.
|
|
// The Stack must resolve the gateway hardware address if set.
|
|
func (netstack *Netstack) Reset(cfg StackConfig, stackBackoff lneto.BackoffStrategy, poolcfg TCPPoolConfig) error {
|
|
err := netstack.stack.Reset(cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
netstack.gstack = netstack.stack.StackGo(stackBackoff, StackGoConfig{
|
|
ListenerPoolConfig: poolcfg,
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (netstack *Netstack) IPAddr4() [4]byte {
|
|
return netstack.stack.Addr4()
|
|
}
|
|
|
|
// EnableICMP enables responding/sending ICMP echo frames.
|
|
func (netstack *Netstack) EnableICMP(enabled bool) error {
|
|
return netstack.stack.EnableICMP(enabled)
|
|
}
|
|
|
|
// EnableDHCP performs a DHCPv4 request, writes the assigned address into the
|
|
// stack, and resolves the gateway hardware address via ARP.
|
|
func (netstack *Netstack) EnableDHCP(ctx context.Context, enabled bool, requestAddr netip.Addr) (assigned netip.Addr, routerGW netip.Addr, subnetBits int, err error) {
|
|
var addr [4]byte
|
|
if !enabled {
|
|
netstack.stack.dhcp.Reset()
|
|
return netip.Addr{}, netip.Addr{}, 0, nil
|
|
} else if requestAddr.Is4() {
|
|
addr = requestAddr.As4()
|
|
} else if requestAddr.IsValid() {
|
|
return netip.Addr{}, netip.Addr{}, 0, lneto.ErrUnsupported
|
|
}
|
|
timeout := 4 * time.Second
|
|
deadline, ok := ctx.Deadline()
|
|
if ok {
|
|
timeout = time.Until(deadline)
|
|
}
|
|
results, err := netstack.gstack.blk.DoDHCPv4(addr, timeout)
|
|
if err != nil {
|
|
return netip.Addr{}, netip.Addr{}, 0, err
|
|
}
|
|
// Write IP, subnet and DNS into the stack.
|
|
if err = netstack.stack.AssimilateDHCPResults(results); err != nil {
|
|
return netip.AddrFrom4(results.AssignedAddr4), results.Router, results.Subnet.Bits(), err
|
|
}
|
|
// Resolve gateway hardware address so egress packets are unicasted to the
|
|
// router rather than broadcast. Failure is non-fatal.
|
|
if results.Router.IsValid() {
|
|
gwHW, gwErr := netstack.gstack.blk.DoResolveHardwareAddress6(results.Router, 2*time.Second)
|
|
if gwErr == nil {
|
|
netstack.stack.SetGatewayHardwareAddr(gwHW)
|
|
}
|
|
}
|
|
return netip.AddrFrom4(results.AssignedAddr4), results.Router, results.Subnet.Bits(), nil
|
|
}
|
|
|
|
// Socket is a berkeley socket abstraction. Returns an [net.Listener] or [net.Conn] depending on laddr/raddr combination.
|
|
func (netstack *Netstack) Socket(ctx context.Context, network string, family, sotype int, laddr, raddr netip.AddrPort) (c any, err error) {
|
|
return netstack.gstack.SocketNetip(ctx, network, family, sotype, laddr, raddr)
|
|
}
|
|
|
|
// EgressPackets instructs Stack to write outgoing packets into bufs and writing the sizes into sizes not including initial offset.
|
|
// offset can be used to tell the stack to start writing after an offset for each buffer.
|
|
func (netstack *Netstack) EgressPackets(bufs [][]byte, sizes []int, offset int) (err error) {
|
|
var err0 error
|
|
for i := range bufs {
|
|
sizes[i], err0 = netstack.stack.EgressEthernet(bufs[i][offset:])
|
|
if sizes[i] == 0 {
|
|
return err
|
|
} else if err0 != nil {
|
|
err = err0
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
// IngressPackets is called on incoming packets so the Stack can direct packets to
|
|
// their respective node/connection and update internal state.
|
|
// offset instructs the Stack to start reading packets at an offset.
|
|
func (netstack *Netstack) IngressPackets(bufs [][]byte, offset int) (err error) {
|
|
for _, buf := range bufs {
|
|
err0 := netstack.stack.IngressEthernet(buf[offset:])
|
|
if err0 != nil {
|
|
err = err0
|
|
}
|
|
}
|
|
return err
|
|
}
|