File: /usr/src/linux/drivers/isdn/hysdn/hysdn_boot.c

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