tpam_nco.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: tpam_nco.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  2.  *
  3.  * Turbo PAM ISDN driver for Linux. 
  4.  * (Kernel Driver - Low Level NCO Manipulation)
  5.  *
  6.  * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alc魐e
  7.  *
  8.  * This software may be used and distributed according to the terms
  9.  * of the GNU General Public License, incorporated herein by reference.
  10.  *
  11.  * For all support questions please contact: <support@auvertech.fr>
  12.  *
  13.  */
  14. #include <linux/pci.h>
  15. #include <linux/sched.h>
  16. #include <linux/tqueue.h>
  17. #include <linux/interrupt.h>
  18. #include <asm/io.h>
  19. #include "tpam.h"
  20. /* Local function prototypes */
  21. static struct sk_buff *build_NCOpacket(u16, u16, u16, u16, u16);
  22. static int extract_NCOParameter(struct sk_buff *, u8, void *, u16);
  23. /*
  24.  * Build a NCO packet (PCI message).
  25.  *
  26.  *  messageID: the message type (ID_*)
  27.  *  size: size of the TLV block
  28.  *  data_size: size of the data block
  29.  *  ack: packet needs to send ack upon send
  30.  *  ack_size: size of data to be acknowledged upon send
  31.  *
  32.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  33.  */
  34. static struct sk_buff *build_NCOpacket(u16 messageID, u16 size, 
  35.        u16 data_size, u16 ack, 
  36.        u16 ack_size) {
  37. struct sk_buff *skb;
  38. skb_header *h;
  39. pci_mpb *p;
  40. u16 finalsize;
  41. /* reserve enough space for the sk_buff header, the pci * header, 
  42.  * size bytes for the TLV block, size bytes for the data and 4 more
  43.  * bytes in order to make sure we can write dwords to the board. */
  44. finalsize = sizeof(skb_header) + sizeof(pci_mpb) + size + data_size + 4;
  45. /* allocate the sk_buff */
  46. if (!(skb = alloc_skb(finalsize, GFP_ATOMIC))) {
  47. printk(KERN_ERR "TurboPAM(make_NCOpacket): alloc_skb failedn");
  48. return NULL;
  49. }
  50. /* construct the skb_header */
  51. h = (skb_header *)skb_put(skb, sizeof(skb_header));
  52. h->size = sizeof(pci_mpb) + size;
  53. h->data_size = data_size;
  54. h->ack = ack;
  55. h->ack_size = ack_size;
  56. /* construct the pci_mpb */
  57. p = (pci_mpb *)skb_put(skb, sizeof(pci_mpb));
  58. p->exID = 0;
  59. p->flags = 0;
  60. p->errorCode = 0;
  61. p->messageID = messageID;
  62. p->maximumBlockTLVSize = MPB_MAXIMUMBLOCKTLVSIZE;
  63. p->actualBlockTLVSize = size;
  64. p->maximumDataSize = MPB_MAXIMUMDATASIZE;
  65. p->actualDataSize = data_size;
  66. return skb;
  67. }
  68. /*
  69.  * Build a ACreateNCOReq message.
  70.  *
  71.  *  phone: the local phone number.
  72.  *
  73.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  74.  */
  75. struct sk_buff *build_ACreateNCOReq(const u8 *phone) {
  76. struct sk_buff *skb;
  77. u8 *tlv;
  78. dprintk("TurboPAM(build_ACreateNCOReq): phone=%sn", phone);
  79. /* build the NCO packet */
  80. if (!(skb = build_NCOpacket(ID_ACreateNCOReq, 23 + strlen(phone), 0, 0, 0))) 
  81. return NULL;
  82. /* add the parameters */
  83. tlv = (u8 *)skb_put(skb, 3);
  84. *tlv = PAR_NCOType; 
  85. *(tlv+1) = 1;
  86. *(tlv+2) = 5; /* mistery value... */
  87. tlv = (u8 *)skb_put(skb, 4);
  88. *tlv = PAR_U3Protocol;
  89. *(tlv+1) = 2;
  90. *(tlv+2) = 4; /* no level 3 protocol */
  91. *(tlv+3) = 1; /* HDLC in level 2 */
  92. tlv = (u8 *)skb_put(skb, 3);
  93. *tlv = PAR_Cdirection;
  94. *(tlv+1) = 1;
  95. *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
  96. tlv = (u8 *)skb_put(skb, 3);
  97. *tlv = PAR_Udirection;
  98. *(tlv+1) = 1;
  99. *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
  100. tlv = (u8 *)skb_put(skb, 4);
  101. *tlv = PAR_BearerCap;
  102. *(tlv+1) = 2;
  103. *(tlv+2) = 0x88;
  104. *(tlv+3) = 0x90;
  105. tlv = (u8 *)skb_put(skb, 6 + strlen(phone));
  106. *tlv = PAR_CallingNumber;
  107. *(tlv+1) = strlen(phone) + 4;
  108. *(tlv+2) = 0x01; /* international */
  109. *(tlv+3) = 0x01; /* isdn */
  110. *(tlv+4) = 0x00;
  111. *(tlv+5) = 0x00;
  112. memcpy(tlv + 6, phone, strlen(phone));
  113. return skb;
  114. }
  115. /*
  116.  * Build a ADestroyNCOReq message.
  117.  *
  118.  *  ncoid: the NCO id.
  119.  *
  120.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  121.  */
  122. struct sk_buff *build_ADestroyNCOReq(u32 ncoid) {
  123. struct sk_buff *skb;
  124. u8 *tlv;
  125. dprintk("TurboPAM(build_ADestroyNCOReq): ncoid=%lun", 
  126. (unsigned long)ncoid);
  127. /* build the NCO packet */
  128. if (!(skb = build_NCOpacket(ID_ADestroyNCOReq, 6, 0, 0, 0)))
  129. return NULL;
  130. /* add the parameters */
  131. tlv = (u8 *)skb_put(skb, 6);
  132. *tlv = PAR_NCOID;
  133. *(tlv+1) = 4;
  134. *((u32 *)(tlv+2)) = ncoid;
  135. return skb;
  136. }
  137. /*
  138.  * Build a CConnectReq message.
  139.  *
  140.  *  ncoid: the NCO id.
  141.  *  called: the destination phone number
  142.  *  hdlc: type of connection: 1 (HDLC) or 0(modem)
  143.  *
  144.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  145.  */
  146. struct sk_buff *build_CConnectReq(u32 ncoid, const u8 *called, u8 hdlc) {
  147. struct sk_buff *skb;
  148. u8 *tlv;
  149. dprintk("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%dn",
  150. (unsigned long)ncoid, called, hdlc);
  151. /* build the NCO packet */
  152. if (!(skb = build_NCOpacket(ID_CConnectReq, 20 + strlen(called), 0, 0, 0)))
  153. return NULL;
  154. /* add the parameters */
  155. tlv = (u8 *)skb_put(skb, 6);
  156. *tlv = PAR_NCOID;
  157. *(tlv+1) = 4;
  158. *((u32 *)(tlv+2)) = ncoid;
  159. tlv = (u8 *)skb_put(skb, 4 + strlen(called));
  160. *tlv = PAR_CalledNumber;
  161. *(tlv+1) = strlen(called) + 2;
  162. *(tlv+2) = 0x01; /* international */
  163. *(tlv+3) = 0x01; /* isdn */
  164. memcpy(tlv + 4, called, strlen(called));
  165. tlv = (u8 *)skb_put(skb, 3);
  166. *tlv = PAR_BearerCap;
  167. *(tlv+1) = 1;
  168. *(tlv+2) = hdlc ? 0x88 /* HDLC */ : 0x80 /* MODEM */;
  169. tlv = (u8 *)skb_put(skb, 4);
  170. *tlv = PAR_HLC;
  171. *(tlv+1) = 2;
  172. *(tlv+2) = 0x2;
  173. *(tlv+3) = 0x7f;
  174. tlv = (u8 *)skb_put(skb, 3);
  175. *tlv = PAR_Facility;
  176. *(tlv+1) = 1;
  177. *(tlv+2) = 2;
  178. return skb;
  179. }
  180. /*
  181.  * Build a CConnectRsp message.
  182.  *
  183.  *  ncoid: the NCO id.
  184.  *
  185.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  186.  */
  187. struct sk_buff *build_CConnectRsp(u32 ncoid) {
  188. struct sk_buff *skb;
  189. u8 *tlv;
  190. dprintk("TurboPAM(build_CConnectRsp): ncoid=%lun",
  191. (unsigned long)ncoid);
  192. /* build the NCO packet */
  193. if (!(skb = build_NCOpacket(ID_CConnectRsp, 6, 0, 0, 0)))
  194. return NULL;
  195. /* add the parameters */
  196. tlv = (u8 *)skb_put(skb, 6);
  197. *tlv = PAR_NCOID;
  198. *(tlv+1) = 4;
  199. *((u32 *)(tlv+2)) = ncoid;
  200. return skb;
  201. }
  202. /*
  203.  * Build a CDisconnectReq message.
  204.  *
  205.  *  ncoid: the NCO id.
  206.  *
  207.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  208.  */
  209. struct sk_buff *build_CDisconnectReq(u32 ncoid) {
  210. struct sk_buff *skb;
  211. u8 *tlv;
  212. dprintk("TurboPAM(build_CDisconnectReq): ncoid=%lun",
  213. (unsigned long)ncoid);
  214. /* build the NCO packet */
  215. if (!(skb = build_NCOpacket(ID_CDisconnectReq, 6, 0, 0, 0)))
  216. return NULL;
  217. /* add the parameters */
  218. tlv = (u8 *)skb_put(skb, 6);
  219. *tlv = PAR_NCOID;
  220. *(tlv+1) = 4;
  221. *((u32 *)(tlv+2)) = ncoid;
  222. return skb;
  223. }
  224. /*
  225.  * Build a CDisconnectRsp message.
  226.  *
  227.  *  ncoid: the NCO id.
  228.  *
  229.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  230.  */
  231. struct sk_buff *build_CDisconnectRsp(u32 ncoid) {
  232. struct sk_buff *skb;
  233. u8 *tlv;
  234. dprintk("TurboPAM(build_CDisconnectRsp): ncoid=%lun",
  235. (unsigned long)ncoid);
  236. /* build the NCO packet */
  237. if (!(skb = build_NCOpacket(ID_CDisconnectRsp, 6, 0, 0, 0)))
  238. return NULL;
  239. /* add the parameters */
  240. tlv = (u8 *)skb_put(skb, 6);
  241. *tlv = PAR_NCOID;
  242. *(tlv+1) = 4;
  243. *((u32 *)(tlv+2)) = ncoid;
  244. return skb;
  245. }
  246. /*
  247.  * Build a U3DataReq message.
  248.  *
  249.  *  ncoid: the NCO id.
  250.  *  data: the data to be send
  251.  *  len: length of the data
  252.  *  ack: send ack upon send
  253.  *  ack_size: size of data to be acknowledged upon send
  254.  *
  255.  * Return: the sk_buff filled with the NCO packet, or NULL if error.
  256.  */
  257. struct sk_buff *build_U3DataReq(u32 ncoid, void *data, u16 len,
  258. u16 ack, u16 ack_size) {
  259. struct sk_buff *skb;
  260. u8 *tlv;
  261. void *p;
  262. dprintk("TurboPAM(build_U3DataReq): "
  263. "ncoid=%lu, len=%d, ack=%d, ack_size=%dn", 
  264. (unsigned long)ncoid, len, ack, ack_size);
  265. /* build the NCO packet */
  266. if (!(skb = build_NCOpacket(ID_U3DataReq, 6, len, ack, ack_size)))
  267. return NULL;
  268. /* add the parameters */
  269. tlv = (u8 *)skb_put(skb, 6);
  270. *tlv = PAR_NCOID;
  271. *(tlv+1) = 4;
  272. *((u32 *)(tlv+2)) = ncoid;
  273. p = skb_put(skb, len);
  274. memcpy(p, data, len);
  275. return skb;
  276. }
  277. /*
  278.  * Extract a parameter from a TLV block.
  279.  *
  280.  *  skb: sk_buff containing the PCI message
  281.  *  type: parameter to search for (PARAM_*)
  282.  *  value: to be filled with the value of the parameter
  283.  *  len: maximum length of the parameter value
  284.  *
  285.  * Return: 0 if OK, <0 if error.
  286.  */
  287. static int extract_NCOParameter(struct sk_buff *skb, u8 type, 
  288. void *value, u16 len) {
  289. void *buffer = (void *)skb->data;
  290. pci_mpb *p;
  291. void * bufferend;
  292. u8 valtype;
  293. u16 vallen;
  294. /* calculate the start and end of the TLV block */
  295. buffer += sizeof(skb_header);
  296. p = (pci_mpb *)buffer;
  297. buffer += sizeof(pci_mpb);
  298. bufferend = buffer + p->actualBlockTLVSize;
  299. /* walk through the parameters */
  300. while (buffer < bufferend) {
  301. /* parameter type */
  302. valtype = *((u8 *)buffer++);
  303. /* parameter length */
  304. vallen = *((u8 *)buffer++);
  305. if (vallen == 0xff) {
  306. /* parameter length is on 2 bytes */
  307. vallen = *((u8 *)buffer++);
  308. vallen <<= 8;
  309. vallen |= *((u8 *)buffer++);
  310. }
  311. /* got the right parameter */
  312. if (valtype == type) {
  313. /* not enough space for returning the value */
  314. if (vallen > len)
  315. return -1;
  316. /* OK, return it */
  317. memcpy(value, buffer, vallen);
  318. return 0;
  319. }
  320. buffer += vallen;
  321. }
  322. return -1;
  323. }
  324. /*
  325.  * Parse a ACreateNCOCnf message.
  326.  *
  327.  *  skb: the sk_buff containing the message
  328.  *  status: to be filled with the status field value
  329.  *  ncoid: to be filled with the ncoid field value
  330.  *
  331.  * Return: 0 if OK, <0 if error.
  332.  */
  333. int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
  334. /* extract the status */
  335. if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
  336. printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
  337.        "CompletionStatus not foundn");
  338. return -1;
  339. }
  340. if (*status) {
  341. dprintk("TurboPAM(parse_ACreateNCOCnf): status=%dn", *status);
  342. return 0;
  343. }
  344. /* extract the ncoid */
  345. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  346. printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
  347.        "NCOID not foundn");
  348. return -1;
  349. }
  350. dprintk("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%dn",
  351. (unsigned long)*ncoid, *status);
  352. return 0;
  353. }
  354. /*
  355.  * Parse a ADestroyNCOCnf message. Not used in the driver.
  356.  *
  357.  *  skb: the sk_buff containing the message
  358.  *  status: to be filled with the status field value
  359.  *  ncoid: to be filled with the ncoid field value
  360.  *
  361.  * Return: 0 if OK, <0 if error.
  362.  */
  363. int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
  364. /* extract the status */
  365. if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
  366. printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
  367.        "CompletionStatus not foundn");
  368. return -1;
  369. }
  370. if (*status) {
  371. dprintk("TurboPAM(parse_ADestroyNCOCnf): status=%dn", *status);
  372. return 0;
  373. }
  374. /* extract the ncoid */
  375. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  376. printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
  377.        "NCOID not foundn");
  378. return -1;
  379. }
  380. dprintk("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%dn", 
  381. (unsigned long)*ncoid, *status);
  382. return 0;
  383. }
  384. /*
  385.  * Parse a CConnectCnf message.
  386.  *
  387.  *  skb: the sk_buff containing the message
  388.  *  ncoid: to be filled with the ncoid field value
  389.  *
  390.  * Return: 0 if OK, <0 if error.
  391.  */
  392. int parse_CConnectCnf(struct sk_buff *skb, u32 *ncoid) {
  393. /* extract the ncoid */
  394. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  395. printk(KERN_ERR "TurboPAM(parse_CConnectCnf): "
  396.        "NCOID not foundn");
  397. return -1;
  398. }
  399. dprintk("TurboPAM(parse_CConnectCnf): ncoid=%lun", 
  400. (unsigned long)*ncoid);
  401. return 0;
  402. }
  403. /*
  404.  * Parse a CConnectInd message.
  405.  *
  406.  *  skb: the sk_buff containing the message
  407.  *  ncoid: to be filled with the ncoid field value
  408.  *  hdlc: to be filled with 1 if the incoming connection is a HDLC one,
  409.  *  with 0 if the incoming connection is a modem one
  410.  *  calling: to be filled with the calling phone number value
  411.  *  called: to be filled with the called phone number value
  412.  *  plan: to be filled with the plan value
  413.  *  screen: to be filled with the screen value
  414.  *
  415.  * Return: 0 if OK, <0 if error.
  416.  */
  417. int parse_CConnectInd(struct sk_buff *skb, u32 *ncoid, u8 *hdlc, 
  418.       u8 *calling, u8 *called, u8 *plan, u8 *screen) {
  419. u8 phone[PHONE_MAXIMUMSIZE + 4];
  420. /* extract the ncoid */
  421. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  422. printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
  423.        "NCOID not foundn");
  424. return -1;
  425. }
  426. /* extract the bearer capability field */
  427. if (extract_NCOParameter(skb, PAR_BearerCap, hdlc, 1)) {
  428. printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
  429.        "BearerCap not foundn");
  430. return -1;
  431. }
  432. *hdlc = (*hdlc == 0x88) ? 1 : 0;
  433. /* extract the calling number / plan / screen */
  434. if (extract_NCOParameter(skb, PAR_CallingNumber, phone, 
  435.  PHONE_MAXIMUMSIZE + 4)) {
  436. printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
  437.        "CallingNumber not foundn");
  438. return -1;
  439. }
  440. memcpy(calling, phone + 4, PHONE_MAXIMUMSIZE);
  441. *plan = phone[1];
  442. *screen = phone[3];
  443. /* extract the called number */
  444. if (extract_NCOParameter(skb, PAR_CalledNumber, phone, 
  445.  PHONE_MAXIMUMSIZE + 2)) {
  446. printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
  447.        "CalledNumber not foundn");
  448. return -1;
  449. }
  450. memcpy(called, phone + 2, PHONE_MAXIMUMSIZE);
  451. dprintk("TurboPAM(parse_CConnectInd): "
  452. "ncoid=%lu, hdlc=%d, plan=%d, scr=%d, calling=%s, called=%sn",
  453. (unsigned long)*ncoid, *hdlc, *plan, *screen, calling, called);
  454. return 0;
  455. }
  456. /*
  457.  * Parse a CDisconnectCnf message.
  458.  *
  459.  *  skb: the sk_buff containing the message
  460.  *  ncoid: to be filled with the ncoid field value
  461.  *  causetopuf: to be filled with the cause field value
  462.  *
  463.  * Return: 0 if OK, <0 if error.
  464.  */
  465. int parse_CDisconnectCnf(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
  466. /* extract the ncoid */
  467. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  468. printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
  469.        "NCOID not foundn");
  470. return -1;
  471. }
  472. /* extract the cause of disconnection */
  473. if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
  474. printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
  475.        "CauseToPUF not foundn");
  476. return -1;
  477. }
  478. dprintk("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lun", 
  479. (unsigned long)*ncoid, (unsigned long)*causetopuf);
  480. return 0;
  481. }
  482. /*
  483.  * Parse a CDisconnectInd message.
  484.  *
  485.  *  skb: the sk_buff containing the message
  486.  *  ncoid: to be filled with the ncoid field value
  487.  *  causetopuf: to be filled with the cause field value
  488.  *
  489.  * Return: 0 if OK, <0 if error.
  490.  */
  491. int parse_CDisconnectInd(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
  492. /* extract the ncoid */
  493. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  494. printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
  495.        "NCOID not foundn");
  496. return -1;
  497. }
  498. /* extract the cause of disconnection */
  499. if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
  500. printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
  501.        "CauseToPUF not foundn");
  502. return -1;
  503. }
  504. dprintk("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lun", 
  505. (unsigned long)*ncoid, (unsigned long)*causetopuf);
  506. return 0;
  507. }
  508. /*
  509.  * Parse a U3ReadyToReceiveInd message.
  510.  *
  511.  *  skb: the sk_buff containing the message
  512.  *  ncoid: to be filled with the ncoid field value
  513.  *  ready: to be filled with the ready field value
  514.  *
  515.  * Return: 0 if OK, <0 if error.
  516.  */
  517. int parse_U3ReadyToReceiveInd(struct sk_buff *skb, u32 *ncoid, u8 *ready) {
  518. /* extract the ncoid */
  519. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
  520. printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
  521.        "NCOID not foundn");
  522. return -1;
  523. }
  524. /* extract the ready flag */
  525. if (extract_NCOParameter(skb, PAR_ReadyFlag, ready, 1)) {
  526. printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
  527.        "ReadyFlag not foundn");
  528. return -1;
  529. }
  530. dprintk("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%dn", 
  531. (unsigned long)*ncoid, *ready);
  532. return 0;
  533. }
  534. /*
  535.  * Parse a U3DataInd message.
  536.  *
  537.  *  skb: the sk_buff containing the message + data
  538.  *  ncoid: to be filled with the ncoid field value
  539.  *  data: to be filled with the data 
  540.  *  ready: to be filled with the data length
  541.  *
  542.  * Return: 0 if OK, <0 if error.
  543.  */
  544. int parse_U3DataInd(struct sk_buff *skb, u32 *ncoid, u8 **data, u16 *len) {
  545. pci_mpb *p;
  546. /* extract the ncoid */
  547. if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4) == -1) {
  548. printk(KERN_ERR "TurboPAM(parse_U3DataInd): NCOID not foundn");
  549. return -1;
  550. }
  551. /* get a pointer to the beginning of the data block and its length */
  552. p = (pci_mpb *)(skb->data + sizeof(skb_header));
  553. *len = p->actualDataSize;
  554. skb_pull(skb, 
  555.  sizeof(skb_header) + sizeof(pci_mpb) + p->actualBlockTLVSize);
  556. *data = skb->data;
  557. dprintk("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%dn", 
  558. (unsigned long)*ncoid, *len);
  559. return 0;
  560. }