hysdn_boot.c 14 KB

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