Skip to content

Commit

Permalink
add dhcp.ClientState (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Apr 30, 2024
1 parent 60c7db9 commit faa9181
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 1 deletion.
27 changes: 27 additions & 0 deletions eth/dhcp/clientstate_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions eth/dhcp/dhcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,35 @@ const (
DefaultServerPort = 67
)

// ClientState represents the state of a DHCP client.
// Below is a state diagram of a DHCP client.
type ClientState uint8

// IsValid returns true if the state is within the valid range.
func (s ClientState) IsValid() bool {
return s > 0 || s < ClientState(s)
}

// install stringer with `go install golang.org/x/tools/cmd/stringer@latest`
//
//go:generate stringer -type=ClientState -trimprefix=State
const (
_ ClientState = iota
// On clean slate boot, abort, NAK or decline enter the INIT state.
StateInit
// After sending out a Discover enter SELECTING.
StateSelecting
// After receiving a worthy offer enter REQUESTING.
StateRequesting
// On reboot enter INIT-REBOOT state.
// StateInitReboot
// On sending out a Request enter REBOOTING.
// StateRebooting
// On ACK to Request enter BOUND.
StateBound
numStates uint8 = iota
)

type Option struct {
Num OptNum
Data []byte
Expand Down
2 changes: 1 addition & 1 deletion eth/dns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const (
// An RCode is a DNS response status code.
type RCode uint16

//go:generate stringer -type=RCode -trimprefix=RCode -output=rcode_string.go
// /go:generate stringer -type=RCode -trimprefix=RCode -output=rcode_string.go
const (
RCodeSuccess RCode = 0 // No error condition.
RCodeFormatError RCode = 1 // Format error - The name server was unable to interpret the query.
Expand Down
20 changes: 20 additions & 0 deletions stacks/dhcp_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,30 @@ func (d *DHCPClient) BeginRequest(cfg DHCPRequestConfig) error {
return d.stack.FlagPendingUDP(d.port)
}

// IsDone
//
// Deprecated: Use d.State()==dhcp.StateBound instead.
func (d *DHCPClient) IsDone() bool {
return d.state == dhcpStateDone || d.state == dhcpStateNaked
}

// State returns the current state of the DHCP client.
func (d *DHCPClient) State() dhcp.ClientState {
switch d.state {
case dhcpStateNone:
return dhcp.StateInit
case dhcpStateWaitOffer, dhcpStateGotOffer:
return dhcp.StateSelecting
case dhcpStateWaitAck:
return dhcp.StateRequesting
case dhcpStateDone:
return dhcp.StateBound
case dhcpStateNaked:
return dhcp.StateInit
}
return 0
}

// DHCPServer IP address field of the DHCP packet. Is the siaddr field of the DHCP packet, which can be overriden with the Server IP option.
func (d *DHCPClient) DHCPServer() netip.Addr {
return ipv4orInvalid(d.svip)
Expand Down
13 changes: 13 additions & 0 deletions stacks/stacks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/soypat/seqs"
"github.com/soypat/seqs/eth"
"github.com/soypat/seqs/eth/dhcp"
"github.com/soypat/seqs/eth/dns"
"github.com/soypat/seqs/stacks"
)
Expand Down Expand Up @@ -89,6 +90,13 @@ func TestDHCP(t *testing.T) {
}

func testDHCP(t *testing.T, cl *stacks.DHCPClient, sv *stacks.DHCPServer) {
checkClientState := func(t *testing.T, want dhcp.ClientState) {
t.Helper()
if cl.State() != want {
t.Fatalf("client state=%s want=%s", cl.State().String(), want.String())
}
}
checkClientState(t, dhcp.StateInit)
var requestedIP = netip.AddrFrom4([4]byte{192, 168, 1, 69})
cstack := cl.PortStack()
sstack := sv.PortStack()
Expand All @@ -103,6 +111,7 @@ func testDHCP(t *testing.T, cl *stacks.DHCPClient, sv *stacks.DHCPServer) {
if err != nil {
t.Fatal(err)
}

checkClientNotDone := func(msg string) {
t.Helper()
if cl.IsDone() {
Expand All @@ -116,6 +125,7 @@ func testDHCP(t *testing.T, cl *stacks.DHCPClient, sv *stacks.DHCPServer) {
if n < minDHCPSize {
t.Errorf("ex[%d] sent=%d want>=%d", ex, n, minDHCPSize)
}
checkClientState(t, dhcp.StateSelecting)
checkNoMoreDataSent(t, "after cl DISCOVER send", egr)
checkClientNotDone("after DISCOVER send")
egr.HandleRx(t)
Expand All @@ -125,6 +135,7 @@ func testDHCP(t *testing.T, cl *stacks.DHCPClient, sv *stacks.DHCPServer) {
if n < minDHCPSize {
t.Errorf("ex[%d] sent=%d want>=%d", ex, n, minDHCPSize)
}
checkClientState(t, dhcp.StateSelecting)
checkNoMoreDataSent(t, "after sv OFFER send", egr)
egr.HandleRx(t) // Client receives OFFER.
checkClientNotDone("after OFFER recv")
Expand All @@ -134,6 +145,7 @@ func testDHCP(t *testing.T, cl *stacks.DHCPClient, sv *stacks.DHCPServer) {
if n < minDHCPSize {
t.Errorf("ex[%d] sent=%d want>=%d", ex, n, minDHCPSize)
}
checkClientState(t, dhcp.StateRequesting)
checkNoMoreDataSent(t, "after client REQUEST send", egr)
checkClientNotDone("after REQUEST send")
egr.HandleRx(t) // Server receives REQUEST.
Expand All @@ -148,6 +160,7 @@ func testDHCP(t *testing.T, cl *stacks.DHCPClient, sv *stacks.DHCPServer) {
if !cl.IsDone() {
t.Fatal("client not processed ACK yet")
}
checkClientState(t, dhcp.StateBound)
}

func TestARP(t *testing.T) {
Expand Down

0 comments on commit faa9181

Please sign in to comment.