Files
lneto/tcp/control_rcvhandlers.go
T
2025-02-10 20:26:02 -03:00

108 lines
2.7 KiB
Go

package tcp
func (tcb *ControlBlock) rcvListen(seg Segment) (pending Flags, err error) {
switch {
case !seg.Flags.HasAll(FlagSYN):
err = errExpectedSYN
}
if err != nil {
return 0, err
}
// Initialize all connection state:
tcb.resetSnd(tcb.snd.ISS, seg.WND)
tcb.resetRcv(tcb.rcv.WND, seg.SEQ)
// We must respond with SYN|ACK frame after receiving SYN in listen state (three way handshake).
tcb.pending[0] = synack
tcb._state = StateSynRcvd
return synack, nil
}
func (tcb *ControlBlock) rcvSynSent(seg Segment) (pending Flags, err error) {
hasSyn := seg.Flags.HasAny(FlagSYN)
hasAck := seg.Flags.HasAny(FlagACK)
switch {
case !hasSyn:
err = errExpectedSYN
case hasAck && seg.ACK != tcb.snd.UNA+1:
err = errBadSegack
}
if err != nil {
return 0, err
}
if hasAck {
tcb._state = StateEstablished
pending = FlagACK
tcb.resetRcv(tcb.rcv.WND, seg.SEQ)
} else {
// Simultaneous connection sync edge case.
pending = synack
tcb._state = StateSynRcvd
tcb.resetSnd(tcb.snd.ISS, seg.WND)
tcb.resetRcv(tcb.rcv.WND, seg.SEQ)
}
return pending, nil
}
func (tcb *ControlBlock) rcvSynRcvd(seg Segment) (pending Flags, err error) {
switch {
// case !seg.Flags.HasAll(FlagACK):
// err = errors.New("rcvSynRcvd: expected ACK")
case seg.ACK != tcb.snd.UNA+1:
err = errBadSegack
}
if err != nil {
return 0, err
}
tcb._state = StateEstablished
return 0, nil
}
func (tcb *ControlBlock) rcvEstablished(seg Segment) (pending Flags, err error) {
flags := seg.Flags
dataToAck := seg.DATALEN > 0
hasFin := flags.HasAny(FlagFIN)
if dataToAck || hasFin {
pending = FlagACK
if hasFin {
// See Figure 5: TCP Connection State Diagram of RFC 9293.
tcb._state = StateCloseWait
tcb.pending[1] = FlagFIN // Queue FIN for after the CloseWait ACK.
}
}
return pending, nil
}
func (tcb *ControlBlock) rcvFinWait1(seg Segment) (pending Flags, err error) {
flags := seg.Flags
hasFin := flags&FlagFIN != 0
hasAck := flags&FlagACK != 0
switch {
case hasFin && hasAck && seg.ACK == tcb.snd.NXT:
// Special case: Server sent a FINACK response to our FIN so we enter TimeWait directly.
// We have to check ACK against send NXT to avoid simultaneous close sequence edge case.
tcb._state = StateTimeWait
case hasFin:
tcb._state = StateClosing
case hasAck:
// TODO(soypat): Check if this branch does NOT need ACK queued. Online flowcharts say not needed.
tcb._state = StateFinWait2
default:
return 0, errFinwaitExpectedACK
}
pending = FlagACK
return pending, nil
}
func (tcb *ControlBlock) rcvFinWait2(seg Segment) (pending Flags, err error) {
if !seg.Flags.HasAll(finack) {
return pending, errFinwaitExpectedFinack
}
tcb._state = StateTimeWait
return FlagACK, nil
}