1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <common.h> 8 #include <net.h> 9 #include <net/fastboot.h> 10 #include <stdlib.h> 11 #include <version.h> 12 13 /* Fastboot port # defined in spec */ 14 #define WELL_KNOWN_PORT 5554 15 16 enum { 17 FASTBOOT_ERROR = 0, 18 FASTBOOT_QUERY = 1, 19 FASTBOOT_INIT = 2, 20 FASTBOOT_FASTBOOT = 3, 21 }; 22 23 struct __attribute__((packed)) fastboot_header { 24 uchar id; 25 uchar flags; 26 unsigned short seq; 27 }; 28 29 #define PACKET_SIZE 1024 30 #define FASTBOOT_HEADER_SIZE sizeof(struct fastboot_header) 31 32 /* Sequence number sent for every packet */ 33 static unsigned short fb_sequence_number = 1; 34 static const unsigned short fb_packet_size = PACKET_SIZE; 35 static const unsigned short fb_udp_version = 1; 36 37 /* Keep track of last packet for resubmission */ 38 static uchar last_packet[PACKET_SIZE]; 39 static unsigned int last_packet_len = 0; 40 41 static struct in_addr fastboot_remote_ip; 42 /* The UDP port at their end */ 43 static int fastboot_remote_port; 44 /* The UDP port at our end */ 45 static int fastboot_our_port; 46 47 /** 48 * Constructs and sends a packet in response to received fastboot packet 49 * 50 * @param fb_header Header for response packet 51 * @param retransmit Nonzero if sending last sent packet 52 */ 53 static void fastboot_send(struct fastboot_header fb_header, uchar retransmit) 54 { 55 uchar *packet; 56 uchar *packet_base; 57 int len = 0; 58 const char *error_msg = "An error occurred."; 59 short tmp; 60 struct fastboot_header fb_response_header = fb_header; 61 /* 62 * We will always be sending some sort of packet, so 63 * cobble together the packet headers now. 64 */ 65 packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE; 66 packet_base = packet; 67 68 /* Resend last packet */ 69 if (retransmit) { 70 memcpy(packet, last_packet, last_packet_len); 71 net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip, 72 fastboot_remote_port, fastboot_our_port, last_packet_len); 73 return; 74 } 75 76 fb_response_header.seq = htons(fb_response_header.seq); 77 memcpy(packet, &fb_response_header, sizeof(fb_response_header)); 78 packet += sizeof(fb_response_header); 79 80 switch (fb_header.id) { 81 case FASTBOOT_QUERY: 82 tmp = htons(fb_sequence_number); 83 memcpy(packet, &tmp, sizeof(tmp)); 84 packet += sizeof(tmp); 85 break; 86 case FASTBOOT_INIT: 87 tmp = htons(fb_udp_version); 88 memcpy(packet, &tmp, sizeof(tmp)); 89 packet += sizeof(tmp); 90 tmp = htons(fb_packet_size); 91 memcpy(packet, &tmp, sizeof(tmp)); 92 packet += sizeof(tmp); 93 break; 94 case FASTBOOT_ERROR: 95 memcpy(packet, error_msg, strlen(error_msg)); 96 packet += strlen(error_msg); 97 break; 98 case FASTBOOT_FASTBOOT: 99 default: 100 error("ID %d not implemented.\n", fb_header.id); 101 return; 102 } 103 104 len = packet-packet_base; 105 106 /* Save packet for retransmitting */ 107 last_packet_len = len; 108 memcpy(last_packet, packet_base, last_packet_len); 109 110 net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip, 111 fastboot_remote_port, fastboot_our_port, len); 112 } 113 114 /** 115 * Incoming UDP packet handler. 116 * 117 * @param packet Pointer to incoming UDP packet 118 * @param dport Destination UDP port 119 * @param sip Source IP address 120 * @param sport Source UDP port 121 * @param len Packet length 122 */ 123 static void fastboot_handler(uchar *packet, unsigned dport, struct in_addr sip, 124 unsigned sport, unsigned len) 125 { 126 struct fastboot_header fb_header; 127 128 if (dport != fastboot_our_port) { 129 return; 130 } 131 132 fastboot_remote_ip = sip; 133 fastboot_remote_port = sport; 134 135 if (len < FASTBOOT_HEADER_SIZE || len > PACKET_SIZE) { 136 return; 137 } 138 memcpy(&fb_header, packet, sizeof(fb_header)); 139 fb_header.flags = 0; 140 fb_header.seq = ntohs(fb_header.seq); 141 packet += sizeof(fb_header); 142 len -= sizeof(fb_header); 143 144 switch (fb_header.id) { 145 case FASTBOOT_QUERY: 146 fastboot_send(fb_header, 0); 147 break; 148 case FASTBOOT_INIT: 149 if (fb_header.seq == fb_sequence_number) { 150 fastboot_send(fb_header, 0); 151 fb_sequence_number++; 152 } else if (fb_header.seq == fb_sequence_number - 1) { 153 /* Retransmit last sent packet */ 154 fastboot_send(fb_header, 1); 155 } 156 break; 157 case FASTBOOT_FASTBOOT: 158 default: 159 error("ID %d not implemented.\n", fb_header.id); 160 fb_header.id = FASTBOOT_ERROR; 161 fastboot_send(fb_header, 0); 162 break; 163 } 164 } 165 166 void fastboot_start_server(void) 167 { 168 printf("Using %s device\n", eth_get_name()); 169 printf("Listening for fastboot command on %pI4\n", &net_ip); 170 171 fastboot_our_port = WELL_KNOWN_PORT; 172 173 net_set_udp_handler(fastboot_handler); 174 175 /* zero out server ether in case the server ip has changed */ 176 memset(net_server_ethaddr, 0, 6); 177 } 178