hysdn_boot.c 14 KB

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