Messages in this thread Patch in this message | | | Subject | [PATCH] [2.4] ATM SAR support, based on SARlib | From | Luca Barbieri <> | Date | 30 May 2002 20:12:09 +0200 |
| |
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);[unhandled content-type:application/pgp-signature] | |