1 // SPDX-License-Identifier: BSD-2-Clause
3 * Copyright (C) 2023 The Android Open Source Project
9 #include <net/fastboot_tcp.h>
12 static char command
[FASTBOOT_COMMAND_LEN
] = {0};
13 static char response
[FASTBOOT_RESPONSE_LEN
] = {0};
15 static const unsigned short handshake_length
= 4;
16 static const uchar
*handshake
= "FB01";
18 static u16 curr_sport
;
19 static u16 curr_dport
;
20 static u32 curr_tcp_seq_num
;
21 static u32 curr_tcp_ack_num
;
22 static unsigned int curr_request_len
;
23 static enum fastboot_tcp_state
{
26 FASTBOOT_DISCONNECTING
27 } state
= FASTBOOT_CLOSED
;
29 static void fastboot_tcp_answer(u8 action
, unsigned int len
)
31 const u32 response_seq_num
= curr_tcp_ack_num
;
32 const u32 response_ack_num
= curr_tcp_seq_num
+
33 (curr_request_len
> 0 ? curr_request_len
: 1);
35 net_send_tcp_packet(len
, htons(curr_sport
), htons(curr_dport
),
36 action
, response_seq_num
, response_ack_num
);
39 static void fastboot_tcp_reset(void)
41 fastboot_tcp_answer(TCP_RST
, 0);
42 state
= FASTBOOT_CLOSED
;
45 static void fastboot_tcp_send_packet(u8 action
, const uchar
*data
, unsigned int len
)
47 uchar
*pkt
= net_get_async_tx_pkt_buf();
49 memset(pkt
, '\0', PKTSIZE
);
50 pkt
+= net_eth_hdr_size() + IP_TCP_HDR_SIZE
+ TCP_TSOPT_SIZE
+ 2;
51 memcpy(pkt
, data
, len
);
52 fastboot_tcp_answer(action
, len
);
53 memset(pkt
, '\0', PKTSIZE
);
56 static void fastboot_tcp_send_message(const char *message
, unsigned int len
)
58 __be64 len_be
= __cpu_to_be64(len
);
59 uchar
*pkt
= net_get_async_tx_pkt_buf();
61 memset(pkt
, '\0', PKTSIZE
);
62 pkt
+= net_eth_hdr_size() + IP_TCP_HDR_SIZE
+ TCP_TSOPT_SIZE
+ 2;
63 // Put first 8 bytes as a big endian message length
64 memcpy(pkt
, &len_be
, 8);
66 memcpy(pkt
, message
, len
);
67 fastboot_tcp_answer(TCP_ACK
| TCP_PUSH
, len
+ 8);
68 memset(pkt
, '\0', PKTSIZE
);
71 static void fastboot_tcp_handler_ipv4(uchar
*pkt
, u16 dport
,
72 struct in_addr sip
, u16 sport
,
73 u32 tcp_seq_num
, u32 tcp_ack_num
,
74 u8 action
, unsigned int len
)
76 int fastboot_command_id
;
78 u8 tcp_fin
= action
& TCP_FIN
;
79 u8 tcp_push
= action
& TCP_PUSH
;
83 curr_tcp_seq_num
= tcp_seq_num
;
84 curr_tcp_ack_num
= tcp_ack_num
;
85 curr_request_len
= len
;
90 if (len
!= handshake_length
||
91 strlen(pkt
) != handshake_length
||
92 memcmp(pkt
, handshake
, handshake_length
) != 0) {
96 fastboot_tcp_send_packet(TCP_ACK
| TCP_PUSH
,
97 handshake
, handshake_length
);
98 state
= FASTBOOT_CONNECTED
;
101 case FASTBOOT_CONNECTED
:
103 fastboot_tcp_answer(TCP_FIN
| TCP_ACK
, 0);
104 state
= FASTBOOT_DISCONNECTING
;
108 // First 8 bytes is big endian message length
109 command_size
= __be64_to_cpu(*(u64
*)pkt
);
113 // Only single packet messages are supported ATM
114 if (strlen(pkt
) != command_size
) {
115 fastboot_tcp_reset();
118 strlcpy(command
, pkt
, len
+ 1);
119 fastboot_command_id
= fastboot_handle_command(command
, response
);
120 fastboot_tcp_send_message(response
, strlen(response
));
121 fastboot_handle_boot(fastboot_command_id
,
122 strncmp("OKAY", response
, 4) == 0);
125 case FASTBOOT_DISCONNECTING
:
127 state
= FASTBOOT_CLOSED
;
131 memset(command
, 0, FASTBOOT_COMMAND_LEN
);
132 memset(response
, 0, FASTBOOT_RESPONSE_LEN
);
135 curr_tcp_seq_num
= 0;
136 curr_tcp_ack_num
= 0;
137 curr_request_len
= 0;
140 void fastboot_tcp_start_server(void)
142 printf("Using %s device\n", eth_get_name());
143 printf("Listening for fastboot command on tcp %pI4\n", &net_ip
);
145 tcp_set_tcp_handler(fastboot_tcp_handler_ipv4
);