[PATCH] [2.4] ATM SAR support, based on SARlib

Luca Barbieri (ldb@ldb.ods.org)
30 May 2002 20:12:09 +0200


--=-s7+TWHvobxmEDXilQJ2s
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

This code is a slightly version of Johan Verrept's SARlib.
It does ATM SAR (segmentation and reassembly, in other words it converts
upper layer packets to ATM cells and the opposite) in software.

diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/Documentation/networking/atmsar.txt linux/Documentation/networking/atmsar.txt
--- linux-base/Documentation/networking/atmsar.txt Thu Jan 1 01:00:00 1970
+++ linux/Documentation/networking/atmsar.txt Thu May 30 16:09:19 2002
@@ -0,0 +1,104 @@
+#
+## ATM SAR Library (C) 2000, Johan Verrept (Johan.Verrept@advalvas.be)
+#
+# 30/may/2002, Luca Barbieri <ldb@ldb.ods.org>:
+# "sarlib"/"SARlib" name replaced with "atmsar"/"ATM SAR"
+
+For updates, check the linux-atm mailing list or mail me.
+The updates will be very infrequent because I don't have much time.
+Any remarks, patches and bug fixes are welcome.
+
+WARNING: This is experimental software. Use at your own risk.
+
+License
+=======
+
+This code falls under the GNU Public License, see COPYING
+If you want to use this in a commercial product, contact me.
+
+Usage & requirements
+====================
+
+Usage: Just link this library to your driver/module/kernel.
+Requirements:
+ This needs the Linux ATM stuff, but can be easily ported to
+ any platform.
+
+API
+===
+
+The API to the ATM SAR is simple. At least, I tried to make it as simple as I
+could. I alsi tried to map it to the ATM Linux API as much as I could.
+
+There is a atmsar_open() function which will initialize the atmsar_vcc
+structure with the provided parameters. The atmsar_close() function frees
+this all.
+the atmsar_open() function is passed in a type, all the header parts, a
+pointer to the Linux ATM vcc, a pointer to a list of atmsar_vcc's and a
+flags field.
+there are 2 flags available now:
+ ATMSAR_USE_53BYTE_CELL will force atmsar_encode_rawcell() to produce
+53 byte cell in stead of the linux 52 byte cells.
+ ATMSAR_SET_PTI this will cause the pti bit of the last cell
+int the provided buffer to be set ( by atmsar_encode_rawcell())
+
+Real SARing happens in the atmsar_encode_xxx() and atmsar_decode_xxx()
+functions. Everything is straight forward for the encoding of the data,
+althought there are a few assumptions.
+
+atmsar_encode_rawcell assumes it gets a multiple of 48 bytes.
+ if ATMSAR_SET_PTI is set, it assumes a full aal5 pdu is supplied.
+ It does NOT calculate the cell header CRC at the moment.
+
+atmsar_encode_aal5 assumes it gets a full aal5 pdu.
+
+The decode functions have no assumptions. Both decode functions need to be
+repeated until they return NULL.
+
+atmsar_decode_rawcell() requires a LIST of atmsar_vcc's. This allows the user
+to pass in any cells they received, atmsar_decode_rawcell() will drop the
+ones it doesn't know, the others are copied into the relevant atmsar_vcc
+reassembly buffer. Depending on the type of reassemly (only AAL5 at the
+moment) it will return a pointer to that buffer when a complete AAL5 pdu
+has been received. The third argument will contains a pointer the relevant
+atmsar_vcc. You must repeat the call with the same arguments after
+processing the buffer, to allow atmsar_decode_rawcell() to process the
+remaining cells in the receive skb. It does NOT check the cell header crc.
+
+atmsar_decode_aal5() requires a complete AAL5 packet to process.
+This will do aal5 length and crc checking. There is some intelligence in
+there that will try to recover from an illegal length. It will take the
+length from the trailer and check whether the crc over this part is valid.
+This allows the ATM SAR to only drop 1 AAL5 pdu when the last cell of a pdu
+is lost. ( otherwise it would have to drop both...)
+
+There is also a atmsar_alloc_tx function now. It is supposed to be called
+with a atmsar_vcc structure instead of a atm_vcc, I had to do this because I
+had no way of getting to the atmsar_vcc structure from the atm_vcc
+structure... the user program will have to wrap the atmsar_vcc function.
+BE CAREFULL!! the atmsar_open function will copy the alloc_tx pointer from
+the atm_vcc and call it! You cannot set the alloc_tx function in the vcc
+BEFORE passing it to atmsar_open!! You will have to do it afterwards...
+
+To Do
+=====
+
+Lots to do.
+
+- Adding AAL1, AAL34 and maybe even AAL2 ( probably not, unless the
+ telephony thing wants it, need to look into it).
+- Add atm cell header crc calculation.
+- more optimalisations
+ - crc_calc / copy combinations.
+- completing support to run as well in userspace as in kernel space.
+ ( replacing skb's with generalised functions, define for kernel
+ space to skb functions and to ATM SAR buffer system for user space.
+- completing buffer management on receive size. introduced mru setting to
+ reduce problem. would maybe be better to go to scatter gather method.
+
+Acknowledgements
+================
+
+Thanks to :
+
+- Whoever wrote the CRC routines in linux/drivers/net/wan/sbni.c
diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/include/linux/atmsar.h linux/include/linux/atmsar.h
--- linux-base/include/linux/atmsar.h Thu Jan 1 01:00:00 1970
+++ linux/include/linux/atmsar.h Thu May 30 16:36:53 2002
@@ -0,0 +1,85 @@
+/*
+ *
+ * General SAR library for ATM devices.
+ *
+ * Copyright (c) 2000, Johan Verrept
+ *
+ * This package 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _ATMSAR_H_
+#define _ATMSAR_H_
+
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/atmdev.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/atm.h>
+
+#define ATMSAR_USE_53BYTE_CELL 0x1L
+#define ATMSAR_SET_PTI 0x2L
+
+
+/* types */
+#define ATMSAR_TYPE_AAL0 ATM_AAL0
+#define ATMSAR_TYPE_AAL1 ATM_AAL1
+#define ATMSAR_TYPE_AAL2 ATM_AAL2
+#define ATMSAR_TYPE_AAL34 ATM_AAL34
+#define ATMSAR_TYPE_AAL5 ATM_AAL5
+
+
+/* default MTU's */
+#define ATMSAR_DEF_MTU_AAL0 48
+#define ATMSAR_DEF_MTU_AAL1 47
+#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */
+#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */
+#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */
+
+typedef struct atmsar_vcc_data {
+ struct atmsar_vcc_data *next;
+
+ /* general atmsar flags, per connection */
+ int flags;
+ int type;
+
+ /* connection specific non-atmsar data */
+ struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc, unsigned int size);
+ struct atm_vcc *vcc;
+ struct k_atm_aal_stats *stats;
+ unsigned short mtu; /* max is actually 65k for AAL5... */
+
+ /* cell data */
+ unsigned int vp;
+ unsigned int vc;
+ unsigned char gfc;
+ unsigned char pti;
+ unsigned int headerFlags;
+ unsigned long atmHeader;
+
+ /* raw cell reassembly */
+ struct sk_buff *reasBuffer;
+ } atmsar_vcc_data_t;
+
+
+extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type, ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags);
+extern void atmsar_close(struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc);
+
+extern struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
+extern struct sk_buff *atmsar_encode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
+
+struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb, struct atmsar_vcc_data **ctx);
+struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
+
+struct sk_buff *atmsar_alloc_tx(struct atmsar_vcc_data *vcc, unsigned int size);
+
+#endif /* _ATMSAR_H_ */
diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/net/atm/Makefile linux/net/atm/Makefile
--- linux-base/net/atm/Makefile Thu May 30 13:09:51 2002
+++ linux/net/atm/Makefile Mon May 27 15:29:08 2002
@@ -9,12 +9,12 @@

O_TARGET := atm.o

-export-objs := common.o atm_misc.o raw.o resources.o ipcommon.o proc.o
+export-objs := common.o atm_misc.o raw.o resources.o ipcommon.o proc.o atmsar.o

list-multi := mpoa.o
mpoa-objs := mpc.o mpoa_caches.o mpoa_proc.o

-obj-$(CONFIG_ATM) := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o
+obj-$(CONFIG_ATM) := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o atmsar.o

ifeq ($(CONFIG_ATM_CLIP),y)
obj-y += clip.o
diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/net/atm/atmsar.c linux/net/atm/atmsar.c
--- linux-base/net/atm/atmsar.c Thu Jan 1 01:00:00 1970
+++ linux/net/atm/atmsar.c Thu May 30 14:01:30 2002
@@ -0,0 +1,729 @@
+/*
+ * General SAR library for ATM devices.
+ *
+ * Written By Johan Verrept ( Johan.Verrept@advalvas.be )
+ *
+ * Copyright (c) 2000, Johan Verrept
+ *
+ * This package 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 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Version 0.2.5-linuxkernel (30/may/2002, Luca Barbieri <ldb@ldb.ods.org>):
+ - shift expressions relaced with byteswap functions
+ - replaced "sarlib" with "atmsar"
+ - adaptations for inclusion in kernel tree
+
+Version 0.2.4:
+ - Fixed wrong buffer overrun check in sarlib_decode_rawcell()
+ reported by Stephen Robinson <stephen.robinson@zen.co.uk>
+ - Fixed bug when input skb did not contain a multple of 52/53 bytes.
+ (would happen when the speedtouch device resynced)
+ also reported by Stephen Robinson <stephen.robinson@zen.co.uk>
+
+Version 0.2.3:
+ - Fixed wrong allocation size. caused memory corruption in some
+ cases. Reported by Vladimir Dergachev <volodya@mindspring.com>
+ - Added some comments
+
+Version 0.2.2:
+ - Fixed CRCASM (patch from Linus Flannagan <linusf@netservices.eng.net>)
+ - Fixed problem when user did NOT use the SARLIB_USE_53BYTE_CELL flag.
+ (reported by Piers Scannell <email@lot105.com> )
+ - No more in-buffer rewriting for cloned buffers.
+ - Removed the PII specific CFLAGS in the Makefile.
+
+Version 0.2.1:
+ - removed dependancy on alloc_tx. tis presented problems when using
+ this with the br2684 code.
+
+Version 0.2:
+ - added AAL0 reassembly
+ - added alloc_tx support
+ - replaced alloc_skb in decode functions to dev_alloc_skb to allow
+ calling from interrupt
+ - fixed embarassing AAL5 bug. I was setting the pti bit in the wrong
+ byte...
+ - fixed another emabrassing bug.. picked up the wrong crc type and
+ forgot to invert the crc result...
+ - fixed AAL5 length calculations.
+ - removed automatic skb freeing from encode functions.
+ This caused problems because i did kfree_skb it, while it
+ needed to be popped. I cannot determine though whether it
+ needs to be popped or not. Figu'e it out ye'self ;-)
+ - added mru field. This is the buffersize. sarlib_decode_aal0 will
+ use when it allocates a receive buffer. A stop gap for real
+ buffer management.
+
+Version 0.1:
+ - library created.
+ - only contains AAL5, AAL0 can be easily added. ( actually, only
+ AAL0 reassembly is missing)
+*/
+
+#include <linux/module.h>
+#include <linux/atmsar.h>
+
+static const char printk_header[] = "ATM SAR: ";
+
+#ifndef __KERNEL__
+
+/* user space functions */
+#define atomic_add(i,v) *(v) += i
+#define atomic_inc(v) *(v) ++
+
+#define Malloc(size) malloc(size)
+
+#else
+/* kernel functions */
+
+#define Malloc(size) dev_alloc_skb(size)
+#endif
+
+#define CRCASM 1
+
+/***********************
+ **
+ ** things to remember
+ **
+ ***********************/
+
+/*
+ 1. the atmsar_vcc_data list pointer MUST be initialized to NULL
+ 2. atmsar_encode_rawcell will drop incomplete cells.
+ 3. ownership of the skb goes to the library !
+*/
+
+#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
+
+/***********************
+ **
+ ** LOCAL STRUCTURES
+ **
+ ***********************/
+
+/***********************
+ **
+ ** LOCAL MACROS
+ **
+ ***********************/
+
+#define ADD_HEADER(dest, header) *(*(u32**)&dest)++ = cpu_to_be32(header)
+
+/*
+ * CRC Routines from net/wan/sbni.c)
+ * table generated by Rocksoft^tm Model CRC Algorithm Table Generation Program V1.0
+ */
+#define CRC32_REMAINDER CBF43926
+#define CRC32_INITIAL 0xffffffff
+#define CRC32(c,crc) (crc32tab[((size_t)(crc>>24) ^ (c)) & 0xff] ^ (((crc) << 8)))
+unsigned long crc32tab[256] = {
+ 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
+ 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
+ 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
+ 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
+ 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
+ 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
+ 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
+ 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
+ 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
+ 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
+ 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
+ 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
+ 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
+ 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
+ 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
+ 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
+ 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
+ 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
+ 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
+ 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
+ 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
+ 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
+ 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
+ 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
+ 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
+ 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
+ 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
+ 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
+ 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
+ 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
+ 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
+ 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
+ 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
+ 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
+ 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
+ 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
+ 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
+ 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
+ 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
+ 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
+ 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
+ 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
+ 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
+ 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
+ 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
+ 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
+ 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
+ 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
+ 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
+ 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
+ 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
+ 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
+ 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
+ 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
+ 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
+ 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
+ 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
+ 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
+ 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
+ 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
+ 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
+ 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
+ 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
+ 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
+};
+
+#ifdef CRCASM
+
+#if defined(__i386__)
+unsigned long
+calc_crc(char *mem, int len, unsigned initial)
+{
+ unsigned crc, dummy_len;
+ __asm__("xorl %%eax,%%eax\n\t" "1:\n\t" "movl %%edx,%%eax\n\t" "shrl $16,%%eax\n\t" "lodsb\n\t" "xorb %%ah,%%al\n\t" "andl $255,%%eax\n\t" "shll $8,%%edx\n\t" "xorl (%%edi,%%eax,4),%%edx\n\t" "loop 1b":"=d"(crc),
+ "=c"
+ (dummy_len)
+ : "S"(mem), "D"(&crc32tab[0]), "1"(len), "0"(initial)
+ : "eax");
+ return crc;
+}
+#else
+#undef CRCASM
+#endif
+
+#endif
+
+#ifndef CRCASM
+unsigned long
+calc_crc(char *mem, int len, unsigned initial)
+{
+ unsigned crc;
+ crc = initial;
+
+ for (; len; mem++, len--) {
+ crc = CRC32(*mem, crc);
+ }
+ return (crc);
+}
+#endif
+
+#define crc32( crc, mem, len) calc_crc(mem, len, crc);
+
+/* ATOMIC version of alloc_tx */
+struct sk_buff *
+atmsar_alloc_skb_wrapper(struct atm_vcc *vcc, unsigned int size)
+{
+ struct sk_buff *skb;
+
+ if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc, size)) {
+ printk_dbg("sorry: tx_inuse = %d, size = %d, sndbuf = %d",
+ atomic_read(&vcc->tx_inuse), size, vcc->sk->sndbuf);
+ return NULL;
+ }
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+ atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
+ return skb;
+}
+
+struct sk_buff *
+atmsar_alloc_tx(struct atmsar_vcc_data *vcc, unsigned int size)
+{
+ struct sk_buff *tmp = NULL;
+ int bufsize = 0;
+
+ switch (vcc->type) {
+ case ATMSAR_TYPE_AAL0:
+ /* reserving adequate headroom */
+ bufsize =
+ size +
+ (((size / 48) +
+ 1) * ((vcc->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
+ break;
+ case ATMSAR_TYPE_AAL1:
+ /* reserving adequate headroom */
+ bufsize =
+ size +
+ (((size / 47) +
+ 1) * ((vcc->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
+ break;
+ case ATMSAR_TYPE_AAL2:
+ case ATMSAR_TYPE_AAL34:
+ /* not supported */
+ break;
+ case ATMSAR_TYPE_AAL5:
+ /* reserving adequate tailroom */
+ bufsize = size + (((size + 8 + 47) / 48) * 48);
+ break;
+ }
+
+ printk_dbg("requested size %d, allocating size %d", size, bufsize);
+ tmp = vcc->alloc_tx(vcc->vcc, bufsize);
+ skb_put(tmp, bufsize);
+
+ return tmp;
+}
+
+struct atmsar_vcc_data *
+atmsar_open(struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
+ ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
+{
+ struct atmsar_vcc_data *new;
+
+ new = kmalloc(sizeof (struct atmsar_vcc_data), GFP_KERNEL);
+
+ if (!new)
+ return NULL;
+
+ if (!vcc)
+ return NULL;
+
+ memset(new, 0, sizeof (struct atmsar_vcc_data));
+ new->vcc = vcc;
+/*
+ * This gives problems with the ATM layer alloc_tx().
+ * It is not usable from interrupt context and for
+ * some reason this is used in interurpt context
+ * with br2684.c
+ *
+ if (vcc->alloc_tx)
+ new->alloc_tx = vcc->alloc_tx;
+ else
+*/
+ new->alloc_tx = atmsar_alloc_skb_wrapper;
+
+ new->stats = vcc->stats;
+ new->type = type;
+ new->next = NULL;
+ new->gfc = gfc;
+ new->vp = vpi;
+ new->vc = vci;
+ new->pti = pti;
+
+ switch (type) {
+ case ATMSAR_TYPE_AAL0:
+ new->mtu = ATMSAR_DEF_MTU_AAL0;
+ break;
+ case ATMSAR_TYPE_AAL1:
+ new->mtu = ATMSAR_DEF_MTU_AAL1;
+ break;
+ case ATMSAR_TYPE_AAL2:
+ new->mtu = ATMSAR_DEF_MTU_AAL2;
+ break;
+ case ATMSAR_TYPE_AAL34:
+ /* not supported */
+ new->mtu = ATMSAR_DEF_MTU_AAL34;
+ break;
+ case ATMSAR_TYPE_AAL5:
+ new->mtu = ATMSAR_DEF_MTU_AAL5;
+ break;
+ }
+
+ new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
+ | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
+ | ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
+ | ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
+ new->flags = flags;
+ new->next = NULL;
+ new->reasBuffer = NULL;
+
+ new->next = *list;
+ *list = new;
+
+ printk_dbg("allocated new atmsar vcc 0x%p with vp %d vc %d", new, vpi,
+ vci);
+
+ return new;
+}
+
+void
+atmsar_close(struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
+{
+ struct atmsar_vcc_data *work;
+
+ if (*list == vcc) {
+ *list = (*list)->next;
+ } else {
+ for (work = *list; work && work->next && (work->next != vcc);
+ work = work->next) ;
+
+ /* return if not found */
+ if (work->next != vcc)
+ return;
+
+ work->next = work->next->next;
+ }
+
+ if (vcc->reasBuffer) {
+ dev_kfree_skb(vcc->reasBuffer);
+ }
+
+ printk_dbg("allocated atmsar vcc 0x%p with vp %d vc %d", vcc, vcc->vp,
+ vcc->vc);
+
+ kfree(vcc);
+}
+
+/***********************
+ **
+ ** ENCODE FUNCTIONS
+ **
+ ***********************/
+
+struct sk_buff *
+atmsar_encode_rawcell(struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+ int number_of_cells = (skb->len) / 48;
+ int total_length =
+ number_of_cells * (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52);
+ unsigned char *source;
+ unsigned char *target;
+ struct sk_buff *out = NULL;
+ int i;
+
+ printk_dbg("called (0x%p, 0x%p)", ctx, skb);
+
+ if (skb_cloned(skb)
+ || (skb_headroom(skb) <
+ (number_of_cells *
+ (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4)))) {
+ printk_dbg
+ ("allocating new skb: ctx->alloc_tx = 0x%p, ctx->vcc = 0x%p",
+ ctx->alloc_tx, ctx->vcc);
+ /* get new skb */
+ out = ctx->alloc_tx(ctx->vcc, total_length);
+ if (!out)
+ return NULL;
+
+ skb_put(out, total_length);
+ source = skb->data;
+ target = out->data;
+ } else {
+ printk_dbg("sufficient headroom");
+ source = skb->data;
+ skb_push(skb,
+ number_of_cells *
+ ((ctx->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
+ target = skb->data;
+ out = skb;
+ }
+
+ printk_dbg("source 0x=%p, target 0x%p", source, target);
+
+ if (ctx->flags & ATMSAR_USE_53BYTE_CELL) {
+ for (i = 0; i < number_of_cells; i++) {
+ ADD_HEADER(target, ctx->atmHeader);
+ *target++ = (char) 0xEC;
+ memcpy(target, source, 48);
+ target += 48;
+ source += 48;
+ printk_dbg("source 0x=%p, target 0x%p", source,
+ target);
+ }
+ } else {
+ for (i = 0; i < number_of_cells; i++) {
+ ADD_HEADER(target, ctx->atmHeader);
+ memcpy(target, source, 48);
+ target += 48;
+ source += 48;
+ printk_dbg("source 0x=%p, target 0x%p", source,
+ target);
+ };
+ }
+
+ if (ctx->flags & ATMSAR_SET_PTI) {
+ /* setting pti bit in last cell */
+ *(target - (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 50 : 49)) |=
+ 0x2;
+ }
+
+ /* update stats */
+ if (ctx->stats && (ctx->type <= ATMSAR_TYPE_AAL1))
+ atomic_add(number_of_cells, &(ctx->stats->tx));
+
+ printk_dbg("return 0x%p (length %d)", out, out->len);
+ return out;
+}
+
+struct sk_buff *
+atmsar_encode_aal5(struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+ int length, pdu_length;
+ unsigned char *trailer;
+ unsigned char *pad;
+ uint crc = 0xffffffff;
+
+ printk_dbg("(0x%p, 0x%p) called", ctx, skb);
+
+ /* determine aal5 length */
+ pdu_length = skb->len;
+ length = ((pdu_length + 8 + 47) / 48) * 48;
+
+ if (skb_tailroom(skb) < (length - pdu_length)) {
+ struct sk_buff *out;
+ printk_dbg
+ ("allocating new skb: ctx->alloc_tx = 0x%p, ctx->vcc = 0x%p",
+ ctx->alloc_tx, ctx->vcc);
+ /* get new skb */
+ out = ctx->alloc_tx(ctx->vcc, length);
+ if (!out)
+ return NULL;
+
+ printk_dbg("out->data = 0x%p", out->data);
+ printk_dbg("pdu length %d, allocated length %d", skb->len,
+ length);
+ memcpy(out->data, skb->data, skb->len);
+ skb_put(out, skb->len);
+
+ skb = out;
+ }
+
+ printk_dbg("skb->data = 0x%p", skb->data);
+ /* note end of pdu and add length */
+ pad = skb_put(skb, length - pdu_length);
+ trailer = skb->tail - 8;
+
+ printk_dbg("trailer = 0x%p", trailer);
+
+ /* zero padding space */
+ memset(pad, 0, length - pdu_length - 8);
+
+ /* add trailer */
+ *trailer++ = (unsigned char) 0; /* UU = 0 */
+ *trailer++ = (unsigned char) 0; /* CPI = 0 */
+ *(*(u16 **) & trailer)++ = cpu_to_be16(pdu_length);
+ crc = ~crc32(crc, skb->data, length - 4);
+ *(*(u32 **) & trailer)++ = cpu_to_be32(crc);
+
+ /* update stats */
+ if (ctx->stats)
+ atomic_inc(&ctx->stats->tx);
+
+ printk_dbg("return 0x%p (length %d)", skb, skb->len);
+ return skb;
+}
+
+/***********************
+ **
+ ** DECODE FUNCTIONS
+ **
+ ***********************/
+
+struct sk_buff *
+atmsar_decode_rawcell(struct atmsar_vcc_data *list, struct sk_buff *skb,
+ struct atmsar_vcc_data **ctx)
+{
+ while (skb->len) {
+ unsigned char *cell = skb->data;
+ unsigned char *cell_payload;
+ struct atmsar_vcc_data *vcc = list;
+ unsigned long atmHeader = be32_to_cpu(*(u32 *) cell);
+
+ printk_dbg("called (0x%p, 0x%p, 0x%p)", list, skb, ctx);
+ printk_dbg("skb->data %p, skb->tail %p", skb->data, skb->tail);
+
+ if (!list || !skb || !ctx)
+ return NULL;
+ if (!skb->data || !skb->tail)
+ return NULL;
+
+ /* here should the header CRC check be... */
+
+ /* look up correct vcc */
+ for (;
+ vcc
+ && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) !=
+ (atmHeader & ATM_HDR_VPVC_MASK)); vcc = vcc->next) ;
+
+ printk_dbg("found vcc %p for packet on vp %d, vc %d", vcc,
+ (int) ((atmHeader & ATM_HDR_VPI_MASK) >>
+ ATM_HDR_VPI_SHIFT),
+ (int) ((atmHeader & ATM_HDR_VCI_MASK) >>
+ ATM_HDR_VCI_SHIFT));
+
+ if (vcc
+ && (skb->len >=
+ (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
+ cell_payload =
+ cell +
+ (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
+
+ switch (vcc->type) {
+ case ATMSAR_TYPE_AAL0:
+ /* case ATMSAR_TYPE_AAL1: when we have a decode AAL1 function... */
+ {
+ struct sk_buff *tmp = Malloc(vcc->mtu);
+
+ if (tmp) {
+ memcpy(tmp->tail, cell_payload,
+ 48);
+ skb_put(tmp, 48);
+
+ if (vcc->stats)
+ atomic_inc(&vcc->stats->
+ rx);
+
+ skb_pull(skb,
+ (vcc->
+ flags &
+ ATMSAR_USE_53BYTE_CELL
+ ? 53 : 52));
+ printk_dbg
+ ("returns ATMSAR_TYPE_AAL0 pdu 0x%p with length %d",
+ tmp, tmp->len);
+ return tmp;
+ };
+ }
+ break;
+ case ATMSAR_TYPE_AAL1:
+ case ATMSAR_TYPE_AAL2:
+ case ATMSAR_TYPE_AAL34:
+ /* not supported */
+ break;
+ case ATMSAR_TYPE_AAL5:
+ if (!vcc->reasBuffer)
+ vcc->reasBuffer = Malloc(vcc->mtu);
+
+ /* if alloc fails, we just drop the cell. it is possible that we can still
+ * receive cells on other vcc's
+ */
+ if (vcc->reasBuffer) {
+ /* if (buffer overrun) discard received cells until now */
+ if ((vcc->reasBuffer->len) >
+ (vcc->mtu - 48))
+ skb_trim(vcc->reasBuffer, 0);
+
+ /* copy data */
+ memcpy(vcc->reasBuffer->tail,
+ cell_payload, 48);
+ skb_put(vcc->reasBuffer, 48);
+
+ /* check for end of buffer */
+ if (cell[3] & 0x2) {
+ struct sk_buff *tmp;
+
+ /* the aal5 buffer ends here, cut the buffer. */
+ /* buffer will always have at least one whole cell, so */
+ /* don't need to check return from skb_pull */
+ skb_pull(skb,
+ (vcc->
+ flags &
+ ATMSAR_USE_53BYTE_CELL
+ ? 53 : 52));
+ *ctx = vcc;
+ tmp = vcc->reasBuffer;
+ vcc->reasBuffer = NULL;
+
+ printk_dbg
+ ("returns ATMSAR_TYPE_AAL5 pdu 0x%p with length %d",
+ tmp, tmp->len);
+ return tmp;
+ }
+ }
+ break;
+ };
+ /* flush the cell */
+ /* buffer will always contain at least one whole cell, so don't */
+ /* need to check return value from skb_pull */
+ skb_pull(skb,
+ (vcc->
+ flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
+ } else {
+ /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
+ if (skb_pull
+ (skb,
+ (list->
+ flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
+ NULL) {
+ skb_trim(skb, 0);
+ }
+ }
+ }
+
+ return NULL;
+};
+
+struct sk_buff *
+atmsar_decode_aal5(struct atmsar_vcc_data *ctx, struct sk_buff *skb)
+{
+ uint crc = 0xffffffff;
+ uint length, pdu_crc, pdu_length;
+
+ printk_dbg("atmsar_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
+
+ if (skb->len && (skb->len % 48))
+ return NULL;
+
+ length = be16_to_cpu(*(u16 *) (skb->tail - 6));
+ pdu_crc = be32_to_cpu(*(u32 *) (skb->tail - 4));
+ pdu_length = ((length + 47 + 8) / 48) * 48;
+
+ printk_dbg
+ ("skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d",
+ skb->len, length, pdu_crc, pdu_length);
+
+ /* is skb long enough ? */
+ if (skb->len < pdu_length) {
+ if (ctx->stats)
+ atomic_inc(&ctx->stats->rx_err);
+ return NULL;
+ }
+
+ /* is skb too long ? */
+ if (skb->len > pdu_length) {
+ printk_dbg("warning: readjusting illegal size %d -> %d",
+ skb->len, pdu_length);
+ /* buffer is too long. we can try to recover
+ * if we discard the first part of the skb.
+ * the crc will decide whether this was ok
+ */
+ skb_pull(skb, skb->len - pdu_length);
+ }
+
+ crc = ~crc32(crc, skb->data, pdu_length - 4);
+
+ /* check crc */
+ if (pdu_crc != crc) {
+ printk_dbg("crc check failed!");
+
+ if (ctx->stats)
+ atomic_inc(&ctx->stats->rx_err);
+ return NULL;
+ }
+
+ /* pdu is ok */
+ skb_trim(skb, length);
+
+ /* update stats */
+ if (ctx->stats)
+ atomic_inc(&ctx->stats->rx);
+
+ printk_dbg("atmsar_decode_aal5 returns pdu 0x%p with length %d", skb,
+ skb->len);
+ return skb;
+};
+
+EXPORT_SYMBOL(atmsar_open);
+EXPORT_SYMBOL(atmsar_close);
+EXPORT_SYMBOL(atmsar_encode_rawcell);
+EXPORT_SYMBOL(atmsar_encode_aal5);
+EXPORT_SYMBOL(atmsar_decode_rawcell);
+EXPORT_SYMBOL(atmsar_decode_aal5);
+EXPORT_SYMBOL(atmsar_alloc_tx);

--=-s7+TWHvobxmEDXilQJ2s
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQA89mt5djkty3ft5+cRAs0gAJ4ryXme8xRhrHClGz3CS8DD50oyKgCaAz+b
cUcgbaKxWTSR8EohTpJLpoM=
=OyHI
-----END PGP SIGNATURE-----

--=-s7+TWHvobxmEDXilQJ2s--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/