2 * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
3 * based on: code from RedBoot (C) Uwe Steinkohl <US@KARO-electronics.de>
5 * See file CREDITS for list of people who contributed to this
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 #include <asm/errno.h>
30 DECLARE_GLOBAL_DATA_PTR;
32 static enum bootme_state bootme_state;
33 static int bootme_src_port = 0xdeadface;
34 static int bootme_dst_port = 0xdeadbeef;
35 static uchar bootme_ether[ETH_ALEN];
36 static IPaddr_t bootme_ip;
37 static int bootme_timed_out;
38 static const char *output_packet; /* used by first send udp */
39 static int output_packet_len;
40 static unsigned long bootme_timeout;
41 static bootme_hand_f *bootme_packet_handler;
44 static void __attribute__((unused)) ce_dump_block(const void *ptr, int length)
50 for (i = 0; i < length; i++) {
52 printf("\n%p: ", ptr + i);
55 printf("%02x ", p[i]);
58 for (j = i - 15; j <= i; j++){
59 if((p[j] > 0x1f) && (p[j] < 0x7f)) {
70 static inline void ce_dump_block(void *ptr, int length)
75 static void bootme_timeout_handler(void)
77 printf("%s\n", __func__);
78 net_set_state(NETLOOP_SUCCESS);
82 static inline int env_changed(int *id)
84 int env_id = get_env_id();
87 debug("env_id: %d -> %d\n", *id, env_id);
96 static int is_broadcast(IPaddr_t ip)
98 static IPaddr_t netmask;
99 static IPaddr_t our_ip;
101 return (ip == ~0 || /* 255.255.255.255 */
102 ((netmask & our_ip) == (netmask & ip) && /* on the same net */
103 (netmask | ip) == ~0)); /* broadcast to our net */
106 static int check_net_config(void)
108 if (env_changed(&env_id)) {
112 bootme_dst_port = EDBG_DOWNLOAD_PORT;
113 if (bootme_ip == 0) {
114 bip = getenv("bootmeip");
116 bootme_ip = getenv_IPaddr("bootmeip");
119 p = strchr(bip, ':');
121 bootme_dst_port = simple_strtoul(p + 1, NULL, 10);
124 memset(&bootme_ip, 0xff, sizeof(bootme_ip));
128 p = getenv("bootme_dst_port");
130 bootme_dst_port = simple_strtoul(p, NULL, 10);
132 p = getenv("bootme_src_port");
134 bootme_src_port = simple_strtoul(p, NULL, 10);
136 bootme_src_port = bootme_dst_port;
138 if (is_broadcast(bootme_ip))
139 memset(bootme_ether, 0xff, sizeof(bootme_ether));
141 memset(bootme_ether, 0, sizeof(bootme_ether));
144 NetServerIP = bootme_ip;
149 static void bootme_wait_arp_handler(uchar *pkt, unsigned dest,
150 IPaddr_t sip, unsigned src,
153 net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
156 static inline char next_cursor(char c)
171 static void bootme_handler(uchar *pkt, unsigned dest_port, IPaddr_t src_ip,
172 unsigned src_port, unsigned len)
174 uchar *eth_pkt = pkt;
175 unsigned eth_len = len;
176 static char cursor = '|';
177 enum bootme_state last_state = bootme_state;
179 debug("received packet of len %d from %pI4:%d to port %d\n",
180 len, &src_ip, src_port, dest_port);
181 ce_dump_block(pkt, len);
183 if (!bootme_packet_handler) {
184 printf("No packet handler set for BOOTME protocol; dropping packet\n");
187 if (dest_port != bootme_src_port || !len)
188 return; /* not for us */
190 printf("%c\x08", cursor);
191 cursor = next_cursor(cursor);
193 if (!is_broadcast(bootme_ip) && src_ip != bootme_ip) {
194 debug("src_ip %pI4 does not match destination IP %pI4\n",
195 &src_ip, &bootme_ip);
196 return; /* not from our server */
198 if (bootme_state == BOOTME_INIT || bootme_state == BOOTME_DEBUG_INIT) {
199 struct ethernet_hdr *eth = (struct ethernet_hdr *)(pkt -
200 NetEthHdrSize() - IP_UDP_HDR_SIZE);
201 memcpy(bootme_ether, eth->et_src, sizeof(bootme_ether));
202 printf("Target MAC address set to %pM\n", bootme_ether);
204 if (is_broadcast(bootme_ip)) {
205 NetCopyIP(&bootme_ip, &src_ip);
208 if (bootme_state == BOOTME_INIT) {
209 bootme_src_port = EDBG_SVC_PORT;
210 debug("%s: bootme_src_port set to %d\n", __func__, bootme_src_port);
213 debug("bootme_dst_port %d -> %d\n", bootme_dst_port, src_port);
214 bootme_dst_port = src_port;
216 bootme_state = bootme_packet_handler(eth_pkt, eth_len);
217 debug("bootme_packet_handler() returned %d\n", bootme_state);
218 if (bootme_state != last_state)
219 debug("%s@%d: bootme_state: %d -> %d\n", __func__, __LINE__,
220 last_state, bootme_state);
221 switch (bootme_state) {
223 case BOOTME_DEBUG_INIT:
226 case BOOTME_DOWNLOAD:
227 if (last_state != BOOTME_INIT)
228 NetBootFileXferSize += len - 4;
231 if (last_state == BOOTME_INIT ||
232 last_state == BOOTME_DEBUG_INIT)
233 bootme_timeout = 3 * 1000;
234 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
238 net_set_state(NETLOOP_SUCCESS);
239 bootme_packet_handler = NULL;
243 net_set_state(NETLOOP_FAIL);
244 bootme_packet_handler = NULL;
248 void BootmeStart(void)
250 if (bootme_state != BOOTME_DOWNLOAD)
253 if (output_packet_len == 0 ||
254 is_valid_ether_addr(bootme_ether)) {
255 /* wait for incoming packet */
256 net_set_udp_handler(bootme_handler);
257 bootme_timed_out = 0;
258 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
260 /* send ARP request */
263 net_set_arp_handler(bootme_wait_arp_handler);
264 assert(NetTxPacket != NULL);
265 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
266 memcpy(pkt, output_packet, output_packet_len);
267 debug("%s@%d: Sending ARP request:\n", __func__, __LINE__);
268 ce_dump_block(pkt, output_packet_len);
269 NetSendUDPPacket(bootme_ether, bootme_ip, bootme_dst_port,
270 bootme_src_port, output_packet_len);
271 output_packet_len = 0;
275 int bootme_send_frame(const void *buf, size_t len)
278 struct eth_device *eth;
285 if (bootme_state == BOOTME_INIT || bootme_state == BOOTME_DEBUG_INIT)
288 debug("%s: buf: %p len: %u from %pI4:%d to %pI4:%d\n",
289 __func__, buf, len, &NetOurIP, bootme_src_port, &bootme_ip,
292 if (is_zero_ether_addr(bootme_ether)) {
294 output_packet_len = len;
295 /* wait for arp reply and send packet */
296 ret = NetLoop(BOOTME);
299 output_packet_len = 0;
302 if (bootme_timed_out)
307 if (eth->state != ETH_STATE_ACTIVE) {
308 if (eth_is_on_demand_init()) {
309 ret = eth_init(gd->bd);
312 eth_set_last_protocol(BOOTME);
314 eth_init_state_only(gd->bd);
318 assert(NetTxPacket != NULL);
319 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
320 memcpy(pkt, buf, len);
322 ret = NetSendUDPPacket(bootme_ether, bootme_ip, bootme_dst_port,
323 bootme_src_port, len);
325 printf("Failed to send packet: %d\n", ret);
330 static void bootme_init(IPaddr_t server_ip)
332 debug("%s@%d: bootme_state: %d -> %d\n", __func__, __LINE__,
333 bootme_state, BOOTME_INIT);
334 bootme_state = BOOTME_INIT;
335 bootme_ip = server_ip;
336 /* force reconfiguration in check_net_config() */
340 int BootMeDownload(bootme_hand_f *handler)
344 bootme_packet_handler = handler;
346 ret = NetLoop(BOOTME);
349 if (bootme_timed_out && bootme_state != BOOTME_INIT)
355 int BootMeDebugStart(bootme_hand_f *handler)
359 bootme_packet_handler = handler;
361 bootme_init(bootme_ip);
362 debug("%s@%d: bootme_state: %d -> %d\n", __func__, __LINE__,
363 bootme_state, BOOTME_DEBUG_INIT);
364 bootme_state = BOOTME_DEBUG_INIT;
366 bootme_timeout = 3 * 1000;
367 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
369 ret = NetLoop(BOOTME);
372 if (bootme_timed_out)
377 int BootMeRequest(IPaddr_t server_ip, const void *buf, size_t len, int timeout)
379 bootme_init(server_ip);
380 bootme_timeout = timeout * 1000;
381 bootme_timed_out = 0;
382 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
383 return bootme_send_frame(buf, len);