Add Broadcom / Netgear changes from RAXE 1.0.0.48
[project/bcm63xx/u-boot.git] / net / nmrp.c
1 /*
2 * Copyright (C) 2008 Delta Networks Inc.
3 */
4 #include <common.h>
5 #include <command.h>
6 #include <net.h>
7 //#include "tftp.h"
8 #include "bootp.h"
9 #include "nmrp.h"
10 #include <dni_common.h>
11
12 typedef void nmrp_thand_f(void);
13 ulong NmrpOuripaddr;
14 ulong NmrpOuripSubnetMask;
15 ulong NmrpFwOption;
16 int NmrpFwUPOption = 0;
17 int NmrpSTUPOption = 0;
18 int NmrpStringTableUpdateCount = 0;
19 int NmrpStringTableUpdateIndex = 0;
20 int NmrpState = 0;
21 ulong Nmrp_active_start=0;
22 static ulong NmrpBlock;
23 static ulong NmrpLastBlock = 0;
24 int Nmrp_Listen_TimeoutCount = 0;
25 int Nmrp_REQ_TimeoutCount = 0;
26 static ulong NmrptimeStart;
27 static ulong NmrptimeDelta;
28 static nmrp_thand_f *NmrptimeHandler;
29 static uchar Nmrpproto;
30 static int Nmrp_Closing_TimeoutCount = 0;
31 struct in_addr NmrpClientIP;
32 uchar NmrpClientEther[6] = { 0, 0, 0, 0, 0, 0 };
33 uchar NmrpServerEther[6] = { 0, 0, 0, 0, 0, 0 };
34 static u16 NmrpDevRegionOption = 0;
35 static uchar NmrpFirmwareFilename[FIRMWARE_FILENAME_LEN] = FIRMWARE_FILENAME;
36 static u32 NmrpStringTableBitmask = 0;
37 static uchar NmrpStringTableFilename[STRING_TABLE_FILENAME_LEN] = {0};
38 static int NmrpStringTableUpdateList[STRING_TABLE_NUMBER_MAX] = {0};
39 ulong NmrpAliveTimerStart = 0;
40 ulong NmrpAliveTimerBase = 0;
41 int NmrpAliveTimerTimeout = NMRP_TIMEOUT_ACTIVE;
42 int NmrpAliveWaitACK = 0;
43
44 static void Nmrp_Listen_Timeout(void);
45 void NmrpSend(void);
46
47 void NmrpStart(void);
48
49 void NmrpSetTimeout(unchar, ulong, nmrp_thand_f *);
50
51 void Nmrp_Led_Flashing_Timeout();
52
53 extern void board_reset_default();
54
55 static int MyNetSetEther(volatile uchar * xet, uchar * addr, uint prot)
56 {
57 struct ethernet_hdr *et = (struct ethernet_hdr *) xet;
58 ushort myvlanid;
59 myvlanid = ntohs(net_our_vlan);
60 if (myvlanid == (ushort) - 1)
61 myvlanid = VLAN_NONE;
62 memcpy(et->et_dest, addr, 6);
63 eth_env_get_enetaddr("ethaddr", net_server_ethaddr);
64 memcpy(et->et_src, net_server_ethaddr, 6);
65 if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
66 et->et_protlen = htons(prot);
67 return ETHER_HDR_SIZE;
68 } else {
69 struct vlan_ethernet_hdr *vet =
70 (struct vlan_ethernet_hdr *) xet;
71 vet->vet_vlan_type = htons(PROT_VLAN);
72 vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
73 vet->vet_type = htons(prot);
74 return VLAN_ETHER_HDR_SIZE;
75 }
76
77 return ETHER_HDR_SIZE;
78 }
79
80 static void Nmrp_Conf_Timeout(void)
81 {
82 if (++Nmrp_REQ_TimeoutCount > NMRP_MAX_RETRY_CONF) {
83 puts("\n retry conf count exceeded;\n");
84 Nmrp_REQ_TimeoutCount = 0;
85 NmrpStart();
86 } else {
87 puts("T");
88 NmrpSetTimeout(NMRP_CODE_CONF_ACK,
89 (NMRP_TIMEOUT_REQ * CONFIG_SYS_HZ) / 2,
90 Nmrp_Conf_Timeout);
91 NmrpSend();
92 }
93 }
94
95 void Nmrp_Closing_Timeout()
96 {
97
98 if (++Nmrp_Closing_TimeoutCount > NMRP_MAX_RETRY_CLOSE) {
99 puts("\n close retry count exceed;stay idle and blink\n");
100 Nmrp_Closing_TimeoutCount = 0;
101 //board_reset_default(); toso Silver
102
103 puts("\nNMRP is complete. Please switch OFF power.\n");
104
105 Nmrp_Led_Flashing_Timeout();
106 /* Unreachable */
107
108 ctrlc();
109 console_assign(stdout, "nulldev");
110 console_assign(stderr, "nulldev");
111 NmrpState = STATE_CLOSED;
112 net_set_state(NETLOOP_SUCCESS);
113 } else {
114 puts("T");
115 NmrpSetTimeout(NMRP_CODE_CLOSE_ACK,
116 (CONFIG_SYS_HZ * NMRP_TIMEOUT_REQ) / 2,
117 Nmrp_Closing_Timeout);
118 NmrpSend();
119 }
120 }
121
122 #define LED_REG_IN_OUT 0xff800500
123 #define LED_TEST_MASK 0x08000000
124 #define LED_AL_AH_REG 0xff800528
125
126 void board_test_led(int status)
127 {
128 volatile uint32_t *cled_al_ah_reg = (void *)(LED_AL_AH_REG);
129 volatile uint32_t *cled_in_out_reg = (void *)(LED_REG_IN_OUT);
130 uint32_t val32;
131
132 val32 = *cled_in_out_reg;
133 val32 |= LED_TEST_MASK;
134 *cled_in_out_reg = val32;
135
136 val32 = *cled_al_ah_reg;
137 if( status == 0 )
138 val32 &= ~LED_TEST_MASK;
139 else
140 val32 |= LED_TEST_MASK;
141 *cled_al_ah_reg = val32;
142 }
143
144 void Nmrp_Led_Flashing_Timeout()
145 {
146 static int NmrpLedCount = 0;
147 while (1) {
148 NmrpLedCount++;
149 if ((NmrpLedCount % 2) == 1) {
150 board_test_led(0);
151 udelay(500000);
152 } else {
153 board_test_led(1);
154 udelay(500000);
155 }
156 }
157 /* Unreachable */
158
159 /*press ctl+c, turn on test led,then normally boot*/
160 board_test_led(0);
161 }
162
163 extern void NmrpSend(void)
164 {
165 volatile u8 *pkt;
166 volatile u8 *xp;
167 int len = 0;
168 int eth_len = 0;
169 pkt = (u8 *) net_tx_packet;
170 pkt += MyNetSetEther(pkt, NmrpServerEther, PROT_NMRP);
171 eth_len = pkt - net_tx_packet;
172
173 switch (NmrpState) {
174 case STATE_LISTENING:
175 xp = pkt;
176 *((u16 *) pkt) = 0;
177 pkt += 2;
178 *((u8 *) pkt) = (NMRP_CODE_CONF_REQ);
179 pkt++;
180 *((u8 *) pkt) = 0;
181 pkt++;
182 *((u16 *) pkt) = htons(6);
183 pkt += 2;
184
185 len = pkt - xp;
186
187 (void)net_send_packet((u8 *) net_tx_packet, eth_len + len);
188 net_set_timeout_handler((NMRP_TIMEOUT_REQ * CONFIG_SYS_HZ) / 2,
189 Nmrp_Conf_Timeout);
190 NmrpSetTimeout(NMRP_CODE_CONF_ACK,
191 (NMRP_TIMEOUT_REQ * CONFIG_SYS_HZ) / 2,
192 Nmrp_Conf_Timeout);
193 break;
194 case STATE_CONFIGING:
195 xp = pkt;
196 *((u16 *) pkt) = 0;
197 pkt += 2;
198 *((u8 *) pkt) = (NMRP_CODE_TFTP_UL_REQ);
199 pkt++;
200 *((u8 *) pkt) = 0;
201 pkt++;
202 /* Recv ST-UP option, upgrade string table.
203 * add FILE-NAME option to TFTP-UL-REQ
204 * value of FILE-NAME would like "string table 01"*/
205 if (NmrpSTUPOption == 1) {
206 /* Append the total length to packet
207 * NMRP_HEADER_LEN for the length of "Reserved", "Code", "Identifier", "Length"
208 * STRING_TABLE_FILENAME_OPT_LEN for the length of "Options". */
209 *((u16 *) pkt) = htons((NMRP_HEADER_LEN + STRING_TABLE_FILENAME_OPT_LEN));
210 pkt += 2;
211
212 /* Append NMRP option type FILE-NAME */
213 *((u16 *) pkt) = htons(NMRP_OPT_FILE_NAME);
214 pkt += 2;
215
216 /* Append the total length of NMRP option FILE-NAME */
217 *((u16 *) pkt) = htons(STRING_TABLE_FILENAME_OPT_LEN);
218 pkt += 2;
219
220 /* Append the string table filename to FILE-NAME option value */
221 int i;
222 sprintf(NmrpStringTableFilename, "%s%02d", STRING_TABLE_FILENAME_PREFIX,\
223 NmrpStringTableUpdateList[NmrpStringTableUpdateIndex]);
224 for (i = 0; i < STRING_TABLE_FILENAME_LEN; i++) {
225 *((u8 *) pkt) = NmrpStringTableFilename[i];
226 pkt++;
227 }
228 printf("\nReq %s\n", NmrpStringTableFilename);
229 /* No string table updates, or all string table updates finished.
230 * And received FW-UP option, upgrading firmware,
231 * add FILE-NAME option to TFTP-UL-REQ */
232 } else {
233 /* Append the total length to packet
234 * NMRP_HEADER_LEN for the length of "Reserved", "Code", "Identifier", "Length"
235 * STRING_TABLE_FILENAME_OPT_LEN for the length of "Options". */
236 *((u16 *) pkt) = htons((NMRP_HEADER_LEN + FIRMWARE_FILENAME_OPT_LEN));
237 pkt += 2;
238
239 /* Append NMRP option type FILE-NAME */
240 *((u16 *) pkt) = htons(NMRP_OPT_FILE_NAME);
241 pkt += 2;
242
243 /* Append the total length of NMRP option FILE-NAME for firmware*/
244 *((u16 *) pkt) = htons(FIRMWARE_FILENAME_OPT_LEN);
245 pkt += 2;
246
247 /* Append the firmware filename to FILE-NAME option value */
248 sprintf(NmrpFirmwareFilename, "%s\n", FIRMWARE_FILENAME);
249 int i;
250 for (i = 0; i < FIRMWARE_FILENAME_LEN; i++) {
251 *((u8 *) pkt) = NmrpFirmwareFilename[i];
252 pkt++;
253 }
254 }
255 len = pkt - xp;
256 (void)net_send_packet((u8 *) net_tx_packet, eth_len + len);
257 int update_table_num = NmrpStringTableUpdateList[NmrpStringTableUpdateIndex];
258 if (NmrpSTUPOption == 1)
259 UpgradeStringTableFromNmrpServer(update_table_num);
260 else
261 UpgradeFirmwareFromNmrpServer();
262 break;
263 case STATE_TFTPUPLOADING:
264 printf("TFTP upload done\n");
265 NmrpAliveTimerStart = get_timer(0);
266 NmrpAliveTimerBase = NMRP_TIMEOUT_ACTIVE / 4;
267 NmrpState = STATE_KEEP_ALIVE;
268 break;
269 case STATE_KEEP_ALIVE:
270 printf("NMRP Send Keep alive REQ\n");
271 //workaround_ipq40xx_gmac_nmrp_hang_action();
272 xp = pkt;
273 *((u16 *) pkt) = 0;
274 pkt += 2;
275 *((u8 *) pkt) = (NMRP_CODE_KEEP_ALIVE_REQ);
276 pkt++;
277 *((u8 *) pkt) = 0;
278 pkt++;
279 *((u16 *) pkt) = htons(6);
280 pkt += 2;
281 len = pkt - xp;
282 (void)net_send_packet((u8 *) net_tx_packet, eth_len + len);
283 NmrpAliveWaitACK = 1;
284 break;
285 case STATE_CLOSING:
286 printf("NMRP Send Closing REQ\n");
287 //workaround_qca8337_gmac_nmrp_hang_action();
288 //workaround_ipq40xx_gmac_nmrp_hang_action();
289 eth_halt();
290 mdelay(1000);
291 eth_init();
292 mdelay(500);
293 xp = pkt;
294 *((u16 *) pkt) = 0;
295 pkt += 2;
296 *((u8 *) pkt) = (NMRP_CODE_CLOSE_REQ);
297 pkt++;
298 *((u8 *) pkt) = 0;
299 pkt++;
300 *((u16 *) pkt) = htons(6);
301 pkt += 2;
302 len = pkt - xp;
303 NmrpSetTimeout(NMRP_CODE_CLOSE_ACK, (1 * CONFIG_SYS_HZ),
304 Nmrp_Closing_Timeout);
305 (void)net_send_packet((u8 *) net_tx_packet, eth_len + len);
306 break;
307
308 case STATE_CLOSED:
309 run_command("sdk restoredefault", 0); //board_reset_default();
310 #if defined(CONFIG_HW29765352P32P4000P512P2X2P2X2P4X4) || \
311 defined(CONFIG_HW29765352P0P4096P512P2X2P2X2P4X4) || \
312 defined(CONFIG_HW29765515P0P4096P512P2X2P2X2P2X2)
313 char runcmd[256];
314 printf ("boot_partition_set 1\n");
315 snprintf(runcmd, sizeof(runcmd), "boot_partition_set 1");
316 run_command(runcmd, 0);
317 #endif
318 NmrptimeHandler=NULL;
319 puts("\nNMRP is complete. Please switch OFF power.\n");
320
321 Nmrp_Led_Flashing_Timeout();
322 /* Unreachable */
323
324 ctrlc();
325 console_assign(stdout, "nulldev");
326 console_assign(stderr, "nulldev");
327 net_set_state(NETLOOP_SUCCESS);
328 break;
329 default:
330 break;
331
332 }
333
334 }
335
336 static void Nmrp_Listen_Timeout(void)
337 {
338 if (++Nmrp_Listen_TimeoutCount > NMRP_TIMEOUT_LISTEN) {
339 puts("\nRetry count exceeded; boot the image as usual\n");
340 Nmrp_Listen_TimeoutCount = 0;
341 ResetBootup_usual();
342 } else {
343 puts("T");
344 net_set_timeout_handler(CONFIG_SYS_HZ, Nmrp_Listen_Timeout);
345 }
346 }
347
348 static NMRP_PARSED_OPT *Nmrp_Parse(uchar * pkt, ushort optType)
349 {
350 NMRP_PARSED_MSG *msg = (NMRP_PARSED_MSG *) pkt;
351 NMRP_PARSED_OPT *opt, *optEnd;
352 optEnd = &msg->options[msg->numOptions];
353 for (opt = msg->options; opt != optEnd; opt++)
354 if (opt->type == ntohs(optType))
355 break;
356 return msg->numOptions == 0 ? NULL : (opt == optEnd ? NULL : opt);
357 }
358
359 void NmrpSetTimeout(unchar proto, ulong iv, nmrp_thand_f * f)
360 {
361 if (iv == 0) {
362 NmrptimeHandler = (nmrp_thand_f *) 0;
363 Nmrpproto = 0;
364 } else {
365
366 NmrptimeHandler = f;
367 NmrptimeStart = get_timer(0);
368 NmrptimeDelta = iv;
369 Nmrpproto = proto;
370 }
371 }
372 /*
373 Function to parse the NMRP options inside packet.
374 If all options are parsed correctly, it returns 0.
375 */
376 static int Nmrp_Parse_Opts(uchar *pkt, NMRP_PARSED_MSG *nmrp_parsed)
377 {
378 nmrp_t *nmrphdr= (nmrp_t*) pkt;
379 NMRP_OPT *nmrp_opt;
380 int remain_len, opt_index = 0;
381
382 nmrp_parsed->reserved = nmrphdr->reserved;
383 nmrp_parsed->code = nmrphdr->code;
384 nmrp_parsed->id = nmrphdr->id;
385 nmrp_parsed->length = nmrphdr->length;
386
387 remain_len = ntohs(nmrphdr->length) - NMRP_HDR_LEN;
388
389 nmrp_opt = &nmrphdr->opt;
390 while (remain_len > 0){
391 memcpy(&nmrp_parsed->options[opt_index], nmrp_opt, ntohs(nmrp_opt->len));
392 remain_len -= ntohs(nmrp_opt->len);
393 nmrp_opt = ((uchar *)nmrp_opt) + ntohs(nmrp_opt->len);
394 opt_index++;
395 }
396 nmrp_parsed->numOptions=opt_index;
397 return remain_len;
398 }
399
400 void string_table_bitmask_check()
401 {
402 int update_bit;
403
404 /* find string tables need to be update, begin with smallest bit */
405 for (update_bit = 0; update_bit < STRING_TABLE_BITMASK_LEN; update_bit++) {
406 if ((NmrpStringTableBitmask & (1 << update_bit)) != 0) {
407 //if bit 0 is set, update ST 1, ... etc
408 NmrpStringTableUpdateList[NmrpStringTableUpdateCount] = update_bit + 1;
409 NmrpStringTableUpdateCount++;
410 }
411 }
412 }
413
414 void set_region(u16 RegionOption)
415 {
416 uchar region[8];
417 sprintf(region, "%04x", RegionOption);
418 env_set("region", region);
419 run_command("saveenv", 0);
420 }
421
422 void NmrpHandler(uchar * pkt, unsigned dest, struct in_addr src_ip, unsigned src,
423 unsigned type)
424 {
425 nmrp_t *nmrphdr= (nmrp_t*) pkt;
426 uchar proto;
427 unchar *xp = pkt;
428 int fwUpgrade;
429 NMRP_PARSED_MSG nmrp_parsed;
430 NMRP_PARSED_OPT *opt;
431 proto = nmrphdr->code;
432 if (type!=PROT_NMRP)
433 return;
434
435 /* check for timeout,and run the timeout handler
436 if we have one
437 */
438
439 if (NmrptimeHandler && ((get_timer(0) - NmrptimeStart) > NmrptimeDelta)
440 && (proto != Nmrpproto)) {
441 nmrp_thand_f *x;
442 x = NmrptimeHandler;
443 NmrptimeHandler = (nmrp_thand_f *) 0;
444 (*x) ();
445 }
446
447 /*
448 Check if Reserved field is zero. Per the specification, the reserved
449 must be all zero in a valid NMRP packet.
450 */
451 if (nmrphdr->reserved != 0){
452 return;
453 }
454 memset(&nmrp_parsed, 0, sizeof(NMRP_PARSED_MSG));
455
456 /*
457 Parse the options inside the packet and save it into nmrp_parsed for
458 future reference.
459 */
460 if (Nmrp_Parse_Opts(pkt, &nmrp_parsed) != 0){
461 /* Some wrong inside the packet, just discard it */
462 return;
463 }
464
465 NmrpBlock = proto;
466
467 // ignore same packet
468 if (NmrpBlock == NmrpLastBlock)
469 return;
470 NmrpLastBlock = NmrpBlock;
471
472 switch (proto) {
473 case NMRP_CODE_ADVERTISE: /*listening state * */
474 if (NmrpState == 0) {
475 /*
476 Check if we get the MAGIC-NO option and the content is match
477 with the MAGICNO.
478 */
479 if ((opt = Nmrp_Parse(&nmrp_parsed, NMRP_OPT_MAGIC_NO)) != NULL){
480 int opt_hdr_len = sizeof(opt->type) + sizeof(opt->len);
481 if (memcmp(opt->value.magicno, MAGICNO, ntohs(opt->len) - opt_hdr_len) == 0){
482 NmrpState = STATE_LISTENING;
483 board_test_led(0);
484 printf("\nNMRP CONFIGING");
485 NmrpSend();
486 }
487 }
488 }
489 break;
490 case NMRP_CODE_CONF_ACK:
491 if (NmrpState == STATE_LISTENING) {
492 /*
493 If there is no DEV-IP option inside the packet, it must be
494 something wrong in the packet, so just ignore this packet
495 without any action taken.
496 */
497 if ((opt = Nmrp_Parse(&nmrp_parsed, NMRP_OPT_DEV_IP)) != NULL){
498 memcpy(NetOurTftpIP, opt->value.ip.addr,IP_ADDR_LEN);
499 /* Do we need the subnet mask? */
500 memcpy(&NmrpOuripSubnetMask, opt->value.ip.mask,IP_ADDR_LEN);
501 /*
502 FW-UP option is optional for CONF-ACK and it has no effect no
503 matter what is the content of this option, so we just skip the
504 process of this option for now, and will add it back when
505 this option is defined as mandatory.
506 The process for FW-UP would be similar as the action taken for
507 DEV-IP and MAGIC-NO.
508 */
509
510 /*When NMRP Client get CONF-ACK with DEV-REGION option*/
511 if ((opt = Nmrp_Parse(&nmrp_parsed, NMRP_OPT_DEV_REGION)) != NULL) {
512 /* Save DEV-REGION value to board */
513 printf("Get DEV-REGION option, value:0x%04x\n", opt->value.region);
514 NmrpDevRegionOption = ntohs(opt->value.region);
515 printf("Write Region Number 0x%04x to board\n", NmrpDevRegionOption);
516 set_region(NmrpDevRegionOption);
517 }
518 /*Check if NMRP Client get CONF-ACK with FW-UP option*/
519 if ((opt = Nmrp_Parse(&nmrp_parsed, NMRP_OPT_FW_UP)) != NULL) {
520 printf("\nRecv FW-UP option\n");
521 NmrpFwUPOption = 1;
522 } else {
523 printf("\nNo FW-UP option\n");
524 NmrpFwUPOption = 0;
525 }
526
527 /*When NMRP Client get CONF-ACK with ST-UP option*/
528 if ((opt = Nmrp_Parse(&nmrp_parsed, NMRP_OPT_ST_UP)) != NULL) {
529 printf("\nRecv ST-UP option\n");
530 NmrpSTUPOption = 1;
531 /* Reset string tables' update related variables. */
532 NmrpStringTableUpdateCount = 0;
533 NmrpStringTableUpdateIndex = 0;
534 memset(NmrpStringTableUpdateList, 0,\
535 sizeof(NmrpStringTableUpdateList));
536
537 /* Save from network byte-order to host byte-order. */
538 NmrpStringTableBitmask = ntohl(opt->value.string_table_bitmask);
539
540 string_table_bitmask_check();
541 printf("\nTotal %d String Table need updating\n",\
542 NmrpStringTableUpdateCount);
543 } else {
544 printf("\nNo ST-UP option\n");
545 NmrpSTUPOption = 0;
546 }
547 if (NmrpFwUPOption == 0 && NmrpSTUPOption == 0) {
548 NmrpState = STATE_CLOSING;
549 printf("\nNo firmware update, nor string table update\n");
550 NmrpSend();
551 } else {
552 NmrpState = STATE_CONFIGING;
553 printf("\nNMRP WAITING FOR UPLOAD FIRMWARE or STRING TABLES!\n");
554 NmrpSend();
555 }
556 }else
557 break;
558 }
559 break;
560 case NMRP_CODE_KEEP_ALIVE_ACK:
561 if (NmrpState == STATE_KEEP_ALIVE) {
562 if (NmrpAliveWaitACK == 1) {
563 NmrpAliveTimerBase += NMRP_TIMEOUT_ACTIVE / 4;
564 NmrpAliveWaitACK = 0;
565 }
566 }
567 break;
568 case NMRP_CODE_CLOSE_ACK:
569 if (NmrpState == STATE_CLOSING) {
570 NmrpState = STATE_CLOSED;
571 printf("\nNMRP CLOSED");
572 NmrpSend();
573 }
574 break;
575 default:
576 break;
577 }
578
579 }
580
581 void NmrpStart(void)
582 {
583 printf("\n Client starts...[Listening] for ADVERTISE...");
584
585 net_set_timeout_handler(CONFIG_SYS_HZ / 10, Nmrp_Listen_Timeout);
586 net_set_udp_handler(NmrpHandler);
587
588 NmrpState = 0;
589 Nmrp_Listen_TimeoutCount = 0;
590 memset(NmrpClientEther, 0, 6);
591 NmrpClientIP.s_addr = 0;
592 }