patch-2.4.6 linux/drivers/isdn/tpam/tpam_nco.c
Next file: linux/drivers/isdn/tpam/tpam_queues.c
Previous file: linux/drivers/isdn/tpam/tpam_memory.c
Back to the patch index
Back to the overall index
- Lines: 663
- Date:
Mon Jul 2 14:07:55 2001
- Orig file:
v2.4.5/linux/drivers/isdn/tpam/tpam_nco.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/tpam/tpam_nco.c linux/drivers/isdn/tpam/tpam_nco.c
@@ -0,0 +1,662 @@
+/* $Id: tpam_nco.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - Low Level NCO Manipulation)
+ *
+ * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * For all support questions please contact: <support@auvertech.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include "tpam.h"
+
+/* Local function prototypes */
+static struct sk_buff *build_NCOpacket(u16, u16, u16, u16, u16);
+static int extract_NCOParameter(struct sk_buff *, u8, void *, u16);
+
+/*
+ * Build a NCO packet (PCI message).
+ *
+ * messageID: the message type (ID_*)
+ * size: size of the TLV block
+ * data_size: size of the data block
+ * ack: packet needs to send ack upon send
+ * ack_size: size of data to be acknowledged upon send
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+static struct sk_buff *build_NCOpacket(u16 messageID, u16 size,
+ u16 data_size, u16 ack,
+ u16 ack_size) {
+ struct sk_buff *skb;
+ skb_header *h;
+ pci_mpb *p;
+ u16 finalsize;
+
+ /* reserve enough space for the sk_buff header, the pci * header,
+ * size bytes for the TLV block, size bytes for the data and 4 more
+ * bytes in order to make sure we can write dwords to the board. */
+ finalsize = sizeof(skb_header) + sizeof(pci_mpb) + size + data_size + 4;
+
+ /* allocate the sk_buff */
+ if (!(skb = alloc_skb(finalsize, GFP_ATOMIC))) {
+ printk(KERN_ERR "TurboPAM(make_NCOpacket): alloc_skb failed\n");
+ return NULL;
+ }
+
+ /* construct the skb_header */
+ h = (skb_header *)skb_put(skb, sizeof(skb_header));
+ h->size = sizeof(pci_mpb) + size;
+ h->data_size = data_size;
+ h->ack = ack;
+ h->ack_size = ack_size;
+
+ /* construct the pci_mpb */
+ p = (pci_mpb *)skb_put(skb, sizeof(pci_mpb));
+ p->exID = 0;
+ p->flags = 0;
+ p->errorCode = 0;
+ p->messageID = messageID;
+ p->maximumBlockTLVSize = MPB_MAXIMUMBLOCKTLVSIZE;
+ p->actualBlockTLVSize = size;
+ p->maximumDataSize = MPB_MAXIMUMDATASIZE;
+ p->actualDataSize = data_size;
+ return skb;
+}
+
+/*
+ * Build a ACreateNCOReq message.
+ *
+ * phone: the local phone number.
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_ACreateNCOReq(const u8 *phone) {
+ struct sk_buff *skb;
+ u8 *tlv;
+
+ dprintk("TurboPAM(build_ACreateNCOReq): phone=%s\n", phone);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_ACreateNCOReq, 23 + strlen(phone), 0, 0, 0)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 3);
+ *tlv = PAR_NCOType;
+ *(tlv+1) = 1;
+ *(tlv+2) = 5; /* mistery value... */
+
+ tlv = (u8 *)skb_put(skb, 4);
+ *tlv = PAR_U3Protocol;
+ *(tlv+1) = 2;
+ *(tlv+2) = 4; /* no level 3 protocol */
+ *(tlv+3) = 1; /* HDLC in level 2 */
+
+ tlv = (u8 *)skb_put(skb, 3);
+ *tlv = PAR_Cdirection;
+ *(tlv+1) = 1;
+ *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
+
+ tlv = (u8 *)skb_put(skb, 3);
+ *tlv = PAR_Udirection;
+ *(tlv+1) = 1;
+ *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
+
+ tlv = (u8 *)skb_put(skb, 4);
+ *tlv = PAR_BearerCap;
+ *(tlv+1) = 2;
+ *(tlv+2) = 0x88;
+ *(tlv+3) = 0x90;
+
+ tlv = (u8 *)skb_put(skb, 6 + strlen(phone));
+ *tlv = PAR_CallingNumber;
+ *(tlv+1) = strlen(phone) + 4;
+ *(tlv+2) = 0x01; /* international */
+ *(tlv+3) = 0x01; /* isdn */
+ *(tlv+4) = 0x00;
+ *(tlv+5) = 0x00;
+ memcpy(tlv + 6, phone, strlen(phone));
+
+ return skb;
+}
+
+/*
+ * Build a ADestroyNCOReq message.
+ *
+ * ncoid: the NCO id.
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_ADestroyNCOReq(u32 ncoid) {
+ struct sk_buff *skb;
+ u8 *tlv;
+
+ dprintk("TurboPAM(build_ADestroyNCOReq): ncoid=%lu\n",
+ (unsigned long)ncoid);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_ADestroyNCOReq, 6, 0, 0, 0)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 6);
+ *tlv = PAR_NCOID;
+ *(tlv+1) = 4;
+ *((u32 *)(tlv+2)) = ncoid;
+
+ return skb;
+}
+
+/*
+ * Build a CConnectReq message.
+ *
+ * ncoid: the NCO id.
+ * called: the destination phone number
+ * hdlc: type of connection: 1 (HDLC) or 0(modem)
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_CConnectReq(u32 ncoid, const u8 *called, u8 hdlc) {
+ struct sk_buff *skb;
+ u8 *tlv;
+
+ dprintk("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%d\n",
+ (unsigned long)ncoid, called, hdlc);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_CConnectReq, 20 + strlen(called), 0, 0, 0)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 6);
+ *tlv = PAR_NCOID;
+ *(tlv+1) = 4;
+ *((u32 *)(tlv+2)) = ncoid;
+
+ tlv = (u8 *)skb_put(skb, 4 + strlen(called));
+ *tlv = PAR_CalledNumber;
+ *(tlv+1) = strlen(called) + 2;
+ *(tlv+2) = 0x01; /* international */
+ *(tlv+3) = 0x01; /* isdn */
+ memcpy(tlv + 4, called, strlen(called));
+
+ tlv = (u8 *)skb_put(skb, 3);
+ *tlv = PAR_BearerCap;
+ *(tlv+1) = 1;
+ *(tlv+2) = hdlc ? 0x88 /* HDLC */ : 0x80 /* MODEM */;
+
+ tlv = (u8 *)skb_put(skb, 4);
+ *tlv = PAR_HLC;
+ *(tlv+1) = 2;
+ *(tlv+2) = 0x2;
+ *(tlv+3) = 0x7f;
+
+ tlv = (u8 *)skb_put(skb, 3);
+ *tlv = PAR_Facility;
+ *(tlv+1) = 1;
+ *(tlv+2) = 2;
+
+ return skb;
+}
+
+/*
+ * Build a CConnectRsp message.
+ *
+ * ncoid: the NCO id.
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_CConnectRsp(u32 ncoid) {
+ struct sk_buff *skb;
+ u8 *tlv;
+
+ dprintk("TurboPAM(build_CConnectRsp): ncoid=%lu\n",
+ (unsigned long)ncoid);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_CConnectRsp, 6, 0, 0, 0)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 6);
+ *tlv = PAR_NCOID;
+ *(tlv+1) = 4;
+ *((u32 *)(tlv+2)) = ncoid;
+
+ return skb;
+}
+
+/*
+ * Build a CDisconnectReq message.
+ *
+ * ncoid: the NCO id.
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_CDisconnectReq(u32 ncoid) {
+ struct sk_buff *skb;
+ u8 *tlv;
+
+ dprintk("TurboPAM(build_CDisconnectReq): ncoid=%lu\n",
+ (unsigned long)ncoid);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_CDisconnectReq, 6, 0, 0, 0)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 6);
+ *tlv = PAR_NCOID;
+ *(tlv+1) = 4;
+ *((u32 *)(tlv+2)) = ncoid;
+
+ return skb;
+}
+
+/*
+ * Build a CDisconnectRsp message.
+ *
+ * ncoid: the NCO id.
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_CDisconnectRsp(u32 ncoid) {
+ struct sk_buff *skb;
+ u8 *tlv;
+
+ dprintk("TurboPAM(build_CDisconnectRsp): ncoid=%lu\n",
+ (unsigned long)ncoid);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_CDisconnectRsp, 6, 0, 0, 0)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 6);
+ *tlv = PAR_NCOID;
+ *(tlv+1) = 4;
+ *((u32 *)(tlv+2)) = ncoid;
+
+ return skb;
+}
+
+/*
+ * Build a U3DataReq message.
+ *
+ * ncoid: the NCO id.
+ * data: the data to be send
+ * len: length of the data
+ * ack: send ack upon send
+ * ack_size: size of data to be acknowledged upon send
+ *
+ * Return: the sk_buff filled with the NCO packet, or NULL if error.
+ */
+struct sk_buff *build_U3DataReq(u32 ncoid, void *data, u16 len,
+ u16 ack, u16 ack_size) {
+ struct sk_buff *skb;
+ u8 *tlv;
+ void *p;
+
+ dprintk("TurboPAM(build_U3DataReq): "
+ "ncoid=%lu, len=%d, ack=%d, ack_size=%d\n",
+ (unsigned long)ncoid, len, ack, ack_size);
+
+ /* build the NCO packet */
+ if (!(skb = build_NCOpacket(ID_U3DataReq, 6, len, ack, ack_size)))
+ return NULL;
+
+ /* add the parameters */
+ tlv = (u8 *)skb_put(skb, 6);
+ *tlv = PAR_NCOID;
+ *(tlv+1) = 4;
+ *((u32 *)(tlv+2)) = ncoid;
+
+ p = skb_put(skb, len);
+ memcpy(p, data, len);
+
+ return skb;
+}
+
+/*
+ * Extract a parameter from a TLV block.
+ *
+ * skb: sk_buff containing the PCI message
+ * type: parameter to search for (PARAM_*)
+ * value: to be filled with the value of the parameter
+ * len: maximum length of the parameter value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+static int extract_NCOParameter(struct sk_buff *skb, u8 type,
+ void *value, u16 len) {
+ void *buffer = (void *)skb->data;
+ pci_mpb *p;
+ void * bufferend;
+ u8 valtype;
+ u16 vallen;
+
+ /* calculate the start and end of the TLV block */
+ buffer += sizeof(skb_header);
+ p = (pci_mpb *)buffer;
+ buffer += sizeof(pci_mpb);
+ bufferend = buffer + p->actualBlockTLVSize;
+
+ /* walk through the parameters */
+ while (buffer < bufferend) {
+
+ /* parameter type */
+ valtype = *((u8 *)buffer++);
+ /* parameter length */
+ vallen = *((u8 *)buffer++);
+ if (vallen == 0xff) {
+ /* parameter length is on 2 bytes */
+ vallen = *((u8 *)buffer++);
+ vallen <<= 8;
+ vallen |= *((u8 *)buffer++);
+ }
+ /* got the right parameter */
+ if (valtype == type) {
+ /* not enough space for returning the value */
+ if (vallen > len)
+ return -1;
+ /* OK, return it */
+ memcpy(value, buffer, vallen);
+ return 0;
+ }
+ buffer += vallen;
+ }
+ return -1;
+}
+
+/*
+ * Parse a ACreateNCOCnf message.
+ *
+ * skb: the sk_buff containing the message
+ * status: to be filled with the status field value
+ * ncoid: to be filled with the ncoid field value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
+
+ /* extract the status */
+ if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
+ printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
+ "CompletionStatus not found\n");
+ return -1;
+ }
+
+ if (*status) {
+ dprintk("TurboPAM(parse_ACreateNCOCnf): status=%d\n", *status);
+ return 0;
+ }
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
+ "NCOID not found\n");
+ return -1;
+ }
+
+ dprintk("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%d\n",
+ (unsigned long)*ncoid, *status);
+ return 0;
+}
+
+/*
+ * Parse a ADestroyNCOCnf message. Not used in the driver.
+ *
+ * skb: the sk_buff containing the message
+ * status: to be filled with the status field value
+ * ncoid: to be filled with the ncoid field value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
+
+ /* extract the status */
+ if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
+ printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
+ "CompletionStatus not found\n");
+ return -1;
+ }
+
+ if (*status) {
+ dprintk("TurboPAM(parse_ADestroyNCOCnf): status=%d\n", *status);
+ return 0;
+ }
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
+ "NCOID not found\n");
+ return -1;
+ }
+
+ dprintk("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%d\n",
+ (unsigned long)*ncoid, *status);
+ return 0;
+}
+
+/*
+ * Parse a CConnectCnf message.
+ *
+ * skb: the sk_buff containing the message
+ * ncoid: to be filled with the ncoid field value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_CConnectCnf(struct sk_buff *skb, u32 *ncoid) {
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CConnectCnf): "
+ "NCOID not found\n");
+ return -1;
+ }
+ dprintk("TurboPAM(parse_CConnectCnf): ncoid=%lu\n",
+ (unsigned long)*ncoid);
+ return 0;
+}
+
+/*
+ * Parse a CConnectInd message.
+ *
+ * skb: the sk_buff containing the message
+ * ncoid: to be filled with the ncoid field value
+ * hdlc: to be filled with 1 if the incoming connection is a HDLC one,
+ * with 0 if the incoming connection is a modem one
+ * calling: to be filled with the calling phone number value
+ * called: to be filled with the called phone number value
+ * plan: to be filled with the plan value
+ * screen: to be filled with the screen value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_CConnectInd(struct sk_buff *skb, u32 *ncoid, u8 *hdlc,
+ u8 *calling, u8 *called, u8 *plan, u8 *screen) {
+ u8 phone[PHONE_MAXIMUMSIZE + 4];
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
+ "NCOID not found\n");
+ return -1;
+ }
+
+ /* extract the bearer capability field */
+ if (extract_NCOParameter(skb, PAR_BearerCap, hdlc, 1)) {
+ printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
+ "BearerCap not found\n");
+ return -1;
+ }
+ *hdlc = (*hdlc == 0x88) ? 1 : 0;
+
+ /* extract the calling number / plan / screen */
+ if (extract_NCOParameter(skb, PAR_CallingNumber, phone,
+ PHONE_MAXIMUMSIZE + 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
+ "CallingNumber not found\n");
+ return -1;
+ }
+ memcpy(calling, phone + 4, PHONE_MAXIMUMSIZE);
+ *plan = phone[1];
+ *screen = phone[3];
+
+ /* extract the called number */
+ if (extract_NCOParameter(skb, PAR_CalledNumber, phone,
+ PHONE_MAXIMUMSIZE + 2)) {
+ printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
+ "CalledNumber not found\n");
+ return -1;
+ }
+ memcpy(called, phone + 2, PHONE_MAXIMUMSIZE);
+
+ dprintk("TurboPAM(parse_CConnectInd): "
+ "ncoid=%lu, hdlc=%d, plan=%d, scr=%d, calling=%s, called=%s\n",
+ (unsigned long)*ncoid, *hdlc, *plan, *screen, calling, called);
+ return 0;
+}
+
+/*
+ * Parse a CDisconnectCnf message.
+ *
+ * skb: the sk_buff containing the message
+ * ncoid: to be filled with the ncoid field value
+ * causetopuf: to be filled with the cause field value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_CDisconnectCnf(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
+ "NCOID not found\n");
+ return -1;
+ }
+
+ /* extract the cause of disconnection */
+ if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
+ "CauseToPUF not found\n");
+ return -1;
+ }
+
+ dprintk("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lu\n",
+ (unsigned long)*ncoid, (unsigned long)*causetopuf);
+ return 0;
+}
+
+/*
+ * Parse a CDisconnectInd message.
+ *
+ * skb: the sk_buff containing the message
+ * ncoid: to be filled with the ncoid field value
+ * causetopuf: to be filled with the cause field value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_CDisconnectInd(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
+ "NCOID not found\n");
+ return -1;
+ }
+
+ /* extract the cause of disconnection */
+ if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
+ "CauseToPUF not found\n");
+ return -1;
+ }
+
+ dprintk("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lu\n",
+ (unsigned long)*ncoid, (unsigned long)*causetopuf);
+ return 0;
+}
+
+/*
+ * Parse a U3ReadyToReceiveInd message.
+ *
+ * skb: the sk_buff containing the message
+ * ncoid: to be filled with the ncoid field value
+ * ready: to be filled with the ready field value
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_U3ReadyToReceiveInd(struct sk_buff *skb, u32 *ncoid, u8 *ready) {
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
+ printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
+ "NCOID not found\n");
+ return -1;
+ }
+
+ /* extract the ready flag */
+ if (extract_NCOParameter(skb, PAR_ReadyFlag, ready, 1)) {
+ printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
+ "ReadyFlag not found\n");
+ return -1;
+ }
+
+ dprintk("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%d\n",
+ (unsigned long)*ncoid, *ready);
+ return 0;
+}
+
+/*
+ * Parse a U3DataInd message.
+ *
+ * skb: the sk_buff containing the message + data
+ * ncoid: to be filled with the ncoid field value
+ * data: to be filled with the data
+ * ready: to be filled with the data length
+ *
+ * Return: 0 if OK, <0 if error.
+ */
+int parse_U3DataInd(struct sk_buff *skb, u32 *ncoid, u8 **data, u16 *len) {
+ pci_mpb *p;
+
+ /* extract the ncoid */
+ if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4) == -1) {
+ printk(KERN_ERR "TurboPAM(parse_U3DataInd): NCOID not found\n");
+ return -1;
+ }
+
+ /* get a pointer to the beginning of the data block and its length */
+ p = (pci_mpb *)(skb->data + sizeof(skb_header));
+ *len = p->actualDataSize;
+ skb_pull(skb,
+ sizeof(skb_header) + sizeof(pci_mpb) + p->actualBlockTLVSize);
+ *data = skb->data;
+
+ dprintk("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%d\n",
+ (unsigned long)*ncoid, *len);
+ return 0;
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)