hysdn_boot.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: hysdn_boot.c,v 1.1.4.1 2001/11/20 14:19:37 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. word Cryptor; /* for use with Decrypt function */
  30. word Nrecs; /* records remaining in file */
  31. uchar pof_state; /* actual state of read handler */
  32. uchar is_crypted; /* card data is crypted */
  33. int BufSize; /* actual number of bytes bufferd */
  34. int last_error; /* last occurred error */
  35. word pof_recid; /* actual pof recid */
  36. ulong pof_reclen; /* total length of pof record data */
  37. ulong pof_recoffset; /* actual offset inside pof record */
  38. union {
  39. uchar 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. 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. void
  63. DecryptBuf(struct boot_data *boot, int cnt)
  64. {
  65. uchar *bufp = boot->buf.BootBuf;
  66. while (cnt--) {
  67. boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
  68. *bufp++ ^= (uchar) boot->Cryptor;
  69. }
  70. } /* DecryptBuf */
  71. /********************************************************************************/
  72. /* pof_handle_data executes the required actions dependant 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. uchar *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 = (word) (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, uchar ** 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 = kmalloc(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. memset(boot, 0, sizeof(struct boot_data));
  249. card->stopcard(card); /* first stop the card */
  250. if (card->testram(card)) {
  251. if (card->debug_flags & LOG_POF_OPEN)
  252. hysdn_addlog(card, "POF open: DPRAM test failure");
  253. boot->last_error = -ERR_BOARD_DPRAM;
  254. card->state = CARD_STATE_BOOTERR; /* show boot error */
  255. return (boot->last_error);
  256. }
  257. boot->BufSize = 0; /* Buffer is empty */
  258. boot->pof_state = POF_READ_FILE_HEAD; /* read file header */
  259. StartDecryption(boot); /* if POF File should be encrypted */
  260. if (card->debug_flags & LOG_POF_OPEN)
  261. hysdn_addlog(card, "POF open: success");
  262. *bufp = boot->buf.BootBuf; /* point to buffer */
  263. return (sizeof(tPofFileHdr));
  264. } /* pof_write_open */
  265. /********************************************************************************/
  266. /* pof_write_close is called when an close of boot on the cardlog device occurs. */
  267. /* The return value must be 0 if everything has happened as desired.            */
  268. /********************************************************************************/
  269. int
  270. pof_write_close(hysdn_card * card)
  271. {
  272. struct boot_data *boot = card->boot; /* pointer to boot specific data */
  273. if (!boot)
  274. return (-EFAULT); /* invalid call */
  275. card->boot = NULL; /* no boot active */
  276. kfree(boot);
  277. if (card->state == CARD_STATE_RUN)
  278. card->set_errlog_state(card, 1); /* activate error log */
  279. if (card->debug_flags & LOG_POF_OPEN)
  280. hysdn_addlog(card, "POF close: success");
  281. return (0);
  282. } /* pof_write_close */
  283. /*********************************************************************************/
  284. /* EvalSysrTokData checks additional records delivered with the Sysready Message */
  285. /* when POF has been booted. A return value of 0 is used if no error occurred.    */
  286. /*********************************************************************************/
  287. int
  288. EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
  289. {
  290. u_char *p;
  291. u_char crc;
  292. if (card->debug_flags & LOG_POF_RECORD)
  293. hysdn_addlog(card, "SysReady Token data length %d", len);
  294. if (len < 2) {
  295. hysdn_addlog(card, "SysReady Token Data to short");
  296. return (1);
  297. }
  298. for (p = cp, crc = 0; p < (cp + len - 2); p++)
  299. if ((crc & 0x80))
  300. crc = (((u_char) (crc << 1)) + 1) + *p;
  301. else
  302. crc = ((u_char) (crc << 1)) + *p;
  303. crc = ~crc;
  304. if (crc != *(cp + len - 1)) {
  305. hysdn_addlog(card, "SysReady Token Data invalid CRC");
  306. return (1);
  307. }
  308. len--; /* dont check CRC byte */
  309. while (len > 0) {
  310. if (*cp == SYSR_TOK_END)
  311. return (0); /* End of Token stream */
  312. if (len < (*(cp + 1) + 2)) {
  313. hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
  314. return (1);
  315. }
  316. switch (*cp) {
  317. case SYSR_TOK_B_CHAN: /* 1 */
  318. if (*(cp + 1) != 1)
  319. return (1); /* length invalid */
  320. card->bchans = *(cp + 2);
  321. break;
  322. case SYSR_TOK_FAX_CHAN: /* 2 */
  323. if (*(cp + 1) != 1)
  324. return (1); /* length invalid */
  325. card->faxchans = *(cp + 2);
  326. break;
  327. case SYSR_TOK_MAC_ADDR: /* 3 */
  328. if (*(cp + 1) != 6)
  329. return (1); /* length invalid */
  330. memcpy(card->mac_addr, cp + 2, 6);
  331. break;
  332. default:
  333. hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
  334. break;
  335. }
  336. len -= (*(cp + 1) + 2); /* adjust len */
  337. cp += (*(cp + 1) + 2); /* and pointer */
  338. }
  339. hysdn_addlog(card, "no end token found");
  340. return (1);
  341. } /* EvalSysrTokData */