root/drivers/staging/isdn/hysdn/hysdn_boot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. StartDecryption
  2. DecryptBuf
  3. pof_handle_data
  4. pof_write_buffer
  5. pof_write_open
  6. pof_write_close
  7. EvalSysrTokData

   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 <linux/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 {
  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 */
  37         int BufSize;            /* actual number of bytes bufferd */
  38         int last_error;         /* last occurred error */
  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 */
  42         union {
  43                 unsigned char BootBuf[BOOT_BUF_SIZE];/* buffer as byte count */
  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 /*****************************************************/
  56 static void
  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 /***************************************************************/
  69 static void
  70 DecryptBuf(struct boot_data *boot, int cnt)
  71 {
  72         unsigned char *bufp = boot->buf.BootBuf;
  73 
  74         while (cnt--) {
  75                 boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
  76                 *bufp++ ^= (unsigned char)boot->Cryptor;
  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;
  89         unsigned char *imgp;
  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                 /* fall through */
 103         case TAG_BOOTDTA:
 104                 if (card->debug_flags & LOG_POF_RECORD)
 105                         hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
 106                                      (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
 107                                      datlen, boot->pof_recoffset);
 108 
 109                 if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
 110                         boot->last_error = EPOF_BAD_IMG_SIZE;   /* invalid length */
 111                         return (boot->last_error);
 112                 }
 113                 imgp = boot->buf.BootBuf;       /* start of buffer */
 114                 img_len = datlen;       /* maximum length to transfer */
 115 
 116                 l = POF_BOOT_LOADER_OFF_IN_PAGE -
 117                         (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
 118                 if (l > 0) {
 119                         /* buffer needs to be truncated */
 120                         imgp += l;      /* advance pointer */
 121                         img_len -= l;   /* adjust len */
 122                 }
 123                 /* at this point no special handling for data wrapping over buffer */
 124                 /* is necessary, because the boot image always will be adjusted to */
 125                 /* match a page boundary inside the buffer.                        */
 126                 /* The buffer for the boot image on the card is filled in 2 cycles */
 127                 /* first the 1024 hi-words are put in the buffer, then the low 1024 */
 128                 /* word are handled in the same way with different offset.         */
 129 
 130                 if (img_len > 0) {
 131                         /* data available for copy */
 132                         if ((boot->last_error =
 133                              card->writebootimg(card, imgp,
 134                                                 (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
 135                                 return (boot->last_error);
 136                 }
 137                 break;  /* end of case boot image hi/lo */
 138 
 139         case TAG_CABSDATA:
 140                 DecryptBuf(boot, datlen);       /* we need to encrypt the buffer */
 141                 /* fall through */
 142         case TAG_ABSDATA:
 143                 if (card->debug_flags & LOG_POF_RECORD)
 144                         hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
 145                                      (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
 146                                      datlen, boot->pof_recoffset);
 147 
 148                 if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0)
 149                         return (boot->last_error);      /* error writing data */
 150 
 151                 if (boot->pof_recoffset + datlen >= boot->pof_reclen)
 152                         return (card->waitpofready(card));      /* data completely spooled, wait for ready */
 153 
 154                 break;  /* end of case boot seq data */
 155 
 156         default:
 157                 if (card->debug_flags & LOG_POF_RECORD)
 158                         hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
 159                                      datlen, boot->pof_recoffset);
 160 
 161                 break;  /* simply skip record */
 162         }                       /* switch boot->pof_recid */
 163 
 164         return (0);
 165 }                               /* pof_handle_data */
 166 
 167 
 168 /******************************************************************************/
 169 /* pof_write_buffer is called when the buffer has been filled with the needed */
 170 /* number of data bytes. The number delivered is additionally supplied for    */
 171 /* verification. The functions handles the data and returns the needed number */
 172 /* of bytes for the next action. If the returned value is 0 or less an error  */
 173 /* occurred and booting must be aborted.                                       */
 174 /******************************************************************************/
 175 int
 176 pof_write_buffer(hysdn_card *card, int datlen)
 177 {
 178         struct boot_data *boot = card->boot;    /* pointer to boot specific data */
 179 
 180         if (!boot)
 181                 return (-EFAULT);       /* invalid call */
 182         if (boot->last_error < 0)
 183                 return (boot->last_error);      /* repeated error */
 184 
 185         if (card->debug_flags & LOG_POF_WRITE)
 186                 hysdn_addlog(card, "POF write: got %d bytes ", datlen);
 187 
 188         switch (boot->pof_state) {
 189         case POF_READ_FILE_HEAD:
 190                 if (card->debug_flags & LOG_POF_WRITE)
 191                         hysdn_addlog(card, "POF write: checking file header");
 192 
 193                 if (datlen != sizeof(tPofFileHdr)) {
 194                         boot->last_error = -EPOF_INTERNAL;
 195                         break;
 196                 }
 197                 if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
 198                         boot->last_error = -EPOF_BAD_MAGIC;
 199                         break;
 200                 }
 201                 /* Setup the new state and vars */
 202                 boot->Nrecs = (unsigned short)(boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
 203                 boot->pof_state = POF_READ_TAG_HEAD;    /* now start with single tags */
 204                 boot->last_error = sizeof(tPofRecHdr);  /* new length */
 205                 break;
 206 
 207         case POF_READ_TAG_HEAD:
 208                 if (card->debug_flags & LOG_POF_WRITE)
 209                         hysdn_addlog(card, "POF write: checking tag header");
 210 
 211                 if (datlen != sizeof(tPofRecHdr)) {
 212                         boot->last_error = -EPOF_INTERNAL;
 213                         break;
 214                 }
 215                 boot->pof_recid = boot->buf.PofRecHdr.PofRecId;         /* actual pof recid */
 216                 boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen;   /* total length */
 217                 boot->pof_recoffset = 0;        /* no starting offset */
 218 
 219                 if (card->debug_flags & LOG_POF_RECORD)
 220                         hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
 221                                      boot->pof_recid, boot->pof_reclen);
 222 
 223                 boot->pof_state = POF_READ_TAG_DATA;    /* now start with tag data */
 224                 if (boot->pof_reclen < BOOT_BUF_SIZE)
 225                         boot->last_error = boot->pof_reclen;    /* limit size */
 226                 else
 227                         boot->last_error = BOOT_BUF_SIZE;       /* maximum */
 228 
 229                 if (!boot->last_error) {        /* no data inside record */
 230                         boot->pof_state = POF_READ_TAG_HEAD;    /* now start with single tags */
 231                         boot->last_error = sizeof(tPofRecHdr);  /* new length */
 232                 }
 233                 break;
 234 
 235         case POF_READ_TAG_DATA:
 236                 if (card->debug_flags & LOG_POF_WRITE)
 237                         hysdn_addlog(card, "POF write: getting tag data");
 238 
 239                 if (datlen != boot->last_error) {
 240                         boot->last_error = -EPOF_INTERNAL;
 241                         break;
 242                 }
 243                 if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
 244                         return (boot->last_error);      /* an error occurred */
 245                 boot->pof_recoffset += datlen;
 246                 if (boot->pof_recoffset >= boot->pof_reclen) {
 247                         boot->pof_state = POF_READ_TAG_HEAD;    /* now start with single tags */
 248                         boot->last_error = sizeof(tPofRecHdr);  /* new length */
 249                 } else {
 250                         if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
 251                                 boot->last_error = boot->pof_reclen - boot->pof_recoffset;      /* limit size */
 252                         else
 253                                 boot->last_error = BOOT_BUF_SIZE;       /* maximum */
 254                 }
 255                 break;
 256 
 257         default:
 258                 boot->last_error = -EPOF_INTERNAL;      /* unknown state */
 259                 break;
 260         }                       /* switch (boot->pof_state) */
 261 
 262         return (boot->last_error);
 263 }                               /* pof_write_buffer */
 264 
 265 
 266 /*******************************************************************************/
 267 /* pof_write_open is called when an open for boot on the cardlog device occurs. */
 268 /* The function returns the needed number of bytes for the next operation. If  */
 269 /* the returned number is less or equal 0 an error specified by this code      */
 270 /* occurred. Additionally the pointer to the buffer data area is set on success */
 271 /*******************************************************************************/
 272 int
 273 pof_write_open(hysdn_card *card, unsigned char **bufp)
 274 {
 275         struct boot_data *boot; /* pointer to boot specific data */
 276 
 277         if (card->boot) {
 278                 if (card->debug_flags & LOG_POF_OPEN)
 279                         hysdn_addlog(card, "POF open: already opened for boot");
 280                 return (-ERR_ALREADY_BOOT);     /* boot already active */
 281         }
 282         /* error no mem available */
 283         if (!(boot = kzalloc(sizeof(struct boot_data), GFP_KERNEL))) {
 284                 if (card->debug_flags & LOG_MEM_ERR)
 285                         hysdn_addlog(card, "POF open: unable to allocate mem");
 286                 return (-EFAULT);
 287         }
 288         card->boot = boot;
 289         card->state = CARD_STATE_BOOTING;
 290 
 291         card->stopcard(card);   /* first stop the card */
 292         if (card->testram(card)) {
 293                 if (card->debug_flags & LOG_POF_OPEN)
 294                         hysdn_addlog(card, "POF open: DPRAM test failure");
 295                 boot->last_error = -ERR_BOARD_DPRAM;
 296                 card->state = CARD_STATE_BOOTERR;       /* show boot error */
 297                 return (boot->last_error);
 298         }
 299         boot->BufSize = 0;      /* Buffer is empty */
 300         boot->pof_state = POF_READ_FILE_HEAD;   /* read file header */
 301         StartDecryption(boot);  /* if POF File should be encrypted */
 302 
 303         if (card->debug_flags & LOG_POF_OPEN)
 304                 hysdn_addlog(card, "POF open: success");
 305 
 306         *bufp = boot->buf.BootBuf;      /* point to buffer */
 307         return (sizeof(tPofFileHdr));
 308 }                               /* pof_write_open */
 309 
 310 /********************************************************************************/
 311 /* pof_write_close is called when an close of boot on the cardlog device occurs. */
 312 /* The return value must be 0 if everything has happened as desired.            */
 313 /********************************************************************************/
 314 int
 315 pof_write_close(hysdn_card *card)
 316 {
 317         struct boot_data *boot = card->boot;    /* pointer to boot specific data */
 318 
 319         if (!boot)
 320                 return (-EFAULT);       /* invalid call */
 321 
 322         card->boot = NULL;      /* no boot active */
 323         kfree(boot);
 324 
 325         if (card->state == CARD_STATE_RUN)
 326                 card->set_errlog_state(card, 1);        /* activate error log */
 327 
 328         if (card->debug_flags & LOG_POF_OPEN)
 329                 hysdn_addlog(card, "POF close: success");
 330 
 331         return (0);
 332 }                               /* pof_write_close */
 333 
 334 /*********************************************************************************/
 335 /* EvalSysrTokData checks additional records delivered with the Sysready Message */
 336 /* when POF has been booted. A return value of 0 is used if no error occurred.    */
 337 /*********************************************************************************/
 338 int
 339 EvalSysrTokData(hysdn_card *card, unsigned char *cp, int len)
 340 {
 341         u_char *p;
 342         u_char crc;
 343 
 344         if (card->debug_flags & LOG_POF_RECORD)
 345                 hysdn_addlog(card, "SysReady Token data length %d", len);
 346 
 347         if (len < 2) {
 348                 hysdn_addlog(card, "SysReady Token Data to short");
 349                 return (1);
 350         }
 351         for (p = cp, crc = 0; p < (cp + len - 2); p++)
 352                 if ((crc & 0x80))
 353                         crc = (((u_char) (crc << 1)) + 1) + *p;
 354                 else
 355                         crc = ((u_char) (crc << 1)) + *p;
 356         crc = ~crc;
 357         if (crc != *(cp + len - 1)) {
 358                 hysdn_addlog(card, "SysReady Token Data invalid CRC");
 359                 return (1);
 360         }
 361         len--;                  /* don't check CRC byte */
 362         while (len > 0) {
 363 
 364                 if (*cp == SYSR_TOK_END)
 365                         return (0);     /* End of Token stream */
 366 
 367                 if (len < (*(cp + 1) + 2)) {
 368                         hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
 369                         return (1);
 370                 }
 371                 switch (*cp) {
 372                 case SYSR_TOK_B_CHAN:   /* 1 */
 373                         if (*(cp + 1) != 1)
 374                                 return (1);     /* length invalid */
 375                         card->bchans = *(cp + 2);
 376                         break;
 377 
 378                 case SYSR_TOK_FAX_CHAN: /* 2 */
 379                         if (*(cp + 1) != 1)
 380                                 return (1);     /* length invalid */
 381                         card->faxchans = *(cp + 2);
 382                         break;
 383 
 384                 case SYSR_TOK_MAC_ADDR: /* 3 */
 385                         if (*(cp + 1) != 6)
 386                                 return (1);     /* length invalid */
 387                         memcpy(card->mac_addr, cp + 2, 6);
 388                         break;
 389 
 390                 default:
 391                         hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
 392                         break;
 393                 }
 394                 len -= (*(cp + 1) + 2);         /* adjust len */
 395                 cp += (*(cp + 1) + 2);  /* and pointer */
 396         }
 397 
 398         hysdn_addlog(card, "no end token found");
 399         return (1);
 400 }                               /* EvalSysrTokData */

/* [<][>][^][v][top][bottom][index][help] */