diff options
Diffstat (limited to 'cmd/sbc_harness')
-rw-r--r-- | cmd/sbc_harness/hw/w5500.c | 164 |
1 files changed, 91 insertions, 73 deletions
diff --git a/cmd/sbc_harness/hw/w5500.c b/cmd/sbc_harness/hw/w5500.c index b4000f4..7470401 100644 --- a/cmd/sbc_harness/hw/w5500.c +++ b/cmd/sbc_harness/hw/w5500.c @@ -163,11 +163,11 @@ struct w5500_block_sock_reg { uint8_t mode; /* Sn_MR; see MODE_{x} below */ uint8_t command; /* Sn_CR; see CMD_{x} below */ uint8_t interrupt; /* Sn_IR */ - uint8_t status; /* Sn_SR; see STATUS_{x} below */ - uint8_t local_port[2]; /* Sn_PORT0, Sn_PORT1 */ - uint8_t remote_eth_addr[6]; /* Sn_DHAR0 ... SnDHAR5 */ - uint8_t remote_ip_addr[4]; /* Sn_DIPR0 ... Sn_DIP3 */ - uint8_t remote_port[2]; /* Sn_DPORT0 ... Sn_DPORT1 */ + uint8_t state; /* Sn_SR; see STATE_{x} below */ + uint8_t local_port[2]; /* Sn_PORT0, Sn_PORT1 */ + uint8_t remote_eth_addr[6]; /* Sn_DHAR0 ... SnDHAR5 */ + uint8_t remote_ip_addr[4]; /* Sn_DIPR0 ... Sn_DIP3 */ + uint8_t remote_port[2]; /* Sn_DPORT0 ... Sn_DPORT1 */ uint8_t max_seg_size[2]; /* Sn_MSSR0, Sn_MSSR1 */ uint8_t _reserved0[1]; @@ -218,74 +218,92 @@ static_assert(sizeof(struct w5500_block_sock_reg) == 0x30); #define CMD_SEND_KEEP ((uint8_t)0x22) /* TCP-only: send a keepalive without any data */ #define CMD_RECV ((uint8_t)0x40) -#define STATUS_CLOSED ((uint8_t)0x00) +#define STATE_CLOSED ((uint8_t)0x00) -/* The status modes starting with an underscore are expected to be - * very short-lived. */ - -#define STATUS_TCP_INIT ((uint8_t)0x13) -#define STATUS_TCP_LISTEN ((uint8_t)0x14) -#define _STATUS_TCP_SYNSENT ((uint8_t)0x15) /* in the CMD_CONNECT INIT->SYNSENT->ESTABLISHED transition */ -#define _STATUS_TCP_SYNRECV ((uint8_t)0x16) /* in the CMD_LISTEN LISTEN->SYNRECV->ESTABLISHED transition */ -#define STATUS_TCP_ESTABLISHED ((uint8_t)0x17) -/* The "graceful shutdown" state diagram (with the exception that - * reading the W5500's "status" register does not distinguish between - * FIN_WAIT_1 and FIN_WAIT_2; it just has a single FIN_WAIT): - * - * ║ - * V - * ┌─────────────┐ - * "active close" │ ESTABLISHED │ "passive close" - * (we send FIN first) └─────────────┘ (we send FIN second) - * V V - * ╔═══════════╝ ╚═════════╗ - * (CMD_DISCON) ║ - * ┌┈┈┈<(send FIN)>┈┈┈┈┈┈┈┈┐ ║ - * ┊ ║ └┈┈┈┈┈┈┈>(recv FIN) - * ┊ V ┌┈┈┈┈┈┈┈<(send ACK) - * "double active" ┊ ┌────────────┐ ┊ ║ - * (both sides think ┊ │ FIN_WAIT_1 │ ┊ V - * they sent FIN first) ┊ └────────────┘ ┊ ┌────────────┐ - * ┊ V V ┊ │ CLOSE_WAIT │ - * ╔═════════════════╝ ╔══╝ ┊ └────────────┘ - * (recv FIN)<┈┈┈┈┈┤ ║ ┊ V - * ┌┈┈<(send ACK)>┈┈┈┐ ┊ ║ ┊ ║ - * ┊ ║ └┈┈┈┈┈>(recv ACK)<┈┈┈┈┈┈┈┈┘ ║ - * ┊ ║ ┊ ║ ║ - * ┊ V ┊ V ║ - * ┊ ┌─────────┐ ┊ ┌────────────┐ ║ - * ┊ │ CLOSING │ ┊ │ FIN_WAIT_2 │ ║ - * ┊ └─────────┘ ┊ └────────────┘ ║ - * ┊ V ┊ V (CMD_DISCON) - * ┊ ║ ┊ ║ ┌┈┈┈┈┈┈┈<(send FIN) - * ┊ ║ └┈┈┈>(recv FIN)<┈┈┈┈┈┈┈┈┘ ║ - * ┊ ║ ┌┈┈┈┈┈<(send ACK)>┈┈┈┈┈┈┈┈┐ V - * └┈┈>(recv ACK)<┈┈┈┘ ║ ┊ ┌──────────┐ - * ╚═════════════════╗ ╚═╗ ┊ │ LAST_ACK │ - * V V ┊ └──────────┘ - * ┌───────────┐ ┊ V - * │ TIME_WAIT │ ┊ ║ - * └───────────┘ └┈┈┈┈┈┈┈>(recv ACK) - * V ║ - * ║ ║ - * (2*MSL has elapsed) ║ - * ╚═══════════╗ ╔══════════╝ - * V V - * ┌────────┐ - * │ CLOSED │ - * └────────┘ +/** + * The TCP state diagram is as follows. + * - Reading the W5500's "state" register does not distinguish between FIN_WAIT_1 and FIN_WAIT_2; + * it just has a single FIN_WAIT. + * - At any point the state can jump to "CLOSED" either by CMD_CLOSE or by a timeout. + * - Writing data is valid in ESTABLISHED and CLOSE_WAIT. + * - Reading data is valid in ESTABLISHED and FIN_WAIT. * - * One can still write in CLOSE_WAIT, and can still read in FIN_WAIT. + * │ CLOSED │ + * └────────┘ + * V + * (CMD_OPEN) + * V + * ┌────────┐ + * ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━│ INIT │━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ + * ┃ server ┃ └────────┘ ┃ client ┃ + * ┣━━━━━━━━━━━━━━━━┛ V ┃┃ V ┗━━━━━━━━━━━━━━━━┫ + * ┃ ╔═══════════╝ ┃┃ ╚═══════════╗ ┃ + * ┃ (CMD_LISTEN) ┃┃ (CMD_CONNECT) ┃ + * ┃ V ┌┃┃┈┈┈┈┈┈┈┈<(send SYN) ┃ + * ┃ ┌────────┐ ┊┃┃ V ┃ + * ┃ │ LISTEN │ ┊┃┃ ┌─────────┐ ┃ + * ┃ └────────┘ ┊┃┃ │ SYNSENT │ ┃ + * ┃ V ┊┃┃ └─────────┘ ┃ + * ┃ (recv SYN)<┈┈┈┈┈┈┘┃┃ V ┃ + * ┃ (send SYN+ACK)>┈┈┈┈┐┃┃ ║ ┃ + * ┃ V └┃┃┈┈┈┈┈┈>(recv SYN+ACK) ┃ + * ┃ ┌─────────┐ ┌┃┃┈┈┈┈┈┈┈┈<(send ack) ┃ + * ┃ │ SYNRECV │ ┊┃┃ ║ ┃ + * ┃ └─────────┘ ┊┃┃ ║ ┃ + * ┃ V V ┊┃┃ ║ ┃ + * ┃ ║ (recv ACK)<┈┈┈┘┃┃ ║ ┃ + * ┃ ║ ╚═════════╗ ┃┃ ╔═══════════╝ ┃ + * ┃ ╚═══╗ V ┃┃ V ┃ + * ┃ ║ ┌─────────────┐ ┃ + * ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━║━━━━━━━│ ESTABLISHED │━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + * ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━║━━━━━━━└─────────────┘━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + * ┃ ║ V ┃┃ V ┃ + * ┃ ╠═══════════╝ ┃┃ ╚═══════════╗ ┃ + * ┃ (CMD_DISCON) ┃┃ ║ ┃ + * ┃ ┌┈┈┈<(send FIN)>┈┈┈┈┈┈┐┃┃ ║ ┃ + * ┃ ┊ V └┃┃┈┈┈┈┈┈┈┈>(recv FIN) ┃ + * ┃ ┊ ┌────────────┐ ┌┃┃┈┈┈┈┈┈┈┈<(send ACK) ┃ + * ┃ ┊ │ FIN_WAIT_1 │ ┊┃┃ V ┃ + * ┃ ┊ └────────────┘ ┊┃┃ ┌────────────┐ ┃ + * ┃ ┊ V V ┊┃┃ │ CLOSE_WAIT │ ┃ + * ┃ ╔════════════════╝ ╔══╝ ┊┃┃ └────────────┘ ┃ + * ┃ (recv FIN)<┈┈┈┈┤ ║ ┊┃┃ V ┃ + * ┃ ┌┈┈<(send ACK)>┈┈┐ ┊ ║ ┊┃┃ ║ ┃ + * ┃ ┊ ║ └┈┈┈┈┈>(recv ACK)<┈┈┈┈┈┈┘┃┃ ║ ┃ + * ┃ ┊ V ┊ V ┃┃ ║ ┃ + * ┃ ┊ ┌─────────┐ ┊ ┌────────────┐ ┃┃ ║ ┃ + * ┃ ┊ │ CLOSING │ ┊ │ FIN_WAIT_2 │ ┃┃ ║ ┃ + * ┃ ┊ └─────────┘ ┊ └────────────┘ ┃┃ (CMD_DISCON) ┃ + * ┃ ┊ V ┊ V ┌┃┃┈┈┈┈┈┈┈┈<(send FIN) ┃ + * ┃ ┊ ║ └┈┈┈>(recv FIN)<┈┈┈┈┈┈┘┃┃ ║ ┃ + * ┃ ┊ ║ ┌┈┈┈┈┈<(send ACK)>┈┈┈┈┈┈┐┃┃ V ┃ + * ┃ └┈┈>(recv ACK)<┈┈┘ ║ ┊┃┃ ┌──────────┐ ┃ + * ┃ ╚════════════════╗ ╚═╗ ┊┃┃ │ LAST_ACK │ ┃ + * ┃ `------, ,-------' V V ┊┃┃ └──────────┘ ┃ + * ┃ \/ ┌───────────┐ ┊┃┃ V ┃ + * ┃ Both sides sent │ TIME_WAIT │ ┊┃┃ ║ ┃ + * ┃ FIN at the "same" └───────────┘ └┃┃┈┈┈┈┈┈┈┈>(recv ACK) ┃ + * ┃ time; both are V ┃┃ ║ ┃ + * ┃ active closers (2*MSL has elapsed) ┃┃ ║ ┃ + * ┃ ╚═══════════╗ ┃┃ ╔══════════╝ ┃ + * ┣━━━━━━━━━━━━━━━━┓ V ┃┃ V ┏━━━━━━━━━━━━━━━━┫ + * ┃ active closer ┃ ┌────────┐ ┃ passive closer ┃ + * ┗━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━│ CLOSED │━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┛ */ -#define _STATUS_TCP_FIN_WAIT ((uint8_t)0x18) /* during active close */ -#define _STATUS_TCP_CLOSING ((uint8_t)0x1a) /* during active close */ -#define _STATUS_TCP_TIME_WAIT ((uint8_t)0x1b) /* during active close */ -#define STATUS_TCP_CLOSE_WAIT ((uint8_t)0x1c) /* during passive close */ -#define _STATUS_TCP_LAST_ACK ((uint8_t)0x1d) /* during passive close */ +#define STATE_TCP_INIT ((uint8_t)0x13) +#define STATE_TCP_LISTEN ((uint8_t)0x14) /* server */ +#define STATE_TCP_SYNSENT ((uint8_t)0x15) /* client; during dial */ +#define STATE_TCP_SYNRECV ((uint8_t)0x16) /* server; during accept */ +#define STATE_TCP_ESTABLISHED ((uint8_t)0x17) +#define STATE_TCP_FIN_WAIT ((uint8_t)0x18) /* during active close */ +#define STATE_TCP_CLOSING ((uint8_t)0x1a) /* during active close */ +#define STATE_TCP_TIME_WAIT ((uint8_t)0x1b) /* during active close */ +#define STATE_TCP_CLOSE_WAIT ((uint8_t)0x1c) /* during passive close */ +#define STATE_TCP_LAST_ACK ((uint8_t)0x1d) /* during passive close */ -#define STATUS_UDP ((uint8_t)0x22) +#define STATE_UDP ((uint8_t)0x22) -#define STATUS_MACRAW ((uint8_t)0x42) +#define STATE_MACRAW ((uint8_t)0x42) #define REGWRITE_COMMON(spidev, field, val) do { \ assert(sizeof(val) == sizeof((struct w5500_block_common_reg).field)); \ @@ -401,7 +419,7 @@ struct libnet_listener *w5500_listen(struct w5500 *chip, uint8_t socknum, uint16 REGWRITE_SOCK(chip->spidev, socknum, command, CMD_OPEN); while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) cr_yield(); - while (REGREAD_SOCK(spidev, socknum, status, uint8_t) != STATUS_TCP_INIT) + while (REGREAD_SOCK(spidev, socknum, state, uint8_t) != STATE_TCP_INIT) cr_yield(); return (struct libnet_listener *)&chip->_listeners[socknum]; @@ -425,10 +443,10 @@ static struct libnet_conn *w5500_accept(struct libnet_listener *_self) { while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) cr_yield(); for (;;) { - uint8_t mode = REGREAD_SOCK(spidev, socknum, status, uint8_t); + uint8_t mode = REGREAD_SOCK(spidev, socknum, state, uint8_t); switch (mode) { - case STATUS_TCP_LISTEN: - case _STATUS_TCP_SYNRECV: + case STATE_TCP_LISTEN: + case STATE_TCP_SYNRECV: cr_yield(); break; default: @@ -464,7 +482,7 @@ static int w5500_close(struct libnet_conn *_self, bool rd, bool wr) { while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) cr_yield(); REGWRITE_SOCK(chip->spidev, socknum, interrupt, (uint8_t)0xff); - while (REGREAD_SOCK(chip->spidev, socknum, status, uint8_t) != STATUS_CLOSED) + while (REGREAD_SOCK(chip->spidev, socknum, state, uint8_t) != STATE_CLOSED) cr_yield(); return 0; |