fastboot_tcp.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: BSD-2-Clause
  2. /*
  3. * Copyright (C) 2023 The Android Open Source Project
  4. */
  5. #include <common.h>
  6. #include <fastboot.h>
  7. #include <net.h>
  8. #include <net/fastboot_tcp.h>
  9. #include <net/tcp.h>
  10. static char command[FASTBOOT_COMMAND_LEN] = {0};
  11. static char response[FASTBOOT_RESPONSE_LEN] = {0};
  12. static const unsigned short handshake_length = 4;
  13. static const uchar *handshake = "FB01";
  14. static u16 curr_sport;
  15. static u16 curr_dport;
  16. static u32 curr_tcp_seq_num;
  17. static u32 curr_tcp_ack_num;
  18. static unsigned int curr_request_len;
  19. static enum fastboot_tcp_state {
  20. FASTBOOT_CLOSED,
  21. FASTBOOT_CONNECTED,
  22. FASTBOOT_DISCONNECTING
  23. } state = FASTBOOT_CLOSED;
  24. static void fastboot_tcp_answer(u8 action, unsigned int len)
  25. {
  26. const u32 response_seq_num = curr_tcp_ack_num;
  27. const u32 response_ack_num = curr_tcp_seq_num +
  28. (curr_request_len > 0 ? curr_request_len : 1);
  29. net_send_tcp_packet(len, htons(curr_sport), htons(curr_dport),
  30. action, response_seq_num, response_ack_num);
  31. }
  32. static void fastboot_tcp_reset(void)
  33. {
  34. fastboot_tcp_answer(TCP_RST, 0);
  35. state = FASTBOOT_CLOSED;
  36. }
  37. static void fastboot_tcp_send_packet(u8 action, const uchar *data, unsigned int len)
  38. {
  39. uchar *pkt = net_get_async_tx_pkt_buf();
  40. memset(pkt, '\0', PKTSIZE);
  41. pkt += net_eth_hdr_size() + IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
  42. memcpy(pkt, data, len);
  43. fastboot_tcp_answer(action, len);
  44. memset(pkt, '\0', PKTSIZE);
  45. }
  46. static void fastboot_tcp_send_message(const char *message, unsigned int len)
  47. {
  48. __be64 len_be = __cpu_to_be64(len);
  49. uchar *pkt = net_get_async_tx_pkt_buf();
  50. memset(pkt, '\0', PKTSIZE);
  51. pkt += net_eth_hdr_size() + IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
  52. // Put first 8 bytes as a big endian message length
  53. memcpy(pkt, &len_be, 8);
  54. pkt += 8;
  55. memcpy(pkt, message, len);
  56. fastboot_tcp_answer(TCP_ACK | TCP_PUSH, len + 8);
  57. memset(pkt, '\0', PKTSIZE);
  58. }
  59. static void fastboot_tcp_handler_ipv4(uchar *pkt, u16 dport,
  60. struct in_addr sip, u16 sport,
  61. u32 tcp_seq_num, u32 tcp_ack_num,
  62. u8 action, unsigned int len)
  63. {
  64. int fastboot_command_id;
  65. u64 command_size;
  66. u8 tcp_fin = action & TCP_FIN;
  67. u8 tcp_push = action & TCP_PUSH;
  68. curr_sport = sport;
  69. curr_dport = dport;
  70. curr_tcp_seq_num = tcp_seq_num;
  71. curr_tcp_ack_num = tcp_ack_num;
  72. curr_request_len = len;
  73. switch (state) {
  74. case FASTBOOT_CLOSED:
  75. if (tcp_push) {
  76. if (len != handshake_length ||
  77. strlen(pkt) != handshake_length ||
  78. memcmp(pkt, handshake, handshake_length) != 0) {
  79. fastboot_tcp_reset();
  80. break;
  81. }
  82. fastboot_tcp_send_packet(TCP_ACK | TCP_PUSH,
  83. handshake, handshake_length);
  84. state = FASTBOOT_CONNECTED;
  85. }
  86. break;
  87. case FASTBOOT_CONNECTED:
  88. if (tcp_fin) {
  89. fastboot_tcp_answer(TCP_FIN | TCP_ACK, 0);
  90. state = FASTBOOT_DISCONNECTING;
  91. break;
  92. }
  93. if (tcp_push) {
  94. // First 8 bytes is big endian message length
  95. command_size = __be64_to_cpu(*(u64 *)pkt);
  96. len -= 8;
  97. pkt += 8;
  98. // Only single packet messages are supported ATM
  99. if (strlen(pkt) != command_size) {
  100. fastboot_tcp_reset();
  101. break;
  102. }
  103. strlcpy(command, pkt, len + 1);
  104. fastboot_command_id = fastboot_handle_command(command, response);
  105. fastboot_tcp_send_message(response, strlen(response));
  106. fastboot_handle_boot(fastboot_command_id,
  107. strncmp("OKAY", response, 4) == 0);
  108. }
  109. break;
  110. case FASTBOOT_DISCONNECTING:
  111. if (tcp_push)
  112. state = FASTBOOT_CLOSED;
  113. break;
  114. }
  115. memset(command, 0, FASTBOOT_COMMAND_LEN);
  116. memset(response, 0, FASTBOOT_RESPONSE_LEN);
  117. curr_sport = 0;
  118. curr_dport = 0;
  119. curr_tcp_seq_num = 0;
  120. curr_tcp_ack_num = 0;
  121. curr_request_len = 0;
  122. }
  123. void fastboot_tcp_start_server(void)
  124. {
  125. printf("Using %s device\n", eth_get_name());
  126. printf("Listening for fastboot command on tcp %pI4\n", &net_ip);
  127. tcp_set_tcp_handler(fastboot_tcp_handler_ipv4);
  128. }