1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * ASUS Home Gateway Reference Design
19 * Web Page Configuration Support Routines
20 *
21 * Copyright 2004, ASUSTeK Inc.
22 * All Rights Reserved.
23 *
24 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
25 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
26 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
28 */
29
30#ifdef WEBS
31#include <webs.h>
32#include <uemf.h>
33#include <ej.h>
34#else /* !WEBS */
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39#include <errno.h>
40#include <unistd.h>
41#include <limits.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <assert.h>
48#endif /* WEBS */
49#include <asm/types.h>
50#include <typedefs.h>
51#include <bcmnvram.h>
52#include <bcmutils.h>
53#include <shutils.h>
54#ifdef RTCONFIG_RALINK
55#include <ralink.h>
56#include <iwlib.h>
57#include <stapriv.h>
58#include <ethutils.h>
59#endif
60#include <shared.h>
61#include <sys/mman.h>
62#ifndef O_BINARY
63#define O_BINARY 	0
64#endif
65#ifndef MAP_FAILED
66#define MAP_FAILED (-1)
67#endif
68
69#include "tc_ver.h"
70#include "dsl-upg.h"
71
72#define SWAP_LONG(x) \
73	((__u32)( \
74		(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
75		(((__u32)(x) & (__u32)0x0000ff00UL) <<  8) | \
76		(((__u32)(x) & (__u32)0x00ff0000UL) >>  8) | \
77		(((__u32)(x) & (__u32)0xff000000UL) >> 24) ))
78
79
80
81static int update_tc_fw = 0;
82
83#define IH_NMLEN 32
84
85typedef struct {
86	unsigned int ih_magic;
87	unsigned int ih_hcrc;
88	unsigned int ih_time;
89	unsigned int ih_size;
90	unsigned int ih_load;
91	unsigned int ih_ep;
92	unsigned int ih_dcrc;
93	unsigned char ih_os;
94	unsigned char ih_arch;
95	unsigned char ih_type;
96	unsigned char ih_comp;
97	unsigned char ih_name[IH_NMLEN];
98} IMAGE_HEADER_TRX;
99
100int separate_tc_fw_from_trx()
101{
102	IMAGE_HEADER_TRX* TrxHdr;
103	FILE* FpTrx;
104	char TrxHdrBuf[512];
105	char buf[4096];
106	unsigned int* pTrxSize;
107	unsigned int TrxSize;
108	unsigned int filelen;
109	unsigned int TcFwSize;
110	int TcFwExist = 0;
111	int RetVal = 0;
112
113	FILE* fpSrc = NULL;
114	FILE* fpDst = NULL;
115
116	FpTrx = fopen("/tmp/linux.trx","rb");
117	if (FpTrx == NULL) goto err;
118	fread(TrxHdrBuf,1,sizeof(TrxHdrBuf),FpTrx);
119	fseek( FpTrx, 0, SEEK_END);
120	filelen = ftell( FpTrx );
121	fclose(FpTrx);
122
123	pTrxSize = &TrxHdrBuf[12];
124	TrxSize = SWAP_LONG(*pTrxSize) + 64;
125	_dprintf("trx size %x , file size %x\n",TrxSize,filelen);
126	if (filelen > TrxSize)
127	{
128		TcFwSize = filelen - TrxSize;
129		_dprintf("tcfw size %x\n",TcFwSize);
130
131		//
132		// linux trx has several bytes garbage in the file tail
133		// only save tc fw if the tc fw size is a valid number
134		//
135		if (TcFwSize > 0x100)
136		{
137			fpSrc = fopen("/tmp/linux.trx", "rb");
138			if (fpSrc==NULL) goto err;
139			fpDst = fopen("/tmp/tcfw.bin", "wb");
140			if (fpDst==NULL) goto err;
141
142			fseek(fpSrc,TrxSize,SEEK_SET);
143			while (TcFwSize > 0)
144			{
145				if (TcFwSize > sizeof(buf))
146				{
147					fread(buf, 1, sizeof(buf), fpSrc);
148					fwrite(buf, 1, sizeof(buf), fpDst);
149					TcFwSize -= sizeof(buf);
150				}
151				else
152				{
153					fread(buf, 1, TcFwSize, fpSrc);
154					fwrite(buf, 1, TcFwSize, fpDst);
155					TcFwSize = 0;
156				}
157			}
158
159			update_tc_fw = 1;
160		}
161	}
162	else if (TrxSize == filelen)
163	{
164		// only trx, no tc fw
165		_dprintf("no tc fw\n");
166	}
167
168	RetVal = 1;
169
170err:
171	if (fpSrc)
172		fclose(fpSrc);
173
174	if (fpDst)
175		fclose(fpDst);
176
177	return RetVal;
178}
179
180static int crc_table_empty = 1;
181static unsigned long crc_table[256];
182
183static void make_crc_table()
184{
185  unsigned long c;
186  int n, k;
187  unsigned long poly;	    /* polynomial exclusive-or pattern */
188  /* terms of polynomial defining this crc (except x^32): */
189  static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
190
191  /* make exclusive-or pattern from polynomial (0xedb88320L) */
192  poly = 0L;
193  for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
194    poly |= 1L << (31 - p[n]);
195
196  for (n = 0; n < 256; n++)
197  {
198    c = (unsigned long)n;
199    for (k = 0; k < 8; k++)
200      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
201    crc_table[n] = c;
202  }
203  crc_table_empty = 0;
204}
205
206
207#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
208#define DO2(buf)  DO1(buf); DO1(buf);
209#define DO4(buf)  DO2(buf); DO2(buf);
210#define DO8(buf)  DO4(buf); DO4(buf);
211
212unsigned long crc32_no_comp(unsigned long crc,const unsigned char* buf, int len)
213{
214    if (crc_table_empty)
215      make_crc_table();
216
217    while (len >= 8)
218    {
219      DO8(buf);
220      len -= 8;
221    }
222    if (len) do {
223      DO1(buf);
224    } while (--len);
225
226    return crc;
227}
228int check_tc_firmware_crc(void)
229{
230	FILE* fpSrc = NULL;
231	FILE* fpDst = NULL;
232	unsigned long crc_value;
233	unsigned long* crc_value_ptr;
234	unsigned long calc_crc;
235	long tcfilelen;
236	long filelen, *filelenptr;
237	int cmpHeaderErr = 0;
238	int RetVal = 0;
239	char buf[4096];
240	int new_modem_trx_ver;
241	int curr_modem_trx_ver;
242	unsigned char bBuf[4096];
243	unsigned char tag[] = {0x3C, 0x23, 0x24, 0x3E};	//<#$>
244	int bBufsize = sizeof(bBuf);
245
246	if (update_tc_fw == 0) return 0;
247
248
249	fpSrc = fopen("/tmp/tcfw.bin", "rb");
250	if (fpSrc==NULL)
251	{
252		cmpHeaderErr = 1;
253		goto exit;
254	}
255	fpDst = fopen("/tmp/ras.bin", "wb");
256	if (fpDst==NULL)
257	{
258		cmpHeaderErr = 1;
259		goto exit;
260	}
261
262	fread(buf, 1, 0x100, fpSrc);
263
264	_dprintf("TC FW VER : %c%c%c , %s , %s\n",buf[0],buf[1],buf[2],TC_DSL_FW_VER,TC_DSL_FW_VER_FROM_MODEM);
265
266
267	//read tcfw.bin and find the driver ras info, date ...
268	fseek(fpSrc, 0xF000, SEEK_SET);
269	fread(bBuf, 1, bBufsize, fpSrc);
270
271	int read_idx = bBufsize;
272	while (read_idx--) {
273		if(bBuf[read_idx] == tag[3])
274			if(bBuf[--read_idx] == tag[2])
275				if(bBuf[--read_idx] == tag[1])
276					if(bBuf[--read_idx] == tag[0])
277						break;
278					else
279						continue;
280				else
281					continue;
282			else
283				continue;
284		else
285			continue;
286	}
287	_dprintf("bin date: %s\n", (char*)bBuf+read_idx-14);
288	_dprintf("bin ras: %s\n", (char*)bBuf+read_idx+4);
289
290	fseek(fpSrc, 0x0100, SEEK_SET);
291
292	//check Annex mode
293#ifdef RTCONFIG_DSL_ANNEX_B
294	if(bBuf[read_idx+14] != 'B') {	//ASUS_Annex'B'_..
295		if(bBuf[read_idx+9] != '1') {	//check for the old ras info ASUS_1020
296			RetVal = -1;
297			_dprintf("check annex failed\n");
298			goto exit;
299		}
300	}
301#else
302	if(bBuf[read_idx+14] != 'A') {	//ASUS_ANNEX'A'IJLM_..
303		if(bBuf[read_idx+9] != '1') {	//check for the old ras info ASUS_1020
304			RetVal = -1;
305			_dprintf("check annex failed\n");
306			goto exit;
307		}
308	}
309#endif
310	//check driver release date
311		// /tmp/adsl # cat tc_ver_info.txt
312		// Bootbase:VTC_SPI_BR1.6 | 2010/7/30
313		// RAS:ASUS_ANNEXAIJLM_20120423
314		// System:3.6.18.0(BE.C3)3.16.18.0| 2011/10/31   20111031_v012  [Oct 31 2011 12:53:59]
315	FILE *fpCur;
316	char ver_info_buf[256];
317	int line_idx = 3;
318	int ver_idx = 0;
319	fpCur = fopen("/tmp/adsl/tc_ver_info.txt", "r");
320	if(fpCur != NULL) {
321		while(line_idx--)
322			fgets(ver_info_buf, 256, fpCur);
323		fclose(fpCur);
324		while(++ver_idx < 256) {
325			if(ver_info_buf[ver_idx] == 0x7C) {
326				*(ver_info_buf + ver_idx + 12) = '\0';
327				_dprintf("cur date: %s\n", ver_info_buf+ver_idx+2);
328				if(!strncmp(ver_info_buf+ver_idx+2, (char*)bBuf+read_idx-14, 10))
329					update_tc_fw = 0;
330				else
331					update_tc_fw = 1;
332				break;
333			}else
334				continue;
335		}
336	}
337
338	//check RAS
339	fpCur = fopen("/tmp/adsl/tc_ras_ver.txt", "r");
340	if(fpCur != NULL) {
341		fgets(ver_info_buf, 256, fpCur);
342		fclose(fpCur);
343		_dprintf("cur ras: %s\n", ver_info_buf);
344#ifdef RTCONFIG_DSL_ANNEX_B
345		if(!strncmp(ver_info_buf, (char*)bBuf+read_idx+4, 20))	//ASUS_AnnexB_20111031
346#else
347		if(!strncmp(ver_info_buf, (char*)bBuf+read_idx+4, 24))	//ASUS_ANNEXAIJLM_20120423
348#endif
349			update_tc_fw = 0;
350		else
351			update_tc_fw = 1;
352	}
353	_dprintf("update tc fw or not: %d (0 is not)\n", update_tc_fw);
354
355#if 0	//disable by Sam, 2012/07/12
356
357// There are two firmware on single TRX.  One is router firmware and the other is modem firmware.
358// Router firmware could upgrade or downgrade depends on end-user.
359// For ADSL firmware , we will allow end-user to upgrade only because modem firmware updating is really dangerous.
360// That��s okay even uses new modem firmware on old router firmware.
361// End-user could downgrade router firmware below 1.021 first and then upgrade old TRX again. The modem firmware will be downgraded.
362
363	// get ver number from trx
364	buf[3] = 0;
365	new_modem_trx_ver = atoi(buf);
366#ifdef DSL_N55U_ANNEX_B
367	curr_modem_trx_ver = atoi(TC_DSL_FW_VER_ANNEX_B);
368#else
369	curr_modem_trx_ver = atoi(TC_DSL_FW_VER);
370#endif
371	if(curr_modem_trx_ver > new_modem_trx_ver)
372	{
373		update_tc_fw = 0;
374	}
375	else
376	{
377#define TC_BUF_SZIE 256
378		int buf_idx;
379		int tc_fw_ver_diff = 0;
380		int tc_ras_ver_diff = 0;
381		char buf_tc_fw_ver[TC_BUF_SZIE];
382		FILE *fp;
383		fp = fopen("/tmp/adsl/tc_fw_ver_short.txt", "r");
384		if (fp != NULL) {
385			memset(buf_tc_fw_ver, 0, TC_BUF_SZIE);
386			fgets(buf_tc_fw_ver, TC_BUF_SZIE, fp);
387			fclose(fp);
388			// normalize string
389			for (buf_idx=0; buf_idx<TC_BUF_SZIE; buf_idx++) {
390				if (buf_tc_fw_ver[buf_idx]==0x0d || buf_tc_fw_ver[buf_idx]==0x0a) buf_tc_fw_ver[buf_idx] = 0;
391				if (buf_tc_fw_ver[buf_idx] == 0) break;
392			}
393#ifdef DSL_N55U_ANNEX_B
394			if(strcmp(buf_tc_fw_ver, TC_DSL_FW_VER_FROM_MODEM_ANNEX_B) == 0)
395			{
396				_dprintf("annex b firmware is the same\n");
397			}
398			else
399			{
400				tc_fw_ver_diff = 1;
401			}
402#else
403			if(strcmp(buf_tc_fw_ver, TC_DSL_FW_VER_FROM_MODEM) == 0)
404			{
405				_dprintf("annex a firmware is the same\n");
406			}
407			else
408			{
409				tc_fw_ver_diff = 1;
410			}
411#endif
412		}
413
414		fp = fopen("/tmp/adsl/tc_ras_ver.txt", "r");
415		if (fp != NULL) {
416			memset(buf_tc_fw_ver, 0, TC_BUF_SZIE);
417			fgets(buf_tc_fw_ver, TC_BUF_SZIE, fp);
418			fclose(fp);
419			// normalize string
420			for (buf_idx=0; buf_idx<TC_BUF_SZIE; buf_idx++) {
421				if (buf_tc_fw_ver[buf_idx]==0x0d || buf_tc_fw_ver[buf_idx]==0x0a) buf_tc_fw_ver[buf_idx] = 0;
422				if (buf_tc_fw_ver[buf_idx] == 0) break;
423			}
424#ifdef DSL_N55U_ANNEX_B
425			if(strcmp(buf_tc_fw_ver, TC_DSL_RAS_VER_FROM_MODEM_ANNEX_B) == 0)
426			{
427				_dprintf("annex b firmware is the same\n");
428			}
429			else
430			{
431				tc_ras_ver_diff = 1;
432			}
433			//check Annex mode, Sam 2012/06/20
434			if(buf_tc_fw_ver[10] != 'B') {	//ASUS_Annex'B'_..
435				RetVal = -1;
436				goto exit;
437			}
438#else
439			if(strcmp(buf_tc_fw_ver, TC_DSL_RAS_VER_FROM_MODEM) == 0)
440			{
441				_dprintf("annex a firmware is the same\n");
442			}
443			else
444			{
445				tc_ras_ver_diff = 1;
446			}
447			//check Annex mode, Sam 2012/06/20
448			if(buf_tc_fw_ver[10] != 'A') {	//ASUS_ANNEX'A'IJLM_..
449				RetVal = -1;
450				goto exit;
451			}
452#endif
453		}
454
455		if (tc_fw_ver_diff || tc_ras_ver_diff)
456		{
457			// fw ver or ras ver is differnt
458			// then , upgrade the modem firmware
459		}
460		else
461		{
462			update_tc_fw = 0;
463		}
464	}
465#endif	//#if 0
466
467	_dprintf("tcfw magic : %x %x %x\n",buf[4],buf[5],buf[6]);
468
469	if (strncmp(&buf[4], TC_DSL_MAGIC_NUMBER, 3) == 0)
470	{
471		// magic number OK
472	}
473	else
474	{
475		cmpHeaderErr = 1;
476		goto exit;
477	}
478
479
480	filelenptr=(long*)(buf+22);
481	filelen=*filelenptr;
482	_dprintf("tcfw Filelen: %d\n", filelen);
483	tcfilelen=filelen-0x100;
484
485	crc_value_ptr=(unsigned long*)(buf+34);
486	crc_value=*crc_value_ptr;
487	crc_value=SWAP_LONG(crc_value);
488	_dprintf("tcfw crc: %x\n", crc_value);
489
490	calc_crc = 0xffffffff;
491
492	while(tcfilelen>0)
493	{
494		if (tcfilelen > sizeof(buf))
495		{
496			fread(buf, 1, sizeof(buf), fpSrc);
497			fwrite(buf, 1, sizeof(buf), fpDst);
498			calc_crc = crc32_no_comp(calc_crc,buf,sizeof(buf));
499			tcfilelen-=sizeof(buf);
500		}
501		else
502		{
503			fread(buf, 1, tcfilelen, fpSrc);
504			fwrite(buf, 1, tcfilelen, fpDst);
505			calc_crc = crc32_no_comp(calc_crc,buf,tcfilelen);
506			tcfilelen=0;
507		}
508	}
509
510
511	_dprintf("tcfw calc crc is %x\n", calc_crc);
512	_dprintf("tcfw done\n");
513
514
515exit:
516
517	if((calc_crc != crc_value) || cmpHeaderErr)
518	{
519		_dprintf("header crc error\n");
520		RetVal = -1;
521	}
522
523
524	if (fpSrc)
525		fclose(fpSrc);
526
527	if (fpDst)
528		fclose(fpDst);
529
530	return RetVal;
531}
532
533/*
534 * 0: illegal image
535 * 1: legal image
536 *
537 * check product id, crc ..
538 */
539
540// ANNEX A
541//DSL-N55U_1.0.0.9_Annex_A.trx
542// ANNEX B
543//DSL-N55U_1.0.0.9_Annex_B.trx
544
545
546int dsl_check_imagefile_str(char *fname)
547{
548	int len;
549	char end_char;
550	len = strlen(fname);
551	if (len > 0) len--;
552	end_char = *(fname+len);
553#ifdef DSL_N55U_ANNEX_B
554	if (end_char != 'B') return 0;
555#else
556	if (end_char != 'A') return 0;
557#endif
558	return 1;
559}
560
561
562int truncate_trx(void)
563{
564	IMAGE_HEADER_TRX* TrxHdr;
565	FILE* FpTrx;
566	char TrxHdrBuf[512];
567	unsigned int* pTrxSize;
568	unsigned int TrxSize;
569
570//	if (update_tc_fw == 0) return 0;
571
572	FpTrx = fopen("/tmp/linux.trx","rb");
573	if (FpTrx == NULL) return 0;
574	fread(TrxHdrBuf,1,sizeof(TrxHdrBuf),FpTrx);
575	fclose(FpTrx);
576	pTrxSize = &TrxHdrBuf[12];
577	TrxSize = SWAP_LONG(*pTrxSize);
578	//_dprintf("trx size %x\n",TrxSize);
579	truncate("/tmp/linux.trx",TrxSize + 64);
580	// 64 is trx header size
581	return 1;
582}
583
584#define ADSL_FW_IP_PREFIX "194.255.255."
585
586
587void do_upgrade_adsldrv(void)
588{
589	int ret;
590	char UpdateFwBuf[256];
591	char PingBuf[256];
592	char OneLine[80];
593	char ipaddr[80];
594	FILE* fp;
595	int WaitCnt;
596	int chk_image_err = 0;
597
598	if (update_tc_fw == 0) return;
599
600	fp = fopen("/tmp/adsl/tc_ip_addr.txt","r");
601	if (fp == NULL) chk_image_err = 1;
602	fgets(ipaddr,sizeof(ipaddr),fp);
603	fclose(fp);
604
605	// if adsl fw IP address is different, user should update to a new router fw first
606	if (strncmp(ipaddr,ADSL_FW_IP_PREFIX,sizeof(ADSL_FW_IP_PREFIX)-1)!=0) chk_image_err = 1;
607
608	strcpy(UpdateFwBuf,"cd /tmp; tftp -p -l ras.bin ");
609	strcat(UpdateFwBuf,ipaddr);
610
611	_dprintf("## upgrade tc fw\n");
612
613	if (chk_image_err == 0)
614	{
615		_dprintf("IP alias for ADSL firmware update\n");
616		// this command will stop tp_init
617		system("adslate waitadsl;adslate quitdrv");
618		system("ifconfig eth2.1:0 194.255.255.1 netmask 255.255.255.0;ifconfig eth2.1:0 up");
619		// wait if up
620		strcpy(PingBuf,"ping ");
621		strcat(PingBuf,ipaddr);
622		strcat(PingBuf," -c 1");
623		for (WaitCnt=0; WaitCnt<3; WaitCnt++)
624		{
625			system(PingBuf);
626		}
627		_dprintf("Start to update\n");
628		_dprintf(UpdateFwBuf);
629		system(UpdateFwBuf);
630		_dprintf("tftp done\n");
631		//usleep(1000*1000*5);
632		// wait a miniute and send set to default setting
633		for (WaitCnt=0; WaitCnt<20; WaitCnt++)
634		{
635			system(PingBuf);
636		}
637		// ifconfig down also remove IP alias
638		system("tp_init clear_modem_var");
639		// wait tc flash write completed
640		usleep(1000*1000*2);
641		_dprintf("\nupgrade done\n");
642	}
643}
644
645
646
647// -1: different or no origial header, upgrade
648// 0: same or no upgrade file, skip upgrade
649int compare_linux_image(void)
650{
651	IMAGE_HEADER_TRX* TrxHdr;
652	FILE* FpHdr;
653	char TrxHdrBuf[512];
654	unsigned int OrigTime;
655	unsigned int NewTime;
656
657	memset(TrxHdrBuf,0,sizeof(TrxHdrBuf));
658	FpHdr = fopen("/tmp/trx_hdr.bin","rb");
659	if (FpHdr == NULL) return -1;
660	fread(TrxHdrBuf,1,sizeof(TrxHdrBuf),FpHdr);
661	fclose(FpHdr);
662	TrxHdr = (IMAGE_HEADER_TRX*)TrxHdrBuf;
663
664	OrigTime = SWAP_LONG(TrxHdr->ih_time);
665
666	memset(TrxHdrBuf,0,sizeof(TrxHdrBuf));
667	FpHdr = fopen("/tmp/linux.trx","rb");
668	if (FpHdr == NULL) return 0;
669	fread(TrxHdrBuf,1,sizeof(TrxHdrBuf),FpHdr);
670	fclose(FpHdr);
671	TrxHdr = (IMAGE_HEADER_TRX*)TrxHdrBuf;
672
673	NewTime = SWAP_LONG(TrxHdr->ih_time);
674
675	fprintf(stderr, "Trx %x %x\n", NewTime, OrigTime);
676
677	if (NewTime == OrigTime)
678	{
679		fprintf(stderr, "trx same\n");
680		return 0;
681	}
682	fprintf(stderr, "trx different\n");
683	return -1;
684}
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699