]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - net/bootme.c
cleanup debug messages
[karo-tx-uboot.git] / net / bootme.c
1 /*
2  * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
3  * based on: code from RedBoot (C) Uwe Steinkohl <US@KARO-electronics.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
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.
12  *
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.
17  *
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,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <net.h>
27 #include <wince.h>
28 #include <asm/errno.h>
29
30 DECLARE_GLOBAL_DATA_PTR;
31
32 #define WINCE_VRAM_BASE         0x80000000
33 #define CE_FIX_ADDRESS(a)       ((void *)((a) - WINCE_VRAM_BASE + CONFIG_SYS_SDRAM_BASE))
34
35 #ifndef INT_MAX
36 #define INT_MAX                 ((int)(~0 >> 1))
37 #endif
38
39 /* Bin image parse states */
40 #define CE_PS_RTI_ADDR          0
41 #define CE_PS_RTI_LEN           1
42 #define CE_PS_E_ADDR            2
43 #define CE_PS_E_LEN             3
44 #define CE_PS_E_CHKSUM          4
45 #define CE_PS_E_DATA            5
46
47 #define CE_MIN(a, b)            (((a) < (b)) ? (a) : (b))
48 #define CE_MAX(a, b)            (((a) > (b)) ? (a) : (b))
49
50 #define _STRMAC(s)              #s
51 #define STRMAC(s)               _STRMAC(s)
52
53 static enum bootme_state bootme_state;
54 static int bootme_src_port = 0xdeadface;
55 static int bootme_dst_port = 0xdeadbeef;
56 static uchar bootme_ether[ETH_ALEN];
57 static IPaddr_t bootme_ip;
58 static int bootme_timed_out;
59 //static size_t input_len, input_size;
60 //static void *input_packet;
61 static const char *output_packet; /* used by first send udp */
62 static int output_packet_len;
63 static unsigned long bootme_timeout;
64 static bootme_hand_f *bootme_packet_handler;
65
66 #ifdef DEBUG
67 static void __attribute__((unused)) ce_dump_block(const void *ptr, int length)
68 {
69         const char *p = ptr;
70         int i;
71         int j;
72
73         for (i = 0; i < length; i++) {
74                 if (!(i % 16)) {
75                         printf("\n%p: ", ptr + i);
76                 }
77
78                 printf("%02x ", p[i]);
79                 if (!((i + 1) % 16)){
80                         printf("      ");
81                         for (j = i - 15; j <= i; j++){
82                                 if((p[j] > 0x1f) && (p[j] < 0x7f)) {
83                                         printf("%c", p[j]);
84                                 } else {
85                                         printf(".");
86                                 }
87                         }
88                 }
89         }
90         printf("\n");
91 }
92 #else
93 static inline void ce_dump_block(void *ptr, int length)
94 {
95 }
96 #endif
97
98 static void bootme_timeout_handler(void)
99 {
100 printf("%s\n", __func__);
101
102         net_set_state(NETLOOP_SUCCESS);
103         bootme_timed_out++;
104 }
105
106 static inline int env_changed(int *id)
107 {
108         int env_id = get_env_id();
109
110         if (*id != env_id) {
111                 debug("env_id: %d -> %d\n", *id, env_id);
112                 *id = env_id;
113                 return 1;
114         }
115         return 0;
116 }
117
118 static int env_id;
119
120 static int is_broadcast(IPaddr_t ip)
121 {
122         static IPaddr_t netmask;
123         static IPaddr_t our_ip;
124
125         return (ip == ~0 ||                             /* 255.255.255.255 */
126             ((netmask & our_ip) == (netmask & ip) &&    /* on the same net */
127             (netmask | ip) == ~0));             /* broadcast to our net */
128 }
129
130 static int check_net_config(void)
131 {
132         if (env_changed(&env_id)) {
133                 char *p;
134                 char *bip;
135
136                 bootme_dst_port = EDBG_DOWNLOAD_PORT;
137                 if (bootme_ip == 0) {
138                         bip = getenv("bootmeip");
139                         if (bip) {
140                                 bootme_ip = getenv_IPaddr("bootmeip");
141                                 if (!bootme_ip)
142                                         return -EINVAL;
143                                 p = strchr(bip, ':');
144                                 if (p) {
145                                         bootme_dst_port = simple_strtoul(p + 1, NULL, 10);
146                                 }
147                         } else {
148                                 memset(&bootme_ip, 0xff, sizeof(bootme_ip));
149                         }
150                 }
151
152                 p = getenv("bootme_dst_port");
153                 if (p)
154                         bootme_dst_port = simple_strtoul(p, NULL, 10);
155
156                 p = getenv("bootme_src_port");
157                 if (p)
158                         bootme_src_port = simple_strtoul(p, NULL, 10);
159                 else
160                         bootme_src_port = bootme_dst_port;
161
162                 if (is_broadcast(bootme_ip))
163                         memset(bootme_ether, 0xff, sizeof(bootme_ether));
164                 else
165                         memset(bootme_ether, 0, sizeof(bootme_ether));
166
167                 net_init();
168                 NetServerIP = bootme_ip;
169         }
170         return 0;
171 }
172
173 static void bootme_wait_arp_handler(uchar *pkt, unsigned dest,
174                                 IPaddr_t sip, unsigned src,
175                                 unsigned len)
176 {
177         net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
178 }
179
180 static inline char next_cursor(char c)
181 {
182         switch(c) {
183         case '-':
184                 return '\\';
185         case '\\':
186                 return '|';
187         case '|':
188                 return '/';
189         case '/':
190                 return '-';
191         }
192         return 0;
193 }
194
195 static void bootme_handler(uchar *pkt, unsigned dest_port, IPaddr_t src_ip,
196                         unsigned src_port, unsigned len)
197 {
198         uchar *eth_pkt = pkt;
199         unsigned eth_len = len;
200         static char cursor = '|';
201         enum bootme_state last_state = BOOTME_INIT;
202 #if 1
203         debug("received packet of len %d from %pI4:%d to port %d\n",
204                 len, &src_ip, src_port, dest_port);
205         ce_dump_block(pkt, len);
206 #endif
207         if (!bootme_packet_handler) {
208                 printf("No packet handler set for BOOTME protocol; dropping packet\n");
209                 return;
210         }
211         if (dest_port != bootme_src_port || !len)
212                 return; /* not for us */
213
214         printf("%c\x08", cursor);
215         cursor = next_cursor(cursor);
216
217         if (is_broadcast(bootme_ip)) {
218                 bootme_ip = src_ip;
219         } else if (src_ip != bootme_ip) {
220                 debug("src_ip %pI4 does not match destination IP %pI4\n",
221                         &src_ip, &bootme_ip);
222                 return; /* not from our server */
223         }
224
225         last_state = bootme_state;
226         bootme_dst_port = src_port;
227         debug("bootme_dst_port set to %d\n", bootme_dst_port);
228         if (bootme_state == BOOTME_INIT) {
229                 bootme_src_port = EDBG_SVC_PORT;
230                 debug("%s: bootme_src_port set to %d\n", __func__, bootme_src_port);
231         }
232         bootme_state = bootme_packet_handler(eth_pkt, eth_len);
233         debug("bootme_packet_handler() returned %d\n", bootme_state);
234         if (bootme_state != last_state)
235                 debug("bootme_state: %d -> %d\n", last_state, bootme_state);
236         switch (bootme_state) {
237         case BOOTME_INIT:
238                 break;
239
240         case BOOTME_DOWNLOAD:
241                 if (last_state != BOOTME_INIT)
242                         NetBootFileXferSize += len - 4;
243                 /* fallthru */
244         case BOOTME_DEBUG:
245                 if (last_state == BOOTME_INIT) {
246                         bootme_timeout = 3 * 1000;
247                 }
248                 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
249                 break;
250
251         case BOOTME_DONE:
252                 net_set_state(NETLOOP_SUCCESS);
253                 bootme_packet_handler = NULL;
254                 break;
255
256         case BOOTME_ERROR:
257                 net_set_state(NETLOOP_FAIL);
258                 bootme_packet_handler = NULL;
259         }
260 }
261
262 void BootmeStart(void)
263 {
264         if (bootme_state != BOOTME_DOWNLOAD)
265                 check_net_config();
266
267         if (output_packet_len == 0 ||
268                 memcmp(bootme_ether, NetEtherNullAddr, ETH_ALEN) != 0) {
269                 /* wait for incoming packet */
270                 net_set_udp_handler(bootme_handler);
271                 bootme_timed_out = 0;
272                 NetSetTimeout(bootme_timeout, bootme_timeout_handler);
273         } else {
274                 /* send ARP request */
275                 uchar *pkt;
276
277                 net_set_arp_handler(bootme_wait_arp_handler);
278                 assert(NetTxPacket != NULL);
279                 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
280                 memcpy(pkt, output_packet, output_packet_len);
281                 NetSendUDPPacket(bootme_ether, bootme_ip, bootme_dst_port,
282                                 bootme_src_port, output_packet_len);
283         }
284 }
285
286 int bootme_send_frame(const void *buf, size_t len)
287 {
288         int ret;
289         struct eth_device *eth;
290         int inited = 0;
291         uchar *pkt;
292
293         eth = eth_get_dev();
294         if (eth == NULL)
295                 return -EINVAL;
296
297         if (bootme_state == BOOTME_INIT)
298                 check_net_config();
299
300         debug("%s: buf: %p len: %u from %pI4:%d to %pI4:%d\n",
301                 __func__, buf, len, &NetOurIP, bootme_src_port, &bootme_ip, bootme_dst_port);
302
303         if (memcmp(bootme_ether, NetEtherNullAddr, ETH_ALEN) == 0) {
304                 if (eth->state == ETH_STATE_ACTIVE)
305                         return 0;       /* inside net loop */
306
307                 output_packet = buf;
308                 output_packet_len = len;
309                 /* wait for arp reply and send packet */
310                 ret = NetLoop(BOOTME);
311                 if (ret < 0) {
312                         /* drop packet */
313                         output_packet_len = 0;
314                         return ret;
315                 }
316                 if (bootme_timed_out)
317                         return -ETIMEDOUT;
318                 return 0;
319         }
320
321         if (eth->state != ETH_STATE_ACTIVE) {
322                 if (eth_is_on_demand_init()) {
323                         ret = eth_init(gd->bd);
324                         if (ret < 0)
325                                 return ret;
326                         eth_set_last_protocol(BOOTME);
327                 } else {
328                         eth_init_state_only(gd->bd);
329                 }
330                 inited = 1;
331         }
332
333         assert(NetTxPacket != NULL);
334         pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
335         memcpy(pkt, buf, len);
336
337         ret = NetSendUDPPacket(bootme_ether, bootme_ip, bootme_dst_port,
338                         bootme_src_port, len);
339         if (inited) {
340                 debug("Stopping network\n");
341                 if (eth_is_on_demand_init())
342                         eth_halt();
343                 else
344                         eth_halt_state_only();
345         }
346         return ret;
347 }
348
349 static void bootme_init(IPaddr_t server_ip)
350 {
351         bootme_state = BOOTME_INIT;
352         bootme_ip = server_ip;
353         /* force reconfiguration in check_net_config() */
354         env_id = 0;
355 }
356
357 int BootMeDownload(bootme_hand_f *handler)
358 {
359         int ret;
360
361         bootme_packet_handler = handler;
362
363         ret = NetLoop(BOOTME);
364         if (ret < 0)
365                 return BOOTME_ERROR;
366         if (bootme_timed_out && bootme_state != BOOTME_INIT)
367                 return BOOTME_ERROR;
368
369         return bootme_state;
370 }
371
372 int BootMeDebugStart(bootme_hand_f *handler)
373 {
374         int ret;
375
376         bootme_packet_handler = handler;
377
378         bootme_init(bootme_ip);
379         bootme_state = BOOTME_DEBUG;
380         bootme_timeout = 3 * 1000;
381         NetSetTimeout(bootme_timeout, bootme_timeout_handler);
382
383         ret = NetLoop(BOOTME);
384         if (ret < 0)
385                 return BOOTME_ERROR;
386         if (bootme_timed_out)
387                 return BOOTME_DONE;
388         return bootme_state;
389 }
390
391 int BootMeRequest(IPaddr_t server_ip, const void *buf, size_t len, int timeout)
392 {
393         bootme_init(server_ip);
394         bootme_timeout = timeout * 1000;
395         bootme_timed_out = 0;
396         NetSetTimeout(bootme_timeout, bootme_timeout_handler);
397         return bootme_send_frame(buf, len);
398 }