2 * Copyright (C) 2008 Delta Networks Inc.
10 #include <dni_common.h>
12 typedef void nmrp_thand_f(void);
14 ulong NmrpOuripSubnetMask
;
16 int NmrpFwUPOption
= 0;
17 int NmrpSTUPOption
= 0;
18 int NmrpStringTableUpdateCount
= 0;
19 int NmrpStringTableUpdateIndex
= 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;
44 static void Nmrp_Listen_Timeout(void);
49 void NmrpSetTimeout(unchar
, ulong
, nmrp_thand_f
*);
51 void Nmrp_Led_Flashing_Timeout();
53 extern void board_reset_default();
55 static int MyNetSetEther(volatile uchar
* xet
, uchar
* addr
, uint prot
)
57 struct ethernet_hdr
*et
= (struct ethernet_hdr
*) xet
;
59 myvlanid
= ntohs(net_our_vlan
);
60 if (myvlanid
== (ushort
) - 1)
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
;
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
;
77 return ETHER_HDR_SIZE
;
80 static void Nmrp_Conf_Timeout(void)
82 if (++Nmrp_REQ_TimeoutCount
> NMRP_MAX_RETRY_CONF
) {
83 puts("\n retry conf count exceeded;\n");
84 Nmrp_REQ_TimeoutCount
= 0;
88 NmrpSetTimeout(NMRP_CODE_CONF_ACK
,
89 (NMRP_TIMEOUT_REQ
* CONFIG_SYS_HZ
) / 2,
95 void Nmrp_Closing_Timeout()
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
103 puts("\nNMRP is complete. Please switch OFF power.\n");
105 Nmrp_Led_Flashing_Timeout();
109 console_assign(stdout
, "nulldev");
110 console_assign(stderr
, "nulldev");
111 NmrpState
= STATE_CLOSED
;
112 net_set_state(NETLOOP_SUCCESS
);
115 NmrpSetTimeout(NMRP_CODE_CLOSE_ACK
,
116 (CONFIG_SYS_HZ
* NMRP_TIMEOUT_REQ
) / 2,
117 Nmrp_Closing_Timeout
);
122 #define LED_REG_IN_OUT 0xff800500
123 #define LED_TEST_MASK 0x08000000
124 #define LED_AL_AH_REG 0xff800528
126 void board_test_led(int status
)
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
);
132 val32
= *cled_in_out_reg
;
133 val32
|= LED_TEST_MASK
;
134 *cled_in_out_reg
= val32
;
136 val32
= *cled_al_ah_reg
;
138 val32
&= ~LED_TEST_MASK
;
140 val32
|= LED_TEST_MASK
;
141 *cled_al_ah_reg
= val32
;
144 void Nmrp_Led_Flashing_Timeout()
146 static int NmrpLedCount
= 0;
149 if ((NmrpLedCount
% 2) == 1) {
159 /*press ctl+c, turn on test led,then normally boot*/
163 extern void NmrpSend(void)
169 pkt
= (u8
*) net_tx_packet
;
170 pkt
+= MyNetSetEther(pkt
, NmrpServerEther
, PROT_NMRP
);
171 eth_len
= pkt
- net_tx_packet
;
174 case STATE_LISTENING
:
178 *((u8
*) pkt
) = (NMRP_CODE_CONF_REQ
);
182 *((u16
*) pkt
) = htons(6);
187 (void)net_send_packet((u8
*) net_tx_packet
, eth_len
+ len
);
188 net_set_timeout_handler((NMRP_TIMEOUT_REQ
* CONFIG_SYS_HZ
) / 2,
190 NmrpSetTimeout(NMRP_CODE_CONF_ACK
,
191 (NMRP_TIMEOUT_REQ
* CONFIG_SYS_HZ
) / 2,
194 case STATE_CONFIGING
:
198 *((u8
*) pkt
) = (NMRP_CODE_TFTP_UL_REQ
);
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
));
212 /* Append NMRP option type FILE-NAME */
213 *((u16
*) pkt
) = htons(NMRP_OPT_FILE_NAME
);
216 /* Append the total length of NMRP option FILE-NAME */
217 *((u16
*) pkt
) = htons(STRING_TABLE_FILENAME_OPT_LEN
);
220 /* Append the string table filename to FILE-NAME option value */
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
];
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 */
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
));
239 /* Append NMRP option type FILE-NAME */
240 *((u16
*) pkt
) = htons(NMRP_OPT_FILE_NAME
);
243 /* Append the total length of NMRP option FILE-NAME for firmware*/
244 *((u16
*) pkt
) = htons(FIRMWARE_FILENAME_OPT_LEN
);
247 /* Append the firmware filename to FILE-NAME option value */
248 sprintf(NmrpFirmwareFilename
, "%s\n", FIRMWARE_FILENAME
);
250 for (i
= 0; i
< FIRMWARE_FILENAME_LEN
; i
++) {
251 *((u8
*) pkt
) = NmrpFirmwareFilename
[i
];
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
);
261 UpgradeFirmwareFromNmrpServer();
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
;
269 case STATE_KEEP_ALIVE
:
270 printf("NMRP Send Keep alive REQ\n");
271 //workaround_ipq40xx_gmac_nmrp_hang_action();
275 *((u8
*) pkt
) = (NMRP_CODE_KEEP_ALIVE_REQ
);
279 *((u16
*) pkt
) = htons(6);
282 (void)net_send_packet((u8
*) net_tx_packet
, eth_len
+ len
);
283 NmrpAliveWaitACK
= 1;
286 printf("NMRP Send Closing REQ\n");
287 //workaround_qca8337_gmac_nmrp_hang_action();
288 //workaround_ipq40xx_gmac_nmrp_hang_action();
296 *((u8
*) pkt
) = (NMRP_CODE_CLOSE_REQ
);
300 *((u16
*) pkt
) = htons(6);
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
);
309 run_command("sdk restoredefault", 0); //board_reset_default();
310 #if defined(CONFIG_HW29765352P32P4000P512P2X2P2X2P4X4) || \
311 defined(CONFIG_HW29765352P0P4096P512P2X2P2X2P4X4) || \
312 defined(CONFIG_HW29765515P0P4096P512P2X2P2X2P2X2)
314 printf ("boot_partition_set 1\n");
315 snprintf(runcmd
, sizeof(runcmd
), "boot_partition_set 1");
316 run_command(runcmd
, 0);
318 NmrptimeHandler
=NULL
;
319 puts("\nNMRP is complete. Please switch OFF power.\n");
321 Nmrp_Led_Flashing_Timeout();
325 console_assign(stdout
, "nulldev");
326 console_assign(stderr
, "nulldev");
327 net_set_state(NETLOOP_SUCCESS
);
336 static void Nmrp_Listen_Timeout(void)
338 if (++Nmrp_Listen_TimeoutCount
> NMRP_TIMEOUT_LISTEN
) {
339 puts("\nRetry count exceeded; boot the image as usual\n");
340 Nmrp_Listen_TimeoutCount
= 0;
344 net_set_timeout_handler(CONFIG_SYS_HZ
, Nmrp_Listen_Timeout
);
348 static NMRP_PARSED_OPT
*Nmrp_Parse(uchar
* pkt
, ushort optType
)
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
))
356 return msg
->numOptions
== 0 ? NULL
: (opt
== optEnd
? NULL
: opt
);
359 void NmrpSetTimeout(unchar proto
, ulong iv
, nmrp_thand_f
* f
)
362 NmrptimeHandler
= (nmrp_thand_f
*) 0;
367 NmrptimeStart
= get_timer(0);
373 Function to parse the NMRP options inside packet.
374 If all options are parsed correctly, it returns 0.
376 static int Nmrp_Parse_Opts(uchar
*pkt
, NMRP_PARSED_MSG
*nmrp_parsed
)
378 nmrp_t
*nmrphdr
= (nmrp_t
*) pkt
;
380 int remain_len
, opt_index
= 0;
382 nmrp_parsed
->reserved
= nmrphdr
->reserved
;
383 nmrp_parsed
->code
= nmrphdr
->code
;
384 nmrp_parsed
->id
= nmrphdr
->id
;
385 nmrp_parsed
->length
= nmrphdr
->length
;
387 remain_len
= ntohs(nmrphdr
->length
) - NMRP_HDR_LEN
;
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
);
396 nmrp_parsed
->numOptions
=opt_index
;
400 void string_table_bitmask_check()
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
++;
414 void set_region(u16 RegionOption
)
417 sprintf(region
, "%04x", RegionOption
);
418 env_set("region", region
);
419 run_command("saveenv", 0);
422 void NmrpHandler(uchar
* pkt
, unsigned dest
, struct in_addr src_ip
, unsigned src
,
425 nmrp_t
*nmrphdr
= (nmrp_t
*) pkt
;
429 NMRP_PARSED_MSG nmrp_parsed
;
430 NMRP_PARSED_OPT
*opt
;
431 proto
= nmrphdr
->code
;
435 /* check for timeout,and run the timeout handler
439 if (NmrptimeHandler
&& ((get_timer(0) - NmrptimeStart
) > NmrptimeDelta
)
440 && (proto
!= Nmrpproto
)) {
443 NmrptimeHandler
= (nmrp_thand_f
*) 0;
448 Check if Reserved field is zero. Per the specification, the reserved
449 must be all zero in a valid NMRP packet.
451 if (nmrphdr
->reserved
!= 0){
454 memset(&nmrp_parsed
, 0, sizeof(NMRP_PARSED_MSG
));
457 Parse the options inside the packet and save it into nmrp_parsed for
460 if (Nmrp_Parse_Opts(pkt
, &nmrp_parsed
) != 0){
461 /* Some wrong inside the packet, just discard it */
467 // ignore same packet
468 if (NmrpBlock
== NmrpLastBlock
)
470 NmrpLastBlock
= NmrpBlock
;
473 case NMRP_CODE_ADVERTISE
: /*listening state * */
474 if (NmrpState
== 0) {
476 Check if we get the MAGIC-NO option and the content is match
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
;
484 printf("\nNMRP CONFIGING");
490 case NMRP_CODE_CONF_ACK
:
491 if (NmrpState
== STATE_LISTENING
) {
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.
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
);
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
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
);
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");
523 printf("\nNo FW-UP option\n");
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");
531 /* Reset string tables' update related variables. */
532 NmrpStringTableUpdateCount
= 0;
533 NmrpStringTableUpdateIndex
= 0;
534 memset(NmrpStringTableUpdateList
, 0,\
535 sizeof(NmrpStringTableUpdateList
));
537 /* Save from network byte-order to host byte-order. */
538 NmrpStringTableBitmask
= ntohl(opt
->value
.string_table_bitmask
);
540 string_table_bitmask_check();
541 printf("\nTotal %d String Table need updating\n",\
542 NmrpStringTableUpdateCount
);
544 printf("\nNo ST-UP option\n");
547 if (NmrpFwUPOption
== 0 && NmrpSTUPOption
== 0) {
548 NmrpState
= STATE_CLOSING
;
549 printf("\nNo firmware update, nor string table update\n");
552 NmrpState
= STATE_CONFIGING
;
553 printf("\nNMRP WAITING FOR UPLOAD FIRMWARE or STRING TABLES!\n");
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;
568 case NMRP_CODE_CLOSE_ACK
:
569 if (NmrpState
== STATE_CLOSING
) {
570 NmrpState
= STATE_CLOSED
;
571 printf("\nNMRP CLOSED");
583 printf("\n Client starts...[Listening] for ADVERTISE...");
585 net_set_timeout_handler(CONFIG_SYS_HZ
/ 10, Nmrp_Listen_Timeout
);
586 net_set_udp_handler(NmrpHandler
);
589 Nmrp_Listen_TimeoutCount
= 0;
590 memset(NmrpClientEther
, 0, 6);
591 NmrpClientIP
.s_addr
= 0;