cregit-Linux how code gets into the kernel

Release 4.14 drivers/isdn/hysdn/hysdn_boot.c

/* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $
 *
 * Linux driver for HYSDN cards
 * specific routines for booting and pof handling
 *
 * Author    Werner Cornelius (werner@titro.de) for Hypercope GmbH
 * Copyright 1999 by Werner Cornelius (werner@titro.de)
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include "hysdn_defs.h"
#include "hysdn_pof.h"

/********************************/
/* defines for pof read handler */
/********************************/

#define POF_READ_FILE_HEAD  0

#define POF_READ_TAG_HEAD   1

#define POF_READ_TAG_DATA   2

/************************************************************/
/* definition of boot specific data area. This data is only */
/* needed during boot and so allocated dynamically.         */
/************************************************************/

struct boot_data {
	
unsigned short Cryptor;	/* for use with Decrypt function */
	
unsigned short Nrecs;	/* records remaining in file */
	
unsigned char pof_state;/* actual state of read handler */
	
unsigned char is_crypted;/* card data is crypted */
	
int BufSize;		/* actual number of bytes bufferd */
	
int last_error;		/* last occurred error */
	
unsigned short pof_recid;/* actual pof recid */
	
unsigned long pof_reclen;/* total length of pof record data */
	
unsigned long pof_recoffset;/* actual offset inside pof record */
	union {
		
unsigned char BootBuf[BOOT_BUF_SIZE];/* buffer as byte count */
		
tPofRecHdr PofRecHdr;	/* header for actual record/chunk */
		
tPofFileHdr PofFileHdr;		/* header from POF file */
		
tPofTimeStamp PofTime;	/* time information */
	
} buf;
};

/*****************************************************/
/*  start decryption of successive POF file chuncks.  */
/*                                                   */
/*  to be called at start of POF file reading,       */
/*  before starting any decryption on any POF record. */
/*****************************************************/

static void StartDecryption(struct boot_data *boot) { boot->Cryptor = CRYPT_STARTTERM; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1694.12%150.00%
Adrian Bunk15.88%150.00%
Total17100.00%2100.00%

/* StartDecryption */ /***************************************************************/ /* decrypt complete BootBuf */ /* NOTE: decryption must be applied to all or none boot tags - */ /* to HI and LO boot loader and (all) seq tags, because */ /* global Cryptor is started for whole POF. */ /***************************************************************/
static void DecryptBuf(struct boot_data *boot, int cnt) { unsigned char *bufp = boot->buf.BootBuf; while (cnt--) { boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); *bufp++ ^= (unsigned char)boot->Cryptor; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6592.86%133.33%
Andrew Morton45.71%133.33%
Adrian Bunk11.43%133.33%
Total70100.00%3100.00%

/* DecryptBuf */ /********************************************************************************/ /* pof_handle_data executes the required actions dependent on the active record */ /* id. If successful 0 is returned, a negative value shows an error. */ /********************************************************************************/
static int pof_handle_data(hysdn_card *card, int datlen) { struct boot_data *boot = card->boot; /* pointer to boot specific data */ long l; unsigned char *imgp; int img_len; /* handle the different record types */ switch (boot->pof_recid) { case TAG_TIMESTMP: if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); break; case TAG_CBOOTDTA: DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ case TAG_BOOTDTA: if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", datlen, boot->pof_recoffset); if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */ return (boot->last_error); } imgp = boot->buf.BootBuf; /* start of buffer */ img_len = datlen; /* maximum length to transfer */ l = POF_BOOT_LOADER_OFF_IN_PAGE - (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); if (l > 0) { /* buffer needs to be truncated */ imgp += l; /* advance pointer */ img_len -= l; /* adjust len */ } /* at this point no special handling for data wrapping over buffer */ /* is necessary, because the boot image always will be adjusted to */ /* match a page boundary inside the buffer. */ /* The buffer for the boot image on the card is filled in 2 cycles */ /* first the 1024 hi-words are put in the buffer, then the low 1024 */ /* word are handled in the same way with different offset. */ if (img_len > 0) { /* data available for copy */ if ((boot->last_error = card->writebootimg(card, imgp, (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) return (boot->last_error); } break; /* end of case boot image hi/lo */ case TAG_CABSDATA: DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ case TAG_ABSDATA: if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", datlen, boot->pof_recoffset); if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0) return (boot->last_error); /* error writing data */ if (boot->pof_recoffset + datlen >= boot->pof_reclen) return (card->waitpofready(card)); /* data completely spooled, wait for ready */ break; /* end of case boot seq data */ default: if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, datlen, boot->pof_recoffset); break; /* simply skip record */ } /* switch boot->pof_recid */ return (0); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)38199.22%133.33%
Andrew Morton20.52%133.33%
Roel Kluin10.26%133.33%
Total384100.00%3100.00%

/* pof_handle_data */ /******************************************************************************/ /* pof_write_buffer is called when the buffer has been filled with the needed */ /* number of data bytes. The number delivered is additionally supplied for */ /* verification. The functions handles the data and returns the needed number */ /* of bytes for the next action. If the returned value is 0 or less an error */ /* occurred and booting must be aborted. */ /******************************************************************************/
int pof_write_buffer(hysdn_card *card, int datlen) { struct boot_data *boot = card->boot; /* pointer to boot specific data */ if (!boot) return (-EFAULT); /* invalid call */ if (boot->last_error < 0) return (boot->last_error); /* repeated error */ if (card->debug_flags & LOG_POF_WRITE) hysdn_addlog(card, "POF write: got %d bytes ", datlen); switch (boot->pof_state) { case POF_READ_FILE_HEAD: if (card->debug_flags & LOG_POF_WRITE) hysdn_addlog(card, "POF write: checking file header"); if (datlen != sizeof(tPofFileHdr)) { boot->last_error = -EPOF_INTERNAL; break; } if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { boot->last_error = -EPOF_BAD_MAGIC; break; } /* Setup the new state and vars */ boot->Nrecs = (unsigned short)(boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ boot->last_error = sizeof(tPofRecHdr); /* new length */ break; case POF_READ_TAG_HEAD: if (card->debug_flags & LOG_POF_WRITE) hysdn_addlog(card, "POF write: checking tag header"); if (datlen != sizeof(tPofRecHdr)) { boot->last_error = -EPOF_INTERNAL; break; } boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */ boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */ boot->pof_recoffset = 0; /* no starting offset */ if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", boot->pof_recid, boot->pof_reclen); boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */ if (boot->pof_reclen < BOOT_BUF_SIZE) boot->last_error = boot->pof_reclen; /* limit size */ else boot->last_error = BOOT_BUF_SIZE; /* maximum */ if (!boot->last_error) { /* no data inside record */ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ boot->last_error = sizeof(tPofRecHdr); /* new length */ } break; case POF_READ_TAG_DATA: if (card->debug_flags & LOG_POF_WRITE) hysdn_addlog(card, "POF write: getting tag data"); if (datlen != boot->last_error) { boot->last_error = -EPOF_INTERNAL; break; } if ((boot->last_error = pof_handle_data(card, datlen)) < 0) return (boot->last_error); /* an error occurred */ boot->pof_recoffset += datlen; if (boot->pof_recoffset >= boot->pof_reclen) { boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ boot->last_error = sizeof(tPofRecHdr); /* new length */ } else { if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */ else boot->last_error = BOOT_BUF_SIZE; /* maximum */ } break; default: boot->last_error = -EPOF_INTERNAL; /* unknown state */ break; } /* switch (boot->pof_state) */ return (boot->last_error); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)47399.37%133.33%
Andrew Morton20.42%133.33%
Linus Torvalds10.21%133.33%
Total476100.00%3100.00%

/* pof_write_buffer */ /*******************************************************************************/ /* pof_write_open is called when an open for boot on the cardlog device occurs. */ /* The function returns the needed number of bytes for the next operation. If */ /* the returned number is less or equal 0 an error specified by this code */ /* occurred. Additionally the pointer to the buffer data area is set on success */ /*******************************************************************************/
int pof_write_open(hysdn_card *card, unsigned char **bufp) { struct boot_data *boot; /* pointer to boot specific data */ if (card->boot) { if (card->debug_flags & LOG_POF_OPEN) hysdn_addlog(card, "POF open: already opened for boot"); return (-ERR_ALREADY_BOOT); /* boot already active */ } /* error no mem available */ if (!(boot = kzalloc(sizeof(struct boot_data), GFP_KERNEL))) { if (card->debug_flags & LOG_MEM_ERR) hysdn_addlog(card, "POF open: unable to allocate mem"); return (-EFAULT); } card->boot = boot; card->state = CARD_STATE_BOOTING; card->stopcard(card); /* first stop the card */ if (card->testram(card)) { if (card->debug_flags & LOG_POF_OPEN) hysdn_addlog(card, "POF open: DPRAM test failure"); boot->last_error = -ERR_BOARD_DPRAM; card->state = CARD_STATE_BOOTERR; /* show boot error */ return (boot->last_error); } boot->BufSize = 0; /* Buffer is empty */ boot->pof_state = POF_READ_FILE_HEAD; /* read file header */ StartDecryption(boot); /* if POF File should be encrypted */ if (card->debug_flags & LOG_POF_OPEN) hysdn_addlog(card, "POF open: success"); *bufp = boot->buf.BootBuf; /* point to buffer */ return (sizeof(tPofFileHdr)); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)21098.59%133.33%
Andrew Morton20.94%133.33%
Burman Yan10.47%133.33%
Total213100.00%3100.00%

/* pof_write_open */ /********************************************************************************/ /* pof_write_close is called when an close of boot on the cardlog device occurs. */ /* The return value must be 0 if everything has happened as desired. */ /********************************************************************************/
int pof_write_close(hysdn_card *card) { struct boot_data *boot = card->boot; /* pointer to boot specific data */ if (!boot) return (-EFAULT); /* invalid call */ card->boot = NULL; /* no boot active */ kfree(boot); if (card->state == CARD_STATE_RUN) card->set_errlog_state(card, 1); /* activate error log */ if (card->debug_flags & LOG_POF_OPEN) hysdn_addlog(card, "POF close: success"); return (0); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)81100.00%1100.00%
Total81100.00%1100.00%

/* pof_write_close */ /*********************************************************************************/ /* EvalSysrTokData checks additional records delivered with the Sysready Message */ /* when POF has been booted. A return value of 0 is used if no error occurred. */ /*********************************************************************************/
int EvalSysrTokData(hysdn_card *card, unsigned char *cp, int len) { u_char *p; u_char crc; if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "SysReady Token data length %d", len); if (len < 2) { hysdn_addlog(card, "SysReady Token Data to short"); return (1); } for (p = cp, crc = 0; p < (cp + len - 2); p++) if ((crc & 0x80)) crc = (((u_char) (crc << 1)) + 1) + *p; else crc = ((u_char) (crc << 1)) + *p; crc = ~crc; if (crc != *(cp + len - 1)) { hysdn_addlog(card, "SysReady Token Data invalid CRC"); return (1); } len--; /* don't check CRC byte */ while (len > 0) { if (*cp == SYSR_TOK_END) return (0); /* End of Token stream */ if (len < (*(cp + 1) + 2)) { hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); return (1); } switch (*cp) { case SYSR_TOK_B_CHAN: /* 1 */ if (*(cp + 1) != 1) return (1); /* length invalid */ card->bchans = *(cp + 2); break; case SYSR_TOK_FAX_CHAN: /* 2 */ if (*(cp + 1) != 1) return (1); /* length invalid */ card->faxchans = *(cp + 2); break; case SYSR_TOK_MAC_ADDR: /* 3 */ if (*(cp + 1) != 6) return (1); /* length invalid */ memcpy(card->mac_addr, cp + 2, 6); break; default: hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); break; } len -= (*(cp + 1) + 2); /* adjust len */ cp += (*(cp + 1) + 2); /* and pointer */ } hysdn_addlog(card, "no end token found"); return (1); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)38999.23%133.33%
Andrew Morton20.51%133.33%
Michael Hayes10.26%133.33%
Total392100.00%3100.00%

/* EvalSysrTokData */

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)174297.59%19.09%
Andrew Morton281.57%19.09%
Linus Torvalds90.50%436.36%
Adrian Bunk20.11%19.09%
Steven Cole10.06%19.09%
Roel Kluin10.06%19.09%
Michael Hayes10.06%19.09%
Burman Yan10.06%19.09%
Total1785100.00%11100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.