package main import ( "fmt" // "log" "github.com/insomniacslk/dhcp/dhcpv6" ) // FSM from RFC 2131 Figure 5 type DHCP interface { SendDiscover() SendRequest() } type FSM struct { state State dhcp DHCP } type DHCPv4 struct { } func (f FSM) Init(d DHCP) { fmt.Println("Init") f.dhcp = d f.state = stInit(f.dhcp, nil) // go } func (f FSM) InputMessage() { } func (d DHCPv4) SendDiscover() { } type DHCPv6 struct { } func (d DHCPv6) SendDiscover() { fmt.Println("SendDiscover") } func (d DHCPv6) SendRequest() { fmt.Println("SendRequest") } type EventType uint8 const ( EventTypeNone EventType = 0 EventTypeMessage EventType = 1 EventTypeTimeoutT1 EventType = 2 EventTypeTimeoutT2 EventType = 3 EventTypeTimeoutLease EventType = 3 ) type Event interface { Type() EventType } // type TimerType uint8 // const ( // TimerNone TimerType = 0 // TimerT1 TimerType = 1 // TimerT2 TimerType = 2 // TimerLease TimerType = 3 // ) // type EventTimeout struct { // Event // Timer TimerType // } type EventMessage struct { Event msg dhcpv6.Message } func (ev *EventMessage) Type() EventType { return EventTypeMessage } func (ev *EventMessage) Msg() dhcpv6.Message { return ev.msg } type State func (d DHCP, ev Event) (next State) func stInit(d DHCP, ev Event) State { // Send Discover d.SendDiscover() return stSelecting } func stSelecting(d DHCP, ev Event) State { switch ev.Type() { case EventTypeMessage: msg := ev.(*EventMessage).Msg() switch msg.Type() { case dhcpv6.MessageTypeAdvertise: // Select first offer d.SendRequest() return stRequesting } } return stSelecting } func stRequesting(d DHCP, ev Event) State { switch ev.Type() { case EventTypeMessage: msg := ev.(*EventMessage).Msg() switch msg.Type() { case dhcpv6.MessageTypeAdvertise: // Discard return stRequesting case dhcpv6.MessageTypeReply: // Record lease, set T1, T2 return stBound case dhcpv6.MessageTypeNone: // FIXME NAK // Send Decline return stInit } } return stRequesting } func stBound(d DHCP, ev Event) State { switch ev.Type() { case EventTypeTimeoutT1: // Send Request return stRenewing case EventTypeMessage: msg := ev.(*EventMessage).Msg() switch msg.Type() { case dhcpv6.MessageTypeAdvertise: case dhcpv6.MessageTypeReply: case dhcpv6.MessageTypeNone: // TODO or NACK // Send Decline return stBound } } return stBound } func stRenewing(d DHCP, ev Event) State { // FIXME switch ev.Type() { case EventTypeTimeoutT2: // Broadcast request? return stRebinding case EventTypeMessage: msg := ev.(*EventMessage).Msg() switch msg.Type() { case dhcpv6.MessageTypeReply: // Record lease, set T1, T2 return stBound case dhcpv6.MessageTypeNone: // FIXME NAK // HALT network return stInit } } return stRenewing } func stRebinding(d DHCP, ev Event) State { switch ev.Type() { case EventTypeTimeoutLease: // Halt network return stInit case EventTypeMessage: msg := ev.(*EventMessage).Msg() switch msg.Type() { case dhcpv6.MessageTypeReply: // Record lease, set timers T1, T2 return stBound case dhcpv6.MessageTypeNone: // FIXME NAK // Halt network return stInit } } return stRebinding }