| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $ | 
 | 2 |  * | 
 | 3 |  * Linux driver for HYSDN cards | 
 | 4 |  * specific routines for booting and pof handling | 
 | 5 |  * | 
 | 6 |  * Author    Werner Cornelius (werner@titro.de) for Hypercope GmbH | 
 | 7 |  * Copyright 1999 by Werner Cornelius (werner@titro.de) | 
 | 8 |  * | 
 | 9 |  * This software may be used and distributed according to the terms | 
 | 10 |  * of the GNU General Public License, incorporated herein by reference. | 
 | 11 |  * | 
 | 12 |  */ | 
 | 13 |  | 
 | 14 | #include <linux/vmalloc.h> | 
 | 15 | #include <linux/slab.h> | 
 | 16 | #include <asm/uaccess.h> | 
 | 17 |  | 
 | 18 | #include "hysdn_defs.h" | 
 | 19 | #include "hysdn_pof.h" | 
 | 20 |  | 
 | 21 | /********************************/ | 
 | 22 | /* defines for pof read handler */ | 
 | 23 | /********************************/ | 
 | 24 | #define POF_READ_FILE_HEAD  0 | 
 | 25 | #define POF_READ_TAG_HEAD   1 | 
 | 26 | #define POF_READ_TAG_DATA   2 | 
 | 27 |  | 
 | 28 | /************************************************************/ | 
 | 29 | /* definition of boot specific data area. This data is only */ | 
 | 30 | /* needed during boot and so allocated dynamically.         */ | 
 | 31 | /************************************************************/ | 
 | 32 | struct boot_data { | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 33 | 	unsigned short Cryptor;	/* for use with Decrypt function */ | 
 | 34 | 	unsigned short Nrecs;	/* records remaining in file */ | 
 | 35 | 	unsigned char pof_state;/* actual state of read handler */ | 
 | 36 | 	unsigned char is_crypted;/* card data is crypted */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 | 	int BufSize;		/* actual number of bytes bufferd */ | 
 | 38 | 	int last_error;		/* last occurred error */ | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 39 | 	unsigned short pof_recid;/* actual pof recid */ | 
 | 40 | 	unsigned long pof_reclen;/* total length of pof record data */ | 
 | 41 | 	unsigned long pof_recoffset;/* actual offset inside pof record */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | 	union { | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 43 | 		unsigned char BootBuf[BOOT_BUF_SIZE];/* buffer as byte count */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | 		tPofRecHdr PofRecHdr;	/* header for actual record/chunk */ | 
 | 45 | 		tPofFileHdr PofFileHdr;		/* header from POF file */ | 
 | 46 | 		tPofTimeStamp PofTime;	/* time information */ | 
 | 47 | 	} buf; | 
 | 48 | }; | 
 | 49 |  | 
 | 50 | /*****************************************************/ | 
 | 51 | /*  start decryption of successive POF file chuncks.  */ | 
 | 52 | /*                                                   */ | 
 | 53 | /*  to be called at start of POF file reading,       */ | 
 | 54 | /*  before starting any decryption on any POF record. */ | 
 | 55 | /*****************************************************/ | 
| Adrian Bunk | aade0e8 | 2005-06-28 20:44:56 -0700 | [diff] [blame] | 56 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 57 | StartDecryption(struct boot_data *boot) | 
 | 58 | { | 
 | 59 | 	boot->Cryptor = CRYPT_STARTTERM; | 
 | 60 | }				/* StartDecryption */ | 
 | 61 |  | 
 | 62 |  | 
 | 63 | /***************************************************************/ | 
 | 64 | /* decrypt complete BootBuf                                    */ | 
 | 65 | /* NOTE: decryption must be applied to all or none boot tags - */ | 
 | 66 | /*       to HI and LO boot loader and (all) seq tags, because  */ | 
 | 67 | /*       global Cryptor is started for whole POF.              */ | 
 | 68 | /***************************************************************/ | 
| Adrian Bunk | aade0e8 | 2005-06-28 20:44:56 -0700 | [diff] [blame] | 69 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | DecryptBuf(struct boot_data *boot, int cnt) | 
 | 71 | { | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 72 | 	unsigned char *bufp = boot->buf.BootBuf; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 |  | 
 | 74 | 	while (cnt--) { | 
 | 75 | 		boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 76 | 		*bufp++ ^= (unsigned char)boot->Cryptor; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | 	} | 
 | 78 | }				/* DecryptBuf */ | 
 | 79 |  | 
 | 80 | /********************************************************************************/ | 
 | 81 | /* pof_handle_data executes the required actions dependent on the active record */ | 
 | 82 | /* id. If successful 0 is returned, a negative value shows an error.           */ | 
 | 83 | /********************************************************************************/ | 
 | 84 | static int | 
 | 85 | pof_handle_data(hysdn_card * card, int datlen) | 
 | 86 | { | 
 | 87 | 	struct boot_data *boot = card->boot;	/* pointer to boot specific data */ | 
 | 88 | 	long l; | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 89 | 	unsigned char *imgp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | 	int img_len; | 
 | 91 |  | 
 | 92 | 	/* handle the different record types */ | 
 | 93 | 	switch (boot->pof_recid) { | 
 | 94 |  | 
 | 95 | 		case TAG_TIMESTMP: | 
 | 96 | 			if (card->debug_flags & LOG_POF_RECORD) | 
 | 97 | 				hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); | 
 | 98 | 			break; | 
 | 99 |  | 
 | 100 | 		case TAG_CBOOTDTA: | 
 | 101 | 			DecryptBuf(boot, datlen);	/* we need to encrypt the buffer */ | 
 | 102 | 		case TAG_BOOTDTA: | 
 | 103 | 			if (card->debug_flags & LOG_POF_RECORD) | 
 | 104 | 				hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", | 
 | 105 | 					     (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", | 
 | 106 | 					     datlen, boot->pof_recoffset); | 
 | 107 |  | 
 | 108 | 			if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { | 
 | 109 | 				boot->last_error = EPOF_BAD_IMG_SIZE;	/* invalid length */ | 
 | 110 | 				return (boot->last_error); | 
 | 111 | 			} | 
 | 112 | 			imgp = boot->buf.BootBuf;	/* start of buffer */ | 
 | 113 | 			img_len = datlen;	/* maximum length to transfer */ | 
 | 114 |  | 
 | 115 | 			l = POF_BOOT_LOADER_OFF_IN_PAGE - | 
 | 116 | 			    (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); | 
 | 117 | 			if (l > 0) { | 
 | 118 | 				/* buffer needs to be truncated */ | 
 | 119 | 				imgp += l;	/* advance pointer */ | 
 | 120 | 				img_len -= l;	/* adjust len */ | 
 | 121 | 			} | 
 | 122 | 			/* at this point no special handling for data wrapping over buffer */ | 
 | 123 | 			/* is necessary, because the boot image always will be adjusted to */ | 
 | 124 | 			/* match a page boundary inside the buffer.                        */ | 
 | 125 | 			/* The buffer for the boot image on the card is filled in 2 cycles */ | 
 | 126 | 			/* first the 1024 hi-words are put in the buffer, then the low 1024 */ | 
 | 127 | 			/* word are handled in the same way with different offset.         */ | 
 | 128 |  | 
 | 129 | 			if (img_len > 0) { | 
 | 130 | 				/* data available for copy */ | 
 | 131 | 				if ((boot->last_error = | 
 | 132 | 				     card->writebootimg(card, imgp, | 
 | 133 | 							(boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) | 
 | 134 | 					return (boot->last_error); | 
 | 135 | 			} | 
 | 136 | 			break;	/* end of case boot image hi/lo */ | 
 | 137 |  | 
 | 138 | 		case TAG_CABSDATA: | 
 | 139 | 			DecryptBuf(boot, datlen);	/* we need to encrypt the buffer */ | 
 | 140 | 		case TAG_ABSDATA: | 
 | 141 | 			if (card->debug_flags & LOG_POF_RECORD) | 
 | 142 | 				hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", | 
 | 143 | 					     (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", | 
 | 144 | 					     datlen, boot->pof_recoffset); | 
 | 145 |  | 
| Roel Kluin | dec9951 | 2010-03-11 12:07:22 +0000 | [diff] [blame] | 146 | 			if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | 				return (boot->last_error);	/* error writing data */ | 
 | 148 |  | 
 | 149 | 			if (boot->pof_recoffset + datlen >= boot->pof_reclen) | 
 | 150 | 				return (card->waitpofready(card));	/* data completely spooled, wait for ready */ | 
 | 151 |  | 
 | 152 | 			break;	/* end of case boot seq data */ | 
 | 153 |  | 
 | 154 | 		default: | 
 | 155 | 			if (card->debug_flags & LOG_POF_RECORD) | 
 | 156 | 				hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, | 
 | 157 | 					     datlen, boot->pof_recoffset); | 
 | 158 |  | 
 | 159 | 			break;	/* simply skip record */ | 
 | 160 | 	}			/* switch boot->pof_recid */ | 
 | 161 |  | 
 | 162 | 	return (0); | 
 | 163 | }				/* pof_handle_data */ | 
 | 164 |  | 
 | 165 |  | 
 | 166 | /******************************************************************************/ | 
 | 167 | /* pof_write_buffer is called when the buffer has been filled with the needed */ | 
 | 168 | /* number of data bytes. The number delivered is additionally supplied for    */ | 
 | 169 | /* verification. The functions handles the data and returns the needed number */ | 
 | 170 | /* of bytes for the next action. If the returned value is 0 or less an error  */ | 
 | 171 | /* occurred and booting must be aborted.                                       */ | 
 | 172 | /******************************************************************************/ | 
 | 173 | int | 
 | 174 | pof_write_buffer(hysdn_card * card, int datlen) | 
 | 175 | { | 
 | 176 | 	struct boot_data *boot = card->boot;	/* pointer to boot specific data */ | 
 | 177 |  | 
 | 178 | 	if (!boot) | 
 | 179 | 		return (-EFAULT);	/* invalid call */ | 
 | 180 | 	if (boot->last_error < 0) | 
 | 181 | 		return (boot->last_error);	/* repeated error */ | 
 | 182 |  | 
 | 183 | 	if (card->debug_flags & LOG_POF_WRITE) | 
 | 184 | 		hysdn_addlog(card, "POF write: got %d bytes ", datlen); | 
 | 185 |  | 
 | 186 | 	switch (boot->pof_state) { | 
 | 187 | 		case POF_READ_FILE_HEAD: | 
 | 188 | 			if (card->debug_flags & LOG_POF_WRITE) | 
 | 189 | 				hysdn_addlog(card, "POF write: checking file header"); | 
 | 190 |  | 
 | 191 | 			if (datlen != sizeof(tPofFileHdr)) { | 
 | 192 | 				boot->last_error = -EPOF_INTERNAL; | 
 | 193 | 				break; | 
 | 194 | 			} | 
 | 195 | 			if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { | 
 | 196 | 				boot->last_error = -EPOF_BAD_MAGIC; | 
 | 197 | 				break; | 
 | 198 | 			} | 
 | 199 | 			/* Setup the new state and vars */ | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 200 | 			boot->Nrecs = (unsigned short)(boot->buf.PofFileHdr.N_PofRecs);	/* limited to 65535 */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | 			boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */ | 
 | 202 | 			boot->last_error = sizeof(tPofRecHdr);	/* new length */ | 
 | 203 | 			break; | 
 | 204 |  | 
 | 205 | 		case POF_READ_TAG_HEAD: | 
 | 206 | 			if (card->debug_flags & LOG_POF_WRITE) | 
 | 207 | 				hysdn_addlog(card, "POF write: checking tag header"); | 
 | 208 |  | 
 | 209 | 			if (datlen != sizeof(tPofRecHdr)) { | 
 | 210 | 				boot->last_error = -EPOF_INTERNAL; | 
 | 211 | 				break; | 
 | 212 | 			} | 
 | 213 | 			boot->pof_recid = boot->buf.PofRecHdr.PofRecId;		/* actual pof recid */ | 
 | 214 | 			boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen;	/* total length */ | 
 | 215 | 			boot->pof_recoffset = 0;	/* no starting offset */ | 
 | 216 |  | 
 | 217 | 			if (card->debug_flags & LOG_POF_RECORD) | 
 | 218 | 				hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", | 
 | 219 | 				      boot->pof_recid, boot->pof_reclen); | 
 | 220 |  | 
 | 221 | 			boot->pof_state = POF_READ_TAG_DATA;	/* now start with tag data */ | 
 | 222 | 			if (boot->pof_reclen < BOOT_BUF_SIZE) | 
 | 223 | 				boot->last_error = boot->pof_reclen;	/* limit size */ | 
 | 224 | 			else | 
 | 225 | 				boot->last_error = BOOT_BUF_SIZE;	/* maximum */ | 
 | 226 |  | 
 | 227 | 			if (!boot->last_error) {	/* no data inside record */ | 
 | 228 | 				boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */ | 
 | 229 | 				boot->last_error = sizeof(tPofRecHdr);	/* new length */ | 
 | 230 | 			} | 
 | 231 | 			break; | 
 | 232 |  | 
 | 233 | 		case POF_READ_TAG_DATA: | 
 | 234 | 			if (card->debug_flags & LOG_POF_WRITE) | 
 | 235 | 				hysdn_addlog(card, "POF write: getting tag data"); | 
 | 236 |  | 
 | 237 | 			if (datlen != boot->last_error) { | 
 | 238 | 				boot->last_error = -EPOF_INTERNAL; | 
 | 239 | 				break; | 
 | 240 | 			} | 
 | 241 | 			if ((boot->last_error = pof_handle_data(card, datlen)) < 0) | 
 | 242 | 				return (boot->last_error);	/* an error occurred */ | 
 | 243 | 			boot->pof_recoffset += datlen; | 
 | 244 | 			if (boot->pof_recoffset >= boot->pof_reclen) { | 
 | 245 | 				boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */ | 
 | 246 | 				boot->last_error = sizeof(tPofRecHdr);	/* new length */ | 
 | 247 | 			} else { | 
 | 248 | 				if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) | 
 | 249 | 					boot->last_error = boot->pof_reclen - boot->pof_recoffset;	/* limit size */ | 
 | 250 | 				else | 
 | 251 | 					boot->last_error = BOOT_BUF_SIZE;	/* maximum */ | 
 | 252 | 			} | 
 | 253 | 			break; | 
 | 254 |  | 
 | 255 | 		default: | 
 | 256 | 			boot->last_error = -EPOF_INTERNAL;	/* unknown state */ | 
 | 257 | 			break; | 
 | 258 | 	}			/* switch (boot->pof_state) */ | 
 | 259 |  | 
 | 260 | 	return (boot->last_error); | 
 | 261 | }				/* pof_write_buffer */ | 
 | 262 |  | 
 | 263 |  | 
 | 264 | /*******************************************************************************/ | 
 | 265 | /* pof_write_open is called when an open for boot on the cardlog device occurs. */ | 
 | 266 | /* The function returns the needed number of bytes for the next operation. If  */ | 
 | 267 | /* the returned number is less or equal 0 an error specified by this code      */ | 
 | 268 | /* occurred. Additionally the pointer to the buffer data area is set on success */ | 
 | 269 | /*******************************************************************************/ | 
 | 270 | int | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 271 | pof_write_open(hysdn_card * card, unsigned char **bufp) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 272 | { | 
 | 273 | 	struct boot_data *boot;	/* pointer to boot specific data */ | 
 | 274 |  | 
 | 275 | 	if (card->boot) { | 
 | 276 | 		if (card->debug_flags & LOG_POF_OPEN) | 
 | 277 | 			hysdn_addlog(card, "POF open: already opened for boot"); | 
 | 278 | 		return (-ERR_ALREADY_BOOT);	/* boot already active */ | 
 | 279 | 	} | 
 | 280 | 	/* error no mem available */ | 
| Burman Yan | 41f9693 | 2006-12-08 02:39:35 -0800 | [diff] [blame] | 281 | 	if (!(boot = kzalloc(sizeof(struct boot_data), GFP_KERNEL))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 282 | 		if (card->debug_flags & LOG_MEM_ERR) | 
 | 283 | 			hysdn_addlog(card, "POF open: unable to allocate mem"); | 
 | 284 | 		return (-EFAULT); | 
 | 285 | 	} | 
 | 286 | 	card->boot = boot; | 
 | 287 | 	card->state = CARD_STATE_BOOTING; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 |  | 
 | 289 | 	card->stopcard(card);	/* first stop the card */ | 
 | 290 | 	if (card->testram(card)) { | 
 | 291 | 		if (card->debug_flags & LOG_POF_OPEN) | 
 | 292 | 			hysdn_addlog(card, "POF open: DPRAM test failure"); | 
 | 293 | 		boot->last_error = -ERR_BOARD_DPRAM; | 
 | 294 | 		card->state = CARD_STATE_BOOTERR;	/* show boot error */ | 
 | 295 | 		return (boot->last_error); | 
 | 296 | 	} | 
 | 297 | 	boot->BufSize = 0;	/* Buffer is empty */ | 
 | 298 | 	boot->pof_state = POF_READ_FILE_HEAD;	/* read file header */ | 
 | 299 | 	StartDecryption(boot);	/* if POF File should be encrypted */ | 
 | 300 |  | 
 | 301 | 	if (card->debug_flags & LOG_POF_OPEN) | 
 | 302 | 		hysdn_addlog(card, "POF open: success"); | 
 | 303 |  | 
 | 304 | 	*bufp = boot->buf.BootBuf;	/* point to buffer */ | 
 | 305 | 	return (sizeof(tPofFileHdr)); | 
 | 306 | }				/* pof_write_open */ | 
 | 307 |  | 
 | 308 | /********************************************************************************/ | 
 | 309 | /* pof_write_close is called when an close of boot on the cardlog device occurs. */ | 
 | 310 | /* The return value must be 0 if everything has happened as desired.            */ | 
 | 311 | /********************************************************************************/ | 
 | 312 | int | 
 | 313 | pof_write_close(hysdn_card * card) | 
 | 314 | { | 
 | 315 | 	struct boot_data *boot = card->boot;	/* pointer to boot specific data */ | 
 | 316 |  | 
 | 317 | 	if (!boot) | 
 | 318 | 		return (-EFAULT);	/* invalid call */ | 
 | 319 |  | 
 | 320 | 	card->boot = NULL;	/* no boot active */ | 
 | 321 | 	kfree(boot); | 
 | 322 |  | 
 | 323 | 	if (card->state == CARD_STATE_RUN) | 
 | 324 | 		card->set_errlog_state(card, 1);	/* activate error log */ | 
 | 325 |  | 
 | 326 | 	if (card->debug_flags & LOG_POF_OPEN) | 
 | 327 | 		hysdn_addlog(card, "POF close: success"); | 
 | 328 |  | 
 | 329 | 	return (0); | 
 | 330 | }				/* pof_write_close */ | 
 | 331 |  | 
 | 332 | /*********************************************************************************/ | 
 | 333 | /* EvalSysrTokData checks additional records delivered with the Sysready Message */ | 
 | 334 | /* when POF has been booted. A return value of 0 is used if no error occurred.    */ | 
 | 335 | /*********************************************************************************/ | 
 | 336 | int | 
| Andrew Morton | c721bcc | 2006-03-25 03:07:04 -0800 | [diff] [blame] | 337 | EvalSysrTokData(hysdn_card *card, unsigned char *cp, int len) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 338 | { | 
 | 339 | 	u_char *p; | 
 | 340 | 	u_char crc; | 
 | 341 |  | 
 | 342 | 	if (card->debug_flags & LOG_POF_RECORD) | 
 | 343 | 		hysdn_addlog(card, "SysReady Token data length %d", len); | 
 | 344 |  | 
 | 345 | 	if (len < 2) { | 
 | 346 | 		hysdn_addlog(card, "SysReady Token Data to short"); | 
 | 347 | 		return (1); | 
 | 348 | 	} | 
 | 349 | 	for (p = cp, crc = 0; p < (cp + len - 2); p++) | 
 | 350 | 		if ((crc & 0x80)) | 
 | 351 | 			crc = (((u_char) (crc << 1)) + 1) + *p; | 
 | 352 | 		else | 
 | 353 | 			crc = ((u_char) (crc << 1)) + *p; | 
 | 354 | 	crc = ~crc; | 
 | 355 | 	if (crc != *(cp + len - 1)) { | 
 | 356 | 		hysdn_addlog(card, "SysReady Token Data invalid CRC"); | 
 | 357 | 		return (1); | 
 | 358 | 	} | 
 | 359 | 	len--;			/* don't check CRC byte */ | 
 | 360 | 	while (len > 0) { | 
 | 361 |  | 
 | 362 | 		if (*cp == SYSR_TOK_END) | 
 | 363 | 			return (0);	/* End of Token stream */ | 
 | 364 |  | 
 | 365 | 		if (len < (*(cp + 1) + 2)) { | 
 | 366 | 			hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); | 
 | 367 | 			return (1); | 
 | 368 | 		} | 
 | 369 | 		switch (*cp) { | 
 | 370 | 			case SYSR_TOK_B_CHAN:	/* 1 */ | 
 | 371 | 				if (*(cp + 1) != 1) | 
 | 372 | 					return (1);	/* length invalid */ | 
 | 373 | 				card->bchans = *(cp + 2); | 
 | 374 | 				break; | 
 | 375 |  | 
 | 376 | 			case SYSR_TOK_FAX_CHAN:	/* 2 */ | 
 | 377 | 				if (*(cp + 1) != 1) | 
 | 378 | 					return (1);	/* length invalid */ | 
 | 379 | 				card->faxchans = *(cp + 2); | 
 | 380 | 				break; | 
 | 381 |  | 
 | 382 | 			case SYSR_TOK_MAC_ADDR:	/* 3 */ | 
 | 383 | 				if (*(cp + 1) != 6) | 
 | 384 | 					return (1);	/* length invalid */ | 
 | 385 | 				memcpy(card->mac_addr, cp + 2, 6); | 
 | 386 | 				break; | 
 | 387 |  | 
 | 388 | 			default: | 
 | 389 | 				hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); | 
 | 390 | 				break; | 
 | 391 | 		} | 
 | 392 | 		len -= (*(cp + 1) + 2);		/* adjust len */ | 
 | 393 | 		cp += (*(cp + 1) + 2);	/* and pointer */ | 
 | 394 | 	} | 
 | 395 |  | 
 | 396 | 	hysdn_addlog(card, "no end token found"); | 
 | 397 | 	return (1); | 
 | 398 | }				/* EvalSysrTokData */ |