All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v3 0/8] CAIF Protocol Stack
@ 2009-11-30 15:00 sjur.brandeland
  2009-11-30 15:00 ` [RFC PATCH v3 1/8] " sjur.brandeland
                   ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

This is the third RFC on the CAIF patch set. CAIF is the primary protocol
used to communicate between to ST-Ericsson modems and the external host system.

Feedback on the patch set is welcomed!

This time I have reworked the architecture a bit.
The Link Layers in CAIF are now proper NET Devices of type ETH_P_CAIF,
and Character Devices are replaced by CAIF Sockets.

This patch set is compiled on x86 for 2.6.32.

Issues:
* Line Discipline implementation is working on 2.6.28,
  but not on 2.6.32.
* A few known stability issues when running high load over TTY.
* Different physical layers types (e.g. SPI) are currently identified in
  the "CAIF Protocol layer". CAIF Protocol layer should be ignorant
  of the kind of physical connection. This will be fixed later on.
* Too many log statements scattered throughout the code.
* Checks on LINUX_VERSION not yet removed.
* Global defines such as PF_CAIF, AF_CAIF, SOL_CAIF, N_CAIF, ETH_P_CAIF
  are defined locally as well. This duplication will be fixed  later on.
* CAIF Socket interface not all sockopt are implemented.
* RTNL configuration of CAIF is not yet tested.



Change Log:

General:
* Sockets has replaced the character device implementation,
  when accessing the modem. AT channels has to open sockets.
* CAIF Link layer is now implemented as net-devices.
* Cleanup of asserts no using caif_assert everywhere.
* Style cleanups, spacing, typedefs etc.

Documentation/CAIF
* Removed tool chardevconfig for configuration.
  Instead  CAIF NET device can be configured with RTNL or socket IOCTL.
* Removed replaced user space tool ldiscd to configure TTY.
  TTY is now opened from kernel when loading caif_serial.ko
* Added caif socket MAN page to Documentation (Will be moved later on).
* Added example on CAIF NET device configuration.
* Removed reference to  Doc No: 155 19-CRH 109 913.

include/linux
* Added caif_socket.h defining CAIF Socket interface.
* Added if_caif.h define CAIF IP Net Device configuration

include/net
* Added caif_dev.h defining interface between driver and caif-core.

include/net/generic
* Updated assert statement
* Removed typedefs

net/caif
* Added socket implementation and removed character device.
* General removed typedefs and fixed CHECKPATCH warnings
* Minor change on error handling in cfcnfg.c
* chnl_net.c Added RTNL support and IOCTL
* Fixed typos in Kconfig


I have merged feedback on previous patchset:

RE: [PATCH] [CAIF-RFC 0/8-v2] CAIF Protocol Stack
David Miller wrote:
> There is a lot of coding style issues here I'd like you to address in
> your next submission.
> Comments are formatted in several places like this:
>
> /*
> *
> *
> */
>
> It should be: ....
>
> /*
>  *
>  *
>  */
>
> Also often there are tons of extraneous empty lines in the source
> files.  Particularly right after the comment at the top of the source
> file.  For example include/net/caif/generic/cfcnfg.h there is the top
> comment (which needs to be fixed as described above) and then 8 empty
> lines before the #ifndef CFCNFG_H_  
>
> That's rediculious, just have one empty line there seperating things.
>
> Seriously, you should be able to just scan over your patch and see
> all of these oddities.  They jumped right out at me.  Please clean
> them up. 
I think I have fixed up License statements and got rid of empty lines. 
I'm afraid there are still style issues left, but I have tried to fix
those you pointed out and have ran checkpatch. Complaints on 
LINUX_VERSION_CODE will be fixed in a later patch-set.


RE: [PATCH] [CAIF-RFC 1/8-v2] CAIF Protocol Stack
Stefano Babic wrote:
>> + * \b Documentation see STE Doc No: 155 19-CRH 109 913.
> Probably you should remove this line as you already did in other
> places.
Yes, agree - I have done so.

RE: [PATCH] [CAIF-RFC 2/8-v2] CAIF Protocol Stack
Stefano Babic wrote:
> You actually removed the shared memory driver. Do you plan to insert
> it again ?
Well,  yes and no. The shared memory driver is actually back on the chart,
and we  have support for more drivers internally,
but I want to start contributing the main CAIF protocol before releasing more
drivers.

On the other hand, the CAIF protocol itself should not need to know the 
type of physical link protocol. I intend to remove the references to physical 
layer types (e.g. SPI) later on.

> There are references to pictures that are not provided.
Fixed: I have removed the references to the gifs.

>> +/* ASSERT */
>> +#define cfglu_assert(exp) BUG_ON(!(exp))
>
> I do not why, but even GENERIC_BUG is not defined for all
> architectures.
> This means that BUG_ON is simply removed by the compiler and we get
> no track if the assert fails.
> It should be better to add at least an internal trace (adding for
> example a CFLOG_FATAL call).
Fixed: We have updated caif_assert with BUG_ON and printout.

> Is this file probably obsolete ?
Yes, but I'm not sure I'm able to remove all legacies right now.

>
> Not sure I have understood. There is an abstraction layer for SPI in
> kernel and some generic purpose functions are provided (spy_sync,
> spi_async, etc.) that are HW independent. I know they provide only
> the methods for the data transfer, but I have imagined that we need
> at this point some kind of "caif_spi_device" that is able to talk
> with the caif stack on one side and uses the functions in the SPI
> framework. In any case, HW independent. Have I missed something ?   

As mentioned above we have internally support for physical link layers 
used for CAIF like SPI and others.
I hope we'll be able to contribute this in a later stage.
This is why the source code indicates support for things distributed.
But as previously mentioned, I'm planning to remove all references to 
physical devices (except the Serial Driver) in the general CAIF part in 
our next patch-set

RE: [PATCH] [CAIF-RFC 4/8-v2] CAIF Protocol Stack
Stefano Babic wrote:
> sjur.brandeland@stericsson.com wrote:
> s/happends/happens/, there are other occurencies.
Done, thanks
>
>> +
>> +bool cfcnfg_del_adapt_layer(struct _cfcnfg_t *cnfg, layer_t
>> +*adap_layer) { + uint8 channel_id = 0;
>> + struct cfcnfg_phyinfo *phyinfo = NULL;
>> + uint8 phyid = 0;
>> + CFLOG_TRACE(("cfcnfg: enter del_adaptation_layer\n")); +
>> + cfglu_assert(adap_layer != NULL);
>> + channel_id = adap_layer->id;
>> + cfglu_assert(channel_id != 0);
>
> My two cents about using assert in the code, but I prefer to get some
> info from system when something goes wrong as to call in some way
> panic (the assert calls BUG_ON) and blocks forever. This line is not
> different as checking the adapt_layer->dn pointer some lines after
> and I think an error is better recognized in that case. So IMHO
> should be better something like:   
>
> if (channel_id == 0) {
> CFLOG_ERROR(("cfcnfg:adap_layer->dn is NULL\n"));
> return CFGLU_EINVAL;
> }
Ok, I have fixed this particular case as you have suggested.
I have also updated cfglu_assert to do printout before calling BUG_ON.
My thinking is to use asserts on internal in-variants. But error checking
on APIs e.g. between physical interface drivers and CAIF Stack should at
least be proper checks as you suggested.
Please check what you think of the asserts in this release and get back to be!

>
>> diff --git a/net/caif/generic/cfpkt_plain.c
> Probably you plan to use always the magic number in your buffer
> management. Then should be better to remove all the #if CHECK_MEM
> stuff. 
The file cfpkt_plain.c is removed, the file cfpkt_pain.c should be
used instead.

RE: [PATCH] [CAIF-RFC 5/8-v2] CAIF Protocol Stack
Stefano Babic wrote:
> sjur.brandeland@stericsson.com wrote:
>> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
>
> Hi Sjur,
>
>> diff --git a/net/caif/caif_chr.c b/net/caif/caif_chr.c
>
>> +#define caif_assert(assert) BUG_ON(!(assert))
>
> Do we need special assert for each module (cfglu_assert,
> caif_assert,...) ? They are all defined in the same way.
> At this point I have already set a comment about using BUG_ON in a
> previous patch.
OK, Fixed we should have 'caif_assert' all over.

>
> I see a mixed policy in this patch, using sometimes _assert and
> sometimes directly BUG_ON, too.
Fixed.

>
>> + mutex_lock_interruptible(&dev->mutex);
> The return value is not checked and it must be, as in all other cases.
OK Fixed.


RE: [PATCH] [CAIF-RFC 5/8-v2] CAIF Protocol Stack
Randy Dunlap wrote:
>> diff --git a/net/caif/Kconfig b/net/caif/Kconfig new file mode 100644
>> + Say Y here if you need to use a phone modem that uses CAIF as
>> +transport
>
> end above with period ('.').
OK, thanks.
>
>> + You will also need to say yes to any caif physical devices that
>> your platform + supports. + This can be either built-in or as a
>> loadable module, if you select +to build it as module
>
> s/,/;/
OK, thanks.
>
>> + the other CAIF also needs to built as modules
>
> the other CAIF {options or drivers or some other word here} also
> need  ... modules. (end with period)
>
>
...
>> +
>> +config  CAIF_USE_PLAIN
>> + bool  "Use plain buffers instead of SKB in caif"
>> + default n
>> + ---help---
>> + Use plain buffer to transport data,
>
> s/,/./
OK, thanks.
>
...
>> + Enable the inclusion of debug code in the caif stack,
>> + be aware that doing this will impact performance. + If unsure say
>> N here. +
>> +# Include physical drivers
>> +# source "drivers/net/caif/Kconfig"
>
> Drop the above line.
OK, thanks.


RE: [PATCH] [CAIF-RFC 6/8-v2] CAIF Protocol Stack
Stefano Babic wrote:
> s/disicpline/discipline/
OK, Removed the line discipline completely.
>
>> diff --git a/drivers/net/caif/phyif_loop.c
>
> Is there a reason why do you prefer to implement your own ring buffer
> management else to use the circ_buf already implemented in kernel ?
I've re-written and simplified this loopback device completely.
>
>> +#define phyif_assert(assert) BUG_ON(!(assert))
>
> Specialized assert function for this module, really needed ?
Nop, this has also gone.
>
>> +
>> + result = tty_register_ldisc(N_MOUSE, &phyif_ldisc);
>
> I think it is time to set up your own discipline include/linux/tty.h,
> inserting a N_CAIF line discipline. Reusing other discipline
> conflicts with other drivers. 

OK, I will look into this.

RE: [PATCH] [CAIF-RFC 7/8-v2] CAIF Protocol Stack
Stefano Babic wrote:
> sjur.brandeland@stericsson.com wrote:
>> +ST-Ericsson modems support a number of transports between modem and
>> +host, currently Uart and Shared Memory are available for Linux.
>
> Shared Memory was removed in this patchset.
OK - s/Shared Memory/Loopback
>
>> +== CAIF structure ==
>> +
>> +The goal is to have caif as system independent as possible.
>> +All caif code can be found under GenCaif/src and GenCaif/inc.
>
> The path are wrong, I think you mean net/caif/generic and
> include/net/caif.
OK - corrected path.
>
>> +The actual linux module implementation is under src/kernel.
>> +There is also a user space program that is not up to date to run the
>> +stack in user space for testing.
>
> I think you can remove these phrases.
OK, done.
>
>> +
>> +We have tested the kernel implementation on the emulator with a
>> modem +and we are able to enumerate and make a link setup.
>
> Only as comment: I tested this patchset again on an ARM platform and
> I am able to send successfully AT commands to the Ericsson Test
> Device "B26". 
Great! It is reassuring to hear that you're able to run CAIF :-)

>
>> +      - CFSHML CAIF Shared Memory layer.
>
> Again, this layer was removed and there is no track about SPI Layer.
Done, removed.
>
>> +To achieve this we need the help of a daemon program called ldiscd.
>> +The benefit is that we can hook up to any TTY, the downside is that
>> +we need an extra operation in order to install the line discipline.
>
> I understand the reason, it looks only a quite odd that we need to
> start only for this purpose a user space program. And there is no
> hint if the daemon is not started, simply caif does not work. What do
> you think to set up the line discipline directly in kernel ?  

OK, I have removed the line discipline now and moved this code
into kernel. The tty to be used is now a module argument.

Ref. "Re: [PATCH] [CAIF-RFC 6/8-v2] CAIF Protocol Stack".

>> +Install the VEI channel (this will enumerate and do the linksetup
>> of the first VEI channel. If this goes well you should see
>> /dev/chn*) (There are printks logging all buffers that can be
>> checked with dmesg): +$ modprobe chnl_chr + +The AT (VEI) channel is
>> ready to use (you can now send AT commands on it): 
>
> Not really. at this point, the channels are not configured if we do
> not use chardevconfig (or we do the same in kernel).

Agree, I have removed this paragraph.

>
>> diff --git a/Documentation/CAIF/caif_user_config.dox
>> b/Documentation/CAIF/caif_user_config.dox
>
> This file seems obsolete. There is no track about ACTIVATE/DEACTIVATE.
Yes, Agree I have removed this file completely.
This patch set removes the use of character devices for access and configuration,
and introduces Sockets and RTNL instead.

>> diff --git a/Documentation/CAIF/ldiscd/ldiscd.c
>> b/Documentation/CAIF/ldiscd/ldiscd.c
>> +#define CAIF_LDISC_TTY "/dev/ttyS0"
>
> I think it should not be bad to avoid a fixed device name and take it
> as program parameter.
Yes, agree. It is now a module paramter to caif_serial.c

BR/Sjur Brændeland

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  1/8] CAIF Protocol Stack
  2009-11-30 15:00 [RFC PATCH v3 0/8] CAIF Protocol Stack sjur.brandeland
@ 2009-11-30 15:00 ` sjur.brandeland
  2009-11-30 15:00   ` [RFC PATCH v3 2/8] " sjur.brandeland
  2009-12-08 23:42   ` [RFC PATCH v3 1/8] " stefano babic
  2009-11-30 16:08 ` [RFC PATCH v3 0/8] " Patrick McHardy
  2009-12-02 17:02 ` Stefano Babic
  2 siblings, 2 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 include/linux/caif/caif_config.h |  174 ++++++++++++++++++++++++++++++++++++++
 include/linux/caif/caif_ioctl.h  |   91 ++++++++++++++++++++
 include/linux/caif/caif_socket.h |  157 ++++++++++++++++++++++++++++++++++
 include/linux/caif/if_caif.h     |   69 +++++++++++++++
 include/linux/if_arp.h           |    1 +
 include/linux/if_ether.h         |    1 +
 include/linux/socket.h           |    5 +-
 include/linux/tty.h              |    3 +-
 8 files changed, 499 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/caif/caif_config.h
 create mode 100644 include/linux/caif/caif_ioctl.h
 create mode 100644 include/linux/caif/caif_socket.h
 create mode 100644 include/linux/caif/if_caif.h

diff --git a/include/linux/caif/caif_config.h b/include/linux/caif/caif_config.h
new file mode 100644
index 0000000..b4ff87f
--- /dev/null
+++ b/include/linux/caif/caif_config.h
@@ -0,0 +1,174 @@
+/*
+ * CAIF Channel Configuration definitions.
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_CONFIG_H_
+#define CAIF_CONFIG_H_
+
+/**
+ * enum caif_phy_preference     Types of physical HW interfaces
+ *				towards modem defined in CAIF stack
+ * @CAIF_PHYPREF_UNSPECIFIED:	Default physical interface
+ * @CAIF_PHYPREF_LOW_LAT:	Default physical interface for low-latency
+ *				traffic
+ * @CAIF_PHYPREF_HIGH_BW:	Default physical interface for high-bandwidth
+ *				traffic
+ * @_CAIF_PHYPREF_LOOP:		TEST Loopback interface, simulating modem
+ *				responses
+ *
+ * For client convenience, two special types are defined:
+ * CAIF_PHYPREF_LOW_LAT is the preferred low-latency physical link.
+ * Typically used for "control" purposes.
+ * CAIF_PHYPREF_HIGH_BW is the preferred high-bandwidth physical link.
+ * Typically used for "payload" purposes.
+ *
+ */
+enum caif_phy_preference {
+	CAIF_PHYPREF_UNSPECIFIED	= 0x00,
+	CAIF_PHYPREF_LOW_LAT		= 0xd0,
+	CAIF_PHYPREF_HIGH_BW		= 0xe0,
+	_CAIF_PHYPREF_LOOP		= 0x70
+};
+
+/*!
+ * Define CAIF channel priority.
+ * Used when setting up a channel to specify the
+ * priority level of the channel.
+ */
+#define CAIF_PRIO_UNSPCEIFIED  0x0
+#define CAIF_PRIO_MIN	       0x01	/*! Minimum priority level */
+#define CAIF_PRIO_LOW	       0x04	/*!< Suggested priority level for
+					 *   low-priority channel.
+					 */
+#define CAIF_PRIO_NORMAL       0x0f	/*!< Suggested normal/default
+					 *   priority level.
+					 */
+#define CAIF_PRIO_HIGH	       0x14	/*!< Suggested high priority level */
+#define CAIF_PRIO_MAX	       0x1F	/*!< Max priority for channel
+					 *   (do not use)
+					 */
+
+/**
+ * enum caif_channel_type  	Types of CAIF channel type defined in CAIF Stack.
+ * @CAIF_CHTY_AT:		Classical AT
+ * @CAIF_CHTY_AT_CTRL:		AT control only
+ * @CAIF_CHTY_AT_PAIRED:	Paired control and data
+ * @CAIF_CHTY_DATAGRAM:		Datagram. Requires: connection_id
+ * @CAIF_CHTY_DATAGRAM_LOOP:	Datagram loopback (testing purposes only)
+ * @CAIF_CHTY_VIDEO:		Video channel
+ * @CAIF_CHTY_DEBUG:		Debug service (Debug server and
+ *					       interactive debug)
+ * @CAIF_CHTY_DEBUG_TRACE:	Debug server only
+ * @CAIF_CHTY_DEBUG_INTERACT:	Debug interactive
+ * @CAIF_CHTY_RFM:		RFM service. Params: connection_id, volume
+ * @CAIF_CHTY_UTILITY:		Utility (Psock) service.
+ *				Params: fifo_kb,fifo_pkt, name, psock_param
+ * @CAIF_CHTY_RAW:		DO NOT USE. This is for testing only.
+ *
+ * This is used for channel configuration, specifying the type of channel.
+ */
+enum caif_channel_type {
+	CAIF_CHTY_AT,
+	CAIF_CHTY_AT_CTRL,
+	CAIF_CHTY_AT_PAIRED,
+	CAIF_CHTY_DATAGRAM,
+	CAIF_CHTY_DATAGRAM_LOOP,
+	CAIF_CHTY_VIDEO,
+	CAIF_CHTY_DEBUG,
+	CAIF_CHTY_DEBUG_TRACE,
+	CAIF_CHTY_DEBUG_INTERACT,
+	CAIF_CHTY_RFM,
+	CAIF_CHTY_UTILITY,
+	CAIF_CHTY_RAW
+};
+
+/**
+ *struct caif_channel_config This structure is used for configuring
+ *			     CAIF channels.
+ * @name: 		     Mandatory - Nickname for this device
+ * @type:		     Mandatory - Define the type of caif service
+ * @priority:		     Mandatory - Value between  CAIF_PRIO_MIN and
+ *			     CAIF_PRIO_MAX.
+ *			     CAIF_PRIO_LOW, CAIF_PRIO_NORMAL, CAIF_PRIO_HIGH
+ *			     are suggested values.
+ * @phy_pref:		     Either: Specify type of physical interface to use.
+ * @phy_name:		     Or: Specify identity of the physical interface.
+ *
+ * @u:			     Union of channel type-specific configuration
+ *			     parameters
+ *
+ * @u.dgm:		     CAIF_CHTYPE_DATAGRAM
+ * @u.dgm.connection_id:     Mandatory - Connection ID must be specified.
+ *
+ * @u.video:		     CAIF_CHTYPE_VIDEO
+ * @u.video.connection_id:   Mandatory - Connection ID must be specified.
+ *
+ * @u.rfm		     CAIF_CHTYPE_RFM
+ * @u.rfm.connection_id:     Mandatory - Connection ID must be specified.
+ * @u.rfm.volume:	     Mandatory - Volume to mount.
+ *
+ * @u.utility:		     CAIF_CHTYPE_UTILITY
+ * @u.utility.fifosize_kb:   Psock: FIFO size in KB
+ * @u.utility.fifosize_bufs: Psock: Number of signal buffers
+ * @u.utility.name:	     Psock: Name of service
+ * @u.utility.params:	     Psock: Channel config parameters
+ * @u.utility.paramlen:	     Psock: Length of channel config parameters
+ *
+ *
+ * It holds configuration parameters for setting up all defined CAIF
+ * channel types.
+ * The four first fields are mandatory, then physical interface can be specified
+ * either by name or by prefered characteristics.
+ * The rest of the configuration fields are held in a union for each
+ * channel type and are channel type specific.
+ */
+struct caif_channel_config {
+	char name[16];
+	enum caif_channel_type type;
+	unsigned priority;
+	enum caif_phy_preference phy_pref;
+	char phy_name[16];
+
+	/** Union of channel type-specific configuration parameters.
+	 * 'switched' by attribute type.
+	 */
+	union {
+		/* CAIF_CHTYPE_DATAGRAM */
+		struct {
+			unsigned connection_id;
+		} dgm;
+		/* CAIF_CHTYPE_VIDEO */
+		struct {
+			unsigned connection_id;
+		} video;
+		/* CAIF_CHTYPE_RFM */
+		struct {
+			unsigned connection_id;
+			char volume[20];
+		} rfm;
+		/* CAIF_CHTYPE_UTILITY */
+		struct {
+			unsigned fifosize_kb;
+			unsigned fifosize_bufs;
+			char name[16];
+			unsigned char params[256];
+			int paramlen;
+		} utility;
+
+		/* Raw data configuration: DO NOT USE.
+		 * Applies for testing only.
+		 */
+		struct raw {
+			unsigned channeltype;
+			unsigned char endpoint:2;
+			unsigned char subtype:2;
+			unsigned char serviceconfig[512];
+			unsigned int service_length;
+		} _raw;
+	} u;
+};
+
+#endif				/* CAIF_CONFIG_H_ */
diff --git a/include/linux/caif/caif_ioctl.h b/include/linux/caif/caif_ioctl.h
new file mode 100644
index 0000000..a42adf5
--- /dev/null
+++ b/include/linux/caif/caif_ioctl.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_IOCTL_H_
+#define CAIF_IOCTL_H_
+#include <linux/caif/caif_config.h>
+
+/*!\page  caif_ioctl.h
+ * This file defines the management interface to CAIF.
+ * It defines how CAIF channels are configured and become visible in the
+ * Linux file system, typically under "/dev".
+ *
+ *\b Example - creating a new AT character device:
+ * \code
+   fd = open("/dev/caifconfig",..);
+   struct caif_channel_create_action at_config = {
+	 .name = "cnhl2",
+	 .config = {
+	    .channel = CAIF_CHTY_AT,
+	    .phy_ref = CAIF_PHY_LOW_LAT,
+	    .priority = CAIF_PRIO_HIGH
+	 }};
+   ioctl(fd, CAIF_IOC_CONFIG_DEVICE,&at_config);
+   close(fd);
+ * \endcode
+ * This will cause a new AT channel to be available in at "/dev/chnl2".
+ * This CAIF channel can then be connected by using \ref open.
+ */
+
+#define CAIF_IOC_MAGIC 'g'
+#define DEVICE_NAME_LEN 16
+
+/* Specifies the type of device to create: NET device or CHAR device*/
+enum caif_dev_type {
+	CAIF_DEV_CHR = 1,
+	CAIF_DEV_NET = 2
+};
+
+/** Used for identifying devices, PHY interfaces, etc.*/
+struct caif_device_name {
+	char name[DEVICE_NAME_LEN];	/*!< Device name */
+	enum caif_dev_type devtype;	/*!< Device type */
+};
+
+/**
+ * CAIF ACTION for \ref CAIF_ACT_CHANNEL_CONFIG.
+ * This structure is used to configure a new CAIF Channel and
+ * create the corresponding character device.
+ */
+struct caif_channel_create_action {
+	/** \b in  CAIF configuration request */
+	struct caif_channel_config config;
+	/** \b in/out Device name returned from ACTION */
+	struct caif_device_name name;
+	/** \b out Major device id */
+	int major;
+	/** \b out Minor device id */
+	int minor;
+};
+
+/**
+ * union caif_action
+ * This union is used to create and delete CAIF channels.
+ */
+union caif_action {
+	struct caif_device_name delete_channel;
+	struct caif_channel_create_action create_channel;
+};
+
+/**
+ * CAIF IOCTL for \ref CAIF_IOC_CHANNEL_CONFIG.
+ * This structure is used to configure a new CAIF Channel and
+ * create the corresponding character device.
+ */
+
+/** Create and Configure a new CAIF device.
+ * Note that the device is not implicitly connected.
+ */
+#define CAIF_IOC_CONFIG_DEVICE		_IOWR(CAIF_IOC_MAGIC, 1,\
+struct caif_channel_create_action)
+
+/** Remove a CAIF device. Requires the device to be previously disconnected. */
+#define CAIF_IOC_REMOVE_DEVICE		_IOWR(CAIF_IOC_MAGIC, 2,\
+		struct caif_device_name)
+#define CAIF__IOC_MAXNR				9
+/*! @} */
+
+#endif				/* CAIF_IOCTL_H_ */
diff --git a/include/linux/caif/caif_socket.h b/include/linux/caif/caif_socket.h
new file mode 100644
index 0000000..239fb00
--- /dev/null
+++ b/include/linux/caif/caif_socket.h
@@ -0,0 +1,157 @@
+/* linux/caif_socket.h
+ * CAIF Definitions for CAIF socket and network layer
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	 Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _LINUX_CAIF_SOCKET_H
+#define _LINUX_CAIF_SOCKET_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/* TODO: Move these defs to /usr/include/linux/socket.h */
+#define AF_CAIF    37 		/* CAIF Socket Address Family */
+#define PF_CAIF    37           /* CAIF Socket Protocol Family */
+#define SOL_CAIF   278		/* CAIF Socket Option Level */
+
+#define CAIF_DEFAULT_PRI       0xf
+
+/*
+ * enum caif_link_selector -   Physical Link Selection.
+ * @CAIF_LINK_UNSPECIFIED:	Default physical interface
+ * @CAIF_LINK_LOW_LATENCY:	Default physical interface for low-latency
+ *                              traffic.
+ * @CAIF_LINK_HIGH_BANDW:	Default physical interface for high-bandwidth
+ *				traffic.
+ */
+enum caif_link_selector {
+	CAIF_LINK_UNSPECIFIED	= 0x00,
+	CAIF_LINK_LOW_LATENCY	= 0xd0,
+	CAIF_LINK_HIGH_BANDW	= 0xe0
+};
+
+/**
+ * enum caif_protocol_type  	Types of CAIF protocols in the CAIF Stack.
+ * @CAIFPROTO_AT:		Classic AT channel.
+ * @CAIFPROTO_DATAGRAM:		Datagram channel.
+ * @CAIFPROTO_DATAGRAM_LOOP:	Datagram loopback channel,used for test purpose
+ * @CAIFPROTO_UTILITY:		Utility (Psock) channel.
+ * @CAIFPROTO_RFM:		Remote File Manager
+ */
+enum caif_protocol_type {
+	CAIFPROTO_AT,
+	CAIFPROTO_DATAGRAM,
+	CAIFPROTO_DATAGRAM_LOOP,
+	CAIFPROTO_UTIL,
+	CAIFPROTO_RFM,
+	CAIFPROTO_MAX
+};
+
+enum caif_at_type {
+	CAIF_ATTYPE_PLAIN
+};
+
+/*
+ * struct sockaddr_caif - the sockaddr structure for CAIF sockets.
+ * @family:	address family number AF_CAIF
+ * @u.dgm:		     CAIFPROTO_AT
+ * @u.dgm.at_type: 	     Type of AT link to setup of type enum caif_at_type
+ * @u.dgm:		     CAIFPROTO_DATAGRAM
+ * @u.dgm.connection_id:     Datagram connection id.
+ * @u.dgm.nsapi:             NSAPI of the PDP-Context.
+ * @u.rfm		     CAIFPROTO_RFM
+ * @u.rfm.connection_id:     Connection ID for RFM.
+ * @u.rfm.volume:	     Volume to mount.
+ * @u.util:		     CAIFPROTO_UTILITY
+ * @u.utility.name:	     Service name.
+ */
+struct sockaddr_caif {
+	sa_family_t  family;
+	union {
+		struct {
+			u_int8_t  type; 	/* type: enum caif_at_type */
+		} at;				/* CAIFPROTO_AT */
+		union {
+			u_int32_t connection_id;
+			u_int8_t  nsapi;
+		} dgm;				/* CAIFPROTO_DATAGRAM */
+		struct {
+			char      service[16];
+		} util;				/* CAIFPROTO_UTIL */
+		struct {
+			u_int32_t connection_id;
+			char 	  volume[16];
+		} rfm;				/* CAIFPROTO_RFM */
+	} u;
+};
+
+/*
+ * struct caif_channel_opt - CAIF channel connect options.
+ * @priority:		Priority of the channel (between 0 and 0x1f)
+ * @link_selector:	Selector for the physical link.
+ *              	(see enum caif_phy_preference in caif_config.h)
+ * @phy_name    Prefered physical link name.
+ */
+struct caif_channel_opt {
+	u_int16_t  priority;
+	u_int16_t  link_selector;
+	char       link_name[16];
+};
+
+/*
+ * struct caif_param - CAIF parameters
+ * @datalen:	Length of data
+ * @data:	Binary Data Blob
+ */
+struct caif_param {
+	u_int16_t  size;
+	u_int8_t   data[256];
+};
+
+/*
+ * struct caif_util_modem_flow_opt - CAIF utility channel flow parameters.
+ * This specifies the queue size for down-link messages.
+ * @fifosize_kb:	Maximum number of unsent DN
+ * @fifosize_bufs:	Actual parameters
+ */
+struct caif_util_modem_flow_opt {
+	u_int32_t  fifosize_kb;
+	u_int32_t  fifosize_bufs;
+};
+
+/* enum caif_socket_opts - CAIF option values for getsockopt and setsockopt.
+ * @CAIF_CHANNEL_OPT:	        Used to set the connect options on a CAIF
+ *				socket. (struct caif_config_opt). This must
+ *				be set before connecting.
+ * @CAIF_REQ_PARAM_OPT:		Used to set the request parameters for a
+ *				utility channel. (struct caif_param). This
+ *				must be set before connecting.
+ *
+ * @CAIF_RES_PARAM_OPT:		Gets the request parameters for a utility
+ *				channel. (struct caif_param). This must be
+ *				fetched after connecting the socket.
+ *
+ * @CAIF_UTIL_FLOW_OPT:		Sets the utility channels flow options.
+ *				This must be set before connecting.
+ *				(struct caif_util_modem_flow_opt)
+ *
+ * @CAIF_CONN_ID_OPT:           Gets the channel id on a CAIF Channel.
+ *				This can only be done after connect.
+ *                              ( u_int32_t)
+ */
+enum caif_socket_opts {
+	CAIF_CHANNEL_OPT = 127,
+	CAIF_REQ_PARAM_OPT  	= 128,
+	CAIF_RSP_PARAM_OPT  	= 129,
+	CAIF_UTIL_FLOW_OPT  	= 130,
+	CAIF_CONN_ID_OPT    	= 131
+};
+
+#ifdef __cplusplus
+}				/* extern "C" */
+#endif
+#endif /* _LINUX_CAIF_SOCKET_H */
diff --git a/include/linux/caif/if_caif.h b/include/linux/caif/if_caif.h
new file mode 100644
index 0000000..ab1d154
--- /dev/null
+++ b/include/linux/caif/if_caif.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef IF_CAIF_H_
+#define IF_CAIF_H_
+
+/**
+ * enum sioc_caif
+ *
+ * CAIF IP Interface can be created, changed and deleted,
+ * by this enum. In addition standard Socket IO Controls (SIGIOC*)
+ * can be used to manage standard IP Interface parameters.
+ * The struct ifreq are used to carry parameters.
+ *
+ * @SIOCCAIFNETNEW    - Used to create a new instance of the CAIF IP Interface.
+ *                      struct ifreq containing struct ifcaif_param are used
+ *                      as parameters. ifr_name must be filled in.
+ * @SIOCCAIFNETCHANGE - As above, but changes a disconnected CAIF IP Inteface.
+ * @SIOCCAIFNETREMOVE - Removes a CAIF IP Interface.
+ */
+enum sioc_caif {
+	SIOCCAIFNETNEW = SIOCPROTOPRIVATE,
+	SIOCCAIFNETCHANGE,
+	SIOCCAIFNETREMOVE,
+};
+
+
+/**
+ * struct ifcaif_param
+ *
+ * When using SIOCCAIFNETNEW to create a CAIF IP interface, this structure
+ * is used for configuration data.
+ * The attribute ifr_ifru.ifru_data in struct struct ifreq must be set
+ * point at an instance of struct ifcaif_param.
+ *
+ * @ipv4_connif - Connection ID for IPv4 PDP Context.
+ * @ipv6_connif - Connection ID for IPv6 PDP Context.
+ * @loop        - If different from zero, device is doing loopback
+ */
+struct ifcaif_param {
+	__u32                   ipv4_connid;
+	__u32                   ipv6_connid;
+	__u8			loop;
+};
+
+/**
+ * enum ifla_caif
+ * When using RT Netlink to create, destroy or configure a CAIF IP interface,
+ * enum ifla_caif is used to specify the configuration attributes.
+ *
+ * @IFLA_CAIF_IPV4_CONNID - Connection ID for IPv4 PDP Context.
+ *                          The type of attribute is NLA_U32.
+ * @IFLA_CAIF_IPV6_CONNID - Connection ID for IPv6 PDP Context.
+ *                          The type of attribute is NLA_U32.
+ * @IFLA_CAIF_LOOPBACK   -  If different from zero, device is doing loopback
+ *                          The type of attribute is NLA_U8.
+ */
+enum ifla_caif {
+	IFLA_CAIF_IPV4_CONNID,
+	IFLA_CAIF_IPV6_CONNID,
+	IFLA_CAIF_LOOPBACK,
+	__IFLA_CAIF_MAX
+};
+#define	IFLA_CAIF_MAX (__IFLA_CAIF_MAX-1)
+
+#endif /*IF_CAIF_H_*/
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 282eb37..4efa69a 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -90,6 +90,7 @@
 
 #define ARPHRD_PHONET	820		/* PhoNet media type		*/
 #define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/
+#define ARPHRD_CAIF     822		/* CAIF media type		*/
 
 #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
 #define ARPHRD_NONE	  0xFFFE	/* zero header length */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 580b600..c66d48a 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -109,6 +109,7 @@
 #define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
 #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
+#define ETH_P_CAIF      0x00F7          /* ST-Ericsson CAIF protocol    */
 
 /*
  *	This is an Ethernet frame header.
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 3273a0c..ad0dd43 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -180,7 +180,8 @@ struct ucred {
 #define AF_ISDN		34	/* mISDN sockets 		*/
 #define AF_PHONET	35	/* Phonet sockets		*/
 #define AF_IEEE802154	36	/* IEEE802154 sockets		*/
-#define AF_MAX		37	/* For now.. */
+#define AF_CAIF		37	/* CAIF sockets		        */
+#define AF_MAX		38	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -220,6 +221,7 @@ struct ucred {
 #define PF_ISDN		AF_ISDN
 #define PF_PHONET	AF_PHONET
 #define PF_IEEE802154	AF_IEEE802154
+#define PF_CAIF         AF_CAIF
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -291,6 +293,7 @@ struct ucred {
 #define SOL_PNPIPE	275
 #define SOL_RDS		276
 #define SOL_IUCV	277
+#define SOL_CAIF	278
 
 /* IPX options */
 #define IPX_TYPE	1
diff --git a/include/linux/tty.h b/include/linux/tty.h
index f0f43d0..3f8e793 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS		20
+#define NR_LDISCS		21
 
 /* line disciplines */
 #define N_TTY		0
@@ -48,6 +48,7 @@
 #define N_PPS		18	/* Pulse per Second */
 
 #define N_V253		19	/* Codec control over voice modem */
+#define N_CAIF		20
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  2/8] CAIF Protocol Stack
  2009-11-30 15:00 ` [RFC PATCH v3 1/8] " sjur.brandeland
@ 2009-11-30 15:00   ` sjur.brandeland
  2009-11-30 15:00     ` [RFC PATCH v3 3/8] " sjur.brandeland
  2009-12-09  0:18     ` [RFC PATCH v3 2/8] " stefano babic
  2009-12-08 23:42   ` [RFC PATCH v3 1/8] " stefano babic
  1 sibling, 2 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 include/net/caif/generic/caif_layer.h |  341 +++++++++++++++++++++++++++++++++
 include/net/caif/generic/cfcnfg.h     |  211 ++++++++++++++++++++
 include/net/caif/generic/cfctrl.h     |  137 +++++++++++++
 include/net/caif/generic/cffrml.h     |   20 ++
 include/net/caif/generic/cfglue.h     |  174 +++++++++++++++++
 include/net/caif/generic/cfloopcfg.h  |   16 ++
 include/net/caif/generic/cflst.h      |   19 ++
 include/net/caif/generic/cfmsll.h     |   13 ++
 include/net/caif/generic/cfmuxl.h     |   22 ++
 include/net/caif/generic/cfpkt.h      |  264 +++++++++++++++++++++++++
 include/net/caif/generic/cfserl.h     |   20 ++
 include/net/caif/generic/cfshml.h     |   12 ++
 include/net/caif/generic/cfspil.h     |   85 ++++++++
 include/net/caif/generic/cfsrvl.h     |   33 ++++
 include/net/caif/generic/cfusbl.h     |   13 ++
 include/net/caif/generic/fcs.h        |   13 ++
 16 files changed, 1393 insertions(+), 0 deletions(-)
 create mode 100644 include/net/caif/generic/caif_layer.h
 create mode 100644 include/net/caif/generic/cfcnfg.h
 create mode 100644 include/net/caif/generic/cfctrl.h
 create mode 100644 include/net/caif/generic/cffrml.h
 create mode 100644 include/net/caif/generic/cfglue.h
 create mode 100644 include/net/caif/generic/cfloopcfg.h
 create mode 100644 include/net/caif/generic/cflst.h
 create mode 100644 include/net/caif/generic/cfmsll.h
 create mode 100644 include/net/caif/generic/cfmuxl.h
 create mode 100644 include/net/caif/generic/cfpkt.h
 create mode 100644 include/net/caif/generic/cfserl.h
 create mode 100644 include/net/caif/generic/cfshml.h
 create mode 100644 include/net/caif/generic/cfspil.h
 create mode 100644 include/net/caif/generic/cfsrvl.h
 create mode 100644 include/net/caif/generic/cfusbl.h
 create mode 100644 include/net/caif/generic/fcs.h

diff --git a/include/net/caif/generic/caif_layer.h b/include/net/caif/generic/caif_layer.h
new file mode 100644
index 0000000..0ae98b5
--- /dev/null
+++ b/include/net/caif/generic/caif_layer.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Braendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_LAYER_H_
+#define CAIF_LAYER_H_
+
+#include <net/caif/generic/cfglue.h>
+
+struct layer;
+struct cfpkt;
+struct cfpktq;
+struct transmt_info;
+struct caif_packet_funcs;
+
+#define CAIF_MAX_FRAMESIZE 4096
+#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64)
+#define CAIF_NEEDED_HEADROOM (10)
+#define CAIF_NEEDED_TAILROOM (2)
+
+
+#define CAIF_LAYER_NAME_SZ 16
+#define CAIF_SUCCESS    1
+#define CAIF_FAILURE    0
+
+/*! \addtogroup GenCaifExternal
+ *  Additional documentation for group `GenCaifExternal'
+ *  @{
+ */
+
+/** CAIF Control Signaling.
+ *  These commands are sent upwards in the CAIF stack. They are used for
+ *  signaling originating from the modem.
+ *  These are either responses (*_RSP) or events (*_IND).
+ */
+enum caif_ctrlcmd {
+	/** Flow Control is OFF, transmit function should stop sending data */
+	CAIF_CTRLCMD_FLOW_OFF_IND = 0,
+	/** Flow Control is ON, transmit function can start sending data */
+	CAIF_CTRLCMD_FLOW_ON_IND = 1,
+	/** Remote end modem has decided to close down channel */
+	CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND = 5,
+	/** Called initially when the layer below has finished initialization */
+	CAIF_CTRLCMD_INIT_RSP = 3,
+	/** Called when de-initialization is complete */
+	CAIF_CTRLCMD_DEINIT_RSP = 4,
+	/** Called if initialization fails */
+	CAIF_CTRLCMD_INIT_FAIL_RSP = 6,
+	/** Note: Only used internally in GenCaif.
+	 * Called if physical interface cannot send more packets.
+	 */
+	_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND = 7,
+	/** Note: Only used internally in GenCaif.
+	 * Called if physical interface is able to send packets again.
+	 */
+	_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND = 8,
+	_CAIF_CTRLCMD_PHYIF_DOWN_IND = 9,
+};
+
+/** Modem Control Signaling.
+ *  These are requests sent 'downwards' in the stack.
+ *  Flow ON, OFF can be indicated to the modem.
+ */
+enum caif_modemcmd {
+	/** Flow Control is ON, transmit function can start sending data */
+	CAIF_MODEMCMD_FLOW_ON_REQ = 0,
+	/** Flow Control is OFF, transmit function should stop sending data */
+	CAIF_MODEMCMD_FLOW_OFF_REQ = 1,
+	/** Notify physical layer that it is in use */
+	_CAIF_MODEMCMD_PHYIF_USEFULL = 3,
+	/** Notify physical layer that it is no longer in use */
+	_CAIF_MODEMCMD_PHYIF_USELESS = 4
+};
+
+/** CAIF Packet Direction.
+ *  Indicate if a packet is to be sent \b out or to be received \b in.
+ */
+enum caif_direction {
+	CAIF_DIR_IN = 0,	/*!< Incoming packet received. */
+	CAIF_DIR_OUT = 1	/*!< Outgoing packet to be transmitted. */
+};
+
+/** This structure defines the generic layered structure in CAIF.
+ *  It is inspired by the "Protocol Layer Design Pattern" (Streams).
+ *
+ *  It defines a generic layering structure, used by all CAIF Layers and the
+ *  layers interfacing CAIF.
+ *
+ *  In order to integrate with CAIF an adaptation layer on top of the CAIF stack
+ *  and PHY layer below the CAIF stack
+ *  must be implemented. These layer must follow the design principles below.
+ *
+ *  Principles for layering of protocol layers:
+ *    -# All layers must use this structure. If embedding it, then place this
+ *	     structure first in the layer specific structure.
+ *    -# Each layer should not depend on any others layer private data.
+ *    -# In order to send data upwards do
+ *	 \code layer->up->receive(layer->up, packet); \endcode
+ *    -# In order to send data downwards do
+ *	 \code layer->dn->transmit(layer->dn, info, packet); \endcode
+ *
+ *
+ *
+ */
+struct layer {
+
+	struct layer *up;	/*!< Pointer to the layer above */
+	struct layer *dn;	/*!< Pointer to the layer below */
+	/*!
+	 *  Receive Function.
+	 *  Contract: Each layer must implement a receive function passing the
+	 *  CAIF packets upwards in the stack.
+	 *	Packet handling rules:
+	 *	      -# The CAIF packet (cfpkt) cannot be accessed after
+	 *		     passing it to the next layer using up->receive().
+	 *	      -# If parsing of the packet fails, the packet must be
+	 *		     destroyed and -1 returned from the function.
+	 *	      -# If parsing succeeds (and above layers return OK) then
+	 *		      the function must return a value > 0.
+	 *
+	 *  @param[in] layr Pointer to the current layer the receive function is
+	 *		implemented for (this pointer).
+	 *  @param[in] cfpkt Pointer to CaifPacket to be handled.
+	 *  @return result < 0 indicates an error, 0 or positive value
+	 *	     indicates success.
+	 */
+	int (*receive)(struct layer *layr, struct cfpkt *cfpkt);
+
+	/*!
+	 *  Transmit Function.
+	 *  Contract: Each layer must implement a transmit function passing the
+	 *	CAIF packet downwards in the stack.
+	 *	Packet handling rules:
+	 *	      -# The CAIF packet (cfpkt) ownership is passed to the
+	 *		 transmit function. This means that the the packet
+	 *		 cannot be accessed after passing it to the below
+	 *		 layer using dn->transmit().
+	 *
+	 *	      -# If transmit fails, however, the ownership is returned
+	 *		 to thecaller. The caller of "dn->transmit()" must
+	 *		 destroy or resend packet.
+	 *
+	 *	      -# Return value less than zero means error, zero or
+	 *		 greater than zero means OK.
+	 *
+	 *  @param[in] layr  Pointer to the current layer the receive function
+	 *			    is	implemented for (this pointer).
+	 *  @param[in] cfpkt Pointer to CaifPacket to be handled.
+	 *  @param[in] info  Info about physical layer (filled in by MUX layer)
+	 *		     and CAIF header size (each layer adds to hdr_len).
+	 *  @return	     result < 0 indicates an error, 0 or positive value
+	 *		     indicate success.
+	 */
+	int (*transmit) (struct layer *layr, struct transmt_info *info,
+		      struct cfpkt *cfpkt);
+
+	/*!
+	 *  Control Function used to signal upwards in the CAIF stack.
+	 *  Used for signaling responses (CAIF_CTRLCMD_*_RSP)
+	 *  and asynchronous events from the modem  (CAIF_CTRLCMD_*_IND)
+	 *
+	 *  @param[in] layr  Pointer to the current layer the receive function
+	 *		     is implemented for (this pointer).
+	 *  @param[in] ctrl  Control Command.
+	 */
+	void (*ctrlcmd) (struct layer *layr, enum caif_ctrlcmd ctrl,
+			 int phyid);
+
+	/*!
+	 *  Control Function used for controlling the modem. Used to signal
+	 *  down-wards in the CAIF stack.
+	 *  @returns 0 on success, < 0 upon failure.
+	 *  @param[in] layr  Pointer to the current layer the receive function
+	 *		     is implemented for (this pointer).
+	 *  @param[in] ctrl  Control Command.
+	 */
+	int (*modemcmd) (struct layer *layr, enum caif_modemcmd ctrl);
+
+	struct layer *next;	/*!< Pointer to chain of layers, up/dn will
+				 *   then point at the first element of a
+				 *   which then should be iterated through
+				 *   the next pointer.
+				 */
+	unsigned short prio;	/*!< Priority of this layer */
+	unsigned int id;	/*!< The identity of this layer. */
+	unsigned int type;	/*<! The type of this layer */
+	char name[CAIF_LAYER_NAME_SZ];		/*!< Name of the layer */
+};
+/** Set the up pointer for a specified layer.
+ *  @param layr Layer where up pointer shall be set.
+ *  @param above Layer above.
+ */
+#define layer_set_up(layr, above) ((layr)->up = (struct layer *)(above))
+
+/** Set the dn pointer for a specified layer.
+ *  @param layr Layer where down pointer shall be set.
+ *  @param below Layer below.
+ */
+#define layer_set_dn(layr, below) ((layr)->dn = (struct layer *)(below))
+
+/**
+ *  Transmit info, passed downwards in protocol layers.
+ */
+struct transmt_info {
+	/** Channel ID of the logical CAIF connection.
+	 *  Used by the service layer to indicate to mux the PHY-layer
+	 *  (Physical-ID) to send packet over.
+	 */
+	unsigned short channel_id;
+
+	/** Physical ID of the	physical connection used by the logical CAIF
+	 *  connection. Used by service layers to identify their physical id
+	 *   to Caif MUX (CFMUXL)so that the MUX can add the correct physical
+	 * ID to the packet.
+	 */
+	unsigned short phid;
+
+	/** Header length, used to align pay load on 32bit boundary.
+	 *  Used by SPI Layer (CFSPIL) to align start of pay-load data (IP header
+	 *  start) to 16 or 32 bits boundary.
+	 *  All layers add the number of header bytes they are using, then SPI
+	 *  layer adds padding to get correct alignment.
+	 */
+	unsigned short hdr_len;
+
+	/** Packet priority. */
+	unsigned char prio;
+};
+
+/** Packet functions needed by the adaptation layer and PHY layer are exported
+ *  in this structure.
+ *
+ */
+struct caif_packet_funcs {
+
+	/** Used to map from a "native" packet (e.g. Linux Socket Buffer)
+	 *  to a CAIF packet.
+	 *  @param dir - Direction, indicating whether this packet is to be
+	 *  		sent or received.
+	 *  @param nativepkt - The native packet to be transformed to a CAIF
+	 *  		packet.
+	 *  @returns the mapped CAIF packet CFPKT.
+	 */
+	struct cfpkt *
+	    (*cfpkt_fromnative)(enum caif_direction dir, void *nativepkt);
+
+	/** Used to map from a CAIF packet to a "native" packet
+	 *  (e.g. Linux Socket Buffer).
+	 *  @param pkt	- The CAIF packet to be transformed to a "native"
+	 * 		  packet.
+	 *  @returns the native packet transformed from a CAIF packet.
+	 */
+	void *(*cfpkt_tonative)(struct cfpkt *pkt);
+
+	/** Used by "app" layer to create an outgoing CAIF packet to be sent
+	 *  out of the CAIF Stack.
+	 *  @param data - Packet data to copy into the packet.
+	 *		  If NULL then copying will not take place.
+	 *  @param len	- Length of data to copy into the packet.
+	 *  @returns a new CAIF packet CFPKT.
+	 *  @deprecated Use \b cfpkt_create_pkt (above) instead.
+	 */
+	struct cfpkt *
+	    (*cfpkt_create_recv_pkt)(const unsigned char *data,
+				      unsigned int len);
+
+	/** Used by PHY layer to create an incoming CAIF packet to be
+	 *  processed by the CAIF Stack.
+	 *  @param data - Packet data to copy into the packet. If NULL then
+	 *  copying will not take place.
+	 *  @param len	- Length of data to copy into the packet.
+	 *  @returns a new CAIF packet CFPKT.
+	 *  @deprecated Use \b cfpkt_create_pkt (above) instead.
+	 */
+	struct cfpkt *
+	    (*cfpkt_create_xmit_pkt)(const unsigned char *data,
+				      unsigned int len);
+
+	/** Used to extract data from a CAIF packet.
+	 *  @param cfpkt	 Packet to extract data from.
+	 *  @param buf	 Buffer to hold the data to be extracted from the
+	 *			 CAIF packet.
+	 *  @param buflen	 Length of the buffer (maximum length of the
+	 *			 data to copy into the buffer).
+	 *  @param actual_len	 Number of bytes copied from the packet into
+	 *                       the buffer.
+	 */
+	void
+	 (*cfpkt_extract)(struct cfpkt *cfpkt, void *buf, unsigned int buflen,
+			   unsigned int *actual_len);
+
+	/** Releases a CAIF packet.
+	 *  @param cfpkt	 Packet to destroy.
+	 */
+	void
+	 (*cfpkt_destroy)(struct cfpkt *cfpkt);
+
+	/** Append by giving user access to the packet buffer.
+	 * @param pkt Packet to append to.
+	 * @param buf Buffer inside pkt that user shall copy data into.
+	 * @param buflen Length of buffer and number of bytes added to packet.
+	 * @return < 0 on error.
+	 */
+	 int (*cfpkt_raw_append)(struct cfpkt *cfpkt, void **buf,
+				unsigned int buflen);
+
+	/** Extract by giving user access to the packet buffer.
+	 * @param pkt Packet to extract from.
+	 * @param buf Buffer inside pkt that user shall copy data from.
+	 * @param buflen Length of buffer and number of bytes removed from
+	 *        packet.
+	 * @return < 0 on error
+	 */
+	 int (*cfpkt_raw_extract)(struct cfpkt *cfpkt, void **buf,
+				 unsigned int buflen);
+
+	/** Creates a packet queue. */
+	struct cfpktq *(*cfpktq_create)(void);
+
+	/** Inserts a packet into the packet queue, packets are ordered by
+	 *  priority.
+	 *  If the same priority is used packets are ordered as a FIFO.
+	 */
+	void (*cfpkt_queue)(struct cfpktq *pktq, struct cfpkt *pkt,
+			     unsigned short prio);
+
+	/** Peek into the first packet in the queue. */
+	struct cfpkt *(*cfpkt_qpeek)(struct cfpktq *pktq);
+
+	/** Dequeue a packet from the queue. */
+	struct cfpkt *(*cfpkt_dequeue)(struct cfpktq *pktq);
+
+	/** Get length of a packet */
+	uint16(*cfpkt_getlen)(struct cfpkt *pkt);
+};
+
+/*! @} */
+
+#endif				/* CAIF_LAYER_H_ */
diff --git a/include/net/caif/generic/cfcnfg.h b/include/net/caif/generic/cfcnfg.h
new file mode 100644
index 0000000..7e4fc44
--- /dev/null
+++ b/include/net/caif/generic/cfcnfg.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFCNFG_H_
+#define CFCNFG_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfctrl.h>
+
+struct cfcnfg;
+
+/*! \addtogroup GenCaifExternal
+ *  Additional documentation for group `GenCaifExternal'
+ *  @{
+ */
+
+/** Types of physical layers defined in CAIF Stack */
+enum cfcnfg_phy_type {
+	CFPHYTYPE_UNKNOWN = 0,
+	CFPHYTYPE_SERIAL = 1,	/*!< Serial physical interface */
+	CFPHYTYPE_SPI = 2,	/*!< SPI physical interface */
+	CFPHYTYPE_MSL = 3,	/*!< MSL physical interface */
+	CFPHYTYPE_SHM = 4,	/*!< Shared memory physical interface */
+	CFPHYTYPE_LOOP = 5,	/*!< Loopback physical interface */
+	CFPHYTYPE_USB = 6,	/*!< USB physical interface */
+	CFPHYTYPE_MAX = 7
+};
+
+/** Physical preference - HW Abstraction */
+enum cfcnfg_phy_preference {
+	/** Default physical interface */
+	CFPHYPREF_UNSPECIFIED = 0xa0,
+	/** Default physical interface for low-latency traffic */
+	CFPHYPREF_LOW_LAT = 0xd0,
+	/** Default physical interface for high-bandwidth traffic */
+	CFPHYPREF_HIGH_BW = 0xe0,
+	/** \b TEST \b ONLY Loopback interface simulating modem responses */
+	CFPHYPREF_LOOP = 0x70,
+	/** \b TEST \b ONLY Raw loopback interface */
+	CFPHYPREF_RAW_LOOP = 0x80
+};
+
+/** Types of CAIF Links defined in CAIF Stack
+ * @obsolete
+ */
+enum cfcnfg_link_type {
+	_CF_DECM = 0,		/*!< DECM link - NOT SUPPORTED */
+	CF_VEI = CFCTRL_SRV_VEI,	/*!< VEI link - AT */
+	CF_VIDEO = CFCTRL_SRV_VIDEO,	/*!< Video link */
+	CF_DEBUG = CFCTRL_SRV_DBG,	/*!< Debug link */
+	CF_DATAGRAM = CFCTRL_SRV_DATAGRAM,	/*!< Datagram link */
+	CF_RFM = CFCTRL_SRV_RFM,	/*!< RFM link */
+	CF_UTILITY = CFCTRL_SRV_UTIL	/*!< Utility link */
+};
+
+/** Configuration parameters for a physical layer (e.g. serial) */
+struct cfcnfg_phy_param {
+	int foo;
+};
+
+/** Configuration information used to setup the CAIF physical interface */
+struct cfcnfg_phy_config {
+	/** CAIF physical type */
+	enum cfcnfg_phy_type phy_type;
+	/** Instance number, e.g. UART number */
+	uint8 phy_sub_instance;
+	/** Preference low-latency/high-bandwidth */
+	enum cfcnfg_phy_preference pref;
+	/** Device name */
+	char name[20];
+	/** Checksum is used for interface */
+	bool checksum;
+	/** Configuration parameter specific to the PHY Type */
+	struct cfcnfg_phy_param param;
+	/** Pointer to layer above */
+	struct layer *up;
+};
+
+/** Registration information used to set up the CAIF physical interface */
+struct cfcnfg_phy_mgmt {
+	/** Registration of type */
+	enum cfcnfg_phy_type type;
+	/** Creates an instance of the physical layer (e.g. serial)
+	 * and configures it
+	 */
+	struct layer *(*create_phy) (struct cfcnfg_phy_config *config);
+	 /** Delete an instance of the physical layer (e.g. serial) */
+	int (*delete_phy) (struct layer *l);
+};
+
+/**
+ * This variable is used as a global flag, in order to set whether STX is used in
+ * serial communication.
+ * NOTE: This is not a fully future-proof solution.
+ */
+extern int serial_use_stx;
+
+/**
+ * These variable is used as a global flag, in order to configure padding on SPI communication.
+ * NOTE: This is not a fully future-proof solution.
+ */
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+
+/**
+ * Create the CAIF configuration object.
+ * @return The created instance of a CFCNFG object.
+ */
+struct cfcnfg *cfcnfg_create(void);
+
+/**
+ * Adds a physical layer to the CAIF stack.
+ * @param cnfg Pointer to a CAIF configuration object, created by
+ *				cfcnfg_create().
+ * @param phy_type Specifies the type of physical interface, e.g.
+ *		    CFPHYTYPE_SERIAL.
+ * @param phy_layer Specify the physical layer. The transmit function
+ *		    MUST be set in the structure.
+ * @param phyid [out] The assigned physical ID for this layer,
+ *		      used in \ref cfcnfg_add_adapt_layer to specify
+ *		      PHY for the link.
+ */
+
+void
+cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
+		     struct layer *phy_layer, uint16 *phyid,
+		     enum cfcnfg_phy_preference pref);
+
+/**
+ * Deletes an adaptation layer from the CAIF stack.
+ *
+ * @param cnfg Pointer to a CAIF configuration object, created by
+ *			   cfcnfg_create().
+ * @param adap_layer Adaptation layer to be removed.
+ * @return 0 on success.
+ */
+int cfcnfg_del_adapt_layer(struct cfcnfg *cnfg, struct layer *adap_layer);
+
+/**
+ * Adds an adaptation layer to the CAIF stack.
+ * The adaptation Layer is where the interface to application or higher-level
+ * driver functionality is implemented.
+ *
+ * @param cnfg	     Pointer to a CAIF configuration object, created by
+ *		     cfcnfg_create().
+ * @param linktype   Type of link that is set up, e.g. CF_AT_PLAIN.
+ * @param connid     Connection ID, used for datagram links.
+ * @param phyid	     PHY ID received from \ref	cfcnfg_add_phy_layer,
+ *		     specifying the PHY device to use for this link.
+ * @param adap_layer Specify the adaptation layer; the receive
+ *		     and flow-control functions MUST be set in the structure.
+ * @return	     true on success, false upon failure.
+ */
+bool
+cfcnfg_add_adapt_layer(struct cfcnfg *cnfg, enum cfcnfg_link_type linktype,
+		       uint32 connid, uint16 phyid, struct layer *adap_layer);
+
+/**
+ * Adds an adaptation layer to the CAIF stack.
+ * The adaptation Layer is where the interface to application or higher-level
+ * driver functionality is implemented.
+ *
+ * @param cnfg		Pointer to a CAIF configuration object, created by
+ *				cfcnfg_create().
+ * @param param		Link setup parameters.
+ * @param adap_layer	Specify the adaptation layer; the receive and flow-control
+			functions MUST be set in the structure.
+ * @return		true on success, false upon failure.
+ */
+bool
+cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
+			    struct cfctrl_link_param *param,
+			    struct layer *adap_layer);
+
+/**
+ * Returns a handle to the packet functions used to create packets with
+ * content and to extract information from packets.
+ */
+struct caif_packet_funcs cfcnfg_get_packet_funcs(void);
+
+/** Get physical ID, given type.
+ * @return Returns one of the physical interfaces matching the given type.
+ *	   Zero if no match is found.
+ */
+int cfcnfg_get_phyid(struct cfcnfg *cnfg,
+		     enum cfcnfg_phy_preference phy_pref);
+
+/** Get physical ID, given name.
+ * @return Returns the physical interface matching the specified name.
+ */
+int cfcnfg_get_named(struct cfcnfg *cnfg, char *name);
+
+int cfcnfg_instanciate(struct cfcnfg *cnfg,
+		       struct cfcnfg_phy_config *phy_config);
+int cfcnfg_instanciate2(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
+			uint8 instance, char *name, bool checksum,
+			enum cfcnfg_phy_preference pref,
+			struct cfcnfg_phy_param *param);
+int cfcnfg_delete_phy_inst(struct cfcnfg *cfg, char *name);
+int cfcnfg_unregister_phy_type(struct cfcnfg *cfg,
+			       enum cfcnfg_phy_type type);
+int cfcnfg_register_phy_type(struct cfcnfg *cfg,
+			     struct cfcnfg_phy_mgmt *mgmt);
+int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct layer *phy_layer);
+
+/*! @} */
+#endif				/* CFCNFG_H_ */
diff --git a/include/net/caif/generic/cfctrl.h b/include/net/caif/generic/cfctrl.h
new file mode 100644
index 0000000..8d0fcc3
--- /dev/null
+++ b/include/net/caif/generic/cfctrl.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFCTRL_H_
+#define CFCTRL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfsrvl.h>
+
+/* CAIF Control packet commands*/
+enum cfctrl_cmd {
+	CFCTRL_CMD_LINK_SETUP = 0,
+	CFCTRL_CMD_LINK_DESTROY = 1,
+	CFCTRL_CMD_LINK_ERR = 2,
+	CFCTRL_CMD_ENUM = 3,
+	CFCTRL_CMD_SLEEP = 4,
+	CFCTRL_CMD_WAKE = 5,
+	CFCTRL_CMD_LINK_RECONF = 6,
+	CFCTRL_CMD_START_REASON = 7,
+	CFCTRL_CMD_RADIO_SET = 8,
+	CFCTRL_CMD_MODEM_SET = 9,
+	CFCTRL_CMD_DATA = 0,
+	CFCTRL_CMD_MASK = 0xf
+};
+
+enum cfctrl_srv {
+	CFCTRL_SRV_DECM = 0,
+	CFCTRL_SRV_VEI = 1,
+	CFCTRL_SRV_VIDEO = 2,
+	CFCTRL_SRV_DBG = 3,
+	CFCTRL_SRV_DATAGRAM = 4,
+	CFCTRL_SRV_RFM = 5,
+	CFCTRL_SRV_UTIL = 6,
+	CFCTRL_SRV_MASK = 0xf
+};
+
+#define CFCTRL_RSP_BIT 0x20
+#define CFCTRL_ERR_BIT 0x10
+
+struct cfctrl_rsp {
+	void (*linksetup_rsp)(struct layer *layer, uint8 linkid,
+			      enum cfctrl_srv serv, uint8 phyid,
+			      struct layer *adapt_layer);
+	void (*linkdestroy_rsp)(struct layer *layer, uint8 linkid,
+				struct layer *client_layer);
+	void (*linkerror_ind)(void);
+	void (*enum_rsp)(void);
+	void (*sleep_rsp)(void);
+	void (*wake_rsp)(void);
+	void (*restart_rsp)(void);
+	void (*radioset_rsp)(void);
+	void (*reject_rsp)(struct layer *layer, uint8 linkid,
+				struct layer *client_layer);;
+};
+
+/** Link Setup Parameters for CAIF-Links. */
+struct cfctrl_link_param {
+	enum cfctrl_srv linktype;/*!< (T3,T0) Type of Channel */
+	uint8 priority;		  /*!< (P4,P0) Priority of the channel */
+	uint8 phyid;		  /*!< (U2-U0) Physical interface to connect */
+	uint8 endpoint;		  /*!< (E1,E0) Endpoint for data channels */
+	uint8 chtype;		  /*!< (H1,H0) Channel-Type, applies to
+				   *            VEI, DEBUG */
+	union {
+		struct {
+			uint8 connid;	/*!<  (D7,D0) Video LinkId */
+		} video;
+
+		struct {
+			uint32 connid;	/*!< (N31,Ngit0) Connection ID used
+					 *    for Datagram */
+		} datagram;
+
+		struct {
+			uint32 connid;	/*!< Connection ID used for RFM */
+			char volume[20];	/*!< Volume to mount for RFM */
+		} rfm;		/*!< Configuration for RFM */
+
+		struct {
+			uint16 fifosize_kb;	/*!< Psock FIFO size in KB */
+			uint16 fifosize_bufs;	/*!< Psock # signal buffers */
+			char name[16];	/*!< Name of the PSOCK service */
+			uint8 params[255];	/*!< Link setup Parameters> */
+			uint16 paramlen;	/*!< Length of Link Setup
+						 *   Parameters */
+		} utility;	/*!< Configuration for Utility Links (Psock) */
+	} u;
+};
+
+/** This structure is used internally in CFCTRL */
+struct cfctrl_request_info {
+	int sequence_no;
+	enum cfctrl_cmd cmd;
+	uint8 channel_id;
+	struct cfctrl_link_param param;
+	struct cfctrl_request_info *next;
+	struct layer *client_layer;
+};
+
+struct cfctrl {
+	struct cfsrvl serv;
+	struct cfctrl_rsp res;
+	cfglu_atomic_t req_seq_no;
+	cfglu_atomic_t rsp_seq_no;
+	struct cfctrl_request_info *first_req;
+	cfglu_lock_t info_list_lock;
+#ifndef CAIF_NO_LOOP
+	uint8 loop_linkid;
+	int loop_linkused[256];
+	cfglu_lock_t loop_linkid_lock;
+#endif
+
+};
+
+void cfctrl_enum_req(struct layer *cfctrl, uint8 physlinkid);
+void cfctrl_linkup_request(struct layer *cfctrl,
+			   struct cfctrl_link_param *param,
+			   struct layer *user_layer);
+int  cfctrl_linkdown_req(struct layer *cfctrl, uint8 linkid,
+			 struct layer *client);
+void cfctrl_sleep_req(struct layer *cfctrl);
+void cfctrl_wake_req(struct layer *cfctrl);
+void cfctrl_getstartreason_req(struct layer *cfctrl);
+struct layer *cfctrl_create(void);
+void cfctrl_set_dnlayer(struct layer *this, struct layer *dn);
+void cfctrl_set_uplayer(struct layer *this, struct layer *up);
+void cfctrl_set_respfuncs(struct layer *this,
+			  struct cfctrl_rsp *respfuncs);
+bool cfctrl_req_eq(struct cfctrl_request_info *r1,
+		   struct cfctrl_request_info *r2);
+void cfctrl_insert_req(struct cfctrl *ctrl,
+			      struct cfctrl_request_info *req);
+struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
+					      struct cfctrl_request_info *req);
+#endif				/* CFCTRL_H_ */
diff --git a/include/net/caif/generic/cffrml.h b/include/net/caif/generic/cffrml.h
new file mode 100644
index 0000000..b946111
--- /dev/null
+++ b/include/net/caif/generic/cffrml.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFFRM_H_
+#define CFFRM_H_
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cflst.h>
+
+struct cffrml;
+
+struct layer *cffrml_create(uint16 phyid, bool DoFCS);
+void cffrml_set_uplayer(struct layer *this, struct layer *up);
+void cffrml_set_dnlayer(struct layer *this, struct layer *dn);
+void cffrml_destroy(struct layer *layer);
+
+#endif				/* CFFRM_H_ */
diff --git a/include/net/caif/generic/cfglue.h b/include/net/caif/generic/cfglue.h
new file mode 100644
index 0000000..c84d39c
--- /dev/null
+++ b/include/net/caif/generic/cfglue.h
@@ -0,0 +1,174 @@
+/*
+ * This file contains the OS and HW dependencies for CAIF.
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFGLU_H_
+#define CFGLU_H_
+
+/*! \addtogroup GenCaifGlue
+ *  Additional documentation for group `GenCaifGlue'
+ *  @{
+ */
+
+#define CFLOG_LEVEL_ERROR   1
+#define CFLOG_LEVEL_WARNING 2
+#define CFLOG_LEVEL_TRACE   3
+#define CFLOG_LEVEL_TRACE2  4
+#define CFLOG_LEVEL_TRACE3  5
+#define CFLOG_LEVEL_FUNC    6
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include "linux/stddef.h"
+#include "linux/types.h"
+
+/** Unsigned 8 bit */
+typedef __u8 uint8;
+
+/** Unsigned 16 bit */
+typedef __u16 uint16;
+
+/** Unsigned 32 bit */
+typedef __u32 uint32;
+
+/******************************************
+ *  HANDLING ENDIANNES.
+ *  CAIF uses little-endian byte order.
+ ******************************************/
+
+/** CAIF Endian handling Net to Host of 16 bits unsigned */
+#define cfglu_le16_to_cpu(v)  le16_to_cpu(v)
+
+/** CAIF Endian handling Host to Net of 16 bits unsigned */
+#define cfglu_cpu_to_le16(v)  cpu_to_le16(v)
+
+/** CAIF Endian handling Host to Net of 32 bits unsigned */
+#define cfglu_le32_to_cpu(v)  le32_to_cpu(v)
+
+/** CAIF Endian handling Net to Host of 32 bits unsigned */
+#define cfglu_cpu_to_le32(v)  cpu_to_le32(v)
+
+extern int caif_dbg_level;
+
+/* LOGGING */
+#define _CFLOG_FATAL(format, args...) \
+	do {if (caif_dbg_level > CFLOG_LEVEL_ERROR) {\
+		printk(KERN_ERR "<%s:%d, FATAL> " format "\n",\
+				__func__, __LINE__ ,  ## args); } } while (0)
+
+#define CFLOG_FATAL(format) _CFLOG_FATAL format
+
+/** CAIF Error Logging. */
+#define _CFLOG_ERROR(format, args...)\
+	do {if (caif_dbg_level > CFLOG_LEVEL_ERROR) {\
+		printk(KERN_ERR "<%s:%d, ERROR> " format "\n",\
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_ERROR(format)  _CFLOG_ERROR format
+
+/** CAIF Warning Logging. */
+#define _CFLOG_WARN(format, args...)\
+	do {if (caif_dbg_level > CFLOG_LEVEL_WARNING) {\
+		printk(KERN_WARNING "<%s:%d, WARN> "  format "\n",\
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#ifdef CAIF_DEBUG_ON
+#define CFLOG_WARN(format)   _CFLOG_WARN format
+
+/** CAIF Trace Control Logging. Level 1 control trace (Channel setup etc) */
+#define _CFLOG_TRACE(format, args...)  \
+	do { if (caif_dbg_level > CFLOG_LEVEL_TRACE) {\
+		printk(KERN_INFO "<%s:%d, TRACE> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_TRACE(format)  _CFLOG_TRACE format
+
+/** CAIF Trace Payload Logging. Level payload trace */
+#define _CFLOG_TRACE2(format, args...) \
+	do {if (caif_dbg_level > CFLOG_LEVEL_TRACE2) {\
+		printk(KERN_INFO "<%s:%d, TRACE2> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_TRACE2(format) _CFLOG_TRACE2 format
+
+/** CAIF Trace Detailed Logging including packet dumps */
+#define _CFLOG_TRACE3(format, args...)\
+	do {if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {\
+		printk(KERN_INFO "<%s:%d, TRACE3> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_TRACE3(format) _CFLOG_TRACE3 format
+
+/** CAIF Trace Entering Function */
+#define _CFLOG_ENTER(format, args...) \
+	do {if (caif_dbg_level > CFLOG_LEVEL_FUNC) {\
+		printk("KERN_INFO <%s:%d, ENTER> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+#define CFLOG_ENTER(format)  _CFLOG_ENTER format
+
+/** CAIF Trace Exiting Function */
+
+#define _CFLOG_EXIT(format, args...)  \
+	do {if (caif_dbg_level > CFLOG_LEVEL_FUNC) {\
+		printk("KERN_INFO <%s:%d, EXIT> "  format "\n",\
+				__func__, __LINE__ ,  ## args); } }  while (0)
+#define CFLOG_EXIT(format)   _CFLOG_EXIT format
+
+#else
+
+#define CFLOG_WARN(args)
+#define CFLOG_TRACE(args)
+#define CFLOG_TRACE2(args)
+#define CFLOG_TRACE3(args)
+#define CFLOG_ENTER(args)
+#define CFLOG_EXIT(args)
+
+#endif
+
+/* Critical Section support, one thread only between startsync
+ * and endsync
+ */
+#define cfglu_lock_t spinlock_t
+#define cfglu_init_lock(sync) spin_lock_init(&(sync))
+#define cfglu_lock(sync) spin_lock_bh(&(sync))
+#define cfglu_unlock(sync) spin_unlock_bh(&(sync))
+#define cfglu_deinit_lock(sync)
+
+/* Atomic counting */
+#define cfglu_atomic_t atomic_t
+#define cfglu_atomic_read(a) atomic_read(&a)
+#define cfglu_atomic_set(a, val) atomic_set(&a, val)
+#define cfglu_atomic_inc(a) atomic_inc(&a)
+#define cfglu_atomic_dec(a) atomic_dec(&a)
+
+/* HEAP */
+#define cfglu_alloc(size) kmalloc(size, GFP_ATOMIC)
+#define cfglu_free(ptr) kfree(ptr)
+#define cfglu_container_of(p, t, m) container_of(p, t, m)
+
+/*FIXME: Comment error codes*/
+enum cfglu_errno {
+	CFGLU_EOK = 0,
+	CFGLU_EPKT = -EPROTO,
+	CFGLU_EADDRINUSE = -EADDRINUSE,
+	CFGLU_EIO = -EIO,
+	CFGLU_EFCS = -EILSEQ,
+	CFGLU_EBADPARAM = -EINVAL,
+	CFGLU_EINVAL = -EINVAL,
+	CFGLU_ENODEV = -ENODEV,
+	CFGLU_ENOTCONN = -ENOTCONN,
+	CFGLU_EPROTO = -EPROTO,
+	CFGLU_EOVERFLOW = -EOVERFLOW,
+	CFGLU_ENOMEM = -ENOMEM,
+	CFGLU_ERETRY = -EAGAIN,
+	CFGLU_ENOSPC = -ENOSPC,
+	CFGLU_ENXIO = -ENXIO
+};
+
+#endif				/* CFGLU_H_ */
diff --git a/include/net/caif/generic/cfloopcfg.h b/include/net/caif/generic/cfloopcfg.h
new file mode 100644
index 0000000..3cffd73
--- /dev/null
+++ b/include/net/caif/generic/cfloopcfg.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFLOOPCFG_H_
+#define CFLOOPCFG_H_
+#include <net/caif/generic/caif_layer.h>
+
+struct cfloopcfg *cfloopcfg_create(void);
+void cfloopcfg_add_phy_layer(struct cfloopcfg *cnfg,
+			     enum cfcnfg_phy_type phy_type,
+			     struct layer *phy_layer);
+struct layer *cflooplayer_create(void);
+#endif				/* CFLOOPCFG_H_ */
diff --git a/include/net/caif/generic/cflst.h b/include/net/caif/generic/cflst.h
new file mode 100644
index 0000000..29e4d33
--- /dev/null
+++ b/include/net/caif/generic/cflst.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFLST_H_
+#define CFLST_H_
+
+#include <net/caif/generic/cfglue.h>
+
+bool cflst_put(struct layer **lst, uint8 id, struct layer *node);
+struct layer *cflst_get(struct layer **lst, uint8 id);
+struct layer *cflst_del(struct layer **lst, uint8 id);
+#define CFLST_FIRST(lst) lst
+#define CFLST_MORE(node) ((node) != NULL)
+#define CFLST_NEXT(node) ((node)->next)
+void cflst_init(struct layer **lst);
+#endif				/* CFLST_H_ */
diff --git a/include/net/caif/generic/cfmsll.h b/include/net/caif/generic/cfmsll.h
new file mode 100644
index 0000000..4339af8
--- /dev/null
+++ b/include/net/caif/generic/cfmsll.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFMSLL_H_
+#define CFMSLL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+struct layer *cfmsll_create(int type, int instance);
+
+#endif				/* CFMSLL_H_ */
diff --git a/include/net/caif/generic/cfmuxl.h b/include/net/caif/generic/cfmuxl.h
new file mode 100644
index 0000000..0790574
--- /dev/null
+++ b/include/net/caif/generic/cfmuxl.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFMUXL_H_
+#define CFMUXL_H_
+#include <net/caif/generic/caif_layer.h>
+
+struct cfsrvl;
+struct cffrml;
+
+struct layer *cfmuxl_create(void);
+bool cfmuxl_set_uplayer(struct layer *layr, struct layer *up, uint8 linkid);
+struct layer *cfmuxl_remove_dnlayer(struct layer *layr, uint8 phyid);
+bool cfmuxl_set_dnlayer(struct layer *layr, struct layer *up, uint8 phyid);
+struct layer *cfmuxl_remove_uplayer(struct layer *layr, uint8 linkid);
+bool cfmuxl_is_phy_inuse(struct layer *layr, uint8 phyid);
+uint8 cfmuxl_get_phyid(struct layer *layr, uint8 channel_id);
+
+#endif				/* CFMUXL_H_ */
diff --git a/include/net/caif/generic/cfpkt.h b/include/net/caif/generic/cfpkt.h
new file mode 100644
index 0000000..874f09b
--- /dev/null
+++ b/include/net/caif/generic/cfpkt.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFPKT_H_
+#define CFPKT_H_
+#include <net/caif/generic/caif_layer.h>
+
+struct cfpkt;
+/*! \addtogroup GenCaifGlue
+ *  Additional documentation for group `GenCaifGlue'
+ *  @{
+ */
+
+/** Checksum iteration function used to iterate buffers
+ * (we may have packets consisting of a chain of buffers)
+ * @param chs Checksum calculated so far.
+ * @param buf Pointer to the buffer to checksum
+ * @param len Length of buf.
+ * @return Checksum of buffer
+ */
+typedef uint16(*iterfunc_t)(uint16 chks, void *buf, uint16 len);
+
+struct caif_packet_funcs caif_get_packet_funcs(void);
+
+/** Create a CAIF packet.
+ * @param len Length of packet to be created
+ * @return New packet.
+ */
+struct cfpkt *cfpkt_create(uint16 len);
+
+/**
+ * Destroy a CAIF Packet.
+ * @param pkt Packet to be destoyed.
+ */
+void cfpkt_destroy(struct cfpkt *pkt);
+
+/**
+ * Extract header from packet.
+ *
+ * @param pkt Packet to extract header data from.
+ * @param data Pointer to copy the header data into.
+ * @param len Length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_extr_head(struct cfpkt *pkt, void *data, uint16 len);
+
+/**
+ * Peek header from packet.
+ * Reads data from packet without changing packet.
+ *
+ * @param pkt Packet to extract header data from.
+ * @param data Pointer to copy the header data into.
+ * @param len Length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_peek_head(struct cfpkt *pkt, void *data, uint16 len);
+
+/**
+ * Extract header from trailer (end of packet).
+ *
+ * @param pkt Packet to extract header data from.
+ * @param data Pointer to copy the trailer data into.
+ * @param len Length of header data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_extr_trail(struct cfpkt *pkt, void *data, uint16 len);
+
+/**
+ * Add header to packet.
+ *
+ *
+ * @param pkt Packet to add header data to.
+ * @param data Pointer to data to copy into the header.
+ * @param len Length of header data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_add_head(struct cfpkt *pkt, const void *data, uint16 len);
+
+/**
+ * Add trailer to packet.
+ *
+ *
+ * @param pkt Packet to add trailer data to.
+ * @param data Pointer to data to copy into the trailer.
+ * @param len Length of trailer data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_add_trail(struct cfpkt *pkt, const void *data, uint16 len);
+
+/**
+ * Pad trailer on packet.
+ * Moves data pointer in packet, no content copied.
+ *
+ * @param pkt Packet in which to pad trailer.
+ * @param len Length of padding to add.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_pad_trail(struct cfpkt *pkt, uint16 len);
+
+/**
+ * Add a single byte to packet body (tail).
+ *
+ * @param pkt Packet in which to add byte.
+ * @param data Byte to add.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_addbdy(struct cfpkt *pkt, const uint8 data);
+
+/**
+ * Add a data to packet body (tail).
+ *
+ * @param pkt Packet in which to add data.
+ * @param data Pointer to data to copy into the packet body.
+ * @param len Length of data to add.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_add_body(struct cfpkt *pkt, const void *data, uint16 len);
+
+/**
+ * Checks whether there are more data to process in packet.
+ * @param pkt Packet to check.
+ * @return \ref true if more data are available in packet \ref false if no more data can be extracted
+ */
+bool cfpkt_more(struct cfpkt *pkt);
+
+/**
+ * Checks whether the packet is erroneous, i.e. if it has been attempted to extract more data than available in packet
+ * or writing more data than has been allocated in \ref cfpkt_create().
+ * @param pkt Packet to check.
+ * @return \ref true on error \ref false otherwise
+ */
+bool cfpkt_erroneous(struct cfpkt *pkt);
+
+/**
+ * Get the packet length.
+ * @param pkt Packet to get length from.
+ * @return Number of bytes in packet.
+ */
+uint16 cfpkt_getlen(struct cfpkt *pkt);
+
+/**
+ * Set the packet length, by adjusting the trailer pointer according to length.
+ * @param pkt Packet to set length.
+ * @param len Packet length.
+ * @return Number of bytes in packet.
+ */
+int cfpkt_setlen(struct cfpkt *pkt, uint16 len);
+
+/**
+ * Appends a packet's data to another packet.
+ * NB: Input packets will be destroyed after appending and cannot be used
+ * after calling this function.
+ * @param dstpkt Packet to append data into, WILL BE FREED BY THIS FUNCTION
+ * @param addpkt Packet to be appended and automatically released, WILL BE FREED BY THIS FUNCTION.
+ * @param expectlen Packet's expected total length. This should be considered as a hint.
+ * @return The new appended packet.
+ */
+struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt,
+		      uint16 expectlen);
+
+/**
+ * Split a packet into two packets at the specified split point.
+ * @param pkt Packet to be split (will contain the first part of the data on exit)
+ * @param pos Position to split packet in two parts.
+ * @return The new packet, containing the second part of the data.
+ */
+struct cfpkt *cfpkt_split(struct cfpkt *pkt, uint16 pos);
+
+/** Iteration function, iterates the packet buffers from start to end.*/
+uint16 cfpkt_iterate(struct cfpkt *pkt, iterfunc_t func, uint16 data);
+
+void
+cfpkt_extract(struct cfpkt *cfpkt, void *buf, unsigned int buflen,
+	      unsigned int *actual_len);
+
+/** Append by giving user access to packet buffer
+ * @param pkt Packet to append to
+ * @param buf Buffer inside pkt that user shall copy data into
+ * @param buflen Length of buffer and number of bytes added to packet
+ * @return 0 on error, 1 on success
+ */
+int cfpkt_raw_append(struct cfpkt *cfpkt, void **buf, unsigned int buflen);
+
+/** Extract by giving user access to packet buffer
+ * @param pkt Packet to extract from
+ * @param buf Buffer inside pkt that user shall copy data from
+ * @param buflen Length of buffer and number of bytes removed from packet
+ * @return 0 on error, 1 on success
+ */
+int cfpkt_raw_extract(struct cfpkt *cfpkt, void **buf, unsigned int buflen);
+
+/** Map from a "native" packet (e.g. Linux Socket Buffer) to a CAIF packet.
+ *  @param dir - Direction indicating whether this packet is to be sent or received.
+ *  @param nativepkt  - The native packet to be transformed to a CAIF packet
+ *  @return The mapped CAIF Packet CFPKT.
+ */
+struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt);
+
+/** Map from a CAIF packet to a "native" packet (e.g. Linux Socket Buffer).
+ *  @param pkt  - The CAIF packet to be transformed into a "native" packet.
+ *  @return The native packet transformed from a CAIF packet.
+ */
+void *cfpkt_tonative(struct cfpkt *pkt);
+
+struct caif_packet_funcs cfpkt_get_packet_funcs(void);
+
+/**
+ * Insert a packet in the packet queue.
+ * @param pkt Packet to be inserted in queue
+ * @param pktq Packet queue to insert into
+ * @param prio Priority of packet
+ */
+void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt,
+		 unsigned short prio);
+
+/**
+ * Remove a packet from the packet queue.
+ * @param pktq Packet queue to fetch packets from.
+ * @return Dequeued packet.
+ */
+struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq);
+
+/**
+ * Peek into a packet from the packet queue.
+ * @param pktq Packet queue to fetch packets from.
+ * @return Peeked packet.
+ */
+struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq);
+
+/**
+ * Initiates the packet queue.
+ * @return Pointer to new packet queue.
+ */
+struct cfpktq *cfpktq_create(void);
+
+/**
+ * Get the number of packets in the queue.
+ * @param pktq Packet queue to fetch count from.
+ * @return Number of packets in queue.
+ */
+int cfpkt_qcount(struct cfpktq *pktq);
+
+/**
+ * Put content of packet into buffer for debuging purposes.
+ * @param pkt Packet to copy data from
+ * @param buf Buffer to copy data into
+ * @param buflen Length of data to copy
+ * @return Pointer to copied data
+ */
+char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen);
+
+/**
+ * Clones a packet and releases the original packet.
+ * This is used for taking ownership of a packet e.g queueing.
+ * @param pkt Packet to clone and release.
+ * @return Cloned packet.
+ */
+struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt);
+
+/*! @} */
+#endif				/* CFPKT_H_ */
diff --git a/include/net/caif/generic/cfserl.h b/include/net/caif/generic/cfserl.h
new file mode 100644
index 0000000..794ee85
--- /dev/null
+++ b/include/net/caif/generic/cfserl.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFSERL_H_
+#define CFSERL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+
+/**
+ * This variable is used as a global flag, in order to set whether STX is
+ * used on serial communication.
+ * NOTE: This is not a fully future proof solution.
+ */
+extern int serial_use_stx;
+struct layer *cfserl_create(int type, int instance, bool use_stx);
+
+#endif				/* CFSERL_H_ */
diff --git a/include/net/caif/generic/cfshml.h b/include/net/caif/generic/cfshml.h
new file mode 100644
index 0000000..0757b02
--- /dev/null
+++ b/include/net/caif/generic/cfshml.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFSHML_H_
+#define CFSHML_H_
+
+struct layer *cfshml_create(int type, int instance);
+
+#endif				/* CFSHML_H_ */
diff --git a/include/net/caif/generic/cfspil.h b/include/net/caif/generic/cfspil.h
new file mode 100644
index 0000000..0145190
--- /dev/null
+++ b/include/net/caif/generic/cfspil.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFSPIL_H_
+#define CFSPIL_H_
+#include <net/caif/generic/cfpkt.h>
+
+struct cfspipad {
+	uint16 up_head_align;	/* Current uplink head alignment: 0 for byte
+				   alignment, 1 for 16bits, 3 for 32bits */
+	uint16 up_tail_align;	/* Current uplink tail alignment: 0 for byte
+				   alignment, 1 for 16bits, 3 for 32bits */
+	uint16 down_head_align;	/* Current downlink head alignment: 0 for byte
+				   alignment, 1 for 16bits, 3 for 32bits */
+	uint16 down_tail_align;	/* Current downlink tail alignment: 0 for byte
+				   alignment, 1 for 16bits, 3 for 32bits */
+};
+
+/* Forward declarations */
+struct cfspil;
+
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+
+
+
+/** @page SPI PHY Layer description.
+ *
+ *  SPI Physical layer is not implemented in GenCaif. The SPI PHY Layer
+ *  is HW dependent. However, the CFSPIL (CAIF SPI Layer) provides support
+ *  for implementing the SPI Layer Protocol.
+ *
+ *  SPI PHY uses a different paradigm for transmit from the rest of GenCaif.
+ *  SPI PHY is pulling packets from CFSPIL. The SPI PHY gets a notification
+ *  about a transfer; it then requests transfer length and data to transfer
+ *  in the following way:
+ *
+ *  -# Wait for transmit request (packet will be \b null pointer), indicating
+ *     GenCaif wants something to be sent to the modem.
+ *  -# Request the transfer length by using function \ref cfspil_xmitlen,
+ *  -# Add CAIF SPI command to SPI transfer.
+ *  -# When SPI is ready for transfer, call \ref cfspil_getxmitpkt to get
+ *      the transfer packet.
+ *  -# Request new transfer length ( \ref cfspil_xmitlen) unless zero
+ *     length is returned.
+ *  -# Wait for next transfer request.
+ *
+ *
+ *   * CFSPIL Specification:
+ * \see { GenCaifSPI }
+ *
+ */
+/*! \addtogroup GenCaifSPI
+ *  Additional documentation for group `GenCaifSPI'
+ *  @{
+ */
+
+/**
+ * Create and initialize SPI layer.
+ */
+struct layer *cfspil_create(int type, int instance, struct cfspipad);
+
+/**
+ *  Check the length of the next SPI frame to send.
+ *  @param layr Pointer to SPI layer
+ *  @return Length of next SPI transfer, 0 if nothing to send.
+ */
+int cfspil_xmitlen(struct cfspil *layr);
+
+/**
+ *  Get the next CAIF SPI frame to send. This packet is guaranteed to have equal size to the
+ *  length given in \ref cfspil_getxmitpkt.
+ *  @param layr Pointer to SPI layer
+ *  @return The CAIF packet to be sent.
+ */
+struct cfpkt *cfspil_getxmitpkt(struct cfspil *layr);
+
+/*! @} */
+
+#endif				/* CFSPIL_H_ */
diff --git a/include/net/caif/generic/cfsrvl.h b/include/net/caif/generic/cfsrvl.h
new file mode 100644
index 0000000..c69f0e7
--- /dev/null
+++ b/include/net/caif/generic/cfsrvl.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFSRVL_H_
+#define CFSRVL_H_
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfglue.h>
+#include <stddef.h>
+
+struct cfsrvl {
+	struct layer layer;
+	/** Physical ID of the logical physical connection */
+	uint8 phid;
+	bool open;
+	bool phy_flow_on;
+	bool modem_flow_on;
+};
+
+struct layer *cfvei_create(uint8 linkid, uint8 phyid);
+struct layer *cfdgml_create(uint8 linkid, uint8 phyid);
+struct layer *cfutill_create(uint8 linkid, uint8 phyid);
+struct layer *cfvidl_create(uint8 linkid, uint8 phyid);
+struct layer *cfrfml_create(uint8 linkid, uint8 phyid);
+bool cfsrvl_phyid_match(struct layer *layer, int phyid);
+void cfservl_destroy(struct layer *layer);
+void cfsrvl_init(struct cfsrvl *service, uint8 channel_id, uint8 phyid);
+bool cfsrvl_ready(struct cfsrvl *service, int *err);
+uint8 cfsrvl_getphyid(struct layer *layer);
+
+#endif				/* CFSRVL_H_ */
diff --git a/include/net/caif/generic/cfusbl.h b/include/net/caif/generic/cfusbl.h
new file mode 100644
index 0000000..cd83b39
--- /dev/null
+++ b/include/net/caif/generic/cfusbl.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFUSBL_H_
+#define CFUSBL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+struct layer *cfusbl_create(int type, int instance);
+
+#endif				/* CFUSBL_H_ */
diff --git a/include/net/caif/generic/fcs.h b/include/net/caif/generic/fcs.h
new file mode 100644
index 0000000..041f5c5
--- /dev/null
+++ b/include/net/caif/generic/fcs.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef FCS_H_
+#define FCS_H_
+
+uint16
+fcs16(uint16 fcs, uint8 *cp, uint16 len);
+
+#endif				/* FCS_H_ */
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  3/8] CAIF Protocol Stack
  2009-11-30 15:00   ` [RFC PATCH v3 2/8] " sjur.brandeland
@ 2009-11-30 15:00     ` sjur.brandeland
  2009-11-30 15:00       ` [RFC PATCH v3 4/8] " sjur.brandeland
  2009-12-15 16:00       ` [RFC PATCH v3 3/8] " stefano babic
  2009-12-09  0:18     ` [RFC PATCH v3 2/8] " stefano babic
  1 sibling, 2 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 include/net/caif/caif_actions.h     |   66 ++++++++
 include/net/caif/caif_chr.h         |   51 ++++++
 include/net/caif/caif_config_util.h |   20 +++
 include/net/caif/caif_dev.h         |   25 +++
 include/net/caif/caif_kernel.h      |  309 +++++++++++++++++++++++++++++++++++
 include/net/caif/caif_log.h         |   88 ++++++++++
 6 files changed, 559 insertions(+), 0 deletions(-)
 create mode 100644 include/net/caif/caif_actions.h
 create mode 100644 include/net/caif/caif_chr.h
 create mode 100644 include/net/caif/caif_config_util.h
 create mode 100644 include/net/caif/caif_dev.h
 create mode 100644 include/net/caif/caif_kernel.h
 create mode 100644 include/net/caif/caif_log.h

diff --git a/include/net/caif/caif_actions.h b/include/net/caif/caif_actions.h
new file mode 100644
index 0000000..535ea90
--- /dev/null
+++ b/include/net/caif/caif_actions.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_ACTION_H_
+#define CAIF_ACTION_H_
+#include <linux/caif/caif_config.h>
+#include <linux/caif/caif_ioctl.h>
+
+#define DEVICE_NAME_LEN 16
+
+/**
+ * Types of physical HW interfaces towards modem defined in the CAIF stack.
+ * Used when CAIF enumerates interfaces and for channel configuration.
+ *
+ * For client convenience, two special types are defined:
+ *  - \ref CAIF_PHY_LOW_LAT is the preferred low-latency physical link.
+ *         Typically used for "control" purposes.
+ *  - \ref CAIF_PHY_HIGH_BW is the preferred high-bandwidth physical link.
+ *         Typically used for "payload" purposes.
+ *  - \ref CAIF_PHY_UNSPECIFIED CAIF stack implementation will assign link
+ *         for you.
+ */
+enum caif_phy_type {
+	CAIF_PHY_UNSPECIFIED = 0x00,	/*!< Default physical interface */
+	CAIF_PHY_SERIAL = 0x10,	/*!< Serial physical interface */
+	CAIF_PHY_SPI = 0x20,	/*!< SPI physical interface */
+	CAIF_PHY_MSL = 0x30,	/*!< MSL physical interface */
+	CAIF_PHY_SHM = 0x40,	/*!< Shared memory interface */
+	CAIF_PHY_USB = 0x50,	/*!< USB interface */
+	CAIF_PHY_LOOP = 0x70,	/*!< Loopback interface simulating
+				 *   modem responses */
+	CAIF_PHY_RAW_LOOP = 0x80,/*!< Raw loopback interface */
+};
+#define CAIF_PHY_MASK  0xf0
+
+/** Query the names of the enumerated CAIF physical interfaces. */
+#define CAIF_ACT_LIST_PHYIFS 	         1	/*struct caif_device_list_action) */
+
+/** Get the physical interface information, given the name. */
+#define CAIF_ACT_GET_PHYIF_INFO 	 2	/*struct caif_phyif_info_action) */
+
+/** Enumerate a physical interface. */
+#define CAIF_ACT_ACTIVATE_PHYIF 		  3	/*struct caif_phy_activate) */
+
+/** Removes (de-enumerates) a physical interface. */
+#define CAIF_ACT_DEACT_DEVICE 		 4	/*struct caif_device_name) */
+
+/** Get the device names of configured devices */
+#define CAIF_ACT_LIST_DEVICE_NAMES 	  5	/*struct caif_device_list_action) */
+
+/** Get configuration and status information for a specified CAIF device */
+#define CAIF_ACT_GET_DEVICE_INFO  	 6	/*struct caif_device_info_action) */
+
+/** Create and Configure a new CAIF device. Note that the device is not
+ * implicitly connected.
+ */
+
+#define CAIF_ACT_CREATE_DEVICE 		 7 /*struct caif_channel_create_action*/
+
+/** Remove a CAIF device. Requires the device to be previously disconnected. */
+#define CAIF_ACT_DELETE_DEVICE           8	/*struct caif_device_name) */
+
+#endif
diff --git a/include/net/caif/caif_chr.h b/include/net/caif/caif_chr.h
new file mode 100644
index 0000000..ebd89f8
--- /dev/null
+++ b/include/net/caif/caif_chr.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_CHR_H_
+#define CAIF_CHR_H_
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfspil.h>
+#include <linux/caif/caif_config.h>
+#include <linux/if.h>
+#include <net/caif/caif_actions.h>
+struct caif_service_config;
+
+enum cf_chr_dev_type {
+	CFDEVTYPE_CHR,
+	CFDEVTYPE_TTY,
+	CFDEVTYPE_NET
+};
+
+extern int serial_use_stx;
+extern int (*netdev_mgmt_func) (int action, union caif_action *param);
+int caifdev_phy_reg(struct layer *phyif, struct cfcnfg_phy_mgmt *mgmt);
+int caifdev_phy_instanciate(struct cfcnfg_phy_config *phy_config);
+int caifdev_phy_register(struct layer *phyif,
+			 enum cfcnfg_phy_type phy_type,
+			 enum cfcnfg_phy_preference phy_pref);
+int caifdev_phy_unregister(struct layer *phyif);
+int caifdev_phy_loop_register(struct layer *phyif,
+			      enum cfcnfg_phy_type phy_type);
+int caifdev_phy_spi_xmitlen(struct cfspil *layr);
+struct cfpkt *caifdev_phy_spi_getxmitpkt(struct cfspil *layr);
+int caifdev_adapt_register(struct caif_channel_config *config,
+			   struct layer *adap_layer);
+int caifdev_adapt_unregister(struct layer *adap_layer);
+
+int caif_register_chrdev(int (*chrdev_mgmt)
+			(int action, union caif_action *param));
+void caif_unregister_chrdev(void);
+int caif_register_netdev(int (*netdev_mgmt)
+			(int action, union caif_action *param));
+void caif_unregister_netdev(void);
+struct cfcnfg *get_caif_conf(void);
+void caif_register_ioctl(int (*ioctl)(unsigned int cmd,
+				      unsigned long arg));
+int caif_ioctl(unsigned int cmd, unsigned long arg);
+#endif				/* CAIF_CHR_H_ */
+
diff --git a/include/net/caif/caif_config_util.h b/include/net/caif/caif_config_util.h
new file mode 100644
index 0000000..cdc1443
--- /dev/null
+++ b/include/net/caif/caif_config_util.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_CONFIG_UTIL_H_
+#define CAIF_CONFIG_UTIL_H_
+
+#include <linux/caif/caif_config.h>
+#include <linux/caif/caif_ioctl.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/caif_actions.h>
+
+int channel_config_2_link_param(struct cfcnfg *cnfg,
+				struct caif_channel_config *s,
+				struct cfctrl_link_param *l);
+
+#endif
diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h
new file mode 100644
index 0000000..12556ba
--- /dev/null
+++ b/include/net/caif/caif_dev.h
@@ -0,0 +1,25 @@
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+
+/* FIXME: Remove when included in include/linux/if_ether.h */
+#ifndef ETH_P_CAIF
+#define ETH_P_CAIF 9
+#endif
+/* FIXME: Remove when included in include/linux/if_arp.h */
+#ifndef ARPHRD_CAIF
+#define ARPHRD_CAIF 823
+#endif
+
+/* FIXME: Remove when included in include/linux/socket.h */
+#ifndef PF_CAIF
+#define PF_CAIF 37
+#endif
+
+struct caif_dev_common {
+	void (*flowctrl)(struct net_device *net, int on);
+	struct module *net_dev_module;
+	atomic_t in_use;
+	int phy_type;
+	int phy_pref;
+};
diff --git a/include/net/caif/caif_kernel.h b/include/net/caif/caif_kernel.h
new file mode 100644
index 0000000..96cbec7
--- /dev/null
+++ b/include/net/caif/caif_kernel.h
@@ -0,0 +1,309 @@
+/*
+ * CAIF Kernel Internal interface for configuring and accessing
+ * CAIF Channels.
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_KERNEL_H_
+#define CAIF_KERNEL_H_
+#include <linux/caif/caif_config.h>
+struct sk_buff;
+
+/*!\page  caif_kernel.h
+ * This is the specification of the CAIF kernel internal interface to
+ * CAIF Channels.
+ * This interface follows the pattern used in Linux device drivers with a
+ *  struct \ref caif_device
+ * holding control data handling each device instance.
+ *
+ * The functional interface consists of a few basic functions:
+ *  - \ref caif_add_device             Configure and connect the CAIF
+ *               channel to the remote end. Configuration is described in
+ *               \ref caif_channel_config.
+ *  - \ref caif_remove_device          Disconnect and remove the channel.
+ *  - \ref caif_transmit               Sends a CAIF message on the link.
+ *  - \ref caif_device.receive_cb      Receive callback function for
+ *                receiving packets.
+ *  - \ref caif_device.control_cb      Control information from the CAIF stack.
+ *  - \ref caif_flow_control           Send flow control message to remote end.
+ *
+ *
+ * Details:
+ * \see { caif_kernel }
+ *
+ * \code
+ *
+#include <net/caif/caif_kernel.h>"
+
+	static void my_receive(struct caif_device *dev, struct sk_buff *skb)
+	{
+	...
+	}
+
+	static void my_control(struct caif_device *dev, enum caif_control ctrl)
+	{
+	....
+	}
+
+	int kernel_caif_usage_example()
+	{
+		struct sk_buff *skb;
+		char *message = "hello";
+
+		// Connect the channel
+		struct caif_device caif_dev = {
+			.caif_config = {
+				.name = "MYDEV",
+				.priority = CAIF_PRIO_NORMAL,
+				.type = CAIF_CHTY_UTILITY,
+				.phy_pref = CAIF_PHYPREF_LOW_LAT,
+				.u.utility.name = "CAIF_PSOCK_TEST",
+				.u.utility.params = {0x01},
+				.u.utility.paramlen = 1,
+		},
+
+		.receive_cb = my_receive,
+		.control_cb = my_control,
+
+		};
+	ret = caif_add_device(&caif_dev);
+	if (ret)
+	goto error;
+
+	// Send a packet
+	skb = caif_create_skb(message, strlen(message));
+	ret = caif_transmit(&caif_dev, skb);
+	if (ret)
+		goto error;
+
+	// Remove device
+	ret = caif_remove_device(&caif_dev);
+	if (ret)
+		goto error;
+
+}
+
+* \endcode
+*
+* \section Linux Socket Buffer (SKB)
+    *          When sending out packets on a connection (\ref caif_transmit)
+    *          the CAIF stack will add CAIF protocol headers.
+    *          This requires space in the SKB.
+    *          CAIF has defined \ref CAIF_SKB_HEAD_RESERVE for minimum
+    *          required reserved head-space in the packet and
+    *          \ref CAIF_SKB_TAIL_RESERVE for minimum reserved tail-space.
+    *
+    *          \b NOTE The Linux kernel SKB operations panic if not
+    *                  enough space is available!
+    *
+    */
+
+    /*! \addtogroup caif_kernel
+     *  @{
+     */
+
+struct caif_device;
+
+	/** Minimum required CAIF socket buffer head-space */
+#define CAIF_SKB_HEAD_RESERVE 32
+
+	/** Minimum required CAIF socket buffer tail-space */
+#define CAIF_SKB_TAIL_RESERVE 32
+
+	/** CAIF control information (used in \ref caif_device.control_cb)
+	 *   used for receiving control information from the modem.
+	 */
+enum caif_control {
+	/** Modem has sent Flow-ON, Clients can start transmitting
+	 *  data using \ref caif_transmit.
+	 */
+	CAIF_CONTROL_FLOW_ON = 0,
+	/** Modem has sent Flow-OFF, Clients must stop transmitting
+	 * data using \ref caif_transmit.
+	 */
+	CAIF_CONTROL_FLOW_OFF = 1,
+
+	/** Channel creation is complete. This is an acknowledgement to
+	 *  \ref caif_add_device from the modem.
+	 *  The channel is ready for transmit (Flow-state is ON).
+	 */
+	CAIF_CONTROL_DEV_INIT = 3,
+
+	/** Spontaneous close request from the modem, only applicable
+	 *   for utility link. The client should respond by calling
+	 *   \ref caif_remove_device.
+	 */
+	CAIF_CONTROL_REMOTE_SHUTDOWN = 4,
+
+	/** Channel disconnect is complete. This is an acknowledgement to
+	 *  \ref caif_remove_device from the modem.
+	 *  \ref caif_transmit or \ref caif_flow_control must not be
+	 *  called after this.
+	 */
+	CAIF_CONTROL_DEV_DEINIT = 5,
+
+	/** Channel creation has failed. This is a negative acknowledgement
+	 *  to \ref caif_add_device from the modem.
+	 */
+	CAIF_CONTROL_DEV_INIT_FAILED = 6
+};
+
+/** Flow control information (used in \ref caif_device.control_cb) used
+ *  for controlling outgoing flow.
+ */
+enum caif_flowctrl {
+	/** Flow Control is ON, transmit function can start sending data */
+	CAIF_FLOWCTRL_ON = 0,
+	/** Flow Control is OFF, transmit function should stop sending data */
+	CAIF_FLOWCTRL_OFF = 1,
+};
+
+/** Transmits CAIF packets on channel.
+ * This function is non-blocking and safe to use in tasklet context.
+ * The CAIF stack takes ownership of the socket buffer (SKB) after calling
+ * \ref caif_transmit.
+ * This means that the user cannot access the SKB afterwards; this applies
+ * even in error situations.
+ *
+ * @return 0 on success, < 0 upon error.
+ *
+ * @param[in] skb         Socket buffer holding data to be written.
+ * @param[in] dev         Structure used when creating the channel
+ *
+ *
+ * Error codes:
+ *  - \b ENOTCONN,   The channel is not connected.
+ *  - \b EPROTO,     Protocol error (or SKB is faulty)
+ *  - \b EIO         IO error (unspecified error)
+ */
+int caif_transmit(struct caif_device *dev, struct sk_buff *skb);
+
+/** Function for sending flow ON / OFF to remote end.
+ * This function is non-blocking and safe to use in tasklet context.
+ *
+ * @param[in] dev        Reference to device data.
+ * @param[in] flow       Flow control information.
+
+ * @return 0 on success, < 0 upon error.
+ * Error codes:
+ *  - \b ENOTCONN,   The channel is not connected.
+ *  - \b EPROTO,     Protocol error.
+ *  - \b EIO         IO error (unspecified error).
+ */
+int caif_flow_control(struct caif_device *dev, enum caif_flowctrl flow);
+
+/** Handle for kernel internal CAIF channels.
+ * All fields in this structure must be filled in by client before calling
+ * \ref caif_add_device (except _caif_handle).
+ */
+struct caif_device {
+
+    /** Channel configuration parameter. Contains information about type
+     *	and configuration of the channel.
+     *  This must be set before calling \ref caif_add_device.
+     */
+	struct caif_channel_config caif_config;
+
+
+    /** Callback function for receiving CAIF Packets from channel.
+     * This callback is called from softirq context (tasklet).
+     * The receiver <b> must </b> free the SKB.
+     * <b> DO NOT BLOCK IN THIS FUNCTION! </b>
+     *
+     * If the client has to do blocking operations then
+     * it must start its own work queue (or kernel thread).
+     *
+     * @param[in] dev       Reference to device data.
+     * @param[in] skb       Socket buffer with received data.
+     */
+	void (*receive_cb) (struct caif_device *dev, struct sk_buff *skb);
+
+
+    /** Callback function for notifying flow control from remote end - see
+     *  \ref caif_control.
+     * This callback is called from from softirq context (tasklet).
+     *
+     * <b> DO NOT BLOCK IN THIS FUNCTION! </b>
+     *
+     * Client must not call \ref caif_transmit from this function.
+     *
+     * If the client has queued packets to send then
+     * it must start its own thread to do \ref caif_transmit.
+     *
+     * @param[in] dev        Reference to device data.
+     * @param[in] ctrl       CAIF control info \ref caif_control.
+     *                       e.g. Flow control
+     *                       \ref CAIF_CONTROL_FLOW_ON or
+     *                       \ref CAIF_CONTROL_FLOW_OFF
+     */
+	void (*control_cb) (struct caif_device *dev, enum caif_control ctrl);
+
+    /** This is a CAIF private attribute, holding CAIF internal reference
+     * to the CAIF stack. Do not update this field.
+     */
+	void *_caif_handle;
+
+    /** This field may be filled in by client for their own usage. */
+	void *user_data;
+};
+
+/** Add (connect) a CAIF Channel.
+ * This function is non-blocking. The channel connect is reported in
+ * \ref caif_device.control_cb.
+ * The channel is not open until \ref caif_device.control_cb is called with
+ * \ref CAIF_CONTROL_DEV_INIT.
+ * If setting up the channel fails then \ref caif_device.control_cb is called
+ * with \ref CAIF_CONTROL_DEV_INIT_FAILED.
+ *
+ * \ref caif_transmit, \ref caif_flow_control or \ref caif_remove_device must
+ * not be called before receiveing CAIF_CONTROL_DEV_INIT.
+ * @return 0 on success, < 0 on failure.
+ *
+ * Error codes:
+ * - \b -EINVAL    Invalid arguments
+ * - \b -ENODEV    No PHY device exists.
+ * - \b -EIO       IO error (unspecified error)
+ */
+int caif_add_device(struct caif_device *dev);
+
+/** Disconnect a CAIF Channel
+ * This function is non-blocking.
+ * The channel has not been disconnected until \ref caif_device : control_cb is
+ * called with \ref CAIF_CONTROL_DEV_DEINIT.
+ * \ref caif_transmit or \ref caif_flow_control \b must not be called after
+ * receiving \ref CAIF_CONTROL_DEV_DEINIT.
+ * The client is responsible for freeing the \ref caif_device structure after
+ * receiving  \ref CAIF_CONTROL_DEV_DEINIT (if applicable).
+ * @return 0 on success.
+ *
+ * - \b EIO       IO error (unspecified error)
+ */
+int caif_remove_device(struct caif_device *caif_dev);
+
+/** Convenience function for allocating a socket buffer for usage with CAIF
+ * and copy user data into the socket buffer.
+ * @param[in] data 		User data to send with CAIF.
+ * @param[in] data_length 	Length of data to send.
+ * @return 	New socket buffer containing user data.
+ */
+struct sk_buff *caif_create_skb(unsigned char *data, unsigned int data_length);
+
+/** Convenience function for extracting data from a socket buffer (SKB) and
+ *  then destroying the SKB.
+ *  Copies data from the SKB and then frees the SKB.
+ * @param[in] skb	SKB to extract data from. SKB will be freed after
+ *			extracting data.
+ *
+ * @param[in] data	User data buffer to extract packet data into.
+ * @param[in] max_length User data buffer length,
+ * @return number of bytes extracted; < 0 upon error.
+ *
+ */
+int caif_extract_and_destroy_skb(struct sk_buff *skb, unsigned char *data,
+				 unsigned int max_length);
+
+/*! @} */
+
+#endif				/* CAIF_KERNEL_H_ */
diff --git a/include/net/caif/caif_log.h b/include/net/caif/caif_log.h
new file mode 100644
index 0000000..bbdead0
--- /dev/null
+++ b/include/net/caif/caif_log.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_LOG_H_
+#define CAIF_LOG_H_
+
+extern int caif_dbg_level;
+
+#define CAIFLOG_ON 1
+
+#define CAIFLOG_MIN_LEVEL     1
+#define CAIFLOG_LEVEL_ERROR   1
+#define CAIFLOG_LEVEL_WARNING 2
+#define CAIFLOG_LEVEL_TRACE   3
+#define CAIFLOG_LEVEL_TRACE2  4
+#define CAIFLOG_LEVEL_TRACE3  5
+#define CAIFLOG_LEVEL_FUNC    6
+#define CAIFLOG_MAX_LEVEL     7
+
+
+/** Fatal error condition, halt the kernel */
+#define CAIFLOG_FATAL(format, args...) do if ( \
+	caif_dbg_level > CAIFLOG_LEVEL_ERROR)  \
+	printk(KERN_ERR "<%s:%d, FATAL> " format, __func__, __LINE__ , \
+	## args);\
+  while (0)
+
+/** CAIF error logging. */
+#define CAIFLOG_ERROR(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_ERROR)  \
+printk(KERN_ERR "<%s:%d, ERROR> " format, __func__, __LINE__ , ## args);\
+  while (0)
+
+/** CAIF warning logging. */
+#define CAIFLOG_WARN(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_WARNING)	 \
+printk(KERN_WARNING "<%s:%d, WARN> "  format, __func__, __LINE__ , ## args);\
+  while (0)
+
+/** CAIF trace control logging. Level 1 control trace (channel setup, etc.) */
+#define CAIFLOG_TRACE(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_TRACE)  \
+printk(KERN_WARNING "<%s:%d, TRACE> " format, __func__, __LINE__ , ## args); \
+ while (0)
+
+/** CAIF trace payload logging. Level payload trace */
+#define CAIFLOG_TRACE2(format, args...) do if ( \
+caif_dbg_level > CAIFLOG_LEVEL_TRACE2)	\
+printk(KERN_WARNING "<%s:%d, TRACE2> " format, __func__, __LINE__ , ## args);\
+  while (0)
+
+/** CAIF trace detailed logging, including packet dumps */
+#define CAIFLOG_TRACE3(format, args...) do if ( \
+caif_dbg_level > CAIFLOG_LEVEL_TRACE3)	\
+printk(KERN_WARNING "<%s:%d, TRACE3> " format, __func__, __LINE__ , ## args); \
+ while (0)
+
+/** CAIF trace entering function */
+#define CAIFLOG_ENTER(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_FUNC)  \
+printk(KERN_WARNING "<%s:%d, ENTER> " format, __func__, __LINE__ , ## args); \
+ while (0)
+
+/** CAIF trace exiting function */
+#define CAIFLOG_EXIT(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_FUNC)  \
+printk(KERN_WARNING "<%s:%d, EXIT> "  format, __func__, __LINE__ , ## args);\
+  while (0)
+
+#define IF_CAIF_TRACE(cmd) do if (caif_dbg_level > CAIFLOG_LEVEL_TRACE)\
+ { cmd; } \
+  while (0)
+
+/** Assert condition, halt the kernel */
+#define CAIFLOG_ASSERT(format, args...)  do if (caif_dbg_level >= 0) \
+printk(KERN_ERR "<%s:%d, FATAL> " format, __func__, __LINE__ , ## args); \
+  while (0)
+
+#define caif_assert(assert)\
+do if (!(assert)) { \
+	CAIFLOG_ASSERT("ASSERT CONDITION DETECTED:'%s'\n", #assert); \
+	BUG_ON(!(assert));\
+} while (0)
+
+#endif				/*CAIF_LOG_H_ */
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  4/8] CAIF Protocol Stack
  2009-11-30 15:00     ` [RFC PATCH v3 3/8] " sjur.brandeland
@ 2009-11-30 15:00       ` sjur.brandeland
  2009-11-30 15:00         ` [RFC PATCH v3 5/8] " sjur.brandeland
  2009-12-15 16:47         ` [RFC PATCH v3 4/8] " stefano babic
  2009-12-15 16:00       ` [RFC PATCH v3 3/8] " stefano babic
  1 sibling, 2 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 net/caif/generic/cfcnfg.c       |  560 ++++++++++++++++++++++++++++++
 net/caif/generic/cfctrl.c       |  685 ++++++++++++++++++++++++++++++++++++
 net/caif/generic/cfdgml.c       |  115 ++++++
 net/caif/generic/cffrml.c       |  149 ++++++++
 net/caif/generic/cflist.c       |   88 +++++
 net/caif/generic/cfloopcfg.c    |  103 ++++++
 net/caif/generic/cflooplayer.c  |  109 ++++++
 net/caif/generic/cfmsll.c       |   52 +++
 net/caif/generic/cfmuxl.c       |  247 +++++++++++++
 net/caif/generic/cfpkt_skbuff.c |  726 +++++++++++++++++++++++++++++++++++++++
 net/caif/generic/cfrfml.c       |  112 ++++++
 net/caif/generic/cfserl.c       |  292 ++++++++++++++++
 net/caif/generic/cfshml.c       |   63 ++++
 net/caif/generic/cfspil.c       |  344 ++++++++++++++++++
 net/caif/generic/cfsrvl.c       |  181 ++++++++++
 net/caif/generic/cfusbl.c       |   51 +++
 net/caif/generic/cfutill.c      |  109 ++++++
 net/caif/generic/cfveil.c       |  113 ++++++
 net/caif/generic/cfvidl.c       |   62 ++++
 net/caif/generic/fcs.c          |   51 +++
 20 files changed, 4212 insertions(+), 0 deletions(-)
 create mode 100644 net/caif/generic/cfcnfg.c
 create mode 100644 net/caif/generic/cfctrl.c
 create mode 100644 net/caif/generic/cfdgml.c
 create mode 100644 net/caif/generic/cffrml.c
 create mode 100644 net/caif/generic/cflist.c
 create mode 100644 net/caif/generic/cfloopcfg.c
 create mode 100644 net/caif/generic/cflooplayer.c
 create mode 100644 net/caif/generic/cfmsll.c
 create mode 100644 net/caif/generic/cfmuxl.c
 create mode 100644 net/caif/generic/cfpkt_skbuff.c
 create mode 100644 net/caif/generic/cfrfml.c
 create mode 100644 net/caif/generic/cfserl.c
 create mode 100644 net/caif/generic/cfshml.c
 create mode 100644 net/caif/generic/cfspil.c
 create mode 100644 net/caif/generic/cfsrvl.c
 create mode 100644 net/caif/generic/cfusbl.c
 create mode 100644 net/caif/generic/cfutill.c
 create mode 100644 net/caif/generic/cfveil.c
 create mode 100644 net/caif/generic/cfvidl.c
 create mode 100644 net/caif/generic/fcs.c

diff --git a/net/caif/generic/cfcnfg.c b/net/caif/generic/cfcnfg.c
new file mode 100644
index 0000000..5ebcb50
--- /dev/null
+++ b/net/caif/generic/cfcnfg.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/generic/cfmuxl.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/generic/cfserl.h>
+#include <net/caif/generic/cfspil.h>
+#include <net/caif/generic/cfshml.h>
+#include <net/caif/generic/cfmsll.h>
+#include <net/caif/generic/cfusbl.h>
+#include <net/caif/generic/cfsrvl.h>
+
+#include <linux/module.h>
+
+#define MAX_PHY_LAYERS 7
+#define PHY_NAME_LEN 20
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfcnfg, layer)
+
+/* Information about CAIF physical interfaces held by Config Module in order
+ * to manage physical interfaces
+ */
+struct cfcnfg_phyinfo {
+	/** Type of physical layer e.g. UART or SPI */
+	enum cfcnfg_phy_type type;
+	/** Pointer to the layer below the MUX (framing layer) */
+	struct layer *frm_layer;
+	/** Pointer to the lowest actual physical layer */
+	struct layer *phy_layer;
+	/** Unique identifier of the physical interface */
+	unsigned int id;
+	/** Name of the physical interface */
+	char name[PHY_NAME_LEN];
+	/** Preference of the physical in interface */
+	enum cfcnfg_phy_preference pref;
+
+	/** Reference count, number of channels using the device */
+	int phy_ref_count;
+};
+
+struct cfcnfg {
+	struct layer layer;
+	struct layer *ctrl;
+	struct layer *mux;
+	uint8 last_phyid;
+	struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS];
+	struct cfcnfg_phy_mgmt phy_registration[CFPHYTYPE_MAX];
+};
+
+static void cncfg_linkup_rsp(struct layer *layer, uint8 linkid,
+			     enum cfctrl_srv serv, uint8 phyid,
+			     struct layer *adapt_layer);
+static void cncfg_linkdestroy_rsp(struct layer *layer, uint8 linkid,
+				  struct layer *client_layer);
+static void cncfg_reject_rsp(struct layer *layer, uint8 linkid,
+			     struct layer *adapt_layer);
+static void cfctrl_resp_func(void);
+static void cfctrl_enum_resp(void);
+
+
+
+struct cfcnfg *cfcnfg_create()
+{
+	struct cfcnfg *this;
+	struct cfctrl_rsp resp;
+	/* Initiate response functions */
+	resp.enum_rsp = cfctrl_enum_resp;
+	resp.linkerror_ind = cfctrl_resp_func;
+	resp.linkdestroy_rsp = cncfg_linkdestroy_rsp;
+	resp.sleep_rsp = cfctrl_resp_func;
+	resp.wake_rsp = cfctrl_resp_func;
+	resp.restart_rsp = cfctrl_resp_func;
+	resp.radioset_rsp = cfctrl_resp_func;
+	resp.linksetup_rsp = cncfg_linkup_rsp;
+	resp.reject_rsp = cncfg_reject_rsp;
+	/* Initiate this layer */
+	this = cfglu_alloc(sizeof(struct cfcnfg));
+	memset(this, 0, sizeof(struct cfcnfg));
+	this->mux = cfmuxl_create();
+	this->ctrl = cfctrl_create();
+	this->last_phyid = 1;
+	cfctrl_set_respfuncs(this->ctrl, &resp);
+	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
+	layer_set_dn(this->ctrl, this->mux);
+	layer_set_up(this->ctrl, this);
+	return this;
+}
+EXPORT_SYMBOL(cfcnfg_create);
+
+static void cfctrl_resp_func(void)
+{
+	CFLOG_ENTER(("cfcnfg: cfctrl_resp_func\n"));
+	CFLOG_EXIT(("cfcnfg: cfctrl_resp_func\n"));
+}
+
+static void cfctrl_enum_resp(void)
+{
+	CFLOG_ENTER(("cfcnfg: enter cfctrl_enum_resp\n"));
+	CFLOG_EXIT(("cfcnfg: exit cfctrl_enum_resp\n"));
+}
+
+int cfcnfg_get_phyid(struct cfcnfg *cnfg, enum cfcnfg_phy_preference phy_pref)
+{
+	int i;
+
+	/* Try to match with specified preference */
+	for (i = 1; i < MAX_PHY_LAYERS; i++) {
+		if (cnfg->phy_layers[i].id == i &&
+		     cnfg->phy_layers[i].pref == phy_pref &&
+		     cnfg->phy_layers[i].frm_layer != NULL) {
+			caif_assert(cnfg->phy_layers != NULL);
+			caif_assert(cnfg->phy_layers[i].id == i);
+			return cnfg->phy_layers[i].frm_layer->id;
+		}
+	}
+	/* Otherwise just return something */
+	for (i = 1; i < MAX_PHY_LAYERS; i++) {
+		if (cnfg->phy_layers[i].id == i) {
+			caif_assert(cnfg->phy_layers != NULL);
+			caif_assert(cnfg->phy_layers[i].id == i);
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
+							uint8 phyid)
+{
+	int i;
+
+	/* Try to match with specified preference */
+	for (i = 0; i < MAX_PHY_LAYERS; i++)
+		if (cnfg->phy_layers[i].frm_layer != NULL &&
+		    cnfg->phy_layers[i].id == phyid)
+			return &cnfg->phy_layers[i];
+	return 0;
+}
+
+int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
+{
+	int i;
+
+	/* Try to match with specified preference */
+	for (i = 0; i < MAX_PHY_LAYERS; i++) {
+		if (cnfg->phy_layers[i].frm_layer != NULL
+		    && strcmp(cnfg->phy_layers[i].frm_layer->name,
+			      name) == 0) {
+			return cnfg->phy_layers[i].frm_layer->id;
+		}
+	}
+	return 0;
+}
+
+/**
+ * NOTE: What happens on destroy failure:
+ *	 1a) No response - Too early
+ *	      This will not happen because enumerate has already
+ *	      completed.
+ *	 1b) No response - FATAL
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	      Modem error, response is really expected -  this
+ *	      case is not really handled.
+ *	 2) O/E-bit indicate error
+ *	      Ignored - this link is destroyed anyway.
+ *	 3) Not able to match on request
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	 4) Link-Error - (no response)
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ */
+
+int cfcnfg_del_adapt_layer(struct cfcnfg *cnfg, struct layer *adap_layer)
+{
+	uint8 channel_id = 0;
+	int ret = 0;
+	struct cfcnfg_phyinfo *phyinfo = NULL;
+	uint8 phyid = 0;
+	CFLOG_TRACE(("cfcnfg: enter del_adaptation_layer\n"));
+
+	caif_assert(adap_layer != NULL);
+	channel_id = adap_layer->id;
+	if (channel_id == 0) {
+		CFLOG_ERROR(("cfcnfg:adap_layer->id is 0\n"));
+		ret = CFGLU_ENOTCONN;
+		goto end;
+	}
+
+	if (adap_layer->dn == NULL) {
+		CFLOG_ERROR(("cfcnfg:adap_layer->dn is NULL\n"));
+		ret = CFGLU_ENODEV;
+		goto end;
+	}
+
+	if (adap_layer->dn != NULL)
+		phyid = cfsrvl_getphyid(adap_layer->dn);
+
+
+	phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
+	if (phyinfo == NULL) {
+		CFLOG_WARN(("cfcnfg: No interface to send disconnect to\n"));
+		ret = CFGLU_ENODEV;
+		goto end;
+	}
+
+	if (phyinfo->id != phyid
+		|| phyinfo->phy_layer->id != phyid
+		|| phyinfo->frm_layer->id != phyid) {
+
+		CFLOG_ERROR(("cfcnfg: Inconsitency in phy registration\n"));
+		ret = CFGLU_EINVAL;
+		goto end;
+	}
+
+	ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
+
+end:
+	if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
+		phyinfo->phy_layer != NULL &&
+		phyinfo->phy_layer->modemcmd != NULL) {
+		CFLOG_TRACE(("cfcnfg: send PHYIF_USELESS\n"));
+		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
+					     _CAIF_MODEMCMD_PHYIF_USELESS);
+	}
+	return ret;
+
+}
+EXPORT_SYMBOL(cfcnfg_del_adapt_layer);
+
+static void cncfg_linkdestroy_rsp(struct layer *layer, uint8 linkid,
+				  struct layer *client_layer)
+{
+	struct cfcnfg *cnfg = container_obj(layer);
+	struct layer *servl;
+
+	CFLOG_TRACE(("cfcnfg: enter linkdestroy_rsp\n"));
+
+	/* 1) Remove service from the MUX layer */
+	servl = cfmuxl_remove_uplayer(cnfg->mux, linkid);
+	/* invar: MUX guarantees no more payload sent "upwards" (receive) */
+
+	if (servl == NULL) {
+		CFLOG_ERROR(("cfcnfg: Error removing service_layer Linkid(%d)",
+			     linkid));
+		return;
+	}
+	caif_assert(linkid == servl->id);
+
+	if (servl != client_layer && servl->up != client_layer) {
+		CFLOG_ERROR(("cfcnfg: Error removing service_layer "
+			     "Linkid(%d) %p %p",
+			     linkid, (void *) servl, (void *) client_layer));
+		return;
+	}
+
+	/* 2) SHUTDOWN must guarantee that no more packets are transmitted
+	 * from adap_layer when it returns.  We assume it locks the layer for
+	 * every transmit and lock when receiving this SHUTDOWN
+	 */
+
+	if (servl->ctrlcmd == NULL) {
+		CFLOG_ERROR(("cfcnfg: Error servl->ctrlcmd == NULL"));
+		return;
+	}
+
+	servl->ctrlcmd(servl, CAIF_CTRLCMD_DEINIT_RSP, 0);
+
+	/* invar: Adaptation Layer guarantees no more payload sent
+	 *  "down-wards" (transmit)
+	 */
+
+	/* 3) It is now safe to destroy the service layer (if any) */
+
+	/*
+	 * FIXME: We need a ref-count in order to safely free
+	 *        the up layer.
+	 */
+	if (client_layer != servl->up)
+		cfservl_destroy(servl);
+}
+
+/**
+ * NOTE: What happens on linksetup failure:
+ *	 1a) No response - Too early
+ *	      This will not happen because enumerate is secured
+ *	      before using interface.
+ *	 1b) No response - FATAL
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	      Modem error, response is really expected -  this case is
+ *	      not really handled.
+ *	 2) O/E-bit indicate error
+ *	      Handled in cnfg_reject_rsp
+ *	 3) Not able to match on request
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	 4) Link-Error - (no response)
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ */
+
+bool
+cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
+				struct cfctrl_link_param *param,
+				struct layer *adap_layer)
+{
+	struct layer *frml;
+	CFLOG_TRACE(("cfcnfg[%p]: enter add_adaptation_layer\n",
+		     (void *) cnfg));
+
+	if (adap_layer == NULL) {
+		CFLOG_ERROR(("cfcnfg: adap_layer is zero"));
+		return CFGLU_EINVAL;
+	}
+	if (adap_layer->receive == NULL) {
+		CFLOG_ERROR(("cfcnfg-add: adap_layer->receive is NULL"));
+		return CFGLU_EINVAL;
+	}
+	if (adap_layer->ctrlcmd == NULL) {
+		CFLOG_ERROR(("cfcnfg-add: adap_layer->ctrlcmd == NULL"));
+		return CFGLU_EINVAL;
+	}
+
+	frml = cnfg->phy_layers[param->phyid].frm_layer;
+	if (frml == NULL) {
+		CFLOG_ERROR(("cfcnfg: Specified PHY type does not exist!"));
+		return false;
+	}
+	caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
+	caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id ==
+		     param->phyid);
+	caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
+		     param->phyid);
+	CFLOG_TRACE(("cfcnfg: send enum request\n"));
+	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
+
+	cfctrl_enum_req(cnfg->ctrl, param->phyid);
+
+	cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
+
+	return true;
+}
+EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);
+
+static void cncfg_reject_rsp(struct layer *layer, uint8 linkid,
+			     struct layer *adapt_layer)
+{
+	CFLOG_ENTER(("layer=%p linkid=%d adapt_layer=%p\n", (void *) layer,
+		     linkid, (void *) adapt_layer));
+	if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
+		adapt_layer->ctrlcmd(adapt_layer,
+				     CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
+}
+
+static void
+cncfg_linkup_rsp(struct layer *layer, uint8 linkid, enum cfctrl_srv serv,
+		 uint8 phyid, struct layer *adapt_layer)
+{
+	struct cfcnfg *cnfg = container_obj(layer);
+	struct layer *servicel = NULL;
+	struct cfcnfg_phyinfo *phyinfo;
+	CFLOG_ENTER(("cfcnfg[%p]: enter scfcnfg_linup_rsp\n", (void *) layer));
+	if (adapt_layer == NULL) {
+		CFLOG_ERROR(("cfcnfg: CAIF PROTOCOL ERROR "
+			     "- LinkUp Request/Response did not match\n"));
+		return;
+	}
+
+	caif_assert(cnfg != NULL);
+	caif_assert(phyid != 0);
+	phyinfo = &cnfg->phy_layers[phyid];
+	caif_assert(phyinfo != NULL);
+	caif_assert(phyinfo->id == phyid);
+	caif_assert(phyinfo->phy_layer != NULL);
+	caif_assert(phyinfo->phy_layer->id == phyid);
+
+	if (phyinfo != NULL &&
+	    phyinfo->phy_ref_count++ == 0 &&
+	    phyinfo->phy_layer != NULL &&
+	    phyinfo->phy_layer->modemcmd != NULL) {
+		caif_assert(phyinfo->phy_layer->id == phyid);
+		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
+					     _CAIF_MODEMCMD_PHYIF_USEFULL);
+
+	}
+	adapt_layer->id = linkid;
+
+	switch (serv) {
+	case CFCTRL_SRV_VEI:
+		servicel = cfvei_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: AT channel created\n"));
+		break;
+	case CFCTRL_SRV_DATAGRAM:
+		servicel = cfdgml_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: Datagram channel created\n"));
+		break;
+	case CFCTRL_SRV_RFM:
+		servicel = cfrfml_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: RFM channel created\n"));
+		break;
+	case CFCTRL_SRV_UTIL:
+		servicel = cfutill_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: Utility channel created\n"));
+		break;
+	case CFCTRL_SRV_VIDEO:
+		servicel = cfvidl_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: Video channel created\n"));
+		break;
+	case CFCTRL_SRV_DBG:
+		CFLOG_TRACE(("cfcnfg: Debug channel created\n"));
+		servicel = adapt_layer;
+		break;
+	default:
+		CFLOG_ERROR(("cfcnfg: ERROR "
+			     "Link setup response - unknown channel type\n"));
+		return;
+	}
+	layer_set_dn(servicel, cnfg->mux);
+
+	CFLOG_TRACE(("cfcnfg: insert service layer in mux\n"));
+
+	cfmuxl_set_uplayer(cnfg->mux, servicel, linkid);
+	if (servicel != adapt_layer) {
+		CFLOG_TRACE(("cfcnfg: insert adapt-layer in service layer\n"));
+		layer_set_up(servicel, adapt_layer);
+		layer_set_dn(adapt_layer, servicel);
+	}
+	CFLOG_TRACE(("cfcnfg: successfull link setup - call flowtrl(init)\n"));
+	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
+}
+
+struct caif_packet_funcs cfcnfg_get_packet_funcs()
+{
+	return cfpkt_get_packet_funcs();
+}
+EXPORT_SYMBOL(cfcnfg_get_packet_funcs);
+
+void
+cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
+		     struct layer *phy_layer, uint16 *phyid,
+		     enum cfcnfg_phy_preference pref)
+{
+	struct layer *frml;
+	struct layer *phy_driver = NULL;
+	int i;
+	bool DoFCS = false;
+	struct cfspipad padopt;
+
+	CFLOG_TRACE(("cfcnfg: enter add_phy_layer\n"));
+
+	if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) {
+		*phyid = cnfg->last_phyid;
+
+		/* range: * 1..(MAX_PHY_LAYERS-1) */
+		cnfg->last_phyid =
+		    (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1;
+	} else {
+		*phyid = 0;
+		for (i = 1; i < MAX_PHY_LAYERS; i++) {
+			if (cnfg->phy_layers[i].frm_layer == NULL) {
+				*phyid = i;
+				break;
+			}
+		}
+	}
+	if (*phyid == 0) {
+		CFLOG_ERROR(("cfcnfg: No Available PHY ID\n"));
+		return;
+	}
+
+	switch (phy_type) {
+	case CFPHYTYPE_SERIAL:
+		CFLOG_TRACE(("cfcnfg: Starting Serial link\n"));
+		DoFCS = true;
+		phy_driver =
+		    cfserl_create(CFPHYTYPE_SERIAL, *phyid, serial_use_stx);
+		break;
+	case CFPHYTYPE_SPI:
+		padopt.up_head_align = (uint16)spi_up_head_align;
+		padopt.up_tail_align = (uint16)spi_up_tail_align;
+		padopt.down_head_align = (uint16)spi_down_head_align;
+		padopt.down_tail_align = (uint16)spi_down_tail_align;
+		CFLOG_TRACE(("cfcnfg: Starting SPI link\n"));
+		phy_driver = cfspil_create(CFPHYTYPE_SPI, *phyid, padopt);
+		break;
+	case CFPHYTYPE_SHM:
+		CFLOG_TRACE(("cfcnfg: Starting SHM link\n"));
+		phy_driver = cfshml_create(CFPHYTYPE_SHM, *phyid);
+		break;
+	case CFPHYTYPE_MSL:
+		CFLOG_TRACE(("cfcnfg: Starting MSL link\n"));
+		phy_driver = cfmsll_create(CFPHYTYPE_MSL, *phyid);
+		break;
+	case CFPHYTYPE_USB:
+		CFLOG_TRACE(("cfcnfg: Starting USB link\n"));
+		phy_driver = cfusbl_create(CFPHYTYPE_USB, *phyid);
+		break;
+	default:
+		CFLOG_ERROR(("cfcnfg: Bad phy_type specified: %d", phy_type));
+		return;
+		break;
+	}
+
+	phy_layer->id = *phyid;
+	phy_driver->id = *phyid;
+	cnfg->phy_layers[*phyid].pref = pref;
+	cnfg->phy_layers[*phyid].id = *phyid;
+	cnfg->phy_layers[*phyid].type = phy_type;
+	cnfg->phy_layers[*phyid].phy_layer = phy_layer;
+	cnfg->phy_layers[*phyid].phy_ref_count = 0;
+	phy_layer->type = phy_type;
+	frml = cffrml_create(*phyid, DoFCS);
+	cnfg->phy_layers[*phyid].frm_layer = frml;
+	cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
+	layer_set_up(frml, cnfg->mux);
+	layer_set_dn(frml, phy_driver);
+	layer_set_up(phy_driver, frml);
+	layer_set_dn(phy_driver, phy_layer);
+	layer_set_up(phy_layer, phy_driver);
+	CFLOG_TRACE(("cfcnfg: phy1=%p phy2=%p transmit=0x%d\n",
+		     (void *) phy_driver, (void *) phy_layer,
+		     (int) phy_layer->transmit));
+}
+EXPORT_SYMBOL(cfcnfg_add_phy_layer);
+
+int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct layer *phy_layer)
+{
+	struct layer *frml, *cfphy;
+	uint16 phyid;
+	phyid = phy_layer->id;
+	caif_assert(phyid == cnfg->phy_layers[phyid].id);
+	caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer);
+	caif_assert(phy_layer->id == phyid);
+	caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid);
+
+	memset(&cnfg->phy_layers[phy_layer->id], 0,
+	       sizeof(struct cfcnfg_phyinfo));
+	frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
+	cfphy = frml->dn;
+
+	cffrml_set_uplayer(frml, NULL);
+	cffrml_set_dnlayer(frml, NULL);
+	cffrml_destroy(frml);
+
+	caif_assert(cfphy->dn == phy_layer);
+	layer_set_up(cfphy, NULL);
+	layer_set_dn(cfphy, NULL);
+	cfglu_free(cfphy);
+
+	layer_set_up(phy_layer, NULL);
+	return CFGLU_EOK;
+}
+EXPORT_SYMBOL(cfcnfg_del_phy_layer);
diff --git a/net/caif/generic/cfctrl.c b/net/caif/generic/cfctrl.c
new file mode 100644
index 0000000..0a27731
--- /dev/null
+++ b/net/caif/generic/cfctrl.c
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfctrl.h>
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfctrl, serv.layer)
+#define UTILITY_NAME_LENGTH 16
+#define CFPKT_CTRL_PKT_LEN 20
+
+
+#ifdef CAIF_NO_LOOP
+static inline int handle_loop(struct cfctrl *ctrl,
+			      int cmd, struct cfpkt *pkt){
+	return CAIF_FAILURE;
+}
+#else
+static int handle_loop(struct cfctrl *ctrl,
+		int cmd, struct cfpkt *pkt);
+#endif
+static int cfctrl_recv(struct layer *layr, struct cfpkt *pkt);
+static void cfctrl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid);
+
+
+struct layer *cfctrl_create()
+{
+	struct cfctrl *this =
+	    (struct cfctrl *) cfglu_alloc(sizeof(struct cfctrl));
+	caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
+	memset(this, 0, sizeof(*this));
+	cfglu_init_lock(this->info_list_lock);
+	cfglu_atomic_set(this->req_seq_no, 1);
+	cfglu_atomic_set(this->rsp_seq_no, 1);
+	this->serv.phid = 0xff;
+	this->serv.layer.id = 0;
+	this->serv.layer.receive = cfctrl_recv;
+	sprintf(this->serv.layer.name, "ctrl");
+	this->serv.layer.ctrlcmd = cfctrl_ctrlcmd;
+	cfglu_init_lock(this->loop_linkid_lock);
+	this->loop_linkid = 1;
+	return &this->serv.layer;
+}
+
+bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2)
+{
+	bool eq =
+	    p1->linktype == p2->linktype &&
+	    p1->priority == p2->priority &&
+	    p1->phyid == p2->phyid &&
+	    p1->endpoint == p2->endpoint && p1->chtype == p2->chtype;
+
+	if (!eq)
+		return false;
+
+	switch (p1->linktype) {
+	case CFCTRL_SRV_VEI:
+		return true;
+	case CFCTRL_SRV_DATAGRAM:
+		return p1->u.datagram.connid == p2->u.datagram.connid;
+	case CFCTRL_SRV_RFM:
+		return
+		    p1->u.rfm.connid == p2->u.rfm.connid &&
+		    strcmp(p1->u.rfm.volume, p2->u.rfm.volume) == 0;
+	case CFCTRL_SRV_UTIL:
+		return
+		    p1->u.utility.fifosize_kb == p2->u.utility.fifosize_kb
+		    && p1->u.utility.fifosize_bufs ==
+		    p2->u.utility.fifosize_bufs
+		    && strcmp(p1->u.utility.name, p2->u.utility.name) == 0
+		    && p1->u.utility.paramlen == p2->u.utility.paramlen
+		    && memcmp(p1->u.utility.params, p2->u.utility.params,
+			      p1->u.utility.paramlen) == 0;
+
+	case CFCTRL_SRV_VIDEO:
+		return p1->u.video.connid == p2->u.video.connid;
+	case CFCTRL_SRV_DBG:
+		return true;
+	case CFCTRL_SRV_DECM:
+		return false;
+	default:
+		return false;
+	}
+	return false;
+}
+
+bool cfctrl_req_eq(struct cfctrl_request_info *r1,
+		   struct cfctrl_request_info *r2)
+{
+	if (r1->cmd != r2->cmd)
+		return false;
+	if (r1->cmd == CFCTRL_CMD_LINK_SETUP)
+		return param_eq(&r1->param, &r2->param);
+	else
+		return r1->channel_id == r2->channel_id;
+}
+
+/* Insert request at the end */
+void cfctrl_insert_req(struct cfctrl *ctrl,
+			      struct cfctrl_request_info *req)
+{
+	struct cfctrl_request_info *p;
+	cfglu_lock(ctrl->info_list_lock);
+	req->next = NULL;
+	cfglu_atomic_inc(ctrl->req_seq_no);
+	req->sequence_no = cfglu_atomic_read(ctrl->req_seq_no);
+	if (ctrl->first_req == NULL) {
+		ctrl->first_req = req;
+		cfglu_unlock(ctrl->info_list_lock);
+		return;
+	}
+	p = ctrl->first_req;
+	while (p->next != NULL)
+		p = p->next;
+	p->next = req;
+	cfglu_unlock(ctrl->info_list_lock);
+}
+
+static void cfctrl_insert_req2(struct cfctrl *ctrl, enum cfctrl_cmd cmd,
+			       uint8 linkid, struct layer *user_layer)
+{
+	struct cfctrl_request_info *req = cfglu_alloc(sizeof(*req));
+	req->client_layer = user_layer;
+	req->cmd = cmd;
+	req->channel_id = linkid;
+	cfctrl_insert_req(ctrl, req);
+}
+
+/* Compare and remove request */
+struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
+					      struct cfctrl_request_info *req)
+{
+	struct cfctrl_request_info *p;
+	struct cfctrl_request_info *ret;
+
+	cfglu_lock(ctrl->info_list_lock);
+	if (ctrl->first_req == NULL) {
+		cfglu_unlock(ctrl->info_list_lock);
+		return NULL;
+	}
+
+	if (cfctrl_req_eq(req, ctrl->first_req)) {
+		ret = ctrl->first_req;
+		cfglu_atomic_set(ctrl->rsp_seq_no,
+				 ctrl->first_req->sequence_no);
+		ctrl->first_req = ctrl->first_req->next;
+		cfglu_unlock(ctrl->info_list_lock);
+		return ret;
+	}
+
+	CFLOG_WARN(("cfctrl: Requests are not received in order/matching\n"));
+
+	p = ctrl->first_req;
+
+	while (p->next != NULL) {
+		if (cfctrl_req_eq(req, p->next)) {
+			ret = p->next;
+			cfglu_atomic_set(ctrl->rsp_seq_no,
+					 p->next->sequence_no);
+			p = p->next;
+			cfglu_unlock(ctrl->info_list_lock);
+			return ret;
+		}
+		p = p->next;
+	}
+	cfglu_unlock(ctrl->info_list_lock);
+	return NULL;
+}
+
+/* Compare and remove old requests based on sequence no. */
+void cfctrl_prune_req(struct cfctrl *ctrl)
+{
+	struct cfctrl_request_info *p;
+	struct cfctrl_request_info *del;
+
+	cfglu_lock(ctrl->info_list_lock);
+	if (ctrl->first_req == NULL) {
+		cfglu_unlock(ctrl->info_list_lock);
+		return;
+	}
+
+	if (ctrl->first_req->sequence_no <
+	    cfglu_atomic_read(ctrl->req_seq_no)) {
+		del = ctrl->first_req;
+		ctrl->first_req = ctrl->first_req->next;
+		cfglu_free(del);
+	}
+	p = ctrl->first_req;
+	while (p->next != NULL) {
+		if (p->next->sequence_no <
+		    cfglu_atomic_read(ctrl->rsp_seq_no)) {
+			del = p->next;
+			p = p->next;
+			cfglu_atomic_set(ctrl->rsp_seq_no,
+					 ctrl->first_req->sequence_no);
+			cfglu_free(del);
+		}
+		p = p->next;
+	}
+	cfglu_unlock(ctrl->info_list_lock);
+}
+
+void cfctrl_set_respfuncs(struct layer *layer, struct cfctrl_rsp *respfuncs)
+{
+	struct cfctrl *this = container_obj(layer);
+	this->res = *respfuncs;
+}
+
+void cfctrl_set_dnlayer(struct layer *this, struct layer *dn)
+{
+	this->dn = dn;
+}
+
+void cfctrl_set_uplayer(struct layer *this, struct layer *up)
+{
+	this->up = up;
+}
+
+static struct transmt_info init_info(struct cfctrl *cfctrl)
+{
+	struct transmt_info info;
+	info.hdr_len = 0;
+	info.prio = 0;
+	info.channel_id = cfctrl->serv.layer.id;
+	info.phid = cfctrl->serv.phid;
+	return info;
+}
+
+void cfctrl_enum_req(struct layer *layer, uint8 physlinkid)
+{
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct transmt_info info = init_info(cfctrl);
+	int ret;
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
+	info.phid = physlinkid;
+	cfctrl->serv.phid = physlinkid;
+	cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM);
+	cfpkt_addbdy(pkt, physlinkid);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0) {
+		CFLOG_ERROR(("Could not transmit enum message\n"));
+		cfpkt_destroy(pkt);
+	}
+}
+
+void cfctrl_linkup_request(struct layer *layer, struct cfctrl_link_param *param,
+			   struct layer *user_layer)
+{
+	struct cfctrl *cfctrl = container_obj(layer);
+	uint32 tmp32;
+	uint16 tmp16;
+	uint8 tmp8;
+	int ret;
+	char utility_name[16];
+	struct cfctrl_request_info *req;
+	struct transmt_info info = init_info(cfctrl);
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	CFLOG_TRACE(("cfctrl: enter linkup_request\n"));
+
+	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
+	cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype);
+	cfpkt_addbdy(pkt, (param->priority << 3) + param->phyid);
+	cfpkt_addbdy(pkt, param->endpoint & 0x03);
+	CFLOG_TRACE2(("channel config: chtype:%d linktype:%d "
+		      "phyid:%d prio:%d endpoint:%d\n",
+		      param->chtype, param->linktype,
+		      param->phyid, param->priority, param->endpoint));
+	switch (param->linktype) {
+	case CFCTRL_SRV_VEI:
+		break;
+	case CFCTRL_SRV_VIDEO:
+		cfpkt_addbdy(pkt, (uint8) param->u.video.connid);
+		break;
+	case CFCTRL_SRV_DBG:
+		break;
+	case CFCTRL_SRV_DATAGRAM:
+		tmp32 = cfglu_cpu_to_le32(param->u.datagram.connid);
+		cfpkt_add_body(pkt, &tmp32, 4);
+		break;
+	case CFCTRL_SRV_RFM:
+		/* Construct a frame, convert DatagramConnectionID to network
+		 * format long and copy it out...
+		 */
+		tmp32 = cfglu_cpu_to_le32(param->u.rfm.connid);
+		cfpkt_add_body(pkt, &tmp32, 4);
+		/* Add volume name, including zero termination... */
+		cfpkt_add_body(pkt, param->u.rfm.volume,
+			       strlen(param->u.rfm.volume) + 1);
+		break;
+	case CFCTRL_SRV_UTIL:
+		tmp16 = cfglu_cpu_to_le16(param->u.utility.fifosize_kb);
+		cfpkt_add_body(pkt, &tmp16, 2);
+		tmp16 = cfglu_cpu_to_le16(param->u.utility.fifosize_bufs);
+		cfpkt_add_body(pkt, &tmp16, 2);
+		memset(utility_name, 0, sizeof(utility_name));
+		strncpy(utility_name, param->u.utility.name,
+			UTILITY_NAME_LENGTH - 1);
+		cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH);
+		tmp8 = param->u.utility.paramlen;
+		cfpkt_add_body(pkt, &tmp8, 1);
+		cfpkt_add_body(pkt, param->u.utility.params,
+			       param->u.utility.paramlen);
+		CFLOG_TRACE2(("util config: kb:%d bufs:%d name:%s paramlen:%d"
+			      "param:0x%02x,%02x,%02x,%02x,%02x\n",
+			      param->u.utility.fifosize_kb,
+			      param->u.utility.fifosize_bufs,
+			      utility_name,
+			      param->u.utility.paramlen,
+			      param->u.utility.params[0],
+			      param->u.utility.params[1],
+			      param->u.utility.params[2],
+			      param->u.utility.params[3],
+			      param->u.utility.params[4]));
+		break;
+	default:
+		CFLOG_ERROR(("CAIF: Request setup of invalid link type = %d\n",
+			     param->linktype));
+	}
+	req = cfglu_alloc(sizeof(*req));
+	memset(req, 0, sizeof(*req));
+	req->client_layer = user_layer;
+	req->cmd = CFCTRL_CMD_LINK_SETUP;
+	req->param = *param;
+	cfctrl_insert_req(cfctrl, req);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0) {
+		CFLOG_ERROR(("cfctl: Could not transmit linksetup request\n"));
+		cfpkt_destroy(pkt);
+	}
+}
+
+int cfctrl_linkdown_req(struct layer *layer, uint8 channelid,
+				struct layer *client)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	struct transmt_info info = init_info(cfctrl);
+	cfctrl_insert_req2(cfctrl, CFCTRL_CMD_LINK_DESTROY, channelid, client);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
+	cfpkt_addbdy(pkt, channelid);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0) {
+		CFLOG_ERROR(("cfctl: Could not transmit link-down request\n"));
+		cfpkt_destroy(pkt);
+	}
+	return ret;
+}
+
+void cfctrl_sleep_req(struct layer *layer)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	struct transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+void cfctrl_wake_req(struct layer *layer)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	struct transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+void cfctrl_getstartreason_req(struct layer *layer)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	struct transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+void cfctrl_setmode_req(struct layer *layer, uint8 mode)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	struct transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_RADIO_SET);
+	cfpkt_addbdy(pkt, mode);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+static int cfctrl_recv(struct layer *layer, struct cfpkt *pkt)
+{
+	uint8 cmdrsp;
+	uint8 cmd;
+	int ret = -1;
+	uint16 tmp16;
+	uint8 len;
+	uint8 param[255];
+	uint8 linkid;
+	struct cfctrl *cfctrl = container_obj(layer);
+	struct cfctrl_request_info rsp, *req;
+
+	CFLOG_TRACE(("cfctrl: enter cfctrl_recv\n"));
+
+	(void) cfpkt_extr_head(pkt, &cmdrsp, 1);
+	cmd = cmdrsp & CFCTRL_CMD_MASK;
+	if (cmd != CFCTRL_CMD_LINK_ERR
+	    && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) {
+		if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE) {
+			CFLOG_ERROR(("CAIF Protocol error:"
+					"Response bit not set\n"));
+			goto error;
+		}
+	}
+
+	switch (cmd) {
+	case CFCTRL_CMD_LINK_SETUP:
+		{
+			enum cfctrl_srv serv;
+			enum cfctrl_srv servtype;
+			uint8 endpoint;
+			uint8 physlinkid;
+			uint8 prio;
+			uint8 tmp;
+			uint32 tmp32;
+			uint8 *cp;
+			int i;
+			struct cfctrl_link_param linkparam;
+			memset(&linkparam, 0, sizeof(linkparam));
+
+			cfpkt_extr_head(pkt, &tmp, 1);
+
+			serv = tmp & CFCTRL_SRV_MASK;
+			linkparam.linktype = serv;
+
+			servtype = tmp >> 4;
+			linkparam.chtype = servtype;
+
+			cfpkt_extr_head(pkt, &tmp, 1);
+			physlinkid = tmp & 0x07;
+			prio = tmp >> 3;
+
+			linkparam.priority = prio;
+			linkparam.phyid = physlinkid;
+			cfpkt_extr_head(pkt, &endpoint, 1);
+			linkparam.endpoint = endpoint & 0x03;
+
+			switch (serv) {
+			case CFCTRL_SRV_VEI:
+			case CFCTRL_SRV_DBG:
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				break;
+			case CFCTRL_SRV_VIDEO:
+				cfpkt_extr_head(pkt, &tmp, 1);
+				linkparam.u.video.connid = tmp;
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				break;
+
+			case CFCTRL_SRV_DATAGRAM:
+				cfpkt_extr_head(pkt, &tmp32, 4);
+				linkparam.u.datagram.connid =
+				    cfglu_le32_to_cpu(tmp32);
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				break;
+			case CFCTRL_SRV_RFM:
+				/* Construct a frame, convert
+				 * DatagramConnectionID
+				 * to network format long and copy it out...
+				 */
+				cfpkt_extr_head(pkt, &tmp32, 4);
+				linkparam.u.rfm.connid =
+				  cfglu_le32_to_cpu(tmp32);
+				cp = (uint8 *) linkparam.u.rfm.volume;
+				for (cfpkt_extr_head(pkt, &tmp, 1);
+				     cfpkt_more(pkt) && tmp != '\0';
+				     cfpkt_extr_head(pkt, &tmp, 1))
+					*cp++ = tmp;
+				*cp = '\0';
+
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+
+				break;
+			case CFCTRL_SRV_UTIL:
+				/* Construct a frame, convert
+				 * DatagramConnectionID
+				 * to network format long and copy it out...
+				 */
+				/* Fifosize KB */
+				cfpkt_extr_head(pkt, &tmp16, 2);
+				linkparam.u.utility.fifosize_kb =
+				    cfglu_le16_to_cpu(tmp16);
+				/* Fifosize bufs */
+				cfpkt_extr_head(pkt, &tmp16, 2);
+				linkparam.u.utility.fifosize_bufs =
+				    cfglu_le16_to_cpu(tmp16);
+				/* name */
+				cp = (uint8 *) linkparam.u.utility.name;
+				caif_assert(sizeof(linkparam.u.utility.name)
+					     >= UTILITY_NAME_LENGTH);
+				for (i = 0;
+				     i < UTILITY_NAME_LENGTH
+				     && cfpkt_more(pkt); i++) {
+					cfpkt_extr_head(pkt, &tmp, 1);
+					*cp++ = tmp;
+				}
+				/* Length */
+				cfpkt_extr_head(pkt, &len, 1);
+				linkparam.u.utility.paramlen = len;
+				/* Param Data */
+				cp = linkparam.u.utility.params;
+				while (cfpkt_more(pkt) && len--) {
+					cfpkt_extr_head(pkt, &tmp, 1);
+					*cp++ = tmp;
+				}
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				/* Length */
+				cfpkt_extr_head(pkt, &len, 1);
+				/* Param Data */
+				cfpkt_extr_head(pkt, &param, len);
+				break;
+			default:
+				CFLOG_ERROR(("cfctrl_rec:Request setup "
+					     "- invalid link type (%d)",
+					     serv));
+				goto error;
+			}
+			if (cfpkt_erroneous(pkt)) {
+				CFLOG_ERROR(("cfctrl: Packet is erroneous!"));
+				goto error;
+			}
+			CFLOG_TRACE(("cfctrl: success parsing linksetup_rsp"));
+			rsp.cmd = cmd;
+			rsp.param = linkparam;
+			req = cfctrl_remove_req(cfctrl, &rsp);
+
+			if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp)) {
+				CFLOG_ERROR(("CaifChannel:Invalid O/E bit "
+					     "on CAIF control channel"));
+				cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
+						       0,
+						       req ? req->client_layer
+						       : NULL);
+			} else {
+				cfctrl->res.linksetup_rsp(cfctrl->serv.
+							  layer.up, linkid,
+							  serv, physlinkid,
+							  req ? req->
+							  client_layer : NULL);
+			}
+
+			if (req != NULL)
+				cfglu_free(req);
+		}
+		break;
+	case CFCTRL_CMD_LINK_DESTROY:
+		cfpkt_extr_head(pkt, &linkid, 1);
+		rsp.cmd = cmd;
+		rsp.channel_id = linkid;
+		req = cfctrl_remove_req(cfctrl, &rsp);
+		cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid,
+					    req ? req->client_layer : NULL);
+		if (req != NULL)
+			cfglu_free(req);
+		break;
+	case CFCTRL_CMD_LINK_ERR:
+		CFLOG_ERROR(("cfctrl: Frame Error Indication received \n"));
+		cfctrl->res.linkerror_ind();
+		break;
+	case CFCTRL_CMD_ENUM:
+		cfctrl->res.enum_rsp();
+		break;
+	case CFCTRL_CMD_SLEEP:
+		cfctrl->res.sleep_rsp();
+		break;
+	case CFCTRL_CMD_WAKE:
+		cfctrl->res.wake_rsp();
+		break;
+	case CFCTRL_CMD_LINK_RECONF:
+		cfctrl->res.restart_rsp();
+		break;
+	case CFCTRL_CMD_RADIO_SET:
+		cfctrl->res.radioset_rsp();
+		break;
+	default:
+		CFLOG_ERROR(("CAIF: Unrecognized Control Frame\n"));
+		goto error;
+		break;
+	}
+	ret = 0;
+error:
+	cfpkt_destroy(pkt);
+	return ret;
+}
+
+static void cfctrl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid)
+{
+	struct cfctrl *this = container_obj(layr);
+	CFLOG_ENTER(("\n"));
+	switch (ctrl) {
+	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+		cfglu_lock(this->info_list_lock);
+		if (this->first_req != NULL) {
+			CFLOG_WARN(("cfctrl:"
+				    "Received flow off in control layer"));
+		}
+		cfglu_unlock(this->info_list_lock);
+		break;
+	default:
+		break;
+	}
+	CFLOG_EXIT(("\n"));
+}
+
+#ifndef CAIF_NO_LOOP
+int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
+{
+	uint8 linkid, linktype, tmp;
+	switch (cmd) {
+	case CFCTRL_CMD_LINK_SETUP:
+		cfglu_lock(ctrl->loop_linkid_lock);
+		for (linkid = 0x1; linkid < 255; linkid++) {
+			if (!ctrl->loop_linkused[linkid]) {
+				ctrl->loop_linkused[linkid] = 1;
+				break;
+			}
+		}
+		if (linkid == 255) {
+			CFLOG_TRACE(("cfctrl_receive: loopback"
+					" no free link id's\n"));
+		}
+		CFLOG_TRACE(("cfcntrl_receive: setup loopback"
+				"linkid = %d\n", linkid));
+		cfpkt_add_trail(pkt, &linkid, 1);
+		cfglu_unlock(ctrl->loop_linkid_lock);
+		cfpkt_peek_head(pkt, &linktype, 1);
+		if (linktype ==  CFCTRL_SRV_UTIL) {
+			tmp = 0x01;
+			cfpkt_add_trail(pkt, &tmp, 1);
+			cfpkt_add_trail(pkt, &tmp, 1);
+		}
+		break;
+
+	case CFCTRL_CMD_LINK_DESTROY:
+		cfglu_lock(ctrl->loop_linkid_lock);
+		(void) cfpkt_peek_head(pkt, &linkid, 1);
+		CFLOG_TRACE(("cfctrl_receive: destroy "
+				"linkid = %d\n", linkid));
+		ctrl->loop_linkused[linkid] = 0;
+		cfglu_unlock(ctrl->loop_linkid_lock);
+		break;
+	default:
+		break;
+	}
+	return CAIF_SUCCESS;
+}
+#endif
diff --git a/net/caif/generic/cfdgml.c b/net/caif/generic/cfdgml.c
new file mode 100644
index 0000000..54be0b4
--- /dev/null
+++ b/net/caif/generic/cfdgml.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
+#define DGM_CMD_BIT  0x80
+#define DGM_FLOW_OFF 0x81
+#define DGM_FLOW_ON  0x80
+#define DGM_CTRL_PKT_SIZE 1
+
+static int cfdgml_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfdgml_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt);
+
+struct layer *cfdgml_create(uint8 channel_id, uint8 phyid)
+{
+	struct cfsrvl *dgm = cfglu_alloc(sizeof(struct cfsrvl));
+	caif_assert(offsetof(struct cfsrvl, layer) == 0);
+	CFLOG_ENTER(("\n"));
+	memset(dgm, 0, sizeof(struct cfsrvl));
+	cfsrvl_init(dgm, channel_id, phyid);
+	dgm->layer.receive = cfdgml_receive;
+	dgm->layer.transmit = cfdgml_transmit;
+	snprintf(dgm->layer.name, CAIF_LAYER_NAME_SZ - 1, "dgm%d", channel_id);
+	dgm->layer.name[CAIF_LAYER_NAME_SZ - 1] = '\0';
+	CFLOG_EXIT(("\n"));
+	return &dgm->layer;
+}
+
+static int cfdgml_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	uint8 cmd = -1;
+	uint8 dgmhdr[3];
+	int ret;
+	caif_assert(layr->up != NULL);
+	caif_assert(layr->receive != NULL);
+	caif_assert(layr->ctrlcmd != NULL);
+	CFLOG_ENTER(("\n"));
+
+	if (!cfpkt_extr_head(pkt, &cmd, 1)) {
+		CFLOG_ERROR(("cfdgml: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EPROTO;
+	}
+
+	if ((cmd & DGM_CMD_BIT) == 0) {
+		if (!cfpkt_extr_head(pkt, &dgmhdr, 3)) {
+			CFLOG_ERROR(("cfdgml: Packet is erroneous!\n"));
+			cfpkt_destroy(pkt);
+			return CFGLU_EPROTO;
+		}
+		ret = layr->up->receive(layr->up, pkt);
+		CFLOG_EXIT(("\n"));
+		return ret;
+	}
+
+	switch (cmd) {
+	case DGM_FLOW_OFF:	/* FLOW OFF */
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return 0;
+	case DGM_FLOW_ON:	/* FLOW ON */
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return 0;
+	default:
+		cfpkt_destroy(pkt);
+		CFLOG_ERROR(("cfdgml: Unknown datagram control %d (0x%x)\n",
+			     cmd, cmd));
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EPROTO;
+	}
+	CFLOG_EXIT(("\n"));
+}
+
+static int cfdgml_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt)
+{
+	uint32 zero = 0;
+	struct transmt_info info;
+	struct cfsrvl *service = container_obj(layr);
+	int ret;
+	CFLOG_ENTER(("\n"));
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	cfpkt_add_head(pkt, &zero, 4);
+
+	/* Add info for MUX-layer to route the packet out. */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	/* To optimize alignment, we add up the size of CAIF header
+	 * before payload.
+	 */
+	info.hdr_len = 4;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0) {
+		uint32 tmp32;
+		cfpkt_extr_head(pkt, &tmp32, 4);
+	}
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
diff --git a/net/caif/generic/cffrml.c b/net/caif/generic/cffrml.c
new file mode 100644
index 0000000..2649da3
--- /dev/null
+++ b/net/caif/generic/cffrml.c
@@ -0,0 +1,149 @@
+/*
+ * Caif Framing Layer.
+ *
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#define container_obj(layr) cfglu_container_of(layr, struct cffrml, layer)
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+#include <net/caif/generic/cffrml.h>
+
+struct cffrml {
+	struct layer layer;
+	bool dofcs;		/* !< FCS active */
+};
+
+static int cffrml_receive(struct layer *layr, struct cfpkt *pkt);
+static int cffrml_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt);
+static void cffrml_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid);
+
+uint32 cffrml_rcv_error;
+uint32 cffrml_rcv_checsum_error;
+struct layer *cffrml_create(uint16 phyid, bool use_fcs)
+{
+	struct cffrml *this = cfglu_alloc(sizeof(struct cffrml));
+	caif_assert(offsetof(struct cffrml, layer) == 0);
+
+	memset(this, 0, sizeof(struct layer));
+	this->layer.receive = cffrml_receive;
+	this->layer.transmit = cffrml_transmit;
+	this->layer.ctrlcmd = cffrml_ctrlcmd;
+	snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid);
+	this->dofcs = use_fcs;
+	this->layer.id = phyid;
+	CFLOG_TRACE(("cffrml: FCS=%d\n", use_fcs));
+	return (struct layer *) this;
+}
+
+void cffrml_set_uplayer(struct layer *this, struct layer *up)
+{
+	this->up = up;
+}
+
+void cffrml_set_dnlayer(struct layer *this, struct layer *dn)
+{
+	this->dn = dn;
+}
+
+static uint16 cffrml_checksum(uint16 chks, void *buf, uint16 len)
+{
+	/* FIXME: FCS should be moved to glue in order to use OS-Specific
+	 * solutions
+	 */
+	return fcs16(chks, buf, len);
+}
+
+static int cffrml_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	uint16 tmp;
+	uint16 len;
+	uint16 hdrchks;
+	uint16 pktchks;
+	struct cffrml *this;
+	this = container_obj(layr);
+
+	(void) cfpkt_extr_head(pkt, &tmp, 2);
+	len = cfglu_le16_to_cpu(tmp);
+
+	/* Subtract for FCS on length if FCS is not used. */
+	if (!this->dofcs)
+		len -= 2;
+
+	if (cfpkt_setlen(pkt, len) < 0) {
+		++cffrml_rcv_error;
+		CFLOG_ERROR(("cffrml: Framing length error (%d)\n", len));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPKT;
+	}
+	/* Don't do extract if FCS is false, rather do setlen - then we don't
+	 * get a cache-miss.
+	 */
+	if (this->dofcs) {
+		(void) cfpkt_extr_trail(pkt, &tmp, 2);
+		hdrchks = cfglu_le16_to_cpu(tmp);
+		pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
+		if (pktchks != hdrchks) {
+			cfpkt_add_trail(pkt, &tmp, 2);
+			++cffrml_rcv_error;
+			++cffrml_rcv_checsum_error;
+			CFLOG_ERROR(("cffrml: Frame checksum error "
+				     "(0x%x != 0x%x)\n", hdrchks, pktchks));
+			return CFGLU_EFCS;
+		}
+	}
+	if (cfpkt_erroneous(pkt)) {
+		++cffrml_rcv_error;
+		CFLOG_ERROR(("cffrml: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPKT;
+	}
+	return layr->up->receive(layr->up, pkt);
+}
+
+static int cffrml_transmit(struct layer *layr, struct transmt_info *info,
+					struct cfpkt *pkt)
+{
+	int tmp;
+	uint16 chks;
+	uint16 len;
+	int ret;
+	struct cffrml *this = container_obj(layr);
+	if (this->dofcs) {
+		chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
+		tmp = cfglu_cpu_to_le16(chks);
+		cfpkt_add_trail(pkt, &tmp, 2);
+	} else {
+		cfpkt_pad_trail(pkt, 2);
+	}
+
+	len = cfpkt_getlen(pkt);
+	tmp = cfglu_cpu_to_le16(len);
+	cfpkt_add_head(pkt, &tmp, 2);
+	info->hdr_len += 2;
+	if (cfpkt_erroneous(pkt)) {
+		CFLOG_ERROR(("cffrml: Packet is erroneous!\n"));
+		return CFGLU_EPROTO;
+	}
+	ret = layr->dn->transmit(layr->dn, info, pkt);
+	if (ret < 0) {
+		/* Remove header on faulty packet. */
+		cfpkt_extr_head(pkt, &tmp, 2);
+	}
+	return ret;
+}
+
+static void cffrml_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+					int phyid)
+{
+	if (layr->up->ctrlcmd)
+		layr->up->ctrlcmd(layr->up, ctrl, layr->id);
+}
diff --git a/net/caif/generic/cflist.c b/net/caif/generic/cflist.c
new file mode 100644
index 0000000..b7b541f
--- /dev/null
+++ b/net/caif/generic/cflist.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+
+void cflst_init(struct layer **lst)
+{
+	*lst = NULL;
+}
+
+struct layer *cflst_remove(struct layer **lst, struct layer *elem)
+{
+	struct layer *tmp;
+	if (*lst == NULL)
+		return NULL;
+
+	tmp = (*lst);
+	(*lst) = (*lst)->next;
+	return tmp;
+}
+
+/** Adds an element from the queue. */
+void cflst_insert(struct layer **lst, struct layer *node)
+{
+	struct layer *tmp;
+	node->next = NULL;
+	if ((*lst) == NULL) {
+		(*lst) = node;
+		return;
+	}
+	tmp = *lst;
+	while (tmp->next != NULL)
+		tmp = tmp->next;
+	tmp->next = node;
+}
+
+bool cflst_put(struct layer **lst, uint8 id, struct layer *node)
+{
+	if (cflst_get(lst, id) != NULL) {
+		CFLOG_ERROR(("CAIF: cflst_put duplicate key\n"));
+		return false;
+	}
+	node->id = id;
+	cflst_insert(lst, node);
+	return true;
+}
+
+struct layer *cflst_get(struct layer * *lst, uint8 id)
+{
+	struct layer *node;
+	for (node = (*lst); node != NULL; node = node->next) {
+		if (id == node->id)
+			return node;
+	}
+	return NULL;
+}
+
+struct layer *cflst_del(struct layer * *lst, uint8 id)
+{
+	struct layer *iter;
+	struct layer *node = NULL;
+
+	if ((*lst) == NULL)
+		return NULL;
+
+	if ((*lst)->id == id) {
+		node = (*lst);
+		(*lst) = (*lst)->next;
+		node->next = NULL;
+
+		return node;
+	}
+
+	for (iter = (*lst); iter->next != NULL; iter = iter->next) {
+		if (id == iter->next->id) {
+			node = iter->next;
+			iter->next = iter->next->next;
+			node->next = NULL;
+			return node;
+		}
+	}
+	return NULL;
+}
diff --git a/net/caif/generic/cfloopcfg.c b/net/caif/generic/cfloopcfg.c
new file mode 100644
index 0000000..4102122
--- /dev/null
+++ b/net/caif/generic/cfloopcfg.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/generic/cfmuxl.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/generic/cfspil.h>
+#include <net/caif/generic/cfserl.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfshml.h>
+#include <net/caif/generic/cfmsll.h>
+#include <net/caif/generic/cfusbl.h>
+#include <net/caif/generic/cfloopcfg.h>
+
+struct cfloopcfg {
+	struct layer *loop;
+
+};
+
+struct cfloopcfg *cfloopcfg_create(void)
+{
+	struct cfloopcfg *this;
+	this = cfglu_alloc(sizeof(struct cfloopcfg));
+	memset(this, 0, sizeof(struct cfloopcfg));
+	this->loop = cflooplayer_create();
+	return this;
+}
+EXPORT_SYMBOL(cfloopcfg_create);
+
+void cfloopcfg_add_phy_layer(struct cfloopcfg *cnfg,
+			     enum cfcnfg_phy_type phy_type,
+			     struct layer *phy_layer)
+{
+	if (phy_type == CFPHYTYPE_SERIAL) {
+		struct layer *frml = cffrml_create(1, true);
+		struct layer *cfser;
+		cfser = cfserl_create(phy_type, 0, serial_use_stx);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfser);
+		layer_set_up(cfser, frml);
+		layer_set_dn(cfser, phy_layer);
+		layer_set_up(phy_layer, cfser);
+	}
+	if (phy_type == CFPHYTYPE_SPI) {
+		struct cfspipad padopt;
+		struct layer *frml = cffrml_create(1, false);
+		struct layer *cfspi;
+		/* The loop device has to invert the padding options. */
+		padopt.up_head_align = (uint16)spi_down_head_align;
+		padopt.up_tail_align = (uint16)spi_down_tail_align;
+		padopt.down_head_align = (uint16)spi_up_head_align;
+		padopt.down_tail_align = (uint16)spi_up_tail_align;
+		cfspi = cfspil_create(phy_type, 0, padopt);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfspi);
+		layer_set_up(cfspi, frml);
+		layer_set_dn(cfspi, phy_layer);
+		layer_set_up(phy_layer, cfspi);
+	}
+	if (phy_type == CFPHYTYPE_SHM) {
+		struct layer *frml = cffrml_create(1, false);
+		struct layer *cfshm;
+		cfshm = cfshml_create(phy_type, 0);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfshm);
+		layer_set_up(cfshm, frml);
+		layer_set_dn(cfshm, phy_layer);
+		layer_set_up(phy_layer, cfshm);
+	}
+	if (phy_type == CFPHYTYPE_MSL) {
+		struct layer *frml = cffrml_create(1, false);
+		struct layer *cfmsl;
+		cfmsl = cfmsll_create(phy_type, 0);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfmsl);
+		layer_set_up(cfmsl, frml);
+		layer_set_dn(cfmsl, phy_layer);
+		layer_set_up(phy_layer, cfmsl);
+	}
+	if (phy_type == CFPHYTYPE_USB) {
+		struct layer *frml = cffrml_create(1, false);
+		struct layer *cfusb;
+		cfusb = cfusbl_create(phy_type, 0);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfusb);
+		layer_set_up(cfusb, frml);
+		layer_set_dn(cfusb, phy_layer);
+		layer_set_up(phy_layer, cfusb);
+	}
+}
+EXPORT_SYMBOL(cfloopcfg_add_phy_layer);
diff --git a/net/caif/generic/cflooplayer.c b/net/caif/generic/cflooplayer.c
new file mode 100644
index 0000000..f989120
--- /dev/null
+++ b/net/caif/generic/cflooplayer.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/generic/cfctrl.h>
+
+static int cflooplayer_receive(struct layer *layr, struct cfpkt *pkt);
+static uint8 linkid;
+static int linkused[256];
+static cfglu_lock_t linkid_lock;
+
+struct layer *cflooplayer_create(void)
+{
+	struct layer *this = cfglu_alloc(sizeof(struct layer));
+	memset(this, 0, sizeof(struct layer));
+	this->receive = cflooplayer_receive;
+	cfglu_init_lock(linkid_lock);
+	snprintf(this->name, CAIF_LAYER_NAME_SZ, "loop1");
+	return this;
+}
+
+static int cflooplayer_receive(struct layer *layr, struct cfpkt *inpkt)
+{
+	uint8 id;
+	struct transmt_info info;
+	uint8 *buf;
+	uint16 pktlen;
+	struct cfpkt *pkt;
+	int ret;
+	struct caif_packet_funcs f = cfpkt_get_packet_funcs();
+	memset(&info, 0, sizeof(info));
+	pktlen = cfpkt_getlen(inpkt);
+	ret = f.cfpkt_raw_extract(inpkt, (void **) &buf, pktlen);
+	caif_assert(ret > 0);
+	pkt = f.cfpkt_create_recv_pkt(buf, pktlen);
+	cfpkt_destroy(inpkt);
+	(void) cfpkt_extr_head(pkt, &id, 1);
+	if (id != 0) {
+		/* This is not a control packet, so just loop it. */
+		cfpkt_add_head(pkt, &id, 1);
+	} else {
+		/* This is a control packet. */
+		uint8 tmp;
+		uint8 cmdrsp;
+		uint8 cmd;
+		uint8 linktype = 0;
+
+		(void) cfpkt_extr_head(pkt, &cmdrsp, 1);
+		cmd = cmdrsp & CFCTRL_CMD_MASK;
+
+		switch (cmd) {
+		case CFCTRL_CMD_LINK_SETUP:
+			{
+				caif_assert(!cfpkt_erroneous(pkt));
+				caif_assert(cfpkt_more(pkt));
+				cfpkt_peek_head(pkt, &linktype, 1);
+				caif_assert(!cfpkt_erroneous(pkt));
+				cmdrsp |= CFCTRL_RSP_BIT;
+				cfpkt_add_head(pkt, &cmdrsp, 1);
+				cfpkt_add_head(pkt, &id, 1);
+				cfglu_lock(linkid_lock);
+				for (linkid = 0x41; linkid < 255; linkid++) {
+					if (!linkused[linkid]) {
+						linkused[linkid] = 1;
+						break;
+					}
+				}
+				if (linkid == 255) {
+					CFLOG_WARN(("cflooplayer_receive:"
+						    " no free link id's\n"));
+				}
+				CFLOG_WARN(("cflooplayer_receive: setup "
+					    "linkid = %d\n", linkid));
+				cfpkt_add_trail(pkt, &linkid, 1);
+				cfglu_unlock(linkid_lock);
+
+				if (linktype == 0x06) {
+					tmp = 0x01;
+					cfpkt_add_trail(pkt, &tmp, 1);
+					cfpkt_add_trail(pkt, &tmp, 1);
+				}
+				break;
+			}
+		case CFCTRL_CMD_LINK_DESTROY:
+			cfglu_lock(linkid_lock);
+			(void) cfpkt_peek_head(pkt, &linkid, 1);
+			CFLOG_WARN(("cflooplayer_receive: destroy "
+				    "linkid = %d\n", linkid));
+			linkused[linkid] = 0;
+			cfglu_unlock(linkid_lock);
+			/* fallthrough */
+		default:
+			cmdrsp |= CFCTRL_RSP_BIT;
+			cfpkt_add_head(pkt, &cmdrsp, 1);
+			cfpkt_add_head(pkt, &id, 1);
+			break;
+		}
+	}
+	return layr->dn->transmit(layr->dn, &info, pkt);
+}
diff --git a/net/caif/generic/cfmsll.c b/net/caif/generic/cfmsll.c
new file mode 100644
index 0000000..588fbd7
--- /dev/null
+++ b/net/caif/generic/cfmsll.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfmsll.h>
+
+static int cfmsll_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfmsll_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt);
+
+struct layer *cfmsll_create(int type, int instance)
+{
+	struct layer *this = cfglu_alloc(sizeof(struct layer));
+	memset(this, 0, sizeof(struct layer));
+	this->receive = cfmsll_receive;
+	this->transmit = cfmsll_transmit;
+	this->type = type;
+	snprintf(this->name, CAIF_LAYER_NAME_SZ - 1, "msl%d", instance);
+	this->name[CAIF_LAYER_NAME_SZ-1] = '\0';
+	return this;
+}
+
+void cfmsll_set_uplayer(struct layer *this, struct layer *up)
+{
+	this->up = up;
+}
+
+void cfmsll_set_dnlayer(struct layer *this, struct layer *dn)
+{
+	this->dn = dn;
+}
+
+static int cfmsll_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	/* Send the first part of the packet upwards. */
+	int ret = layr->up->receive(layr->up, pkt);
+	/* FCS error - don't delete the packet. */
+	if (ret == CFGLU_EFCS)
+		cfpkt_destroy(pkt);
+	return ret;
+}
+
+static int cfmsll_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt)
+{
+	return layr->dn->transmit(layr->dn, info, pkt);
+}
diff --git a/net/caif/generic/cfmuxl.c b/net/caif/generic/cfmuxl.c
new file mode 100644
index 0000000..5b2a2cc
--- /dev/null
+++ b/net/caif/generic/cfmuxl.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfmuxl.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cffrml.h>
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfmuxl, layer)
+
+#define CAIF_CTRL_CHANNEL 0
+#define UP_CACHE_SIZE 8
+#define DN_CACHE_SIZE 8
+
+struct cfmuxl {
+	struct layer layer;
+	struct layer *up_cache[UP_CACHE_SIZE];
+	struct layer *dn_cache[DN_CACHE_SIZE];
+	/*
+	 * Set when inserting or removing downwards layers.
+	 */
+	cfglu_lock_t transmit_lock;
+
+	/*
+	 * Set when inserting or removing upwards layers.
+	 */
+	cfglu_lock_t receive_lock;
+
+};
+
+static int cfmuxl_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfmuxl_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt);
+static void cfmuxl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid);
+static struct layer *get_up(struct cfmuxl *muxl, int id);
+
+struct layer *cfmuxl_create()
+{
+	struct cfmuxl *this = cfglu_alloc(sizeof(struct cfmuxl));
+	memset(this, 0, sizeof(*this));
+	this->layer.receive = cfmuxl_receive;
+	this->layer.transmit = cfmuxl_transmit;
+	this->layer.ctrlcmd = cfmuxl_ctrlcmd;
+	cfglu_init_lock(this->transmit_lock);
+	cfglu_init_lock(this->receive_lock);
+	snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "mux");
+	return &this->layer;
+}
+
+bool cfmuxl_set_uplayer(struct layer *layr, struct layer *up, uint8 linkid)
+{
+	bool ok;
+	struct cfmuxl *muxl = container_obj(layr);
+	CFLOG_ENTER(("layr:%p up:%p linkid:%d\n", (void *) layr, (void *) up,
+		     linkid));
+	cfglu_lock(muxl->receive_lock);
+	ok = cflst_put(&muxl->layer.up, linkid, up);
+	cfglu_unlock(muxl->receive_lock);
+	CFLOG_EXIT(("ok=%d\n", ok));
+	return ok;
+}
+
+bool cfmuxl_is_phy_inuse(struct layer *layr, uint8 phyid)
+{
+	struct layer *p;
+	struct cfmuxl *muxl = container_obj(layr);
+	bool match = false;
+	cfglu_lock(muxl->receive_lock);
+	CFLOG_ENTER(("\n"));
+
+	for (p = layr->up; p != NULL; p = p->next) {
+		if (cfsrvl_phyid_match(p, phyid)) {
+			match = true;
+			break;
+		}
+	}
+	cfglu_unlock(muxl->receive_lock);
+	CFLOG_EXIT(("\n"));
+	return match;
+}
+
+uint8 cfmuxl_get_phyid(struct layer *layr, uint8 channel_id)
+{
+	struct layer *up;
+	int phyid;
+	struct cfmuxl *muxl = container_obj(layr);
+	cfglu_lock(muxl->receive_lock);
+	CFLOG_ENTER(("\n"));
+	up = get_up(muxl, channel_id);
+	if (up != NULL)
+		phyid = cfsrvl_getphyid(up);
+	else
+		phyid = 0;
+	cfglu_unlock(muxl->receive_lock);
+	return phyid;
+}
+
+bool cfmuxl_set_dnlayer(struct layer *layr, struct layer *dn, uint8 phyid)
+{
+	bool ok;
+	struct cfmuxl *muxl = (struct cfmuxl *) layr;
+	CFLOG_ENTER(("\n"));
+	cfglu_lock(muxl->transmit_lock);
+	ok = cflst_put(&muxl->layer.dn, phyid, dn);
+	cfglu_unlock(muxl->transmit_lock);
+	CFLOG_EXIT(("\n"));
+	return ok;
+}
+
+struct layer *cfmuxl_remove_dnlayer(struct layer *layr, uint8 phyid)
+{
+	struct cfmuxl *muxl = container_obj(layr);
+	struct layer *dn;
+	CFLOG_ENTER(("\n"));
+	cfglu_lock(muxl->transmit_lock);
+	memset(muxl->dn_cache, 0, sizeof(muxl->dn_cache));
+	dn = cflst_del(&muxl->layer.dn, phyid);
+	caif_assert(dn != NULL);
+	cfglu_unlock(muxl->transmit_lock);
+	CFLOG_EXIT(("\n"));
+	return dn;
+}
+
+/* Invariant: lock is taken */
+static struct layer *get_up(struct cfmuxl *muxl, int id)
+{
+	struct layer *up;
+	int idx = id % UP_CACHE_SIZE;
+	CFLOG_ENTER(("id:%d\n", id));
+	up = muxl->up_cache[idx];
+	if (up == NULL || up->id != id) {
+		up = cflst_get(&muxl->layer.up, id);
+		muxl->up_cache[idx] = up;
+	}
+	CFLOG_EXIT(("id: %d up:%p", id, (void *) up));
+	return up;
+}
+
+/* Invariant: lock is taken */
+static struct layer *get_dn(struct cfmuxl *muxl, int id)
+{
+	struct layer *dn;
+	int idx = id % DN_CACHE_SIZE;
+	CFLOG_ENTER(("\n"));
+	dn = muxl->dn_cache[idx];
+	if (dn == NULL || dn->id != id) {
+		dn = cflst_get(&muxl->layer.dn, id);
+		muxl->dn_cache[idx] = dn;
+	}
+	CFLOG_EXIT(("\n"));
+	return dn;
+}
+
+struct layer *cfmuxl_remove_uplayer(struct layer *layr, uint8 id)
+{
+	struct layer *up;
+	struct cfmuxl *muxl = container_obj(layr);
+	CFLOG_ENTER(("\n"));
+	cfglu_lock(muxl->receive_lock);
+	memset(muxl->up_cache, 0, sizeof(muxl->up_cache));
+	up = cflst_del(&muxl->layer.up, id);
+	caif_assert(up != NULL);
+	cfglu_unlock(muxl->receive_lock);
+	CFLOG_EXIT(("\n"));
+	return up;
+}
+
+static int cfmuxl_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	int ret;
+	struct cfmuxl *muxl = container_obj(layr);
+	uint8 id;
+	struct layer *up;
+	CFLOG_ENTER(("\n"));
+	if (!cfpkt_extr_head(pkt, &id, 1)) {
+		CFLOG_ERROR(("cfmuxl: erroneous Caif Packet\n"));
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("error"));
+		return CFGLU_EPKT;
+	}
+
+	up = get_up(muxl, id);
+	if (up == NULL) {
+		CFLOG_WARN(("CAIF: Received data on unknown link ID = %d "
+			    "(0x%x)  up == NULL", id, id));
+		cfpkt_destroy(pkt);
+		/* Don't return ERROR, since modem misbehaves and sends out
+		 *  flow before linksetup response.
+		 */
+		CFLOG_EXIT(("error - unknown channel"));
+		return /* CFGLU_EPROT; */ CFGLU_EOK;
+	}
+
+	ret = up->receive(up, pkt);
+
+	CFLOG_EXIT(("\n"));
+
+	return ret;
+}
+
+static int cfmuxl_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt)
+{
+	int ret;
+	struct cfmuxl *muxl = container_obj(layr);
+	uint8 linkid;
+	struct layer *dn;
+	CFLOG_ENTER(("\n"));
+
+	dn = get_dn(muxl, info->phid);
+	if (dn == NULL) {
+		CFLOG_WARN(("CAIF: Send data on unknown phy ID = %d (0x%x)\n",
+			    info->phid, info->phid));
+		CFLOG_EXIT(("error"));
+		return CFGLU_ENOTCONN;
+	}
+	info->hdr_len += 1;
+	linkid = info->channel_id;
+	cfpkt_add_head(pkt, &linkid, 1);
+
+	ret = dn->transmit(dn, info, pkt);
+	if (ret < 0) {
+		/* Remove MUX protocol header upon error. */
+		cfpkt_extr_head(pkt, &linkid, 1);
+	}
+
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
+
+static void cfmuxl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid)
+{
+	struct layer *p;
+	struct cfmuxl *muxl = container_obj(layr);
+	for (p = muxl->layer.up; p != NULL; p = p->next) {
+		if (cfsrvl_phyid_match(p, phyid))
+			p->ctrlcmd(p, ctrl, phyid);
+	}
+}
diff --git a/net/caif/generic/cfpkt_skbuff.c b/net/caif/generic/cfpkt_skbuff.c
new file mode 100644
index 0000000..584c768
--- /dev/null
+++ b/net/caif/generic/cfpkt_skbuff.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/hardirq.h>
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfpkt.h>
+
+/* Maximum size of CAIF header */
+#define PKT_PREFIX CAIF_NEEDED_HEADROOM
+
+/* Maximum size of CAIF trailer */
+#define PKT_POSTFIX CAIF_NEEDED_TAILROOM
+
+#define PKT_LEN_WHEN_EXTENDING 128
+
+#define CFPKT_PRIV_DATA(pkt) ((struct cfpkt_priv_data *) (&pkt->skb.cb[0]))
+
+#define PKT_ERROR(pkt, errmsg) do {	   \
+    CFPKT_PRIV_DATA(pkt)->erronous = true; \
+    skb_reset_tail_pointer(&pkt->skb);	   \
+    CFLOG_WARN((errmsg));		   \
+  } while (0)
+
+#ifdef CFKPKT_PACKET_DUMP
+char pkt_debug_buffer[256];
+#define pkt_dump_debug(pkt) do {				     \
+    cfpkt_log_pkt((pkt), pkt_debug_buffer, 250);		     \
+    printk(KERN_DEBUG "%d: nonlinear: %s, fp=%s %s",		     \
+	__LINE__,						     \
+	skb_is_nonlinear(&(pkt)->skb) ? "true" : "false",	     \
+	CFPKT_PRIV_DATA((pkt))->fastpath ? "true" : "false",	     \
+	pkt_debug_buffer);					     \
+  } while (0)
+#else
+#define pkt_dump_debug(pkt)
+#endif
+
+struct cfpktq {
+	struct sk_buff_head head;
+	cfglu_atomic_t count;
+	spinlock_t lock;
+};
+
+/* struct cfpkt is (memory-wise) an sk_buff, but struct cfpkt is forward
+ * declared in cfpkt.h, so we do it this way (instead of typedef):
+ */
+struct cfpkt {
+	struct sk_buff skb;
+};
+
+/* Private data inside SKB */
+struct cfpkt_priv_data {
+	bool erronous;
+	/*!<Indicate fastpath; buffer has large enough head and tail room,
+	 * so boundary checks are skipped.
+	 */
+	bool fastpath;
+};
+
+cfglu_atomic_t cfpkt_packet_count;
+EXPORT_SYMBOL(cfpkt_packet_count);
+
+struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt)
+{
+	struct cfpkt *pkt = (struct cfpkt *) nativepkt;
+
+	/* In Linux, "native" is always sk_buff: */
+	struct sk_buff *skb = (struct sk_buff *) nativepkt;
+
+	CFPKT_PRIV_DATA(pkt)->erronous = false;
+
+	/* Set Fastpath if we have enough head room */
+	if (likely(dir == CAIF_DIR_OUT && !skb_is_nonlinear(skb)
+		   && skb_headroom(skb) >= PKT_PREFIX
+		   && skb_tailroom(skb) >= PKT_POSTFIX))
+		CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	else if (likely(dir == CAIF_DIR_IN && !skb_is_nonlinear(skb)
+			&& skb_headlen(skb) > PKT_PREFIX + PKT_POSTFIX))
+		CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	else
+		CFPKT_PRIV_DATA(pkt)->fastpath = false;
+
+	CFLOG_TRACE3(("cfpkt_fromnative: fastpath=%s",
+		      CFPKT_PRIV_DATA(pkt)->fastpath ? "true" : "false"));
+	cfglu_atomic_inc(cfpkt_packet_count);
+
+	pkt_dump_debug(pkt);
+	return pkt;
+}
+EXPORT_SYMBOL(cfpkt_fromnative);
+
+void *cfpkt_tonative(struct cfpkt *pkt)
+{
+	/* In Linux, "native" is always sk_buff: */
+	pkt_dump_debug(pkt);
+	return (void *) pkt;
+}
+EXPORT_SYMBOL(cfpkt_tonative);
+
+struct cfpkt *cfpkt_create_pfx(uint16 len, uint16 pfx)
+{
+	struct sk_buff *skb;
+
+	if (likely(in_interrupt()))
+		skb = alloc_skb(len + pfx, GFP_ATOMIC);
+	else
+		skb = alloc_skb(len + pfx, GFP_KERNEL);
+
+	if (unlikely(skb == NULL))
+		return NULL;
+
+	skb_reserve(skb, pfx);
+	cfglu_atomic_inc(cfpkt_packet_count);
+	return (struct cfpkt *) skb;
+}
+
+inline struct cfpkt *cfpkt_create(uint16 len)
+{
+	struct cfpkt *r = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+	CFPKT_PRIV_DATA(r)->fastpath = true;
+
+	pkt_dump_debug(r);
+	return r;
+}
+EXPORT_SYMBOL(cfpkt_create);
+
+void cfpkt_destroy(struct cfpkt *pkt)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	cfglu_atomic_dec(cfpkt_packet_count);
+	caif_assert(cfglu_atomic_read(cfpkt_packet_count) >= 0);
+	kfree_skb(skb);
+}
+EXPORT_SYMBOL(cfpkt_destroy);
+
+inline bool cfpkt_more(struct cfpkt *pkt)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	return skb->len > 0;
+}
+EXPORT_SYMBOL(cfpkt_more);
+
+bool cfpkt_peek_head(struct cfpkt *pkt, void *data, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	pkt_dump_debug(pkt);
+	if (likely(CFPKT_PRIV_DATA(pkt)->fastpath)) {
+		memcpy(data, skb->data, len);
+		pkt_dump_debug(pkt);
+		return true;
+	}
+	return cfpkt_extr_head(pkt, data, len) &&
+	    cfpkt_add_head(pkt, data, len);
+}
+EXPORT_SYMBOL(cfpkt_peek_head);
+
+bool cfpkt_extr_head(struct cfpkt *pkt, void *data, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	uint8 *from;
+	pkt_dump_debug(pkt);
+
+	if (unlikely(len > skb->len)) {
+		PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n");
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+
+	if (unlikely(!(CFPKT_PRIV_DATA(pkt)->fastpath) &&
+		     (len > skb_headlen(skb)))) {
+		if (unlikely(skb_linearize(skb) != 0)) {
+			CFPKT_PRIV_DATA(pkt)->erronous = true;
+			return false;
+		}
+	}
+
+	from = skb_pull(skb, len);
+	from -= len;
+	memcpy(data, from, len);
+	pkt_dump_debug(pkt);
+	return true;
+}
+EXPORT_SYMBOL(cfpkt_extr_head);
+
+bool cfpkt_extr_trail(struct cfpkt *pkt, void *dta, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	uint8 *data = dta;
+	uint8 *from;
+	pkt_dump_debug(pkt);
+	if (unlikely(skb_linearize(skb) != 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+	pkt_dump_debug(pkt);
+	if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
+		PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n");
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+	from = skb_tail_pointer(skb) - len;
+	skb_trim(skb, skb->len - len);
+	pkt_dump_debug(pkt);
+	memcpy(data, from, len);
+	return true;
+}
+EXPORT_SYMBOL(cfpkt_extr_trail);
+
+bool cfpkt_pad_trail(struct cfpkt *pkt, uint16 len)
+{
+	return cfpkt_add_body(pkt, NULL, len);
+}
+EXPORT_SYMBOL(cfpkt_pad_trail);
+
+bool cfpkt_add_body(struct cfpkt *pkt, const void *data, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	struct sk_buff *lastskb;
+	uint8 *to;
+	uint16 addlen = 0;
+
+	pkt_dump_debug(pkt);
+
+	lastskb = skb;
+
+	/* Check whether we need to add space at the tail */
+	if (unlikely(skb_tailroom(skb) < len)) {
+		if (likely(len < PKT_LEN_WHEN_EXTENDING))
+			addlen = PKT_LEN_WHEN_EXTENDING;
+		else
+			addlen = len;
+	}
+
+	/* Check whether we need to change the SKB before writing to the tail */
+	if (unlikely((addlen > 0) || skb_cloned(skb) || skb_shared(skb))) {
+
+		/* Make sure data is writable */
+		if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
+			CFPKT_PRIV_DATA(pkt)->erronous = true;
+			return false;
+		}
+
+		/* Is the SKB non-linear after skb_cow_data()? If so, we are
+		 * going to add data to the last SKB, so we need to adjust
+		 * lengths of the top SKB.
+		 */
+		if (lastskb != skb) {
+			skb->len += len;
+			skb->data_len += len;
+		}
+	}
+
+	/* All set to put the last SKB and optionally write data there. */
+	to = skb_put(lastskb, len);
+	if (likely(data))
+		memcpy(to, data, len);
+	pkt_dump_debug(pkt);
+	return true;
+}
+EXPORT_SYMBOL(cfpkt_add_body);
+
+inline bool cfpkt_addbdy(struct cfpkt *pkt, uint8 data)
+{
+	return cfpkt_add_body(pkt, &data, 1);
+}
+EXPORT_SYMBOL(cfpkt_addbdy);
+
+bool cfpkt_add_head(struct cfpkt *pkt, const void *data2, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	struct sk_buff *lastskb;
+	uint8 *to;
+	const uint8 *data = data2;
+	pkt_dump_debug(pkt);
+	if (unlikely(skb_headroom(skb) < len)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+
+	/* Make sure data is writable */
+	if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+
+	to = skb_push(skb, len);
+	memcpy(to, data, len);
+	pkt_dump_debug(pkt);
+	return true;
+}
+EXPORT_SYMBOL(cfpkt_add_head);
+
+inline bool cfpkt_add_trail(struct cfpkt *pkt, const void *data, uint16 len)
+{
+	return cfpkt_add_body(pkt, data, len);
+}
+EXPORT_SYMBOL(cfpkt_add_trail);
+
+inline uint16 cfpkt_getlen(struct cfpkt *pkt)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	return skb->len;
+}
+EXPORT_SYMBOL(cfpkt_getlen);
+
+inline uint16 cfpkt_iterate(struct cfpkt *pkt, iterfunc_t func, uint16 data)
+{
+
+	/* Don't care about the performance hit of linearizing,
+	 * Checksum should not be used on high-speed interfaces anyway.
+	 */
+	if (unlikely(skb_linearize(&pkt->skb) != 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return 0;
+	}
+	return func(data, pkt->skb.data, cfpkt_getlen(pkt));
+}
+EXPORT_SYMBOL(cfpkt_iterate);
+
+int cfpkt_setlen(struct cfpkt *pkt, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+
+	pkt_dump_debug(pkt);
+
+	if (likely(len <= skb->len)) {
+		if (unlikely(skb->data_len))
+			___pskb_trim(skb, len);
+		else
+			skb_trim(skb, len);
+
+		pkt_dump_debug(pkt);
+		return cfpkt_getlen(pkt);
+	}
+
+	/* Need to expand SKB */
+	if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+
+	pkt_dump_debug(pkt);
+	return cfpkt_getlen(pkt);
+}
+EXPORT_SYMBOL(cfpkt_setlen);
+
+void
+cfpkt_extract(struct cfpkt *cfpkt, void *buf, unsigned int buflen,
+	      unsigned int *actual_len)
+{
+	uint16 pklen;
+
+	pkt_dump_debug(cfpkt);
+	pklen = cfpkt_getlen(cfpkt);
+	if (likely(buflen < pklen))
+		pklen = buflen;
+	*actual_len = pklen;
+	cfpkt_extr_head(cfpkt, buf, pklen);
+	pkt_dump_debug(cfpkt);
+}
+EXPORT_SYMBOL(cfpkt_extract);
+
+struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len)
+{
+	struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+	CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	if (unlikely(data != NULL))
+		cfpkt_add_body(pkt, data, len);
+	return pkt;
+}
+
+
+#ifdef CAIF_FAST_SKB_OPS
+struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt,
+				uint16 expectlen)
+{
+	struct sk_buff *dst = (struct sk_buff *) dstpkt;
+	struct sk_buff *add = (struct sk_buff *) addpkt;
+	struct sk_buff *lastskb;
+	CFPKT_PRIV_DATA(addpkt)->fastpath = false;
+	CFPKT_PRIV_DATA(dstpkt)->fastpath = false;
+	pkt_dump_debug(dstpkt);
+	pkt_dump_debug(addpkt);
+
+	/* TODO Could we (instead of calling skb_cow_data()) check for
+	 * cloned || shared and if true allocate a new skb
+	 * with an empty head and set skb_shinfo(skb)->frag_list = add ?
+	 * If this is safe, would it be more efficient?
+	 */
+
+	/* Make sure destination SKB is writable */
+	if (unlikely(skb_cow_data(dst, 0, &lastskb) < 0)) {
+		CFPKT_PRIV_DATA(dstpkt)->erronous = true;
+		return dstpkt;
+	}
+
+	/* First get the frag_list if any */
+	if (likely(skb_shinfo(dst)->frag_list == NULL))
+		skb_shinfo(dst)->frag_list = add;
+	else {
+		lastskb = skb_shinfo(dst)->frag_list;
+
+		/* Go to the very right in the fragment list */
+		while (lastskb->next)
+			lastskb = lastskb->next;
+
+		lastskb->next = add;
+	}
+
+	/* Update size */
+	dst->data_len += add->len;
+	dst->len += add->len;
+	dst->truesize += add->truesize;
+	pkt_dump_debug(dstpkt);
+	cfglu_atomic_dec(cfpkt_packet_count);
+	return dstpkt;
+}
+EXPORT_SYMBOL(cfpkt_append);
+
+struct cfpkt *cfpkt_split(struct cfpkt *pkt, uint16 pos)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	struct sk_buff *skb2;
+	CFPKT_PRIV_DATA(pkt)->fastpath = false;
+	if (unlikely(pos > skb->len)) {
+		PKT_ERROR(pkt, "cfpkt_split: split beyond end of packet\n");
+		return NULL;
+	}
+	pkt_dump_debug(pkt);
+
+	/* Make sure SKB is writable */
+	if (unlikely(skb_cow_data(skb, 0, &skb2) < 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return NULL;
+	}
+
+	skb2 = (struct sk_buff *) cfpkt_create(skb->len - pos);
+
+	if (unlikely(skb2 == NULL))
+		return NULL;
+
+	CFPKT_PRIV_DATA(pkt)->fastpath = false;
+	CFPKT_PRIV_DATA(pkt)->erronous = false;
+	pkt_dump_debug((struct cfpkt *) skb2);
+
+	skb_split(skb, skb2, pos);
+
+	pkt_dump_debug((struct cfpkt *) skb2);
+	cfglu_atomic_inc(cfpkt_packet_count);
+	return (struct cfpkt *) skb2;
+}
+EXPORT_SYMBOL(cfpkt_split);
+
+#else
+struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
+			     struct cfpkt *addpkt,
+			     uint16 expectlen)
+{
+	struct sk_buff *dst = (struct sk_buff *) dstpkt;
+	struct sk_buff *add = (struct sk_buff *) addpkt;
+	uint16 addlen = add->tail - add->data;
+	uint16 neededtailspace;
+	struct sk_buff *tmp;
+	uint16 dstlen;
+	uint16 createlen;
+
+	if (expectlen > addlen)
+		neededtailspace = expectlen;
+	else
+		neededtailspace = addlen;
+
+	if (dst->tail + neededtailspace > dst->end) {
+		/* Create a dumplicate of 'dst' with more tail space */
+		dstlen = dst->tail - dst->data;
+		createlen = dstlen + addlen;
+		if (expectlen > createlen)
+			createlen = expectlen;
+		tmp = (struct sk_buff *)
+			cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX);
+		tmp->tail = tmp->data + dstlen;
+		tmp->len = dstlen;
+		memcpy(tmp->data, dst->data, dstlen);
+		cfpkt_destroy(dstpkt);
+		dst = tmp;
+	}
+	memcpy(dst->tail, add->data, add->tail - add->data);
+	cfpkt_destroy(addpkt);
+	dst->tail += addlen;
+	dst->len += addlen;
+	return (struct cfpkt *) dst;
+}
+
+struct cfpkt *cfpkt_split(struct cfpkt *pkt, uint16 pos)
+{
+	struct sk_buff *skb2;		/* FIXME: Rename skb2 to pkt2 */
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	uint8 *split = skb->data + pos;
+	uint16 len2nd = skb->tail - split;
+	CFLOG_TRACE3(("cfpkt_split(%p,%d)", (void *) pkt, pos));
+
+	if (skb->data + pos > skb->tail) {
+		PKT_ERROR(pkt,
+			  "cfpkt_split: trying to split beyond end of packet");
+		return 0;
+	}
+
+	/* Create a new packet for the second part of the data */
+	skb2 = (struct sk_buff *)
+		cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX,
+				 PKT_PREFIX);
+
+	if (skb2 == NULL)
+		return NULL;
+
+	/* Reduce the length of the original packet */
+	skb->tail = split;
+	skb->len -= pos;
+
+	memcpy(skb2->data, split, len2nd);
+	skb2->tail += len2nd;
+	skb2->len += len2nd;
+	return (struct cfpkt *) skb2;
+}
+#endif
+
+char *cfpkt_log_pkt(struct cfpkt *cfpkt, char *buf, int buflen)
+{
+	struct sk_buff *skb = (struct sk_buff *) cfpkt;
+	char *p = buf;
+	int i;
+
+	if (skb_linearize(skb) != 0)
+		return NULL;
+	/* Sanity check buffer length, it needs to be at least as large as
+	 *  the header info: ~=50+ bytes
+	 */
+	if (buflen < 50)
+		return NULL;
+
+	snprintf(buf, buflen, " pkt:%p len:%d {%d,%d} data: [",
+		skb,
+		skb->tail - skb->data,
+		skb->data - skb->head, skb->tail - skb->head);
+	p = buf + strlen(buf);
+
+	for (i = 0; i < skb->tail - skb->data; i++) {
+		if (p > buf + buflen - 10) {
+			sprintf(p, "...");
+			p = buf + strlen(buf);
+			break;
+		}
+		sprintf(p, "%02x,", skb->data[i]);
+		p = buf + strlen(buf);
+	}
+	sprintf(p, "]\n");
+	return buf;
+}
+EXPORT_SYMBOL(cfpkt_log_pkt);
+
+int cfpkt_raw_append(struct cfpkt *cfpkt, void **buf, unsigned int buflen)
+{
+	struct sk_buff *skb = (struct sk_buff *) cfpkt;
+	struct sk_buff *lastskb;
+
+	caif_assert(buf != NULL);
+
+	/* Make sure SKB is writable */
+	if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	if (unlikely(skb_linearize(skb) != 0)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	if (unlikely(skb_tailroom(skb) < buflen)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	*buf = skb_put(skb, buflen);
+	return 1;
+}
+EXPORT_SYMBOL(cfpkt_raw_append);
+
+int cfpkt_raw_extract(struct cfpkt *cfpkt, void **buf, unsigned int buflen)
+{
+	struct sk_buff *skb = (struct sk_buff *) cfpkt;
+
+	caif_assert(buf != NULL);
+
+	if (unlikely(buflen > skb->len)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	if (unlikely(buflen > skb_headlen(skb))) {
+		if (unlikely(skb_linearize(skb) != 0)) {
+			CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+			return 0;
+		}
+	}
+
+	*buf = skb->data;
+	skb_pull(skb, buflen);
+
+	return 1;
+}
+EXPORT_SYMBOL(cfpkt_raw_extract);
+
+inline bool cfpkt_erroneous(struct cfpkt *pkt)
+{
+	return CFPKT_PRIV_DATA(pkt)->erronous;
+}
+EXPORT_SYMBOL(cfpkt_erroneous);
+
+struct cfpkt *cfpkt_create_pkt(enum caif_direction dir,
+			  const unsigned char *data, unsigned int len)
+{
+	struct cfpkt *pkt;
+	if (dir == CAIF_DIR_OUT)
+		pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+	else
+		pkt = cfpkt_create_pfx(len, 0);
+
+	if (unlikely(data))
+		cfpkt_add_body(pkt, data, len);
+	CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	CFPKT_PRIV_DATA(pkt)->erronous = false;
+	return pkt;
+}
+EXPORT_SYMBOL(cfpkt_create_pkt);
+
+
+struct caif_packet_funcs cfpkt_get_packet_funcs()
+{
+	struct caif_packet_funcs f;
+	f.cfpkt_fromnative = cfpkt_fromnative;
+	f.cfpkt_tonative = cfpkt_tonative;
+	f.cfpkt_destroy = cfpkt_destroy;
+	f.cfpkt_extract = cfpkt_extract;
+	f.cfpkt_create_xmit_pkt = cfpkt_create_uplink;
+	f.cfpkt_create_recv_pkt = cfpkt_create_uplink;
+	f.cfpkt_dequeue = cfpkt_dequeue;
+	f.cfpkt_qpeek = cfpkt_qpeek;
+	f.cfpkt_queue = cfpkt_queue;
+	f.cfpktq_create = cfpktq_create;
+	f.cfpkt_raw_extract = cfpkt_raw_extract;
+	f.cfpkt_raw_append = cfpkt_raw_append;
+	f.cfpkt_getlen = cfpkt_getlen;
+	return f;
+}
+
+struct cfpktq *cfpktq_create()
+{
+	struct cfpktq *q = cfglu_alloc(sizeof(struct cfpktq));
+	skb_queue_head_init(&q->head);
+	cfglu_atomic_set(q->count, 0);
+	spin_lock_init(&q->lock);
+	return q;
+}
+EXPORT_SYMBOL(cfpktq_create);
+
+void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, unsigned short prio)
+{
+	cfglu_atomic_inc(pktq->count);
+	spin_lock(&pktq->lock);
+	skb_queue_tail(&pktq->head, (struct sk_buff *) pkt);
+	spin_unlock(&pktq->lock);
+
+}
+EXPORT_SYMBOL(cfpkt_queue);
+
+struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq)
+{
+	struct cfpkt *tmp;
+	spin_lock(&pktq->lock);
+	tmp = (struct cfpkt *) skb_peek(&pktq->head);
+	spin_unlock(&pktq->lock);
+	return tmp;
+}
+EXPORT_SYMBOL(cfpkt_qpeek);
+
+struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq)
+{
+	struct cfpkt *pkt;
+	spin_lock(&pktq->lock);
+	pkt = (struct cfpkt *) skb_dequeue(&pktq->head);
+	if (pkt) {
+		cfglu_atomic_dec(pktq->count);
+		caif_assert(cfglu_atomic_read(pktq->count) >= 0);
+	}
+	spin_unlock(&pktq->lock);
+	return pkt;
+}
+EXPORT_SYMBOL(cfpkt_dequeue);
+
+int cfpkt_qcount(struct cfpktq *pktq)
+{
+	return cfglu_atomic_read(pktq->count);
+}
+EXPORT_SYMBOL(cfpkt_qcount);
+
+struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt)
+{
+	struct cfpkt *clone;
+
+	clone  = (struct cfpkt *) skb_clone((struct sk_buff *) pkt, GFP_ATOMIC);
+
+	/* Free original packet. */
+	cfpkt_destroy(pkt);
+
+	if (!clone)
+		return NULL;
+
+	cfglu_atomic_inc(cfpkt_packet_count);
+
+	return clone;
+}
+EXPORT_SYMBOL(cfpkt_clone_release);
diff --git a/net/caif/generic/cfrfml.c b/net/caif/generic/cfrfml.c
new file mode 100644
index 0000000..1ed70b5
--- /dev/null
+++ b/net/caif/generic/cfrfml.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfsrvl, layer)
+
+#define RFM_SEGMENTATION_BIT 0x01
+#define RFM_PAYLOAD  0x00
+#define RFM_CMD_BIT  0x80
+#define RFM_FLOW_OFF 0x81
+#define RFM_FLOW_ON  0x80
+#define RFM_SET_PIN  0x82
+#define RFM_CTRL_PKT_SIZE 1
+
+static int cfrfml_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfrfml_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt);
+
+struct layer *cfrfml_create(uint8 channel_id, uint8 phyid)
+{
+	struct cfsrvl *rfm = cfglu_alloc(sizeof(struct cfsrvl));
+	caif_assert(offsetof(struct cfsrvl, layer) == 0);
+
+	memset(rfm, 0, sizeof(struct cfsrvl));
+	cfsrvl_init(rfm, channel_id, phyid);
+	rfm->layer.receive = cfrfml_receive;
+	rfm->layer.transmit = cfrfml_transmit;
+	snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id);
+	return &rfm->layer;
+}
+
+void cffrml_destroy(struct layer *layer)
+{
+	cfglu_free(layer);
+}
+
+static int cfrfml_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	uint8 tmp;
+	bool segmented;
+	int ret;
+	CFLOG_ENTER(("\n"));
+	caif_assert(layr->up != NULL);
+	caif_assert(layr->receive != NULL);
+
+	/*
+	 * RFM is taking care of segmentation and stripping of
+	 * segmentation bit.
+	 */
+	if (!cfpkt_extr_head(pkt, &tmp, 1)) {
+		CFLOG_ERROR(("cfrfml: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPROTO;
+	}
+	segmented = tmp & RFM_SEGMENTATION_BIT;
+	caif_assert(!segmented);
+
+	ret = layr->up->receive(layr->up, pkt);
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
+
+static int cfrfml_transmit(struct layer *layr, struct transmt_info *dummy,
+			   struct cfpkt *pkt)
+{
+	uint8 tmp = 0;
+	struct transmt_info info;
+	int ret;
+	struct cfsrvl *service = container_obj(layr);
+
+	caif_assert(layr->dn != NULL);
+	caif_assert(layr->dn->transmit != NULL);
+
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("Packet too large - size=%d\n",
+			     cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+
+	if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("Packet too large - size=%d\n",
+			     cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+	if (!cfpkt_add_head(pkt, &tmp, 1)) {
+		CFLOG_ERROR(("cffrml: Packet is erroneous!\n"));
+		return CFGLU_EPKT;
+	}
+
+	/* Add info for MUX-layer to route the packet out. */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	/* To optimize alignment, we add up the size of CAIF header before
+	 * payload.
+	 */
+	info.hdr_len = 1;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_extr_head(pkt, &tmp, 1);
+	return ret;
+}
diff --git a/net/caif/generic/cfserl.c b/net/caif/generic/cfserl.c
new file mode 100644
index 0000000..9697941
--- /dev/null
+++ b/net/caif/generic/cfserl.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+
+#define container_obj(layr) ((struct cfserl *) layr)
+
+#define CFSERL_STX 0x02
+#define CAIF_MINIUM_PACKET_SIZE 4
+struct cfserl {
+	struct layer layer;
+	struct cfpkt *incomplete_frm;
+	cfglu_lock_t sync;
+	bool usestx;
+};
+#define STXLEN(layr) (layr->usestx ? 1 : 0)
+
+/**
+ * This variable is used as a global flag, in order to set whether
+ * STX is used on serial communication.
+ * NOTE: This is not a fully future proof solution.
+ */
+int serial_use_stx;
+EXPORT_SYMBOL(serial_use_stx);
+
+
+
+static int cfserl_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfserl_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt);
+static void cfserl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid);
+
+struct cfserl *cfserl_create(int type, int instance, bool use_stx)
+{
+	struct cfserl *this = cfglu_alloc(sizeof(struct cfserl));
+	caif_assert(offsetof(struct cfserl, layer) == 0);
+
+	memset(this, 0, sizeof(struct cfserl));
+	this->layer.receive = cfserl_receive;
+	this->layer.transmit = cfserl_transmit;
+	this->layer.ctrlcmd = cfserl_ctrlcmd;
+	this->layer.type = type;
+	this->usestx = use_stx;
+	cfglu_init_lock(this->sync);
+	snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1");
+	return this;
+}
+
+void cfserl_set_uplayer(struct cfserl *this, struct layer *up)
+{
+	this->layer.up = up;
+}
+
+void cfserl_set_dnlayer(struct cfserl *this, struct layer *dn)
+{
+	this->layer.dn = dn;
+}
+
+static int cfserl_receive(struct layer *l, struct cfpkt *newpkt)
+{
+	struct cfserl *layr = container_obj(l);
+	uint16 pkt_len;
+	struct cfpkt *pkt = NULL;
+	struct cfpkt *tail_pkt = NULL;
+	uint8 tmp8;
+	uint16 tmp;
+	uint8 stx = CFSERL_STX;
+	int ret;
+	uint16 expectlen = 0;
+#ifdef CAIF_DEBUG_ON
+	uint16 newpktlen;
+	static char buf[10000];
+#endif
+	caif_assert(newpkt != NULL);
+#ifdef CAIF_DEBUG_ON
+	newpktlen = cfpkt_getlen(newpkt);
+	CFLOG_ENTER(("\n"));
+	if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+		cfpkt_log_pkt(newpkt, buf, sizeof(buf));
+		CFLOG_TRACE3(("serl: RECEIVE PACKET %s\n", buf));
+	}
+#endif
+	cfglu_lock(layr->sync);
+
+	if (layr->incomplete_frm != NULL) {
+
+		layr->incomplete_frm =
+		    cfpkt_append(layr->incomplete_frm, newpkt, expectlen);
+#ifdef CAIF_DEBUG_ON
+		CFLOG_TRACE2(("serl: Appending %d bytes, new packet holds %d "
+			      "bytes with expected frame-length=%d\n",
+			      newpktlen,
+			      cfpkt_getlen(layr->incomplete_frm),
+			      expectlen));
+#endif
+		pkt = layr->incomplete_frm;
+	} else {
+		pkt = newpkt;
+	}
+	layr->incomplete_frm = NULL;
+
+	do {
+#ifdef CAIF_DEBUG_ON
+		if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+			cfpkt_log_pkt(pkt, buf, sizeof(buf));
+			CFLOG_TRACE3(("serl: PACKET before STX search: %s\n",
+				      buf));
+		}
+#endif
+		/* Search for STX at start of pkt if STX is used */
+		if (layr->usestx) {
+			CFLOG_TRACE2(("serl: Start looking for STX at "
+				      "start of frame\n"));
+			(void) cfpkt_extr_head(pkt, &tmp8, 1);
+			if (tmp8 != CFSERL_STX) {
+				CFLOG_TRACE(("serl: STX Error! STX not at "
+					     "start of packe\n"));
+				while (cfpkt_more(pkt)
+				       && tmp8 != CFSERL_STX) {
+					(void) cfpkt_extr_head(pkt, &tmp8, 1);
+				}
+				if (!cfpkt_more(pkt)) {
+					CFLOG_TRACE(("serl: Destroying packet "
+						     "when no STX found\n"));
+					cfpkt_destroy(pkt);
+					layr->incomplete_frm = NULL;
+					cfglu_unlock(layr->sync);
+					CFLOG_EXIT(("\n"));
+					return CFGLU_EPROTO;
+				}
+			}
+		}
+
+		pkt_len = cfpkt_getlen(pkt);
+
+		/*
+		 *  pkt_len is the accumulated length of the packet data
+		 *  we have received so far.
+		 *  Exit if frame doesn't hold length.
+		 */
+
+		if (pkt_len < 2) {
+			if (layr->usestx)
+				cfpkt_add_head(pkt, &stx, 1);
+			layr->incomplete_frm = pkt;
+			cfglu_unlock(layr->sync);
+#ifdef CAIF_DEBUG_ON
+			if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+				cfpkt_log_pkt(pkt, buf, sizeof(buf));
+				CFLOG_TRACE3(("serl: PACKET before exit "
+					      "(too short): %s\n", buf));
+			}
+#endif
+			CFLOG_EXIT(("\n"));
+			return 0;
+		}
+
+		/*
+		 *  Find length of frame.
+		 *  expectlen is the length we need for a full frame.
+		 */
+		(void) cfpkt_peek_head(pkt, &tmp, 2);
+		expectlen = cfglu_le16_to_cpu(tmp) + 2;
+		CFLOG_TRACE2(("serl:  Processing a packet of %d bytes with "
+			      "expected length=%d\n", pkt_len, expectlen));
+
+#ifdef CAIF_DEBUG_ON
+		if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+			cfpkt_log_pkt(pkt, buf, sizeof(buf));
+			CFLOG_TRACE3(("serl: PACKET after STX Seach: %s\n",
+				      buf));
+		}
+#endif
+		/*
+		 * Frame error handling
+		 */
+		if (expectlen < CAIF_MINIUM_PACKET_SIZE
+		    || expectlen > CAIF_MAX_FRAMESIZE) {
+			if (!layr->usestx) {
+				CFLOG_ERROR(("cfserl: packet has bad expectlen "
+					     "%d\n", expectlen));
+				CFLOG_ERROR(("serl: Packet is erroneous throw "
+					     "it away (expectlen=%d, len=%d)",
+					     expectlen, pkt_len));
+				if (pkt != NULL)
+					cfpkt_destroy(pkt);
+				layr->incomplete_frm = NULL;
+				expectlen = 0;
+				cfglu_unlock(layr->sync);
+				CFLOG_EXIT(("\n"));
+				return CFGLU_EPROTO;
+			}
+			continue;
+		}
+
+		if (pkt_len < expectlen) {
+			/* Too little received data */
+			CFLOG_TRACE2(("serl: Holding incomplete packet with "
+				      "current length=%d and expected "
+				      "length=%d", pkt_len, expectlen));
+			if (layr->usestx)
+				cfpkt_add_head(pkt, &stx, 1);
+
+#ifdef CAIF_DEBUG_ON
+			if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+				cfpkt_log_pkt(pkt, buf, sizeof(buf));
+				CFLOG_TRACE3(("serl: incomplete_frame: %s\n",
+					      buf));
+			}
+#endif
+			layr->incomplete_frm = pkt;
+			cfglu_unlock(layr->sync);
+			return 0;
+		}
+
+		/* Enough data for at least one frame.
+		 * Split the frame, if too long
+		 */
+		if (pkt_len > expectlen) {
+			CFLOG_TRACE2(("serl: Splitting too long packet of "
+				      "length = %d and frame size =%d\n",
+				      pkt_len, expectlen));
+			tail_pkt = cfpkt_split(pkt, expectlen);
+		} else {
+			tail_pkt = NULL;
+		}
+
+#ifdef CAIF_DEBUG_ON
+		if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+			cfpkt_log_pkt(pkt, buf, sizeof(buf));
+			CFLOG_TRACE3(("serl: PACKET sent up: %s\n", buf));
+		}
+#endif
+		/* Send the first part of packet upwards */
+		ret = layr->layer.up->receive(layr->layer.up, pkt);
+
+		if (ret == CFGLU_EFCS) {
+			CFLOG_ERROR(("cfserl: upper layer return error: %d\n",
+				     ret));
+
+			if (layr->usestx) {
+				CFLOG_WARN(("cfserl: Layer above return fcs "
+					    "error, Search for next STX\n"));
+				if (tail_pkt != NULL)
+					pkt = cfpkt_append(pkt, tail_pkt, 0);
+
+				/* Start search for next STX if frame failed */
+				continue;
+			} else {
+				cfpkt_destroy(pkt);
+				pkt = NULL;
+			}
+		}
+
+		pkt = tail_pkt;
+
+	} while (pkt != NULL);
+
+	cfglu_unlock(layr->sync);
+	return 0;
+}
+
+static int cfserl_transmit(struct layer *layer, struct transmt_info *info,
+			   struct cfpkt *newpkt)
+{
+	struct cfserl *layr = container_obj(layer);
+	int ret;
+	uint8 tmp8 = CFSERL_STX;
+	CFLOG_ENTER(("\n"));
+	if (layr->usestx)
+		cfpkt_add_head(newpkt, &tmp8, 1);
+	ret = layer->dn->transmit(layer->dn, info, newpkt);
+	if (ret < 0)
+		cfpkt_extr_head(newpkt, &tmp8, 1);
+
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
+
+static void cfserl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid)
+{
+	layr->up->ctrlcmd(layr->up, ctrl, phyid);
+}
diff --git a/net/caif/generic/cfshml.c b/net/caif/generic/cfshml.c
new file mode 100644
index 0000000..cdf2cd1
--- /dev/null
+++ b/net/caif/generic/cfshml.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+
+static int cfshml_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfshml_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt);
+static void cfshml_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid);
+
+struct layer *cfshml_create(int type, int instance)
+{
+	struct layer *this = cfglu_alloc(sizeof(struct layer));
+
+	memset(this, 0, sizeof(struct layer));
+	this->receive = cfshml_receive;
+	this->ctrlcmd = cfshml_ctrlcmd;
+	this->transmit = cfshml_transmit;
+	this->type = type;
+	snprintf(this->name, CAIF_LAYER_NAME_SZ, "shm1");
+	return this;
+}
+
+void cfshml_set_uplayer(struct layer *this, struct layer *up)
+{
+	this->up = up;
+}
+
+void cfshml_set_dnlayer(struct layer *this, struct layer *dn)
+{
+	this->dn = dn;
+	this->dn->type = this->type;
+}
+
+static int cfshml_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	int ret;
+	/* Send the first part of packet upwards. */
+	ret = layr->up->receive(layr->up, pkt);
+	/* FCS error - don't delete the packet. */
+	if (ret == CFGLU_EFCS)
+		cfpkt_destroy(pkt);
+	return ret;
+}
+
+static int cfshml_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt)
+{
+	return layr->dn->transmit(layr->dn, info, pkt);
+}
+
+static void cfshml_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid)
+{
+	layr->up->ctrlcmd(layr->up, ctrl, phyid);
+}
diff --git a/net/caif/generic/cfspil.c b/net/caif/generic/cfspil.c
new file mode 100644
index 0000000..4813548
--- /dev/null
+++ b/net/caif/generic/cfspil.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+/** \page CFSPIL - CAIF SPI Layer:
+
+ *  \note: A special protocol is defined for SPI PHYSICAL layer:
+ *	-# CAIF packet is sent by \ref transmit_cb_t "transmit function"
+ *	-# SPI PHY layer will send  \ref ctrlcmd_cb_t "flowcontrol"
+ *	    \ref CAIF_CTRLCMD_FLOW_OFF_IND "off"  upwards in CAIF stack.
+ *	-# CAIF will start appending CAIF Packets upto maximum size.
+ *	-# SPI PHY layer will send  \ref ctrlcmd_cb_t "flowcontrol"
+ *	    \ref CAIF_CTRLCMD_FLOW_ON_IND "on"	upwards in CAIF stack.
+ *	-# Appended CAIF packets are sent by \ref transmit_cb_t
+ *	   "transmit" function.
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/cfspil.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+
+/* Normally this should be aligned on the modem in order to benefit from full
+ * duplex transfers. However a size of 8188 provokes errors when running with
+ * the modem. These errors occur when packet sizes approaches 4 kB of data.
+ */
+#define CAIF_MAX_SPI_FRAME 4092
+
+/* Maximum number of uplink CAIF frames that can reside in the same SPI frame.
+ * This number should correspond with the modem setting. The application side
+ * CAIF accepts any number of embedded downlink CAIF frames.
+ */
+#define CAIF_MAX_SPI_PKTS 9
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfspil, layer)
+
+#define CAIF_SPI_QUEUE_LOW 12
+#define CAIF_SPI_QUEUE_HIGH 24
+
+struct cfspil {
+	struct layer layer;		/* The layer structure must always
+					 * be present first in struct. */
+	struct cfspipad pad;		/* CAIF padding options. */
+	struct cfpkt *xmitpkt;	/* Pending packet to be sent */
+	cfglu_lock_t sync;
+	struct cfpktq *queue;
+	bool flow_stop;			/* Flow control state. */
+};
+
+
+int spi_up_head_align = 1;
+EXPORT_SYMBOL(spi_up_head_align);
+
+int spi_up_tail_align;
+EXPORT_SYMBOL(spi_up_tail_align);
+
+int spi_down_head_align = 3;
+EXPORT_SYMBOL(spi_down_head_align);
+
+int spi_down_tail_align = 1;
+EXPORT_SYMBOL(spi_down_tail_align);
+
+
+
+
+/* Prototype declarations */
+static int cfspil_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfspil_transmit(struct layer *layr, struct transmt_info *info,
+			   struct cfpkt *pkt);
+
+struct layer *cfspil_create(int type, int instance, struct cfspipad cfpad)
+{
+	struct cfspil *this = cfglu_alloc(sizeof(struct cfspil));
+	caif_assert(offsetof(struct cfspil, layer) == 0);
+	memset(this, 0, sizeof(struct cfspil));
+	cfglu_init_lock(this->sync);
+	this->layer.receive = cfspil_receive;
+	this->layer.transmit = cfspil_transmit;
+	this->pad.up_head_align = cfpad.up_head_align;
+	this->pad.up_tail_align = cfpad.up_tail_align;
+	this->pad.down_head_align = cfpad.down_head_align;
+	this->pad.down_tail_align = cfpad.down_tail_align;
+	this->xmitpkt = NULL;	/* Pending packet to be sent */
+	this->layer.type = type;
+	this->flow_stop = false;
+	sprintf(this->layer.name, "spi1");
+	this->queue = cfpktq_create();
+	return &this->layer;
+}
+
+static int cfspil_receive(struct layer *layer, struct cfpkt *pkt)
+{
+	uint8 startpad;
+	uint8 pad[16];
+	uint16 len, tmplen;
+	uint16 pktlen;
+	uint16 endpad;
+	int ret;
+	struct cfspil *layr = container_obj(layer);
+	struct cfpkt *nextpkt = NULL;
+
+	while (pkt && cfpkt_more(pkt)) {
+		if (layr->pad.down_head_align) {
+			/* Read and handle start offset */
+			(void)cfpkt_extr_head(pkt, &startpad, 1);
+			if (startpad >= (layr->pad.down_head_align + 1)) {
+				CFLOG_ERROR(("cfspil: Recieved start pad=%d,"
+					     " expected less than %d\n",
+					     startpad,
+					     (layr->pad.down_head_align + 1)));
+				goto error;
+			}
+		} else
+			startpad = 0;
+
+		caif_assert(startpad < 16);
+
+		if (startpad)
+			(void)cfpkt_extr_head(pkt, &pad, startpad);
+
+		pktlen = cfpkt_getlen(pkt);
+
+		/* Read packet length */
+		(void)cfpkt_peek_head(pkt, &tmplen, 2);
+		len = cfglu_le16_to_cpu(tmplen) + 2;
+		if (cfpkt_erroneous(pkt) || len < 6
+		    || len > CAIF_MAX_SPI_FRAME || pktlen < len) {
+			CFLOG_ERROR(("cfspil: Packet is erroneous throw it "
+				     " away (len=%d)\n", len));
+			cfpkt_destroy(pkt);
+			return CFGLU_EPROTO;
+		}
+
+		/*
+		 * Compute tail offset i.e. number of bytes to
+		 * add to get alignment
+		 */
+		if (layr->pad.down_head_align)
+			endpad =
+			    (len + startpad + 1) & layr->pad.down_tail_align;
+		else
+			endpad = len & layr->pad.down_tail_align;
+
+		CFLOG_TRACE3(("cfspil: recv pkt:0x%p len:%d startpad:%d "
+			      "endpad:%d\n", pkt, len, startpad, endpad));
+
+		nextpkt = NULL;
+		if (pktlen - len > 5)
+			nextpkt = cfpkt_split(pkt, len);
+
+		if (cfpkt_erroneous(pkt)) {
+			CFLOG_ERROR(("cfspil: Packet is erroneous!\n"));
+			goto error;
+		}
+
+		if (endpad && nextpkt)
+			(void)cfpkt_extr_head(nextpkt, &pad, endpad);
+
+		ret = layr->layer.up->receive(layr->layer.up, pkt);
+		/* FCS Error don't delete the packet */
+		if (ret == CFGLU_EFCS)
+			cfpkt_destroy(pkt);
+
+		pkt = nextpkt;
+		nextpkt = NULL;
+	}
+	return 0;
+ error:
+	cfpkt_destroy(pkt);
+	if (nextpkt)
+		cfpkt_destroy(nextpkt);
+	return CFGLU_EPROTO;
+}
+
+static struct cfpkt *cfspil_built_xmit_pkt(struct cfspil *layr)
+{
+	uint16 totallen;
+	int count;
+	int pkts = 0;
+	struct cfpkt *pkt, *xmitpkt;
+
+	cfglu_lock(layr->sync);
+	xmitpkt = cfpkt_dequeue(layr->queue);
+	cfglu_unlock(layr->sync);
+	pkts++;
+
+	count = cfpkt_qcount(layr->queue);
+	if ((layr->flow_stop == true) && (count <= CAIF_SPI_QUEUE_LOW)) {
+		layr->flow_stop = false;
+		if (layr->layer.up->ctrlcmd)
+			layr->layer.up->ctrlcmd(layr->layer.up,
+					_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND,
+					0);
+	}
+
+	/* CFLOG_TRACE(("cfspil_xmitlen - 1: lyr:0x%x,
+	   xmitpkt:0x%x\n", layr, xmitpkt)); */
+
+	if (xmitpkt == NULL)
+		return NULL;
+
+	totallen = cfpkt_getlen(xmitpkt);
+	/* CFLOG_TRACE(("cfspil_xmitlen -2 : xmitpkt:0x%x
+	   len:%d\n", xmitpkt, totallen)); */
+
+	while (xmitpkt != NULL && !cfpkt_erroneous(xmitpkt)) {
+		int len;
+
+		/* Verify that we don't exceed the maximum uplink CAIF
+		 * frame count within a CAIF SPI frame.
+		 */
+		if (pkts >= CAIF_MAX_SPI_PKTS) {
+			caif_assert(pkts <= CAIF_MAX_SPI_PKTS);
+			return xmitpkt;
+		}
+
+		cfglu_lock(layr->sync);
+		pkt = cfpkt_qpeek(layr->queue);
+
+		len = pkt == NULL ? 0 : cfpkt_getlen(pkt);
+		if (pkt != NULL && totallen + len < CAIF_MAX_SPI_FRAME) {
+			pkt = cfpkt_dequeue(layr->queue);
+			cfglu_unlock(layr->sync);
+			pkts++;
+			/* CFLOG_TRACE(("cfspil_xmitlen - 3: pkt:0x%x
+			   len:%d\n", pkt, len)); */
+			totallen += len;
+			xmitpkt = cfpkt_append(xmitpkt, pkt, 0);
+			/* CFLOG_TRACE(("cfspil_xmitlen - 4: pkt:0x%x
+			   len:%d\n", xmitpkt, totallen)); */
+
+			count = cfpkt_qcount(layr->queue);
+			if ((layr->flow_stop == true)
+			    && (count <= CAIF_SPI_QUEUE_LOW)) {
+				layr->flow_stop = false;
+				if (layr->layer.up->ctrlcmd)
+					layr->layer.up->ctrlcmd(layr->layer.up,
+					       _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND,
+					       0);
+			}
+
+		} else {
+			cfglu_unlock(layr->sync);
+			/* CFLOG_TRACE(("cfspil_xmitlen - 5: pkt:0x%x
+			   len:%d\n", xmitpkt, totallen)); */
+
+			return xmitpkt;
+		}
+	}
+
+	/* Error handling */
+	if (xmitpkt != NULL)
+		cfpkt_destroy(xmitpkt);
+
+	return NULL;
+}
+
+int cfspil_xmitlen(struct cfspil *layr)
+{
+	if (layr->xmitpkt == NULL)
+		layr->xmitpkt = cfspil_built_xmit_pkt(layr);
+
+	/* CFLOG_TRACE(("cfspil_xmitlen: lyr:0x%x\n", layr)); */
+
+	if (layr->xmitpkt != NULL)
+		return cfpkt_getlen(layr->xmitpkt);
+	return 0;
+}
+EXPORT_SYMBOL(cfspil_xmitlen);
+
+struct cfpkt *cfspil_getxmitpkt(struct cfspil *layr)
+{
+	struct cfpkt *ret = layr->xmitpkt;
+	layr->xmitpkt = NULL;
+	return ret;
+}
+EXPORT_SYMBOL(cfspil_getxmitpkt);
+
+static int cfspil_transmit(struct layer *layer, struct transmt_info *info,
+			   struct cfpkt *pkt)
+{
+	uint32 pad = -1;
+	int count;
+	uint8 startpad;
+	uint16 endpad;
+	uint16 len;
+	struct cfpkt *clone;
+	struct cfspil *layr = container_obj(layer);
+	CFLOG_TRACE3(("cfspil_transmit: lyr:0x%p, pkt:0x%p "
+		      "pktlen:%d\n", layr, pkt, cfpkt_getlen(pkt)));
+
+	if (layr->pad.up_head_align) {
+		startpad = (info->hdr_len + 1) & layr->pad.up_head_align;
+		if (startpad)
+			cfpkt_add_head(pkt, &pad, startpad);
+		cfpkt_add_head(pkt, &startpad, 1);
+	} else
+		startpad = 0;
+
+	len = cfpkt_getlen(pkt);
+
+	/* Compute tail offset i.e. number of bytes to add to get alignment */
+	if (layr->pad.up_head_align)
+		endpad = (len + startpad + 1) & layr->pad.up_tail_align;
+	else
+		endpad = len & layr->pad.up_tail_align;
+
+	if (endpad)
+		cfpkt_pad_trail(pkt, endpad);
+
+	if (cfpkt_erroneous(pkt)) {
+		CFLOG_ERROR(("cfspil: Packet is erroneous!\n"));
+		return CFGLU_EPROTO;
+	}
+
+	/* Take ownership of packet. */
+	clone = cfpkt_clone_release(pkt);
+	if (!clone) {
+		CFLOG_ERROR(("cfspil: Cloning failed!\n"));
+		return CFGLU_ENOMEM;
+	}
+
+	cfglu_lock(layr->sync);
+	cfpkt_queue(layr->queue, clone, info->prio);
+	cfglu_unlock(layr->sync);
+
+	count = cfpkt_qcount(layr->queue);
+	if (count >= CAIF_SPI_QUEUE_HIGH) {
+		layr->flow_stop = true;
+		if (layr->layer.up->ctrlcmd)
+			layr->layer.up->ctrlcmd(layr->layer.up,
+					_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
+					0);
+	}
+
+	/* Inidicate a transmit request, but SPI PHY pulls the packet */
+	layr->layer.dn->transmit(layr->layer.dn, NULL, NULL);
+
+	return 0;
+}
diff --git a/net/caif/generic/cfsrvl.c b/net/caif/generic/cfsrvl.c
new file mode 100644
index 0000000..cf82dfa
--- /dev/null
+++ b/net/caif/generic/cfsrvl.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define SRVL_CTRL_PKT_SIZE 1
+#define SRVL_FLOW_OFF 0x81
+#define SRVL_FLOW_ON  0x80
+#define SRVL_SET_PIN  0x82
+#define SRVL_CTRL_PKT_SIZE 1
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfsrvl, layer)
+
+static void cfservl_ctrlcmd(struct layer *layr, enum caif_ctrlcmd ctrl,
+				int phyid)
+{
+	struct cfsrvl *service = container_obj(layr);
+	caif_assert(layr->up != NULL);
+	caif_assert(layr->up->ctrlcmd != NULL);
+	CFLOG_ENTER(("\n"));
+	switch (ctrl) {
+	case CAIF_CTRLCMD_INIT_RSP:
+		CFLOG_TRACE(("cfsrvl: ctrlcmd SEND_FLOW_INIT\n"));
+		service->open = true;
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		break;
+	case CAIF_CTRLCMD_DEINIT_RSP:
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+		CFLOG_TRACE(("cfsrvl: ctrlcmd DEINIT_RSP / INIT_FAIL_RSP\n"));
+		service->open = false;
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		break;
+	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
+		if (phyid != service->phid)
+			break;
+		if (service->modem_flow_on)
+			layr->up->ctrlcmd(layr->up,
+					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
+		service->phy_flow_on = false;
+		break;
+	case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
+		if (phyid != service->phid)
+			return;
+		if (service->modem_flow_on) {
+			layr->up->ctrlcmd(layr->up,
+					   CAIF_CTRLCMD_FLOW_ON_IND,
+					   phyid);
+		}
+		service->phy_flow_on = true;
+		break;
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+		if (service->phy_flow_on) {
+			layr->up->ctrlcmd(layr->up,
+					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
+		}
+		service->modem_flow_on = false;
+		break;
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+		if (service->phy_flow_on) {
+			layr->up->ctrlcmd(layr->up,
+					  CAIF_CTRLCMD_FLOW_ON_IND, phyid);
+		}
+		service->modem_flow_on = true;
+		break;
+	case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
+		/* In case interface is down, let's fake a remove shutdown */
+		layr->up->ctrlcmd(layr->up,
+				CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
+		break;
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		break;
+	default:
+		CFLOG_WARN(("cfsrvl: Unexpected ctrl in cfsrvl (%d)\n", ctrl));
+
+		/* We have both modem and phy flow on, send flow on */
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		service->phy_flow_on = true;
+		break;
+	}
+	CFLOG_EXIT(("\n"));
+}
+
+static int cfservl_modemcmd(struct layer *layr, enum caif_modemcmd ctrl)
+{
+	struct cfsrvl *service = container_obj(layr);
+	caif_assert(layr != NULL);
+	caif_assert(layr->dn != NULL);
+	caif_assert(layr->dn->transmit != NULL);
+	switch (ctrl) {
+	case CAIF_MODEMCMD_FLOW_ON_REQ:
+		{
+			struct cfpkt *pkt;
+			struct transmt_info info;
+			uint8 flow_on = SRVL_FLOW_ON;
+			memset(&info, 0, sizeof(info));
+			info.channel_id = service->layer.id;
+			info.phid = service->phid;
+			info.hdr_len = 1;
+			CFLOG_TRACE(("cfsrvl: ctrlcmd SEND_FLOW_ON\n"));
+			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+			if (!cfpkt_add_head(pkt, &flow_on, 1)) {
+				CFLOG_ERROR(("cfsrvl: Packet is erroneous!\n"));
+				cfpkt_destroy(pkt);
+				return CFGLU_EPROTO;
+			}
+			return layr->dn->transmit(layr->dn, &info, pkt);
+		}
+	case CAIF_MODEMCMD_FLOW_OFF_REQ:
+		{
+			struct cfpkt *pkt;
+			struct transmt_info info;
+			uint8 flow_off = SRVL_FLOW_OFF;
+			memset(&info, 0, sizeof(info));
+			info.channel_id = service->layer.id;
+			info.phid = service->phid;
+			info.hdr_len = 1;
+			CFLOG_TRACE(("cfsrvl: ctrlcmd SEND_FLOW_OFF\n"));
+			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+			if (!cfpkt_add_head(pkt, &flow_off, 1)) {
+				CFLOG_ERROR(("cfsrvl: Packet is erroneous!\n"));
+				cfpkt_destroy(pkt);
+				return CFGLU_EPROTO;
+			}
+			return layr->dn->transmit(layr->dn, &info, pkt);
+		}
+	default:
+	  break;
+	}
+	return CFGLU_EINVAL;
+}
+
+void cfservl_destroy(struct layer *layer)
+{
+	cfglu_free(layer);
+}
+
+void cfsrvl_init(struct cfsrvl *service, uint8 channel_id, uint8 phyid)
+{
+	struct cfsrvl *srvl = cfglu_alloc(sizeof(struct cfsrvl));
+	caif_assert(offsetof(struct cfsrvl, layer) == 0);
+	memset(srvl, 0, sizeof(struct cfsrvl));
+	service->open = false;
+	service->modem_flow_on = true;
+	service->phy_flow_on = true;
+	service->layer.id = channel_id;
+	service->phid = phyid;
+	service->layer.ctrlcmd = cfservl_ctrlcmd;
+	service->layer.modemcmd = cfservl_modemcmd;
+}
+
+bool cfsrvl_ready(struct cfsrvl *service, int *err)
+{
+	if (service->open && service->modem_flow_on && service->phy_flow_on)
+		return true;
+	if (!service->open) {
+		*err = CFGLU_ENOTCONN;
+		return false;
+	}
+	caif_assert(!(service->modem_flow_on && service->phy_flow_on));
+	*err = CFGLU_ERETRY;
+	return false;
+}
+uint8 cfsrvl_getphyid(struct layer *layer)
+{
+	struct cfsrvl *servl = container_obj(layer);
+	return servl->phid;
+}
+
+bool cfsrvl_phyid_match(struct layer *layer, int phyid)
+{
+	struct cfsrvl *servl = container_obj(layer);
+	return servl->phid == phyid;
+}
diff --git a/net/caif/generic/cfusbl.c b/net/caif/generic/cfusbl.c
new file mode 100644
index 0000000..0be7b72
--- /dev/null
+++ b/net/caif/generic/cfusbl.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfusbl.h>
+
+static int cfusbl_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfusbl_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt);
+
+struct layer *cfusbl_create(int type, int instance)
+{
+	struct layer *this = cfglu_alloc(sizeof(struct layer));
+	memset(this, 0, sizeof(struct layer));
+	this->receive = cfusbl_receive;
+	this->transmit = cfusbl_transmit;
+	this->type = type;
+	sprintf(this->name, "usb%d", instance);
+	return this;
+}
+
+void cfusbl_set_uplayer(struct layer *this, struct layer *up)
+{
+	this->up = up;
+}
+
+void cfusbl_set_dnlayer(struct layer *this, struct layer *dn)
+{
+	this->dn = dn;
+}
+
+static int cfusbl_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	/* Send the first part of the packet upwards. */
+	int ret = layr->up->receive(layr->up, pkt);
+	/* FCS error - don't delete the packet. */
+	if (ret == CFGLU_EFCS)
+		cfpkt_destroy(pkt);
+	return ret;
+}
+
+static int cfusbl_transmit(struct layer *layr, struct transmt_info *info,
+				struct cfpkt *pkt)
+{
+	return layr->dn->transmit(layr->dn, info, pkt);
+}
diff --git a/net/caif/generic/cfutill.c b/net/caif/generic/cfutill.c
new file mode 100644
index 0000000..2f76968
--- /dev/null
+++ b/net/caif/generic/cfutill.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define container_obj(layr) ((struct cfsrvl *) layr)
+#define UTIL_PAYLOAD  0x00
+#define UTIL_CMD_BIT  0x80
+#define UTIL_REMOTE_SHUTDOWN 0x82
+#define UTIL_FLOW_OFF 0x81
+#define UTIL_FLOW_ON  0x80
+#define UTIL_CTRL_PKT_SIZE 1
+static int cfutill_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfutill_transmit(struct layer *layr, struct transmt_info *dummy,
+			    struct cfpkt *pkt);
+
+struct layer *cfutill_create(uint8 channel_id, uint8 phyid)
+{
+	struct cfsrvl *util = cfglu_alloc(sizeof(struct cfsrvl));
+	caif_assert(offsetof(struct cfsrvl, layer) == 0);
+
+	memset(util, 0, sizeof(struct cfsrvl));
+	cfsrvl_init(util, channel_id, phyid);
+	util->layer.receive = cfutill_receive;
+	util->layer.transmit = cfutill_transmit;
+	snprintf(util->layer.name, CAIF_LAYER_NAME_SZ - 1, "util1");
+	return &util->layer;
+}
+
+static int cfutill_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	uint8 cmd = -1;
+	struct cfsrvl *service = container_obj(layr);
+	caif_assert(layr != NULL);
+	caif_assert(layr->up != NULL);
+	caif_assert(layr->up->receive != NULL);
+	caif_assert(layr->up->ctrlcmd != NULL);
+	if (!cfpkt_extr_head(pkt, &cmd, 1)) {
+		CFLOG_ERROR(("cfutill: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPROTO;
+	}
+
+	switch (cmd) {
+	case UTIL_PAYLOAD:
+		return layr->up->receive(layr->up, pkt);
+	case UTIL_FLOW_OFF:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+		cfpkt_destroy(pkt);
+		return 0;
+	case UTIL_FLOW_ON:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+		cfpkt_destroy(pkt);
+		return 0;
+	case UTIL_REMOTE_SHUTDOWN:	/* Remote Shutdown Request */
+		CFLOG_ERROR(("cfutill: REMOTE SHUTDOWN REQUEST RECEIVED\n"));
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
+		service->open = false;
+		cfpkt_destroy(pkt);
+		return 0;
+	default:
+		cfpkt_destroy(pkt);
+		CFLOG_ERROR(("cfmuxl: Unknown datagram control %d (0x%x!\n",
+			     cmd, cmd));
+		return CFGLU_EPROTO;
+	}
+}
+
+static int cfutill_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt)
+{
+	uint8 zero = 0;
+	struct transmt_info info;
+	int ret;
+	struct cfsrvl *service = container_obj(layr);
+	caif_assert(layr != NULL);
+	caif_assert(layr->dn != NULL);
+	caif_assert(layr->dn->transmit != NULL);
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("packet too large size=%d\n", cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+
+	cfpkt_add_head(pkt, &zero, 1);
+	memset(&info, 0, sizeof(info));
+	/* Add info for MUX-layer to route the packet out. */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	/* To optimize alignment, we add up the size of CAIF header before
+	 * payload.
+	 */
+	info.hdr_len = 1;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0) {
+		uint32 tmp32;
+		cfpkt_extr_head(pkt, &tmp32, 4);
+	}
+	return ret;
+}
diff --git a/net/caif/generic/cfveil.c b/net/caif/generic/cfveil.c
new file mode 100644
index 0000000..9aa6430
--- /dev/null
+++ b/net/caif/generic/cfveil.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/caif_log.h>
+
+#define VEI_PAYLOAD  0x00
+#define VEI_CMD_BIT  0x80
+#define VEI_FLOW_OFF 0x81
+#define VEI_FLOW_ON  0x80
+#define VEI_SET_PIN  0x82
+#define VEI_CTRL_PKT_SIZE 1
+#define container_obj(layr) cfglu_container_of(layr, struct cfsrvl, layer)
+
+static int cfvei_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfvei_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt);
+
+struct layer *cfvei_create(uint8 channel_id, uint8 phyid)
+{
+	struct cfsrvl *vei = cfglu_alloc(sizeof(struct cfsrvl));
+	caif_assert(offsetof(struct cfsrvl, layer) == 0);
+	memset(vei, 0, sizeof(struct cfsrvl));
+	cfsrvl_init(vei, channel_id, phyid);
+	vei->layer.receive = cfvei_receive;
+	vei->layer.transmit = cfvei_transmit;
+	snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ - 1, "vei%d", channel_id);
+	CFLOG_TRACE(("cfvei: Created %p\n", (void *) vei));
+	return &vei->layer;
+}
+
+static int cfvei_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	uint8 cmd;
+	int ret;
+	CFLOG_ENTER(("\n"));
+	caif_assert(layr->up != NULL);
+	caif_assert(layr->receive != NULL);
+	caif_assert(layr->ctrlcmd != NULL);
+
+
+	if (!cfpkt_extr_head(pkt, &cmd, 1)) {
+		CFLOG_ERROR(("cfvei: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		CFLOG_ENTER(("\n"));
+		return CFGLU_EPROTO;
+	}
+	switch (cmd) {
+	case VEI_PAYLOAD:
+		ret = layr->up->receive(layr->up, pkt);
+		CFLOG_EXIT(("\n"));
+		return ret;
+	case VEI_FLOW_OFF:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EOK;
+	case VEI_FLOW_ON:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EOK;
+	case VEI_SET_PIN:	/* SET RS232 PIN */
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EOK;
+	default:		/* SET RS232 PIN */
+		CFLOG_ERROR(("cfvei: Unknown VEI control packet %d (0x%x)!\n",
+			     cmd, cmd));
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("error"));
+		return CFGLU_EPROTO;
+	}
+}
+
+static int cfvei_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt)
+{
+	uint8 tmp = 0;
+	struct transmt_info info;
+	int ret;
+	struct cfsrvl *service = container_obj(layr);
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	caif_assert(layr->dn != NULL);
+	caif_assert(layr->dn->transmit != NULL);
+	if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("Packet too large - size=%d\n",
+			     cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+
+	if (!cfpkt_add_head(pkt, &tmp, 1)) {
+		CFLOG_ERROR(("cfvei: Packet is erroneous!\n"));
+		return CFGLU_EPKT;
+	}
+
+	/* Add info for MUX-layer to route the packet out. */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	info.hdr_len = 1;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_extr_head(pkt, &tmp, 1);
+	return ret;
+}
diff --git a/net/caif/generic/cfvidl.c b/net/caif/generic/cfvidl.c
new file mode 100644
index 0000000..365364a
--- /dev/null
+++ b/net/caif/generic/cfvidl.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
+static int cfvidl_receive(struct layer *layr, struct cfpkt *pkt);
+static int cfvidl_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt);
+
+struct layer *cfvidl_create(uint8 channel_id, uint8 phyid)
+{
+	struct cfsrvl *vid = cfglu_alloc(sizeof(struct cfsrvl));
+	caif_assert(offsetof(struct cfsrvl, layer) == 0);
+
+	memset(vid, 0, sizeof(struct cfsrvl));
+	cfsrvl_init(vid, channel_id, phyid);
+	vid->layer.receive = cfvidl_receive;
+	vid->layer.transmit = cfvidl_transmit;
+	snprintf(vid->layer.name, CAIF_LAYER_NAME_SZ - 1, "vid1");
+	return &vid->layer;
+}
+
+static int cfvidl_receive(struct layer *layr, struct cfpkt *pkt)
+{
+	uint32 videoheader;
+	if (!cfpkt_extr_head(pkt, &videoheader, 4)) {
+		CFLOG_ERROR(("cfvidl: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPROTO;
+	}
+	return layr->up->receive(layr->up, pkt);
+}
+
+static int cfvidl_transmit(struct layer *layr, struct transmt_info *dummy,
+				struct cfpkt *pkt)
+{
+	struct cfsrvl *service = container_obj(layr);
+	uint32 videoheader = 0;
+	int ret;
+	struct transmt_info info;
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+	cfpkt_add_head(pkt, &videoheader, 4);
+	memset(&info, 0, sizeof(info));
+	/* Add info for MUX-layer to route the packet out */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_extr_head(pkt, &videoheader, 4);
+	return ret;
+}
diff --git a/net/caif/generic/fcs.c b/net/caif/generic/fcs.c
new file mode 100644
index 0000000..7dd2768
--- /dev/null
+++ b/net/caif/generic/fcs.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+/* NOTE: Move this to glue and use OS specific function if exists */
+
+#include <net/caif/generic/cfglue.h>
+
+static uint16 fcstab[256] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+uint16 fcs16(uint16 fcs, uint8 *cp, uint16 len)
+{
+	while (len--)
+		fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+	return fcs;
+}
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  5/8] CAIF Protocol Stack
  2009-11-30 15:00       ` [RFC PATCH v3 4/8] " sjur.brandeland
@ 2009-11-30 15:00         ` sjur.brandeland
  2009-11-30 15:00           ` [RFC PATCH v3 6/8] " sjur.brandeland
  2009-11-30 16:41           ` [RFC PATCH v3 5/8] " Randy Dunlap
  2009-12-15 16:47         ` [RFC PATCH v3 4/8] " stefano babic
  1 sibling, 2 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 net/caif/Kconfig            |   51 ++
 net/caif/Makefile           |   51 ++
 net/caif/caif_chnlif.c      |  205 ++++++
 net/caif/caif_config_util.c |  163 +++++
 net/caif/caif_dev.c         |  520 ++++++++++++++
 net/caif/caif_socket.c      | 1560 +++++++++++++++++++++++++++++++++++++++++++
 net/caif/chnl_net.c         |  655 ++++++++++++++++++
 7 files changed, 3205 insertions(+), 0 deletions(-)
 create mode 100644 net/caif/Kconfig
 create mode 100644 net/caif/Makefile
 create mode 100644 net/caif/caif_chnlif.c
 create mode 100644 net/caif/caif_config_util.c
 create mode 100644 net/caif/caif_dev.c
 create mode 100644 net/caif/caif_socket.c
 create mode 100644 net/caif/chnl_net.c

diff --git a/net/caif/Kconfig b/net/caif/Kconfig
new file mode 100644
index 0000000..9349123
--- /dev/null
+++ b/net/caif/Kconfig
@@ -0,0 +1,51 @@
+#
+# CAIF net configurations
+#
+
+#menu "CAIF Support"
+comment "CAIF Support"
+
+menuconfig CAIF
+	tristate "Enable CAIF support"
+	default n
+	---help---
+	Say Y here if you need to use a phone modem that uses CAIF as transport.
+	You will also need to say yes to any CAIF physical devices that your platform
+	supports.
+	This can be either built-in or a loadable module; if you select to build it as module
+	then the rest of CAIF also needs to built as modules.
+	See Documentation/CAIF for a further explanation on how to use and configure.
+
+if CAIF
+
+config CAIF_NETDEV
+	tristate "CAIF Network device"
+	default CAIF
+	---help---
+	Say Y if you will be using the CAIF based network device.
+	This can be either built-in or a loadable module.
+	If you select to build it as a built-in then the main CAIF device must also be a built-in.
+	If unsure say Y.
+
+config CAIF_SOCK
+	tristate "CAIF Sockets"
+	default CAIF
+	---help---
+	Say Y if you will be using the CAIF Sockets.
+	This can be either built-in or a loadable module.
+	If you select to build it as a built-in then the main CAIF device mist also be a built-in.
+	If unsure say Y.
+
+config  CAIF_DEBUG
+	bool "Enable Debug"
+	default n
+	--- help ---
+	Enable the inclusion of debug code in the CAIF stack.
+	Be aware that doing this will impact performance.
+	If unsure say N.
+
+
+# Include physical drivers
+source "drivers/net/caif/Kconfig"
+endif
+#endmenu
diff --git a/net/caif/Makefile b/net/caif/Makefile
new file mode 100644
index 0000000..2b87906
--- /dev/null
+++ b/net/caif/Makefile
@@ -0,0 +1,51 @@
+ifeq ($(CONFIG_CAIF_USE_PLAIN),1)
+CFPKT:=plain
+else
+CFPKT:=skbuff
+CAIF_FLAGS+=-DCAIF_USE_SKB
+endif
+
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_FLAGS+=-DCAIF_DEBUG_ON
+endif
+ccflags-y := $(CAIF_FLAGS)
+
+caif-objs := caif_dev.o caif_chnlif.o \
+	generic/cfcnfg.o generic/cfmuxl.o generic/cfctrl.o \
+	generic/cffrml.o generic/cfveil.o generic/cflist.o  \
+	generic/fcs.o    generic/cfserl.o generic/cfdgml.o \
+	generic/cfspil.o generic/cfrfml.o generic/cfvidl.o \
+	generic/cfmsll.o generic/cfusbl.o generic/cfutill.o  \
+	generic/cfloopcfg.o  generic/cflooplayer.o generic/cfsrvl.o \
+	generic/cfshml.o generic/cfpkt_$(CFPKT).o caif_config_util.o
+
+clean-dirs:= .tmp_versions
+
+clean-files:= Module.symvers modules.order *.cmd *~ \
+	generic/loopback/Module.symvers \
+	generic/loopback/modules.order \
+	generic/loopback/*.cmd \
+	generic/loopback/*.o \
+	generic/loopback/*~ \
+	generic/Module.symvers \
+	generic/modules.order \
+	generic/*.cmd \
+	generic/*.o \
+	generic/*~
+
+# Main CAIF module
+obj-$(CONFIG_CAIF) += caif.o
+
+# CAIF net device
+obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
+
+obj-$(CONFIG_CAIF_SOCK) += caif_socket.o
+
+export-objs := caif.o
+
+clean:
+	${MAKE} -C generic clean
+	rm generic/modules.order  generic/Module.symvers \
+	generic/*.cmd generic/*~ \
+	generic/modules.order generic/Module.symvers \
+	generic/*.o generic/loopback/*.o
diff --git a/net/caif/caif_chnlif.c b/net/caif/caif_chnlif.c
new file mode 100644
index 0000000..9c8a656
--- /dev/null
+++ b/net/caif/caif_chnlif.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/skbuff.h>
+#include <net/caif/caif_kernel.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/caif_config_util.h>
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/caif_chr.h>
+struct caif_kernelif {
+	struct layer layer;
+	struct caif_device *dev;
+	struct cfctrl_link_param param;
+};
+
+
+/**
+ * func caif_create_skb - Creates a CAIF SKB buffer
+ * @data:		data to add to buffer
+ * @data_length:	length of data
+ */
+struct sk_buff *caif_create_skb(unsigned char *data, unsigned int data_length)
+{
+	/* NOTE: Make room for CAIF headers when using SKB inside CAIF. */
+	struct sk_buff *skb =
+	    alloc_skb(data_length + CAIF_SKB_HEAD_RESERVE +
+		      CAIF_SKB_TAIL_RESERVE, GFP_ATOMIC);
+	if (skb == NULL)
+		return NULL;
+	skb_reserve(skb, CAIF_SKB_HEAD_RESERVE);
+
+	memcpy(skb_put(skb, data_length), data, data_length);
+	return skb;
+}
+EXPORT_SYMBOL(caif_create_skb);
+
+int caif_extract_and_destroy_skb(struct sk_buff *skb, unsigned char *data,
+			     unsigned int max_length)
+{
+	unsigned int len;
+	len = skb->len;
+	/* What should actually be done here ?
+	 * skb_linearize only fails on an out of memory condition
+	 * if we fail here we are NOT freeing the skb
+	 */
+	if (!skb_linearize(skb) || skb->len > max_length)
+		return CFGLU_EOVERFLOW;
+	memcpy(data, skb->data, skb->len);
+	kfree_skb(skb);
+	return len;
+}
+EXPORT_SYMBOL(caif_extract_and_destroy_skb);
+
+/* NOTE: transmit takes ownership of the SKB.
+ *       I.e. transmit only fails on severe errors.
+ *       flow_off is not checked on transmit; this is client's responcibility.
+ */
+int caif_transmit(struct caif_device *dev, struct sk_buff *skb)
+{
+	struct caif_kernelif *chnlif =
+	    (struct caif_kernelif *) dev->_caif_handle;
+	struct cfpkt *pkt;
+#ifdef CAIF_USE_SKB
+	pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
+#else
+	pkt = cfpkt_create(skb->len);
+	cfpkt_add_body(pkt, skb->data, skb->len);
+	kfree_skb(skb);
+#endif
+	CAIFLOG_TRACE2("Transmit (%p)", chnlif->layer.dn);
+	return chnlif->layer.dn->transmit(chnlif->layer.dn, NULL, pkt);
+}
+EXPORT_SYMBOL(caif_transmit);
+
+int caif_flow_control(struct caif_device *dev, enum caif_flowctrl flow)
+{
+	enum caif_modemcmd modemcmd;
+	struct caif_kernelif *chnlif =
+	    (struct caif_kernelif *) dev->_caif_handle;
+	switch (flow) {
+	case CAIF_FLOWCTRL_ON:
+		modemcmd = CAIF_MODEMCMD_FLOW_ON_REQ;
+		break;
+	case CAIF_FLOWCTRL_OFF:
+		modemcmd = CAIF_MODEMCMD_FLOW_OFF_REQ;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return chnlif->layer.dn->modemcmd(chnlif->layer.dn, modemcmd);
+}
+EXPORT_SYMBOL(caif_flow_control);
+
+static int chnlif_receive(struct layer *layr, struct cfpkt *cfpkt)
+{
+	/* FIXME: Use container of */
+	struct caif_kernelif *chnl = (struct caif_kernelif *) layr;
+
+	struct sk_buff *skb;
+#ifndef CAIF_USE_SKB
+	unsigned int pktlen = cfpkt_getlen(cfpkt);
+	unsigned int actual_len;
+	skb = alloc_skb(pktlen, GFP_ATOMIC);
+	if (skb == NULL)
+		return CFGLU_ENOMEM;
+
+	/* Extract data from the caif packet and copy it to the skb. */
+	cfpkt_extract(cfpkt, skb_put(skb, pktlen), pktlen, &actual_len);
+	caif_assert(pktlen == actual_len);
+	cfpkt_destroy(cfpkt);
+#else
+	skb = (struct sk_buff *) cfpkt_tonative(cfpkt);
+#endif
+	chnl->dev->receive_cb(chnl->dev, skb);
+	return CFGLU_EOK;
+}
+
+static void chnlif_flowctrl(struct layer *layr, enum caif_ctrlcmd ctrl,
+			int phyid)
+{
+	struct caif_kernelif *chnl = (struct caif_kernelif *) layr;
+	enum caif_control ctl;
+
+	CAIFLOG_TRACE("Flow Control received %d\n", ctrl);
+
+	switch (ctrl) {
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+		ctl = CAIF_CONTROL_FLOW_OFF;
+		break;
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+		ctl = CAIF_CONTROL_FLOW_ON;
+		break;
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		ctl = CAIF_CONTROL_REMOTE_SHUTDOWN;
+		break;
+	case CAIF_CTRLCMD_DEINIT_RSP:
+		ctl = CAIF_CONTROL_DEV_DEINIT;
+		chnl->dev->_caif_handle = NULL;
+		chnl->dev->control_cb(chnl->dev, ctl);
+		memset(chnl, 0, sizeof(chnl));
+		cfglu_free(chnl);
+		return;
+
+	case CAIF_CTRLCMD_INIT_RSP:
+		ctl = CAIF_CONTROL_DEV_INIT;
+		break;
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+		ctl = CAIF_CONTROL_DEV_INIT_FAILED;
+		break;
+	default:
+		return;
+	}
+	chnl->dev->control_cb(chnl->dev, ctl);
+}
+
+int caif_add_device(struct caif_device *dev)
+{
+	int ret;
+	struct caif_kernelif *chnl = cfglu_alloc(sizeof(struct caif_kernelif));
+	chnl->dev = dev;
+	chnl->layer.ctrlcmd = chnlif_flowctrl;
+	chnl->layer.receive = chnlif_receive;
+	ret =
+	    channel_config_2_link_param(get_caif_conf(), &dev->caif_config,
+				&chnl->param);
+
+
+	if (ret < 0) {
+		CAIFLOG_WARN("Bad Channel Configuration\n");
+		ret = CFGLU_EBADPARAM;
+		goto error;
+	}
+
+	if (!cfcnfg_add_adaptation_layer(get_caif_conf(), &chnl->param,
+				&chnl->layer)) {
+		ret = CFGLU_ENOTCONN;
+		goto error;
+	}
+
+	dev->_caif_handle = chnl;
+
+	return CFGLU_EOK;
+error:
+	chnl->dev->_caif_handle = NULL;
+	memset(chnl, 0, sizeof(chnl));
+	cfglu_free(chnl);
+	return ret;
+}
+EXPORT_SYMBOL(caif_add_device);
+
+int caif_remove_device(struct caif_device *caif_dev)
+{
+
+	struct caif_kernelif *chnl =
+	    container_of(caif_dev->_caif_handle, struct caif_kernelif, layer);
+	bool ok = cfcnfg_del_adapt_layer(get_caif_conf(), &chnl->layer);
+	return ok ? CFGLU_EOK : CFGLU_EIO;
+}
+EXPORT_SYMBOL(caif_remove_device);
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
new file mode 100644
index 0000000..8311a7f
--- /dev/null
+++ b/net/caif/caif_config_util.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/caif_config_util.h>
+#include <linux/caif/caif_config.h>
+#include <linux/caif/caif_ioctl.h>
+#include <net/caif/caif_actions.h>
+
+int
+channel_config_2_link_param(struct cfcnfg *cnfg,
+		struct caif_channel_config *s, struct cfctrl_link_param *l)
+{
+
+	enum cfcnfg_phy_preference pref;
+
+	memset(l, 0, sizeof(*l));
+
+	l->priority = s->priority;
+
+	if (s->phy_name[0] != '\0') {
+		l->phyid = cfcnfg_get_named(cnfg, s->phy_name);
+		CFLOG_TRACE(("PHYNAME: '%s' -> id:%d\n", s->phy_name,
+			     l->phyid));
+
+	} else {
+		switch (s->phy_pref) {
+		case CAIF_PHYPREF_UNSPECIFIED:
+			pref = CFPHYPREF_UNSPECIFIED;
+			break;
+		case CAIF_PHYPREF_LOW_LAT:
+			pref = CFPHYPREF_LOW_LAT;
+			break;
+		case CAIF_PHYPREF_HIGH_BW:
+			pref = CFPHYPREF_HIGH_BW;
+			break;
+		case _CAIF_PHYPREF_LOOP:
+			pref = CFPHYPREF_LOOP;
+			break;
+		default:
+			CFLOG_TRACE(("PHYPREF: "
+				     "No Preferered Device Specified '%d'\n",
+				     s->phy_pref));
+			return -CFGLU_ENODEV;
+		}
+		l->phyid = cfcnfg_get_phyid(cnfg, pref);
+		CFLOG_TRACE(("PHYPREF: '%d' -> id:%d\n", pref, l->phyid));
+	}
+
+	switch (s->type) {
+	case CAIF_CHTY_AT:
+		l->linktype = CFCTRL_SRV_VEI;
+		l->chtype = 0x02;
+		l->endpoint = 0x00;
+		CFLOG_TRACE(("CHTY: AT\n"));
+		break;
+
+	case CAIF_CHTY_AT_CTRL:
+		CFLOG_TRACE(("CHTY: AT_CTRL\n"));
+		l->linktype = CFCTRL_SRV_VEI;
+		l->chtype = 0x00;
+		l->endpoint = 0x00;
+		break;
+
+	case CAIF_CHTY_AT_PAIRED:
+		CFLOG_TRACE(("CHTY: AT_PAIRED\n"));
+		l->linktype = CFCTRL_SRV_VEI;
+		l->chtype = 0x03;
+		l->endpoint = 0x00;
+		break;
+
+	case CAIF_CHTY_VIDEO:
+		CFLOG_TRACE(("CHTY: VIDEO\n"));
+		l->linktype = CFCTRL_SRV_VIDEO;
+		l->chtype = 0x00;
+		l->endpoint = 0x00;
+		l->u.video.connid = s->u.dgm.connection_id;
+		break;
+
+	case CAIF_CHTY_DATAGRAM:
+		CFLOG_TRACE(("CHTY: DATAGRAM\n"));
+		l->linktype = CFCTRL_SRV_DATAGRAM;
+		l->chtype = 0x00;
+		l->u.datagram.connid = s->u.dgm.connection_id;
+		break;
+
+	case CAIF_CHTY_DATAGRAM_LOOP:
+		CFLOG_TRACE(("CHTY: DATAGRAM\n"));
+		l->linktype = CFCTRL_SRV_DATAGRAM;
+		l->chtype = 0x03;
+		l->endpoint = 0x00;
+		l->u.datagram.connid = s->u.dgm.connection_id;
+		break;
+
+	case CAIF_CHTY_DEBUG:
+		CFLOG_TRACE(("CHTY: DEBUG\n"));
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = 0x01;	/* ACC SIDE */
+		l->chtype = 0x00;	/* Single channel with interactive
+					 * debug and print-out mixed.
+					 */
+		break;
+
+	case CAIF_CHTY_DEBUG_INTERACT:
+		CFLOG_TRACE(("CHTY: IDEBUG\n"));
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = 0x01;	/* ACC SIDE */
+		l->chtype = 0x02;	/* Interactive debug only */
+		break;
+
+	case CAIF_CHTY_DEBUG_TRACE:
+		CFLOG_TRACE(("CHTY: TRACE\n"));
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = 0x01;	/* ACC SIDE */
+		l->chtype = 0x01;	/* Debug print-out only */
+		break;
+
+	case CAIF_CHTY_RFM:
+
+		CFLOG_TRACE(("CHTY: RFN\n"));
+		l->linktype = CFCTRL_SRV_RFM;
+		l->u.datagram.connid = s->u.rfm.connection_id;
+		strncpy(l->u.rfm.volume, s->u.rfm.volume,
+			sizeof(l->u.rfm.volume)-1);
+		l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0;
+		break;
+
+	case CAIF_CHTY_UTILITY:
+		CFLOG_TRACE(("CHTY: UTILTY\n"));
+		l->linktype = CFCTRL_SRV_UTIL;
+		l->endpoint = 0x00;
+		l->chtype = 0x00;
+		l->u.utility.fifosize_bufs = s->u.utility.fifosize_bufs;
+		l->u.utility.fifosize_kb = s->u.utility.fifosize_kb;
+		strncpy(l->u.utility.name, s->u.utility.name,
+			sizeof(l->u.utility.name)-1);
+		l->u.utility.name[sizeof(l->u.utility.name)-1] = 0;
+		l->u.utility.paramlen = s->u.utility.paramlen;
+		if (l->u.utility.paramlen > sizeof(l->u.utility.params))
+			l->u.utility.paramlen = sizeof(l->u.utility.params);
+		memcpy(l->u.utility.params, s->u.utility.params,
+		       l->u.utility.paramlen);
+		break;
+
+	case CAIF_CHTY_RAW:
+		l->linktype = s->u._raw.channeltype;
+		l->endpoint = s->u._raw.endpoint;
+		l->chtype = s->u._raw.subtype;
+		break;
+
+	default:
+		CFLOG_TRACE(("CAIF_CHTY: Specified bad channel type '%d'\n",
+			     s->type));
+		return -CFGLU_EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(channel_config_2_link_param);
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
new file mode 100644
index 0000000..3c05340
--- /dev/null
+++ b/net/caif/caif_dev.c
@@ -0,0 +1,520 @@
+/*
+ * CAIF Interface registration.
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Borrowed heavily from file: pn_dev.c. Thanks to
+ *  Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ *  and Sakari Ailus <sakari.ailus@nokia.com>
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/netns/generic.h>
+#include <net/netns/generic.h>
+#include <net/net_namespace.h>
+#include <net/caif/caif_dev.h>
+#include <net/caif/caif_chr.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/caif_log.h>
+#include <net/pkt_sched.h>
+#include <net/caif/caif_config_util.h>
+MODULE_LICENSE("GPL");
+
+#define TIMEOUT (HZ*1000)
+/* Used for local tracking of the caif net devices */
+struct caif_device_entry {
+	struct layer layer;
+	struct list_head list;
+	atomic_t in_use;
+	atomic_t state;
+	uint16 phyid;
+	struct net_device *netdev;
+	wait_queue_head_t event;
+};
+
+struct caif_device_entry_list {
+	struct list_head list;
+	spinlock_t lock;
+};
+
+struct caif_net {
+	struct caif_device_entry_list caifdevs;
+};
+
+struct cfcnfg *cfg;
+int caif_net_id;
+
+
+int caif_dbg_level = CAIFLOG_LEVEL_WARNING;
+EXPORT_SYMBOL(caif_dbg_level);
+
+
+struct class caif_class = {
+	.name = "caif",
+};
+
+static ssize_t dbg_lvl_show(struct class *class, char *buf)
+{
+	return sprintf(buf, "%d\n", caif_dbg_level);
+}
+
+static ssize_t dbg_lvl_store(struct class *class, const char *buf,
+			     size_t count)
+{
+	int val;
+
+
+	if ((sscanf(buf, "%d", &val) != 1) || (val < CAIFLOG_MIN_LEVEL)
+			|| (val > CAIFLOG_MAX_LEVEL)) {
+		printk(KERN_WARNING "caif_dbg_level: Invalid value\n");
+		return -EINVAL;
+	}
+	caif_dbg_level = val;
+	return count;
+}
+
+CLASS_ATTR(dbg_lvl, 0644, dbg_lvl_show, dbg_lvl_store);
+
+struct caif_device_entry_list *caif_device_list(struct net *net)
+{
+	struct caif_net *caifn;
+	BUG_ON(!net);
+	caifn = net_generic(net, caif_net_id);
+	BUG_ON(!caifn);
+	return &caifn->caifdevs;
+}
+
+/* Allocate new CAIF device. */
+static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
+{
+	struct caif_device_entry_list *caifdevs;
+	struct caif_device_entry *caifd;
+	caifdevs = caif_device_list(dev_net(dev));
+	BUG_ON(!caifdevs);
+	caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC);
+	if (!caifd)
+		return NULL;
+	caifd->netdev = dev;
+	list_add(&caifd->list, &caifdevs->list);
+	init_waitqueue_head(&caifd->event);
+	return caifd;
+}
+
+static struct caif_device_entry *caif_get(struct net_device *dev)
+{
+	struct caif_device_entry_list *caifdevs =
+	    caif_device_list(dev_net(dev));
+	struct caif_device_entry *caifd;
+	BUG_ON(!caifdevs);
+	list_for_each_entry(caifd, &caifdevs->list, list) {
+		if (caifd->netdev == dev)
+			return caifd;
+	}
+	return NULL;
+}
+
+static void caif_device_destroy(struct net_device *dev)
+{
+	struct caif_device_entry_list *caifdevs =
+	    caif_device_list(dev_net(dev));
+	struct caif_device_entry *caifd;
+	ASSERT_RTNL();
+	if (dev->type != ARPHRD_CAIF)
+		return;
+
+	spin_lock_bh(&caifdevs->lock);
+	caifd = caif_get(dev);
+	if (caifd == NULL) {
+		spin_unlock_bh(&caifdevs->lock);
+		return;
+	}
+
+	list_del(&caifd->list);
+	spin_unlock_bh(&caifdevs->lock);
+
+	kfree(caifd);
+	return;
+}
+
+struct net_device *caif_device_get(struct net *net)
+{
+	struct caif_device_entry_list *caifdevs = caif_device_list(net);
+	struct caif_device_entry *caifd;
+	struct net_device *dev = NULL;
+	spin_lock_bh(&caifdevs->lock);
+	list_for_each_entry(caifd, &caifdevs->list, list) {
+		dev = caifd->netdev;
+		BUG_ON(!dev);
+		if ((dev->reg_state == NETREG_REGISTERED) &&
+		    ((caifd->netdev->flags & IFF_UP)) == IFF_UP)
+			break;
+		dev = NULL;
+	}
+	spin_unlock_bh(&caifdevs->lock);
+	return dev;
+}
+
+static int transmit(struct layer *layer,
+		    struct transmt_info *info, struct cfpkt *pkt)
+{
+	struct caif_device_entry *caifd =
+	    container_of(layer, struct caif_device_entry, layer);
+	struct sk_buff *skb, *skb2;
+	int ret = -EINVAL;
+	struct transmt_info tmp;
+
+	skb = cfpkt_tonative(pkt);
+	memcpy(&tmp, skb->cb, sizeof(tmp));
+	memcpy(skb->cb, info, sizeof(*info));
+	skb->dev = caifd->netdev;
+
+	/*
+	 * Don't allow SKB to be destroyed upon error, but signal resend
+	 * notification to clients. We can't rely on the return value as
+	 * congestion (NET_XMIT_CN) sometimes drops the packet, sometimes don't.
+	 */
+	if (netif_queue_stopped(caifd->netdev))
+		return -EAGAIN;
+	skb2 = skb_get(skb);
+
+	ret = dev_queue_xmit(skb2);
+
+	if (!ret)
+		kfree_skb(skb);
+	else {
+		/* Restore the original skb private data */
+		memcpy(skb->cb, &tmp, sizeof(tmp));
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int modemcmd(struct layer *layr, enum caif_modemcmd ctrl)
+{
+	struct caif_device_entry *caifd;
+	struct caif_dev_common *caifdev;
+	caifd = container_of(layr, struct caif_device_entry, layer);
+	caifdev = netdev_priv(caifd->netdev);
+	if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) {
+		try_module_get(THIS_MODULE);
+		try_module_get(caifdev->net_dev_module);
+		atomic_set(&caifdev->in_use, 1);
+		atomic_set(&caifd->in_use, 1);
+		wake_up_interruptible(&caifd->event);
+
+	} else if (ctrl == _CAIF_MODEMCMD_PHYIF_USELESS) {
+		module_put(THIS_MODULE);
+		module_put(caifdev->net_dev_module);
+		atomic_set(&caifdev->in_use, 0);
+		atomic_set(&caifd->in_use, 0);
+		wake_up_interruptible(&caifd->event);
+	}
+	return 0;
+}
+
+/*
+ * Stuff received packets to associated sockets.
+ * On error, returns non-zero and releases the skb.
+ */
+static int receive(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pkttype, struct net_device *orig_dev)
+{
+	struct net *net;
+	struct cfpkt *pkt;
+	struct caif_device_entry *caifd;
+	net = dev_net(dev);
+	pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
+	caifd = caif_get(dev);
+
+	if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+		return NET_RX_DROP;
+
+	if (caifd->layer.up->receive(caifd->layer.up, pkt))
+		return NET_RX_DROP;
+
+	return 0;
+}
+
+static struct packet_type caif_packet_type __read_mostly = {
+	.type = cpu_to_be16(ETH_P_CAIF),
+	.func = receive,
+};
+
+static void dev_flowctrl(struct net_device *dev, int on)
+{
+	struct caif_device_entry *caifd = caif_get(dev);
+	if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+		return;
+
+	caifd->layer.up->ctrlcmd(caifd->layer.up,
+				 on ?
+				 _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND :
+				 _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
+				 caifd->layer.id);
+}
+
+/* notify Caif of device events */
+static int caif_device_notify(struct notifier_block *me, unsigned long what,
+			      void *arg)
+{
+	struct net_device *dev = arg;
+	struct caif_device_entry *caifd = NULL;
+	struct caif_dev_common *caifdev;
+	int res = -EINVAL;
+
+	if (dev->type != ARPHRD_CAIF)
+		return 0;
+
+	switch (what) {
+	case NETDEV_REGISTER:
+		printk(KERN_INFO "CAIF register:%s\n", dev->name);
+		caifd = caif_device_alloc(dev);
+		if (caifd == NULL)
+			break;
+		caifdev = netdev_priv(dev);
+		caifdev->flowctrl = dev_flowctrl;
+		atomic_set(&caifd->state, what);
+		res = dev_open(dev);
+		break;
+
+	case NETDEV_UP:
+		printk(KERN_INFO "CAIF up:%s\n", dev->name);
+		caifd = caif_get(dev);
+		if (caifd == NULL)
+			break;
+		caifdev = netdev_priv(dev);
+		if (atomic_read(&caifd->state) == NETDEV_UP) {
+			printk(KERN_INFO "CAIF dev:%s already up\n", dev->name);
+			break;
+		}
+		atomic_set(&caifd->state, what);
+		caifd->layer.transmit = transmit;
+		caifd->layer.modemcmd = modemcmd;
+
+		cfcnfg_add_phy_layer(get_caif_conf(),
+				     caifdev->phy_type,
+				     &caifd->layer,
+				     &caifd->phyid,
+				     caifdev->phy_pref);
+		strncpy(caifd->layer.name, dev->name,
+			sizeof(caifd->layer.name) - 1);
+		caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
+		break;
+
+	case NETDEV_GOING_DOWN:
+		caifd = caif_get(dev);
+		if (caifd == NULL)
+			break;
+		printk(KERN_INFO "CAIF Going down:%s\n", dev->name);
+		atomic_set(&caifd->state, what);
+		if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+			return -EINVAL;
+		caifd->layer.up->ctrlcmd(caifd->layer.up,
+					 _CAIF_CTRLCMD_PHYIF_DOWN_IND,
+					 caifd->layer.id);
+		res = wait_event_interruptible_timeout(caifd->event,
+					atomic_read(&caifd->in_use) == 0,
+						       10);
+		break;
+
+	case NETDEV_DOWN:
+		caifd = caif_get(dev);
+		if (caifd == NULL)
+			break;
+		printk(KERN_INFO "CAIF Down:%s\n", dev->name);
+		if (atomic_read(&caifd->in_use))
+			CAIFLOG_WARN("Unregistering an active CAIF device:"
+				     "%s\n", dev->name);
+		cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
+		atomic_set(&caifd->state, what);
+		break;
+
+	case NETDEV_UNREGISTER:
+		caifd = caif_get(dev);
+		printk(KERN_INFO "CAIF unregister:%s\n", dev->name);
+		atomic_set(&caifd->state, what);
+		caif_device_destroy(dev);
+		break;
+	}
+	return 0;
+}
+
+static struct notifier_block caif_device_notifier = {
+	.notifier_call = caif_device_notify,
+	.priority = 0,
+};
+
+/* Per-namespace Caif devices handling */
+static int caif_init_net(struct net *net)
+{
+	struct caif_net *caifn;
+	int ret;
+	caifn = kmalloc(sizeof(*caifn), GFP_KERNEL);
+	if (!caifn)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&caifn->caifdevs.list);
+	spin_lock_init(&caifn->caifdevs.lock);
+	ret = net_assign_generic(net, caif_net_id, caifn);
+	if (ret)
+		kfree(caifn);
+
+	return 0;
+}
+
+static void caif_exit_net(struct net *net)
+{
+	struct caif_net *caifn = net_generic(net, caif_net_id);
+	struct net_device *dev;
+	int res;
+	rtnl_lock();
+	for_each_netdev(net, dev) {
+		if (dev->type != ARPHRD_CAIF)
+			continue;
+		res = dev_close(dev);
+		caif_device_destroy(dev);
+	}
+	rtnl_unlock();
+	kfree(caifn);
+}
+
+struct cfcnfg *get_caif_conf(void)
+{
+	return cfg;
+}
+EXPORT_SYMBOL(get_caif_conf);
+
+int (*netdev_mgmt_func) (int action, union caif_action *param);
+EXPORT_SYMBOL(netdev_mgmt_func);
+
+static int (*caif_ioctl_func)(unsigned int cmd, unsigned long arg);
+
+void caif_register_ioctl(
+			 int (*ioctl)(unsigned int cmd,
+				      unsigned long arg))
+{
+	caif_ioctl_func = ioctl;
+}
+EXPORT_SYMBOL(caif_register_ioctl);
+
+int caif_ioctl(unsigned int cmd, unsigned long arg)
+{
+	printk(KERN_INFO "Enter: caif_ioctl\n");
+	if (caif_ioctl_func == NULL)
+		return -EINVAL;
+	return caif_ioctl_func(cmd, arg);
+}
+EXPORT_SYMBOL(caif_ioctl);
+
+int caifdev_adapt_register(struct caif_channel_config *config,
+			   struct layer *adap_layer)
+{
+	struct cfctrl_link_param param;
+
+	if (channel_config_2_link_param(get_caif_conf(), config, &param) == 0)
+		/* Hook up the adaptation layer. */
+		if (cfcnfg_add_adaptation_layer(get_caif_conf(),
+						&param, adap_layer))
+			return 0;
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(caifdev_adapt_register);
+
+int caifdev_adapt_unregister(struct layer *adap_layer)
+{
+	return cfcnfg_del_adapt_layer(get_caif_conf(), adap_layer);
+}
+EXPORT_SYMBOL(caifdev_adapt_unregister);
+
+
+int caif_register_netdev(int (*netdev_mgmt)
+			  (int action, union caif_action *param))
+{
+	netdev_mgmt_func = netdev_mgmt;
+	return 0;
+}
+EXPORT_SYMBOL(caif_register_netdev);
+
+void caif_unregister_netdev()
+{
+	netdev_mgmt_func = NULL;
+}
+EXPORT_SYMBOL(caif_unregister_netdev);
+
+static struct pernet_operations caif_net_ops = {
+	.init = caif_init_net,
+	.exit = caif_exit_net,
+};
+
+/* Initialize Caif devices list */
+int __init caif_device_init(void)
+{
+	int result;
+
+	cfg = cfcnfg_create();
+	if (!cfg) {
+		printk(KERN_WARNING "caifdev: err: can't create cfcnfg.\n");
+		goto err_cfcnfg_create_failed;
+	}
+
+	result = register_pernet_gen_device(&caif_net_id, &caif_net_ops);
+	if (result)
+		return result;
+	dev_add_pack(&caif_packet_type);
+	register_netdevice_notifier(&caif_device_notifier);
+
+	/* Register class for SYSFS. */
+	result = class_register(&caif_class);
+	if (unlikely(result)) {
+		printk(KERN_WARNING
+		       "caifdev: err: %d, can't create sysfs node.\n", result);
+		goto err_class_register_failed;
+	}
+
+	/* Create SYSFS nodes. */
+	result = class_create_file(&caif_class, &class_attr_dbg_lvl);
+	if (unlikely(result)) {
+		printk(KERN_WARNING
+		       "caifdev: err: %d, can't create sysfs node.\n", result);
+		goto err_sysfs_create_failed;
+	}
+	return result;
+
+err_sysfs_create_failed:
+	class_unregister(&caif_class);
+err_class_register_failed:
+err_cfcnfg_create_failed:
+	return -ENODEV;
+}
+
+void __exit caif_device_exit(void)
+{
+	class_remove_file(&caif_class, &class_attr_dbg_lvl);
+	class_unregister(&caif_class);
+	dev_remove_pack(&caif_packet_type);
+	unregister_pernet_gen_device(caif_net_id, &caif_net_ops);
+	unregister_netdevice_notifier(&caif_device_notifier);
+
+}
+
+module_init(caif_device_init);
+module_exit(caif_device_exit);
+
+
+
+
+
+
+
+
+
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
new file mode 100644
index 0000000..492fcfb
--- /dev/null
+++ b/net/caif/caif_socket.c
@@ -0,0 +1,1560 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brændeland sjur.brandlenad@stericsson.com
+ *              Per Sigmond / Per.Sigmond@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/tcp.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+/* Caif header files. */
+#include <linux/caif/caif_socket.h>
+#include <net/caif/generic/caif_layer.h>
+#include <linux/caif/caif_config.h>
+#include <net/caif/caif_log.h>
+#include <net/caif/caif_chr.h>
+
+MODULE_LICENSE("GPL");
+
+#define CHNL_SKT_READ_QUEUE_HIGH 2000
+#define CHNL_SKT_READ_QUEUE_LOW 100
+
+#ifdef CAIF_USE_CACHE
+int caif_max_links = 32;
+#endif
+
+int caif_sockbuf_size = 40000; /* FIXME: Check this value! */
+static struct kmem_cache *caif_sk_cachep;
+static atomic_t caif_nr_socks = ATOMIC_INIT(0);
+
+#define CONN_STATE_OPEN_BIT           1
+#define CONN_STATE_PENDING_BIT        2
+#define CONN_STATE_PEND_DESTROY_BIT   3
+#define CONN_REMOTE_SHUTDOWN_BIT      4
+
+#define TX_FLOW_ON_BIT                1
+#define RX_FLOW_ON_BIT                2
+
+#define STATE_IS_OPEN(cf_sk) test_bit(CONN_STATE_OPEN_BIT,\
+				    (void *) &(cf_sk)->conn_state)
+#define STATE_IS_REMOTE_SHUTDOWN(cf_sk) test_bit(CONN_REMOTE_SHUTDOWN_BIT,\
+				    (void *) &(cf_sk)->conn_state)
+#define STATE_IS_PENDING(cf_sk) test_bit(CONN_STATE_PENDING_BIT,\
+				       (void *) &(cf_sk)->conn_state)
+#define STATE_IS_PENDING_DESTROY(cf_sk) test_bit(CONN_STATE_PEND_DESTROY_BIT,\
+				       (void *) &(cf_sk)->conn_state)
+
+#define SET_STATE_PENDING_DESTROY(cf_sk) set_bit(CONN_STATE_PEND_DESTROY_BIT,\
+				    (void *) &(cf_sk)->conn_state)
+#define SET_STATE_OPEN(cf_sk) set_bit(CONN_STATE_OPEN_BIT,\
+				    (void *) &(cf_sk)->conn_state)
+#define SET_STATE_CLOSED(cf_sk) clear_bit(CONN_STATE_OPEN_BIT,\
+					(void *) &(cf_sk)->conn_state)
+#define SET_PENDING_ON(cf_sk) set_bit(CONN_STATE_PENDING_BIT,\
+				    (void *) &(cf_sk)->conn_state)
+#define SET_PENDING_OFF(cf_sk) clear_bit(CONN_STATE_PENDING_BIT,\
+				       (void *) &(cf_sk)->conn_state)
+#define SET_REMOTE_SHUTDOWN(cf_sk) set_bit(CONN_REMOTE_SHUTDOWN_BIT,\
+				    (void *) &(cf_sk)->conn_state)
+
+#define RX_FLOW_IS_ON(cf_sk) test_bit(RX_FLOW_ON_BIT,\
+				    (void *) &(cf_sk)->flow_state)
+#define TX_FLOW_IS_ON(cf_sk) test_bit(TX_FLOW_ON_BIT,\
+				    (void *) &(cf_sk)->flow_state)
+
+#define SET_RX_FLOW_OFF(cf_sk) clear_bit(RX_FLOW_ON_BIT,\
+				       (void *) &(cf_sk)->flow_state)
+#define SET_RX_FLOW_ON(cf_sk) set_bit(RX_FLOW_ON_BIT,\
+				    (void *) &(cf_sk)->flow_state)
+#define SET_TX_FLOW_OFF(cf_sk) clear_bit(TX_FLOW_ON_BIT,\
+				       (void *) &(cf_sk)->flow_state)
+#define SET_TX_FLOW_ON(cf_sk) set_bit(TX_FLOW_ON_BIT,\
+				    (void *) &(cf_sk)->flow_state)
+
+#define SKT_READ_FLAG 0x01
+#define SKT_WRITE_FLAG 0x02
+
+#define MAX_CAIF_SOCKETS	200
+
+#ifdef CONFIG_DEBUG_FS
+struct dentry *debugfsdir;
+#include <linux/debugfs.h>
+
+static int max_caif_sockets = MAX_CAIF_SOCKETS;
+#endif
+
+/* The AF_CAIF socket */
+struct caifsock {
+	struct sock sk;		/* NOTE: sk has to be the first member */
+	struct layer layer;
+	char name[CAIF_LAYER_NAME_SZ];
+	u32 conn_state;
+	u32 flow_state;
+	struct cfpktq *pktq;
+	int file_mode;
+	struct caif_channel_config config;
+	int read_queue_len;
+	spinlock_t read_queue_len_lock;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_device_dir;
+	atomic_t num_open;
+	atomic_t num_close;
+	atomic_t num_init;
+	atomic_t num_init_resp;
+	atomic_t num_init_fail_resp;
+	atomic_t num_deinit;
+	atomic_t num_deinit_resp;
+	atomic_t num_remote_shutdown_ind;
+	atomic_t num_tx_flow_off_ind;
+	atomic_t num_tx_flow_on_ind;
+	atomic_t num_rx_flow_off;
+	atomic_t num_rx_flow_on;
+#endif
+};
+
+static void drain_queue(struct caifsock *cf_sk);
+
+/** Packet Receive Callback function called from CAIF Stack */
+static int caif_sktrecv_cb(struct layer *layr, struct cfpkt *pkt)
+{
+	struct caifsock *cf_sk;
+	int read_queue_high;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+	cf_sk = container_of(layr, struct caifsock, layer);
+
+	CAIFLOG_TRACE2("[%s] data received: %d bytes.\n",
+		       __func__, cfpkt_getlen(pkt));
+
+	if (!STATE_IS_OPEN(cf_sk)) {
+		/*FIXME: This should be allowed finally!*/
+		CAIFLOG_TRACE("caif_sktrecv_cb called after close request\n");
+		cfpkt_destroy(pkt);
+		return 0;
+	}
+	/** NOTE: This function may be called in Tasklet context! */
+
+	/* The queue has its own lock */
+	CAIFLOG_TRACE("here %p %p\n", pkt, cf_sk->pktq);
+	cfpkt_queue(cf_sk->pktq, pkt, 0);
+
+	spin_lock(&cf_sk->read_queue_len_lock);
+	cf_sk->read_queue_len++;
+
+	read_queue_high = (cf_sk->read_queue_len > CHNL_SKT_READ_QUEUE_HIGH);
+	spin_unlock(&cf_sk->read_queue_len_lock);
+
+	if (RX_FLOW_IS_ON(cf_sk) && read_queue_high) {
+
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_rx_flow_off);
+#endif
+		SET_RX_FLOW_OFF(cf_sk);
+
+		/* Send flow off (NOTE: must not sleep) */
+		CAIFLOG_TRACE2
+		    ("caif_sktrecv_cb(): sending flow OFF (queue len = %d)\n",
+		     cf_sk->read_queue_len);
+		caif_assert(cf_sk->layer.dn);
+		caif_assert(cf_sk->layer.dn->ctrlcmd);
+
+		(void) cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
+					       CAIF_MODEMCMD_FLOW_OFF_REQ);
+	}
+
+	/* Signal reader that data is available. */
+
+	wake_up_interruptible(cf_sk->sk.sk_sleep);
+
+	return 0;
+}
+
+/** Packet Flow Control Callback function called from CAIF */
+static void caif_sktflowctrl_cb(struct layer *layr, enum caif_ctrlcmd flow, int phyid)
+{
+	struct caifsock *cf_sk;
+
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	/** NOTE: This function may be called in Tasklet context! */
+	CAIFLOG_TRACE("AT flowctrl func called flow: %s.\n",
+		      flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
+		      flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
+		      flow == CAIF_CTRLCMD_INIT_RSP ? "INIT_RSP" :
+		      flow == CAIF_CTRLCMD_DEINIT_RSP ? "DEINIT_RSP" :
+		      flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "INIT_FAIL_RSP" :
+		      flow ==
+		      CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ? "REMOTE_SHUTDOWN" :
+		      "UKNOWN CTRL COMMAND");
+
+	cf_sk = container_of(layr, struct caifsock, layer);
+	switch (flow) {
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_FLOW_ON_IND\n",
+			      __func__, __LINE__);
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_tx_flow_on_ind);
+#endif
+		/* Signal reader that data is available. */
+		SET_TX_FLOW_ON(cf_sk);
+		wake_up_interruptible(cf_sk->sk.sk_sleep);
+		break;
+
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_tx_flow_off_ind);
+#endif
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_FLOW_OFF_IND\n",
+			      __func__, __LINE__);
+		SET_TX_FLOW_OFF(cf_sk);
+		break;
+
+	case CAIF_CTRLCMD_INIT_RSP:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_INIT_RSP\n",
+			      __func__, __LINE__);
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_init_resp);
+#endif
+		/* Signal reader that data is available. */
+		caif_assert(STATE_IS_OPEN(cf_sk));
+		SET_PENDING_OFF(cf_sk);
+		SET_TX_FLOW_ON(cf_sk);
+		wake_up_interruptible(cf_sk->sk.sk_sleep);
+		break;
+
+	case CAIF_CTRLCMD_DEINIT_RSP:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_DEINIT_RSP\n",
+			      __func__, __LINE__);
+
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_deinit_resp);
+#endif
+
+		caif_assert(!STATE_IS_OPEN(cf_sk));
+
+		SET_PENDING_OFF(cf_sk);
+
+		if (!STATE_IS_PENDING_DESTROY(cf_sk)) {
+			if (cf_sk->sk.sk_sleep != NULL)
+				wake_up_interruptible(cf_sk->sk.sk_sleep);
+		}
+
+		sock_put(&cf_sk->sk);
+
+		break;
+
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_INIT_FAIL_RSP\n",
+			      __func__, __LINE__);
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_init_fail_resp);
+#endif
+		caif_assert(STATE_IS_OPEN(cf_sk));
+		SET_STATE_CLOSED(cf_sk);
+		SET_PENDING_OFF(cf_sk);
+		SET_TX_FLOW_OFF(cf_sk);
+		wake_up_interruptible(cf_sk->sk.sk_sleep);
+		break;
+
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND\n",
+			      __func__, __LINE__);
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_remote_shutdown_ind);
+#endif
+		caif_assert(STATE_IS_OPEN(cf_sk));
+		caif_assert(STATE_IS_PENDING(cf_sk));
+
+		SET_REMOTE_SHUTDOWN(cf_sk);
+		SET_TX_FLOW_OFF(cf_sk);
+
+		drain_queue(cf_sk);
+		SET_RX_FLOW_ON(cf_sk);
+		cf_sk->file_mode = 0;
+
+		wake_up_interruptible(cf_sk->sk.sk_sleep);
+		break;
+
+	default:
+		CAIFLOG_TRACE("[%s:%d] Unexpected flow command %d\n",
+			      __func__, __LINE__, flow);
+	}
+}
+
+
+
+static struct sk_buff *caif_alloc_send_skb(struct sock *sk,
+				    unsigned long data_len,
+				    int *err)
+{
+	struct sk_buff *skb;
+	unsigned int sk_allocation = sk->sk_allocation;
+
+	sk->sk_allocation |= GFP_KERNEL;
+
+	/* Allocate a buffer structure to hold the signal. */
+	skb = sock_alloc_send_skb(sk, data_len, 1, err);
+
+	sk->sk_allocation = sk_allocation;
+
+	return skb;
+}
+
+static int caif_recvmsg(struct kiocb *iocb, struct socket *sock,
+				struct msghdr *m, size_t buf_len, int flags)
+
+{
+	struct sock *sk = sock->sk;
+	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+	struct cfpkt *pkt = NULL;
+	size_t len;
+	int result;
+	struct sk_buff *skb;
+	ssize_t ret = -EIO;
+	int read_queue_low;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	if (cf_sk == NULL) {
+		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
+			      __func__, __LINE__);
+		ret = -EBADFD;
+		goto read_error;
+	}
+
+	if (m->msg_iovlen != 1)
+		return -EOPNOTSUPP;   /* Don't do multiple iovec entries yet */
+
+	if (unlikely(!buf_len))
+		return -EINVAL;
+
+	lock_sock(&(cf_sk->sk));
+
+	caif_assert(cf_sk->pktq);
+
+	if (!STATE_IS_OPEN(cf_sk)) {
+		/* Socket is closed or closing. */
+		if (!STATE_IS_PENDING(cf_sk)) {
+			CAIFLOG_TRACE("socket is closed (by remote end)\n");
+			ret = -EPIPE;
+		} else {
+			CAIFLOG_TRACE("socket is closing...\n");
+			ret = -EBADF;
+		}
+		goto read_error;
+	}
+
+	/* Socket is open or opening. */
+	if (STATE_IS_PENDING(cf_sk)) {
+		CAIFLOG_TRACE("socket is opening...\n");
+
+		if (flags & MSG_DONTWAIT) {
+			/* We can't block. */
+			CAIFLOG_TRACE("state pending and MSG_DONTWAIT\n");
+			ret = -EAGAIN;
+			goto read_error;
+		}
+
+		/* Blocking mode; state is pending and we need to wait
+		 * for its conclusion.
+		 */
+		release_sock(&cf_sk->sk);
+
+		result =
+		    wait_event_interruptible(*cf_sk->sk.sk_sleep,
+					     !STATE_IS_PENDING(cf_sk));
+
+		lock_sock(&(cf_sk->sk));
+
+		if (result == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    (" wait_event_interruptible woken by a signal (1)");
+			ret = -ERESTARTSYS;
+			goto read_error;
+		}
+	}
+
+	if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
+		CAIFLOG_TRACE("received remote_shutdown indication\n");
+		ret = -ESHUTDOWN;
+		goto read_error;
+	}
+
+	/* Block if we don't have any received buffers.
+	 * The queue has its own lock.
+	 */
+	while ((pkt = cfpkt_qpeek(cf_sk->pktq)) == NULL) {
+
+		if (flags & MSG_DONTWAIT) {
+			CAIFLOG_TRACE("caif_recvmsg: MSG_DONTWAIT\n");
+			ret = -EAGAIN;
+			goto read_error;
+		}
+		CAIFLOG_TRACE2("[%s:%d] wait_event\n", __func__, __LINE__);
+
+		/* Let writers in. */
+		release_sock(&cf_sk->sk);
+
+		/* Block reader until data arrives or socket is closed. */
+		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
+					cfpkt_qpeek(cf_sk->pktq)
+					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
+					|| !STATE_IS_OPEN(cf_sk)) ==
+		    -ERESTARTSYS) {
+			CAIFLOG_TRACE
+				("caif_recvmsg:"
+				" wait_event_interruptible woken by "
+				"a signal, signal_pending(current) = %d\n",
+				signal_pending(current));
+			return -ERESTARTSYS;
+		}
+
+		CAIFLOG_TRACE2("[%s:%d] awake\n", __func__, __LINE__);
+		if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
+			CAIFLOG_TRACE("received remote_shutdown indication\n");
+			ret = -ESHUTDOWN;
+			goto read_error_no_unlock;
+		}
+
+		/* I want to be alone on cf_sk (except status and queue). */
+		lock_sock(&(cf_sk->sk));
+
+		if (!STATE_IS_OPEN(cf_sk)) {
+			/* Someone closed the link, report error. */
+			CAIFLOG_TRACE("[%s:%d] remote end shutdown!\n",
+				      __func__, __LINE__);
+			ret = -EPIPE;
+			goto read_error;
+		}
+	}
+
+	/* The queue has its own lock. */
+	len = cfpkt_getlen(pkt);
+
+	/* Check max length that can be copied. */
+	if (len > buf_len) {
+		CAIFLOG_TRACE("caif_recvmsg: user buffer too small\n");
+		ret = -EINVAL;
+		goto read_error;
+	}
+
+	/* Get packet from queue.
+	 * The queue has its own lock.
+	 */
+	pkt = cfpkt_dequeue(cf_sk->pktq);
+
+	spin_lock(&cf_sk->read_queue_len_lock);
+	cf_sk->read_queue_len--;
+	read_queue_low = (cf_sk->read_queue_len < CHNL_SKT_READ_QUEUE_LOW);
+	spin_unlock(&cf_sk->read_queue_len_lock);
+
+	if (!RX_FLOW_IS_ON(cf_sk) && read_queue_low) {
+#ifdef CONFIG_DEBUG_FS
+		atomic_inc(&cf_sk->num_rx_flow_on);
+#endif
+		SET_RX_FLOW_ON(cf_sk);
+
+		/* Send flow on. */
+		CAIFLOG_TRACE2
+			("caif_recvmsg(): sending flow ON (queue len = %d)\n",
+			cf_sk->read_queue_len);
+		caif_assert(cf_sk->layer.dn);
+		caif_assert(cf_sk->layer.dn->ctrlcmd);
+		(void) cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
+					       CAIF_MODEMCMD_FLOW_ON_REQ);
+
+		caif_assert(cf_sk->read_queue_len >= 0);
+	}
+	skb = cfpkt_tonative(pkt);
+	result = skb_copy_datagram_iovec(skb, 0, m->msg_iov, len);
+	if (result) {
+		CAIFLOG_TRACE("caif_recvmsg: cfpkt_raw_extract failed\n");
+		cfpkt_destroy(pkt);
+		ret = -EFAULT;
+		goto read_error;
+	}
+	if (unlikely(buf_len < len)) {
+		len = buf_len;
+		m->msg_flags |= MSG_TRUNC;
+	}
+
+	/* Free packet. */
+	skb_free_datagram(sk, skb);
+
+	/* Let the others in. */
+	release_sock(&cf_sk->sk);
+	CAIFLOG_EXIT("");
+	return len;
+
+read_error:
+	release_sock(&cf_sk->sk);
+read_error_no_unlock:
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+/* Send a signal as a consequence of sendmsg, sendto or caif_sendmsg. */
+static int caif_sendmsg(struct kiocb *kiocb, struct socket *sock,
+			struct msghdr *msg, size_t len)
+{
+
+	struct sock *sk = sock->sk;
+	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+	void *payload;
+	size_t payload_size = msg->msg_iov->iov_len;
+	struct cfpkt *pkt = NULL;
+	struct transmt_info info;
+	unsigned char *txbuf;
+	int err = 0;
+	ssize_t ret = -EIO;
+	int result;
+	struct sk_buff *skb;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+	caif_assert(msg->msg_iovlen == 1);
+
+	if (cf_sk == NULL) {
+		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
+			      __func__, __LINE__);
+		ret = -EBADFD;
+		goto write_error_no_unlock;
+	}
+
+	if (unlikely(msg->msg_iov->iov_base == NULL)) {
+		CAIFLOG_WARN("Buffer is NULL.\n");
+		ret = -EINVAL;
+		goto write_error_no_unlock;
+	}
+
+	payload = msg->msg_iov->iov_base;
+	if (payload_size > CAIF_MAX_PAYLOAD_SIZE) {
+		CAIFLOG_TRACE("[%s:%d] buffer too long\n", __func__, __LINE__);
+		ret = -EINVAL;
+		goto write_error_no_unlock;
+	}
+	/* I want to be alone on cf_sk (except status and queue) */
+	lock_sock(&(cf_sk->sk));
+
+	caif_assert(cf_sk->pktq);
+
+	if (!STATE_IS_OPEN(cf_sk)) {
+		/* Socket is closed or closing */
+		if (!STATE_IS_PENDING(cf_sk)) {
+			CAIFLOG_TRACE("socket is closed (by remote end)\n");
+			ret = -EPIPE;
+		} else {
+			CAIFLOG_TRACE("socket is closing...\n");
+			ret = -EBADF;
+		}
+		goto write_error;
+	}
+
+	/* Socket is open or opening */
+	if (STATE_IS_PENDING(cf_sk)) {
+		CAIFLOG_TRACE("socket is opening...\n");
+
+		if (msg->msg_flags & MSG_DONTWAIT) {
+			/* We can't block */
+			CAIFLOG_TRACE("state pending and MSG_DONTWAIT\n");
+			ret = -EAGAIN;
+			goto write_error;
+		}
+
+		/* Let readers in */
+		release_sock(&cf_sk->sk);
+
+		/* Blocking mode; state is pending and we need to wait
+		   for its conclusion */
+		result =
+		    wait_event_interruptible(*cf_sk->sk.sk_sleep,
+					     !STATE_IS_PENDING(cf_sk));
+
+		/* I want to be alone on cf_sk (except status and queue) */
+		lock_sock(&(cf_sk->sk));
+
+		if (result == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    (" wait_event_interruptible woken by a signal (1)");
+			ret = -ERESTARTSYS;
+			goto write_error;
+		}
+	}
+
+	if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
+		CAIFLOG_TRACE("received remote_shutdown indication\n");
+		ret = -ESHUTDOWN;
+		goto write_error;
+	}
+
+	if (!TX_FLOW_IS_ON(cf_sk)) {
+
+		/* Flow is off. Check non-block flag */
+		if (msg->msg_flags & MSG_DONTWAIT) {
+			CAIFLOG_TRACE
+			("caif_sendmsg: MSG_DONTWAIT and tx flow off");
+			ret = -EAGAIN;
+			goto write_error;
+		}
+
+		/* release lock before waiting */
+		release_sock(&cf_sk->sk);
+
+		/* Wait until flow is on or socket is closed */
+		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
+					TX_FLOW_IS_ON(cf_sk)
+					|| !STATE_IS_OPEN(cf_sk)
+					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
+					) == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+				("caif_sendmsg:"
+				" wait_event_interruptible woken by a signal");
+			ret = -ERESTARTSYS;
+			goto write_error_no_unlock;
+		}
+
+		/* I want to be alone on cf_sk (except status and queue) */
+		lock_sock(&(cf_sk->sk));
+
+		if (!STATE_IS_OPEN(cf_sk)) {
+			/* someone closed the link, report error */
+			CAIFLOG_TRACE("[%s:%d] remote end shutdown!\n",
+				      __func__, __LINE__);
+			ret = -EPIPE;
+			goto write_error;
+		}
+
+		if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
+			CAIFLOG_TRACE("received remote_shutdown indication\n");
+			ret = -ESHUTDOWN;
+			goto write_error;
+		}
+	}
+
+	/* Create packet, buf=NULL means no copying */
+	skb = caif_alloc_send_skb(sk,
+				payload_size + CAIF_NEEDED_HEADROOM +
+				CAIF_NEEDED_TAILROOM,
+				&err);
+	skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+	pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
+	caif_assert((void *)pkt == (void *)skb);
+
+	if (pkt == NULL) {
+		CAIFLOG_TRACE
+			("caif_sendmsg: cfpkt_create_pkt returned NULL\n");
+		ret = -EIO;
+		goto write_error;
+	}
+
+	if (!cfpkt_raw_append(pkt, (void **) &txbuf, payload_size)) {
+		CAIFLOG_TRACE("caif_sendmsg: cfpkt_raw_append failed\n");
+		cfpkt_destroy(pkt);
+		ret = -EINVAL;
+		goto write_error;
+	}
+
+	/* Copy data into buffer. */
+	if (copy_from_user(txbuf, payload, payload_size)) {
+		CAIFLOG_TRACE
+			("caif_sendmsg: copy_from_user returned non zero.\n");
+		cfpkt_destroy(pkt);
+		ret = -EINVAL;
+		goto write_error;
+	}
+	memset(&info, 0, sizeof(info));
+
+	/* Send the packet down the stack. */
+	caif_assert(cf_sk->layer.dn);
+	caif_assert(cf_sk->layer.dn->transmit);
+
+	do {
+			ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn,
+							&info, pkt);
+
+		if (likely((ret >= 0) || (ret != -EAGAIN)))
+			break;
+
+		/* EAGAIN - retry */
+		if (msg->msg_flags & MSG_DONTWAIT) {
+			CAIFLOG_TRACE
+			    ("NONBLOCK and transmit failed, error = %d\n",
+			     ret);
+			ret = -EAGAIN;
+			goto write_error;
+		}
+
+		/* Let readers in */
+		release_sock(&cf_sk->sk);
+
+		/* Wait until flow is on or socket is closed */
+		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
+					TX_FLOW_IS_ON(cf_sk)
+					|| !STATE_IS_OPEN(cf_sk)
+					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
+					) == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    ("wait_event_interruptible woken by a signal");
+			ret = -ERESTARTSYS;
+			goto write_error_no_unlock;
+		}
+
+		/* I want to be alone on cf_sk (except status and queue) */
+		lock_sock(&(cf_sk->sk));
+
+	} while (ret == -EAGAIN);
+
+	if (ret < 0) {
+		cfpkt_destroy(pkt);
+		CAIFLOG_TRACE("transmit failed, error = %d\n",
+			      ret);
+
+		goto write_error;
+	}
+
+	release_sock(&cf_sk->sk);
+	CAIFLOG_EXIT("");
+	return payload_size;
+
+write_error:
+	release_sock(&cf_sk->sk);
+write_error_no_unlock:
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+static unsigned int caif_poll(struct file *file, struct socket *sock,
+						poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+	u32 mask = 0;
+	CAIFLOG_ENTER("");
+
+	poll_wait(file, sk->sk_sleep, wait);
+	lock_sock(&(cf_sk->sk));
+	if (cfpkt_qpeek(cf_sk->pktq) != NULL)
+		mask |= (POLLIN | POLLRDNORM);
+	if (!STATE_IS_OPEN(cf_sk))
+		mask |= POLLHUP;
+	else if (TX_FLOW_IS_ON(cf_sk))
+		mask |= (POLLOUT | POLLWRNORM);
+	release_sock(&cf_sk->sk);
+	CAIFLOG_TRACE("[%s:%d] poll mask=0x%04x...\n",
+		      __func__, __LINE__, mask);
+	CAIFLOG_EXIT("");
+	return mask;
+}
+
+static void drain_queue(struct caifsock *cf_sk)
+{
+	struct cfpkt *pkt = NULL;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+	CAIFLOG_TRACE("pktq = %p pkt=%p\n", cf_sk->pktq, pkt);
+
+	/* Empty the queue */
+	do {
+		/* The queue has its own lock */
+		pkt = cfpkt_dequeue(cf_sk->pktq);
+		CAIFLOG_TRACE("pktq = %p pkt=%p\n", cf_sk->pktq, pkt);
+
+		if (!pkt)
+			break;
+
+		CAIFLOG_TRACE
+		    ("[%s:%d] drain_queue(): freeing packet from read queue\n",
+		     __func__, __LINE__);
+		cfpkt_destroy(pkt);
+
+	} while (1);
+
+	spin_lock(&cf_sk->read_queue_len_lock);
+	cf_sk->read_queue_len = 0;
+	spin_unlock(&cf_sk->read_queue_len_lock);
+}
+
+
+static int setsockopt(struct socket *sock,
+			int lvl, int opt, char __user *ov, int ol)
+{
+	struct sock *sk = sock->sk;
+	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+	struct caif_channel_opt confopt;
+	int res;
+
+	if (lvl != SOL_CAIF) {
+		CAIFLOG_TRACE("setsockopt bad level\n");
+			return -ENOPROTOOPT;
+	}
+
+	switch (opt) {
+	case CAIF_CHANNEL_OPT:
+		if (ol < sizeof(struct caif_channel_opt)) {
+			CAIFLOG_TRACE("setsockopt"
+					" CAIF_CHANNEL_CONFIG bad size\n");
+				return -EINVAL;
+		}
+		res = copy_from_user(&confopt, ov, sizeof(confopt));
+		if (res)
+			return res;
+		lock_sock(&(cf_sk->sk));
+		cf_sk->config.priority = confopt.priority;
+		cf_sk->config.phy_pref = confopt.link_selector;
+		strncpy(cf_sk->config.phy_name, confopt.link_name,
+			sizeof(cf_sk->config.phy_name));
+		CAIFLOG_TRACE("Setting sockopt pri=%d pref=%d name=%s\n",
+			      cf_sk->config.priority,
+			      cf_sk->config.phy_pref,
+			      cf_sk->config.phy_name);
+		release_sock(&cf_sk->sk);
+		return 0;
+/* TODO: Implement the remaining options:
+ *	case CAIF_REQ_PARAM_OPT:
+ *	case CAIF_RSP_PARAM_OPT:
+ *	case CAIF_UTIL_FLOW_OPT:
+ *	case CAIF_CONN_INFO_OPT:
+ *	case CAIF_CONN_ID_OPT:
+ */
+	default:
+		CAIFLOG_TRACE("setsockopt: unhandled option %d\n",
+			      opt);
+		return -EINVAL;
+	}
+
+
+}
+
+static int getsockopt(struct socket *sock,
+			int lvl, int opt, char __user *ov, int __user *ol)
+{
+	return -EINVAL;
+}
+
+static int caif_channel_config(struct caifsock *cf_sk,
+				struct sockaddr *sock_addr, int len,
+				struct caif_channel_config *config)
+{
+	struct sockaddr_caif *addr = (struct sockaddr_caif *)sock_addr;
+
+
+		if (len != sizeof(struct sockaddr_caif)) {
+			CAIFLOG_TRACE("Bad address len (%d,%d)\n",
+			      len, sizeof(struct sockaddr_caif));
+			return -EINVAL;
+	}
+	if (sock_addr->sa_family != AF_CAIF) {
+		CAIFLOG_TRACE("Bad address family (%d)\n",
+				sock_addr->sa_family);
+		return -EAFNOSUPPORT;
+	}
+
+	switch (cf_sk->sk.sk_protocol) {
+	case CAIFPROTO_AT:
+		config->type = CAIF_CHTY_AT;
+		break;
+	case CAIFPROTO_DATAGRAM:
+		config->type = CAIF_CHTY_DATAGRAM;
+		break;
+	case CAIFPROTO_DATAGRAM_LOOP:
+		config->type = CAIF_CHTY_DATAGRAM_LOOP;
+		config->u.dgm.connection_id = addr->u.dgm.connection_id;
+		break;
+	case CAIFPROTO_UTIL:
+		config->type = CAIF_CHTY_UTILITY;
+		strncpy(config->u.utility.name, addr->u.util.service,
+				sizeof(config->u.utility.name));
+		/* forcing the end of string to be null-terminated  */
+		config->u.utility.name[sizeof(config->u.utility.name)-1] = '\0';
+		break;
+	case CAIFPROTO_RFM:
+		config->type = CAIF_CHTY_RFM;
+		config->u.rfm.connection_id = addr->u.rfm.connection_id;
+		strncpy(config->u.rfm.volume, addr->u.rfm.volume,
+			sizeof(config->u.rfm.volume));
+		/* forcing the end of string to be null-terminated  */
+		config->u.rfm.volume[sizeof(config->u.rfm.volume)-1] = '\0';
+		break;
+	default:
+		CAIFLOG_TRACE("Bad caif protocol type (%d)\n",
+						cf_sk->sk.sk_protocol);
+		return -EINVAL;
+	}
+	CAIFLOG_TRACE("Setting connect param PROTO=%s\n",
+			(cf_sk->sk.sk_protocol == CAIFPROTO_AT) ?
+			"CAIFPROTO_AT" :
+			(cf_sk->sk.sk_protocol == CAIFPROTO_DATAGRAM) ?
+			"CAIFPROTO_DATAGRAM" :
+			(cf_sk->sk.sk_protocol == CAIFPROTO_DATAGRAM_LOOP) ?
+			"CAIFPROTO_DATAGRAM_LOOP" :
+			(cf_sk->sk.sk_protocol == CAIFPROTO_UTIL) ?
+			"CAIFPROTO_UTIL" :
+			(cf_sk->sk.sk_protocol == CAIFPROTO_RFM) ?
+			"CAIFPROTO_RFM" : "ERROR");
+	return 0;
+}
+
+
+int caif_connect(struct socket *sock, struct sockaddr *uservaddr,
+	       int sockaddr_len, int flags)
+{
+	struct caifsock *cf_sk = NULL;
+	int result = -1;
+	int mode = 0;
+	int ret = -EIO;
+    struct sock *sk = sock->sk;
+
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	BUG_ON(sk == NULL);
+
+	cf_sk = container_of(sk, struct caifsock, sk);
+
+	CAIFLOG_TRACE("cf_sk=%p OPEN=%d, TX_FLOW=%d, RX_FLOW=%d\n", cf_sk,
+		      STATE_IS_OPEN(cf_sk),
+		      TX_FLOW_IS_ON(cf_sk), RX_FLOW_IS_ON(cf_sk));
+
+	sk->sk_state    = TCP_CLOSE;
+	sock->state     = SS_UNCONNECTED;
+
+	/* FIXME: SOCK_DGRAM should be removed? */
+	if (sock->type == SOCK_DGRAM || sock->type == SOCK_SEQPACKET) {
+		sock->state     = SS_CONNECTED;
+		sk->sk_state    = TCP_ESTABLISHED;
+	} else
+		goto out;
+
+	/* I want to be alone on cf_sk (except status and queue) */
+	lock_sock(&(cf_sk->sk));
+
+	ret = caif_channel_config(cf_sk, uservaddr, sockaddr_len,
+				&cf_sk->config);
+	if (ret) {
+		CAIFLOG_TRACE
+		    ("[%s:%d] Cannot set socket address\n",
+		     __func__, __LINE__);
+		goto open_error;
+	}
+
+
+#ifdef CONFIG_DEBUG_FS
+	atomic_inc(&cf_sk->num_open);
+#endif
+	mode = SKT_READ_FLAG | SKT_WRITE_FLAG;
+
+	/* If socket is not open, make sure socket is in fully closed state */
+	if (!STATE_IS_OPEN(cf_sk)) {
+		/* Has link close response been received
+		   (if we ever sent it)? */
+		if (STATE_IS_PENDING(cf_sk)) {
+			/* Still waiting for close response from remote.
+			   If opened non-blocking, report "would block" */
+			if (flags & MSG_DONTWAIT) {
+				CAIFLOG_TRACE("MSG_DONTWAIT"
+					" && close pending\n");
+				ret = -EAGAIN;
+				goto open_error;
+			}
+
+			CAIFLOG_TRACE
+			    ("wait for close response from remote...\n");
+
+			release_sock(&cf_sk->sk);
+
+			/* Blocking mode; close is pending and we need to wait
+			   for its conclusion */
+			result =
+			    wait_event_interruptible(*cf_sk->sk.sk_sleep,
+						     !STATE_IS_PENDING(cf_sk));
+
+			lock_sock(&(cf_sk->sk));
+			if (result == -ERESTARTSYS) {
+				CAIFLOG_TRACE
+				    ("wait_event_interruptible woken"
+				     "by a signal (1)");
+				ret = -ERESTARTSYS;
+				goto open_error;
+			}
+		}
+	}
+
+	/* socket is now either closed, pending open or open */
+	if (STATE_IS_OPEN(cf_sk) && !STATE_IS_PENDING(cf_sk)) {
+		/* Open */
+		CAIFLOG_TRACE
+		    ("[%s:%d] Socket is already opened (cf_sk=%p) check access "
+		     "f_flags = 0x%x file_mode = 0x%x\n",
+		     __func__, __LINE__, cf_sk, mode, cf_sk->file_mode);
+
+		if (mode & cf_sk->file_mode) {
+			CAIFLOG_TRACE
+			    ("[%s:%d] Access mode already in use 0x%x \n",
+			     __func__, __LINE__, mode);
+			ret = -EBUSY;
+			goto open_error;
+		}
+	} else {
+		/* We are closed or pending open.
+		 * If closed:       send link setup
+		 * If pending open: link setup already sent (we could have been
+		 *                  interrupted by a signal last time)
+		 */
+		if (!STATE_IS_OPEN(cf_sk)) {
+			/* First opening of file; connect lower layers: */
+					/* Drain queue (very unlikely) */
+			drain_queue(cf_sk);
+
+			cf_sk->layer.receive = caif_sktrecv_cb;
+
+			SET_STATE_OPEN(cf_sk);
+			SET_PENDING_ON(cf_sk);
+
+			/* Register this channel. */
+			result =
+			    caifdev_adapt_register(&cf_sk->config,
+						&cf_sk->layer);
+			if (result < 0) {
+				CAIFLOG_TRACE
+					("[%s:%d]: can't register channel\n",
+					__func__, __LINE__);
+				ret = -EIO;
+				SET_STATE_CLOSED(cf_sk);
+				SET_PENDING_OFF(cf_sk);
+				goto open_error;
+			}
+#ifdef CONFIG_DEBUG_FS
+			atomic_inc(&cf_sk->num_init);
+#endif
+		}
+
+		/* If opened non-blocking, report "success".
+		 */
+		if (flags & MSG_DONTWAIT) {
+			CAIFLOG_TRACE("[%s:%d]: MSG_DONTWAIT success\n",
+				__func__, __LINE__);
+			ret = 0;
+			goto open_success;
+		}
+
+		CAIFLOG_TRACE("WAIT FOR CONNECT RESPONSE \n");
+
+		/* release lock before waiting */
+		release_sock(&cf_sk->sk);
+
+		result =
+		    wait_event_interruptible(*cf_sk->sk.sk_sleep,
+					     !STATE_IS_PENDING(cf_sk));
+
+		lock_sock(&(cf_sk->sk));
+
+		if (result == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			("%s: "
+			"wait_event_interruptible woken by a signal (2)",
+			__func__);
+			ret = -ERESTARTSYS;
+			goto open_error;
+		}
+
+		if (!STATE_IS_OPEN(cf_sk)) {
+			/* Lower layers said "no" */
+			CAIFLOG_TRACE
+			    ("[%s:%d]: CLOSED RECEIVED\n",
+			     __func__, __LINE__);
+			ret = -EPIPE;
+			goto open_error;
+		}
+
+		CAIFLOG_TRACE("[%s:%d]: CONNECT RECEIVED\n",
+			      __func__, __LINE__);
+	}
+open_success:
+	/* Open is ok */
+	cf_sk->file_mode |= mode;
+
+	CAIFLOG_TRACE("[%s:%d] Open - file mode = %x\n",
+		      __func__, __LINE__, cf_sk->file_mode);
+
+	CAIFLOG_TRACE("[%s:%d] CONNECTED \n", __func__, __LINE__);
+
+	release_sock(&cf_sk->sk);
+	CAIFLOG_EXIT("");
+	return 0;
+open_error:
+	release_sock(&cf_sk->sk);
+out:
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+static int caif_shutdown(struct socket *sock, int how)
+{
+	struct caifsock *cf_sk = NULL;
+	int result;
+	int tx_flow_state_was_on;
+	struct sock *sk = sock->sk;
+	int res = 0;
+
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	if (how != SHUT_RDWR)
+		return -EOPNOTSUPP; /* FIXME: ENOTSUP in userland for POSIX */
+
+	cf_sk = container_of(sk, struct caifsock, sk);
+	if (cf_sk == NULL) {
+		CAIFLOG_TRACE("[%s] COULD NOT FIND SOCKET\n", __func__);
+		return -EBADF;
+	}
+
+	/* I want to be alone on cf_sk (except status queue) */
+	lock_sock(&(cf_sk->sk));
+#ifdef CONFIG_DEBUG_FS
+	atomic_inc(&cf_sk->num_close);
+#endif
+
+	/* Is the socket open? */
+	if (!STATE_IS_OPEN(cf_sk)) {
+		CAIFLOG_TRACE("[%s:%d] socket not open (cf_sk=%p) \n",
+			      __func__, __LINE__, cf_sk);
+		release_sock(&cf_sk->sk);
+		return 0;
+	}
+
+	/* Is the socket waiting for link setup response? */
+	if (STATE_IS_PENDING(cf_sk)) {
+		CAIFLOG_TRACE("[%s:%d] Socket is open pending (cf_sk=%p) \n",
+				__func__, __LINE__, cf_sk);
+		release_sock(&cf_sk->sk);
+		/* What to return here? Seems that EBADF is the closest :-| */
+		return -EBADF;
+	}
+	/* IS_CLOSED have double meaning:
+	 * 1) Spontanous Remote Shutdown Request.
+	 * 2) Ack on a channel teardown(disconnect)
+	 * Must clear bit in case we previously received
+	 * remote shudown request.
+	 */
+
+	SET_STATE_CLOSED(cf_sk);
+	SET_PENDING_ON(cf_sk);
+	sock->state = SS_DISCONNECTING; /* FIXME: Update the sock->states */
+	tx_flow_state_was_on = TX_FLOW_IS_ON(cf_sk);
+	SET_TX_FLOW_OFF(cf_sk);
+	sock_hold(&cf_sk->sk);
+	result = caifdev_adapt_unregister(&cf_sk->layer);
+
+	if (result < 0) {
+		CAIFLOG_TRACE
+		("caif_shutdown: caifdev_adapt_unregister() failed\n");
+		SET_STATE_CLOSED(cf_sk);
+		SET_PENDING_OFF(cf_sk);
+		SET_TX_FLOW_OFF(cf_sk);
+		release_sock(&cf_sk->sk);
+		return -EIO;
+	}
+#ifdef CONFIG_DEBUG_FS
+	atomic_inc(&cf_sk->num_deinit);
+#endif
+
+	/* We don't wait for close response here. Close pending state will be
+	   cleared by flow control callback when response arrives. */
+
+	/* Empty the queue */
+	drain_queue(cf_sk);
+	SET_RX_FLOW_ON(cf_sk);
+	cf_sk->file_mode = 0;
+
+
+	release_sock(&cf_sk->sk);
+	return res;
+}
+static ssize_t caif_sock_no_sendpage(struct socket *sock,
+				     struct page *page,
+				     int offset, size_t size, int flags)
+{
+	return -EOPNOTSUPP;
+}
+
+/* This function is called as part of close. */
+static int caif_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct caifsock *cf_sk = NULL;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	caif_assert(sk != NULL);
+	cf_sk = container_of(sk, struct caifsock, sk);
+
+	caif_shutdown(sock, SHUT_RDWR);
+	lock_sock(&(cf_sk->sk));
+	/* NOTE: This is how the sock->sk structure is used all over the linux
+	 *       socket implementation. Since there is no locking protecting
+	 *       the sock->sk pointer, the linux socket implementation do not
+	 *       support multiple threads using the same socket descriptor,
+	 *       since if one of the threads close the socket, the other
+	 *       threads may end up accessing a pointer to NULL. See for
+	 *       instance sock_setsockopt in net/socket.c, it uses sock->sk
+	 *       without checking if its value is NULL. */
+	sock->sk = NULL;
+
+	/* Unlink the socket from the hunt name table. */
+
+
+	/* Trigger the pending attachs from and to the socket.  This needs to
+	 * be done before the socket starts to be released. */
+
+
+	/* Remove pending new link requests. */
+
+	/* Detach the socket from its process context by making it orphan. */
+	sock_orphan(sk);
+
+	/* Setting SHUTDOWN_MASK means that both send and receive are shutdown
+	 * for the socket. */
+	sk->sk_shutdown = SHUTDOWN_MASK;
+
+	/* Set the socket state to closed, the TCP_CLOSE macro is used when
+	 * closing any socket. */
+	sk->sk_state = TCP_CLOSE;
+
+	/* Flush out this sockets receive queue. */
+	drain_queue(cf_sk);
+
+	/* Finally release the socket. */
+	STATE_IS_PENDING_DESTROY(cf_sk);
+	release_sock(&cf_sk->sk);
+	sock_put(sk);
+
+	return 0;
+
+	/* The rest of the cleanup will be handled from the
+	 * caif_sock_destructor */
+}
+static int caif_sock_ioctl(struct socket *sock,
+		       unsigned int cmd,
+		       unsigned long arg)
+
+{
+	return caif_ioctl(cmd, arg);
+}
+
+static struct proto_ops caif_ops = {
+	.family = PF_CAIF,
+	.owner = THIS_MODULE,
+	.release = caif_release,
+	.bind = sock_no_bind,
+	.connect = caif_connect,
+	.socketpair = sock_no_socketpair,
+	.accept = sock_no_accept,
+	.getname = sock_no_getname,
+	.poll = caif_poll,
+	.ioctl = caif_sock_ioctl,
+	.listen = sock_no_listen,
+	.shutdown = caif_shutdown,
+	.setsockopt = setsockopt,
+	.getsockopt = getsockopt,
+	.sendmsg = caif_sendmsg,
+	.recvmsg = caif_recvmsg,
+	.mmap = sock_no_mmap,
+	.sendpage = caif_sock_no_sendpage,
+};
+
+/* This function is called when a socket is finally destructed. */
+static void caif_sock_destructor(struct sock *sk)
+{
+	struct caifsock *cf_sk = NULL;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+	cf_sk = container_of(sk, struct caifsock, sk);
+
+	/* Error checks. */
+	caif_assert(!atomic_read(&sk->sk_wmem_alloc));
+	caif_assert(sk_unhashed(sk));
+	caif_assert(!sk->sk_socket);
+
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		CAIFLOG_TRACE("Attempt to release alive caif socket: 0x%p", sk);
+		return;
+	}
+
+	lock_sock(&(cf_sk->sk));
+
+	if (STATE_IS_OPEN(cf_sk)) {
+		CAIFLOG_TRACE
+			("[%s:%d] socket is opened (cf_sk=%p)"
+				" file_mode = 0x%x\n", __func__, __LINE__,
+				cf_sk, cf_sk->file_mode);
+		release_sock(&cf_sk->sk);
+		return;
+	}
+
+	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
+	drain_queue(cf_sk);
+	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
+
+	cfglu_free(cf_sk->pktq);
+
+#ifdef CONFIG_DEBUG_FS
+	if (cf_sk->debugfs_device_dir != NULL)
+		debugfs_remove_recursive(cf_sk->debugfs_device_dir);
+#endif
+
+	release_sock(&cf_sk->sk);
+	CAIFLOG_WARN("caif_sock_destructor: Removing socket %s\n",
+		cf_sk->name);
+	/* Decrease the global caif socket counter. */
+	atomic_dec(&caif_nr_socks);
+	return;
+}
+
+
+
+static int caif_create(struct net *net, struct socket *sock, int protocol)
+{
+	struct sock *sk = NULL;
+	struct caifsock *cf_sk = NULL;
+	int result = 0;
+
+	static struct proto prot = {.name = "PF_CAIF",
+		.owner = THIS_MODULE,
+		.obj_size = sizeof(struct caifsock),
+	};
+	prot.slab = caif_sk_cachep;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	if (net != &init_net)
+		return -EAFNOSUPPORT;
+
+
+	if (protocol < 0 || protocol >= CAIFPROTO_MAX)
+		return -EPROTONOSUPPORT;
+
+	/* Set the socket state to unconnected.  The socket state is really
+	 * not used at all in the net/core or socket.c but the
+	 * initialization makes sure that sock->state is not uninitialized.
+	 * An CAIF socket is always unconnected, since it is connectionless.
+	 */
+	sock->state = SS_UNCONNECTED;
+
+	/* Allocate the CAIF sock structure from the socket cache.  Upon
+	 * success the struct sock data structure is zeroed and thus partially
+	 * initialized. The caif specific part of the data structure is left as
+	 * is to avoid clearing the spid instance number.
+	 */
+
+	sk = sk_alloc(net, PF_CAIF, GFP_KERNEL, &prot);
+
+	BUG_ON(sk == NULL);
+
+	cf_sk = container_of(sk, struct caifsock, sk);
+
+	/* Store the protocol */
+	sk->sk_protocol = (unsigned char) protocol;
+
+	CAIFLOG_TRACE("[%s:%d] cf_sk=%p \n", __func__, __LINE__, cf_sk);
+
+	spin_lock_init(&cf_sk->read_queue_len_lock);
+
+	/* Fill in some information concerning the misc socket. */
+	snprintf(cf_sk->name, sizeof(cf_sk->name), "cf_sk%d",
+		atomic_read(&caif_nr_socks));
+	snprintf(cf_sk->config.name, sizeof(cf_sk->config.name), "caifconf%d",
+		atomic_read(&caif_nr_socks));
+
+
+	/* The sock->type specifies the socket type to use. The CAIF socket is
+	 * a datagram in the sence that it is packet based. The reliability of
+	 * the CAIF socket is not a typical SOCK_DGRAM characteristic, but
+	 * SOCK_DGRAM is close enough. */
+	switch (sock->type) {
+	case SOCK_DGRAM:
+	case SOCK_SEQPACKET:
+		/* NOTE: After this line, caif_release() will be called for
+		 *       this socket if this caif_create fails. */
+		sock->ops = &caif_ops;
+		break;
+	default:
+		sk_free(sk);
+		return -ESOCKTNOSUPPORT;
+	}
+
+	/* Lock in order to try to stop someone from opening the socket
+	too early. The misc socket has its own lock. We cannot take our
+	lock until misc_register() is finished, because in open() the
+	locks are taken in this order (misc first and then cf_sk).
+	So anyone managing to open the device between the misc_register
+	and the mutex_lock will get a "device not found" error. Don't
+	think it can be avoided.
+		*/
+	lock_sock(&(cf_sk->sk));
+
+	/* Initialize the nozero default sock structure data. */
+	sock_init_data(sock, sk);
+
+	sk->sk_destruct = caif_sock_destructor;
+
+	sk->sk_sndbuf = caif_sockbuf_size;
+	sk->sk_rcvbuf = caif_sockbuf_size;
+
+	cf_sk->pktq = cfpktq_create();
+	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
+
+	if (!cf_sk->pktq) {
+		CAIFLOG_ERROR("caif_create: queue create failed.\n");
+		result = -ENOMEM;
+		release_sock(&cf_sk->sk);
+		goto err_failed;
+	}
+
+	cf_sk->layer.ctrlcmd = caif_sktflowctrl_cb;
+	SET_STATE_CLOSED(cf_sk);
+	SET_PENDING_OFF(cf_sk);
+	SET_TX_FLOW_OFF(cf_sk);
+	SET_RX_FLOW_ON(cf_sk);
+
+	/* Increase the number of sockets created. */
+	atomic_inc(&caif_nr_socks);
+
+#ifdef CONFIG_DEBUG_FS
+	if (debugfsdir != NULL) {
+		cf_sk->debugfs_device_dir =
+		    debugfs_create_dir(cf_sk->name, debugfsdir);
+		debugfs_create_u32("conn_state", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir, &cf_sk->conn_state);
+		debugfs_create_u32("flow_state", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir, &cf_sk->flow_state);
+		debugfs_create_u32("num_open", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_open);
+		debugfs_create_u32("num_close", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_close);
+		debugfs_create_u32("num_init", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_init);
+		debugfs_create_u32("num_init_resp", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_init_resp);
+		debugfs_create_u32("num_init_fail_resp", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_init_fail_resp);
+		debugfs_create_u32("num_deinit", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_deinit);
+		debugfs_create_u32("num_deinit_resp", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_deinit_resp);
+		debugfs_create_u32("num_remote_shutdown_ind",
+				S_IRUSR | S_IWUSR, cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_remote_shutdown_ind);
+		debugfs_create_u32("num_tx_flow_off_ind", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_tx_flow_off_ind);
+		debugfs_create_u32("num_tx_flow_on_ind", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_tx_flow_on_ind);
+		debugfs_create_u32("num_rx_flow_off", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_rx_flow_off);
+		debugfs_create_u32("num_rx_flow_on", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->num_rx_flow_on);
+		debugfs_create_u32("read_queue_len", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &cf_sk->read_queue_len);
+		debugfs_create_u32("max_caif_sockets", S_IRUSR | S_IWUSR,
+				cf_sk->debugfs_device_dir,
+				(u32 *) &max_caif_sockets);
+	}
+#endif
+	CAIFLOG_EXIT("");
+	release_sock(&cf_sk->sk);
+	return 0;
+err_failed:
+	sk_free(sk);
+	CAIFLOG_EXIT("");
+	return result;
+}
+
+
+static struct net_proto_family caif_family_ops = {
+	.family = PF_CAIF,
+	.create = caif_create,
+	.owner = THIS_MODULE,
+};
+
+int af_caif_init(void)
+{
+	int err;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+#ifdef CAIF_USE_CACHE
+	caif_sk_cachep = kmem_cache_create_compat("caifsock",
+						  sizeof(struct caifsock) +
+						  (sizeof(uint32_t) *
+						   caif_max_links), 0,
+						  SLAB_HWCACHE_ALIGN, NULL,
+						  NULL);
+	if (!caif_sk_cachep) {
+		CAIFLOG_EXIT("");
+		return -ENOMEM;
+	}
+#endif
+	err = sock_register(&caif_family_ops);
+
+	if (err != 0) {
+#ifdef CAIF_USE_CACHE
+		kmem_cache_destroy(caif_sk_cachep);
+#endif
+		CAIFLOG_EXIT("");
+		return err;
+	}
+
+	return 0;
+}
+
+static int __init caif_sktinit_module(void)
+{
+	int stat;
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+	CAIFLOG_TRACE("\nCompiled:%s:%s\n", __DATE__, __TIME__);
+
+#ifdef CONFIG_DEBUG_FS
+	debugfsdir = debugfs_create_dir("chnl_skt", NULL);
+#endif
+
+	stat = af_caif_init();
+	if (stat) {
+		CAIFLOG_ERROR("Failed to initialize CAIF socket layer.");
+		return stat;
+	}
+	return 0;
+}
+
+static void __exit caif_sktexit_module(void)
+{
+	CAIFLOG_TRACE("Enter %s\n", __func__);
+
+	sock_unregister(PF_CAIF);
+
+	/* Destroy the CAIF socket cache. */
+#ifdef CAIF_USE_CACHE
+	kmem_cache_destroy(caif_sk_cachep);
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	if (debugfsdir != NULL)
+		debugfs_remove_recursive(debugfsdir);
+#endif
+
+	CAIFLOG_EXIT("");
+}
+
+module_init(caif_sktinit_module);
+module_exit(caif_sktexit_module);
+
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
new file mode 100644
index 0000000..fbc8a64
--- /dev/null
+++ b/net/caif/chnl_net.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/moduleparam.h>
+#include <linux/ip.h>
+#include <linux/sched.h>
+#include <linux/sockios.h>
+
+/* CAIF header files. */
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/caif_chr.h>
+#include <net/caif/caif_log.h>
+
+/*NetLink Header files*/
+#include <net/rtnetlink.h>
+#include <linux/caif/if_caif.h>
+
+#define CAIF_CONNECT_TIMEOUT 30
+#define SIZE_MTU 1500
+#define SIZE_MTU_MAX 4080
+#define SIZE_MTU_MIN 68
+
+static LIST_HEAD(chnl_net_list);
+static spinlock_t list_lock;
+
+MODULE_LICENSE("GPL");
+
+struct chnl_net {
+	struct layer chnl;
+	struct net_device_stats stats;
+	spinlock_t lock;
+	struct caif_channel_config config;
+	struct list_head list_field;
+	struct net_device *netdev;
+	char name[256];
+	wait_queue_head_t netmgmt_wq;
+	/* Flow status to remember and control the transmission. */
+	bool flowenabled;
+};
+
+
+static struct chnl_net *find_device(char *name, bool remove_from_list)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct chnl_net *dev = NULL;
+	struct chnl_net *tmp;
+	CAIFLOG_ENTER("");
+	spin_lock(&list_lock);
+	CAIFLOG_TRACE("[%s:%d] start looping \n", __func__,
+		__LINE__);
+	list_for_each_safe(list_node, n, &chnl_net_list) {
+		tmp =
+			list_entry(list_node, struct chnl_net, list_field);
+		/* Find from name. */
+		if (name) {
+			if (!strncmp(tmp->name, name, sizeof(tmp->name)))
+				dev = tmp;
+		} else
+			/* Get the first element if name is not specified. */
+			dev = tmp;
+		if (dev) {
+			CAIFLOG_TRACE("[%s:%d] match %s \n",
+				__func__, __LINE__,  name);
+			if (remove_from_list)
+				list_del(list_node);
+			break;
+		}
+	}
+	spin_unlock(&list_lock);
+	return dev;
+}
+
+static int chnl_recv_cb(struct layer *layr, struct cfpkt *pkt)
+{
+	struct sk_buff *skb;
+	struct caif_packet_funcs f;
+	struct chnl_net *priv  = NULL;
+	int pktlen;
+
+#ifdef CAIF_USE_SKB
+#else
+	int actual_len;
+#endif
+	int err = 0;
+
+	priv = container_of(layr, struct chnl_net, chnl);
+
+	if (!priv) {
+		CAIFLOG_TRACE("chnl_recv_cb: netdev container not found\n");
+		return -EINVAL;
+	}
+
+	/* Get CAIF packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	/* Get length of CAIF packet. */
+	pktlen = f.cfpkt_getlen(pkt);
+
+#ifdef CAIF_USE_SKB
+	skb = (struct sk_buff *) f.cfpkt_tonative(pkt);
+#else
+	skb = dev_alloc_skb(pktlen);
+
+	if (!skb) {
+		CAIFLOG_TRACE("chnl_recv_cb: dev_alloc_skb failed.\n");
+		/* Update statistics. */
+		priv->netdev->stats.rx_dropped++;
+		err = -ENOMEM;
+		goto err_alloc_skb;
+	}
+
+	/* Extract data from the caif packet and copy it to the SKB. */
+	f.cfpkt_extract(pkt, skb_put(skb, pktlen), pktlen, &actual_len);
+#endif
+	/* Pass some minimum information and
+	 * send the packet to the net stack.
+	 */
+	skb->dev = priv->netdev;
+	skb->protocol = htons(ETH_P_IP);
+
+	if (priv->config.type == CAIF_CHTY_DATAGRAM_LOOP) {
+		/* We change the header, so the checksum is corrupted. */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	} else {
+		skb->ip_summed = CHECKSUM_COMPLETE;
+	}
+
+	/* FIXME: Drivers should call this in tasklet context. */
+	if (in_interrupt())
+		netif_rx(skb);
+	else
+		netif_rx_ni(skb);
+
+	/* Update statistics. */
+	priv->netdev->stats.rx_packets++;
+	priv->netdev->stats.rx_bytes += pktlen;
+
+#ifdef CAIF_USE_SKB
+#else
+err_alloc_skb:
+	f.cfpkt_destroy(pkt);
+#endif
+	return err;
+}
+
+static void chnl_flowctrl_cb(struct layer *layr, enum caif_ctrlcmd flow,
+				int phyid)
+{
+	struct chnl_net *priv  = NULL;
+	CAIFLOG_TRACE("NET flowctrl func called flow: %s.\n",
+		flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
+		flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
+		flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
+		flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" :
+		flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" :
+		flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ?
+		 "REMOTE_SHUTDOWN" : "UKNOWN CTRL COMMAND");
+
+	priv = container_of(layr, struct chnl_net, chnl);
+
+	switch (flow) {
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+	case CAIF_CTRLCMD_DEINIT_RSP:
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		priv->flowenabled = false;
+		netif_tx_disable(priv->netdev);
+		wake_up_interruptible(&priv->netmgmt_wq);
+	break;
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+	case CAIF_CTRLCMD_INIT_RSP:
+		priv->flowenabled = true;
+		netif_wake_queue(priv->netdev);
+		wake_up_interruptible(&priv->netmgmt_wq);
+	break;
+	default:
+		break;
+	}
+}
+
+static int chnl_net_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct chnl_net *priv;
+	struct cfpkt *pkt = NULL;
+	int len;
+	struct caif_packet_funcs f;
+	int result = -1;
+
+	/* Get our private data. */
+	priv = (struct chnl_net *)netdev_priv(dev);
+	if (!priv) {
+		CAIFLOG_TRACE("chnl_write: priv not found\n");
+#ifndef CAIF_USE_SKB
+			goto err_cfpkt_create;
+#else
+			return -ENOSPC;
+#endif
+	}
+
+	if (skb->len > priv->netdev->mtu) {
+		CAIFLOG_TRACE("chnl_write ERR:"
+			" Size of skb packet exceeded size of set MTU\n");
+#ifndef CAIF_USE_SKB
+			goto err_cfpkt_create;
+#else
+			return -ENOSPC;
+#endif
+	}
+
+	if (!priv->flowenabled) {
+#ifndef CAIF_USE_SKB
+			dev_kfree_skb(skb);
+#endif
+		CAIFLOG_TRACE("Dropping packets Flow OFF\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	if (priv->config.type == CAIF_CHTY_DATAGRAM_LOOP) {
+		struct iphdr *hdr;
+		__be32 swap;
+		/* Retrieve IP header. */
+		hdr = ip_hdr(skb);
+		/* Change source and destination address. */
+		swap = hdr->saddr;
+		hdr->saddr = hdr->daddr;
+		hdr->daddr = swap;
+	}
+	/* Store original SKB length. */
+	len = skb->len;
+
+	/* Get CAIF packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+#ifdef CAIF_USE_SKB
+	pkt = f.cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
+#else
+	/* Create a CAIF packet based on the SKB. */
+	pkt = f.cfpkt_create_xmit_pkt(skb->data, skb->len);
+	if (!pkt) {
+		CAIFLOG_TRACE("chnl_write: cfpkt_create failed.\n");
+		goto err_cfpkt_create;
+	}
+#endif
+
+	/* Send the packet down the stack. */
+	result = priv->chnl.dn->transmit(priv->chnl.dn, NULL, pkt);
+	if (result) {
+		if (result == CFGLU_ERETRY)
+			result = NETDEV_TX_BUSY;
+
+#ifndef CAIF_USE_SKB
+		f.cfpkt_destroy(pkt);
+#endif
+		return result;
+	}
+
+	/* Update statistics. */
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += len;
+
+#ifndef CAIF_USE_SKB
+	dev_kfree_skb(skb);
+#endif
+	return NETDEV_TX_OK;
+
+#ifndef CAIF_USE_SKB
+err_cfpkt_create:
+	dev_kfree_skb(skb);
+	return -ENOSPC;
+#endif
+}
+
+
+static int chnl_net_open(struct net_device *dev)
+{
+	struct chnl_net *priv = NULL;
+	int result = -1;
+
+	CAIFLOG_ENTER("chnl_net_open:\n");
+	priv = (struct chnl_net *)netdev_priv(dev);
+	CAIFLOG_TRACE("chnl_net_open dev name: %s\n", priv->name);
+
+	if (!priv) {
+		CAIFLOG_TRACE("chnl_net_open: no priv\n");
+		return -ENODEV;
+	}
+	result = caifdev_adapt_register(&priv->config, &priv->chnl);
+	if (result != 0) {
+		CAIFLOG_TRACE("chnl_net_open: err: "
+			      "Unable to register and open device, Err:%d\n",
+			       result);
+		return -ENODEV;
+	}
+	result = wait_event_interruptible(priv->netmgmt_wq, priv->flowenabled);
+
+	if (result == -ERESTARTSYS) {
+		CAIFLOG_TRACE
+		   ("chnl_net_open: "
+		     "wait_event_interruptible woken by a signal\n");
+		return -ERESTARTSYS;
+	} else
+		CAIFLOG_TRACE("chnl_net_open: Flow on recieved\n");
+
+
+	CAIFLOG_EXIT("chnl_net_open:\n");
+	return 0;
+}
+
+static int chnl_net_stop(struct net_device *dev)
+{
+	struct chnl_net *priv;
+	int result = -1;
+	CAIFLOG_ENTER("chnl_net_stop:\n");
+	CAIFLOG_TRACE("chnl_net_stop: %s \n", dev->name);
+	priv = (struct chnl_net *)netdev_priv(dev);
+
+	result = caifdev_adapt_unregister(&priv->chnl);
+	if (result != 0) {
+		CAIFLOG_TRACE("chnl_net_stop: err: "
+			      "Unable to STOP device, Err:%d\n", result);
+		return -EBUSY;
+	}
+	result = wait_event_interruptible(priv->netmgmt_wq,
+					  !priv->flowenabled);
+
+	if (result == -ERESTARTSYS) {
+		CAIFLOG_TRACE
+		    ("chnl_net_stop: "
+		     "wait_event_interruptible woken by signal,"
+		     " signal_pending(current) = %d\n",
+		     signal_pending(current));
+	} else {
+		CAIFLOG_TRACE("[%s:%d] chnl_net_stop: DISCONNECT RECEIVED\n",
+			      __func__, __LINE__);
+	}
+
+	CAIFLOG_EXIT("chnl_net_stop:\n");
+	return 0;
+}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static const struct net_device_ops netdev_ops = {
+	.ndo_open = chnl_net_open,
+	.ndo_stop = chnl_net_stop,
+	.ndo_start_xmit = chnl_net_hard_start_xmit,
+};
+#endif
+
+static void chnl_net_init(struct net_device *dev)
+{
+	struct chnl_net *priv;
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28))
+	CAIFLOG_ENTER("chnl_net_init:\n");
+	dev->open = chnl_net_open;
+	dev->stop = chnl_net_stop;
+	dev->hard_start_xmit = chnl_net_hard_start_xmit;
+#else
+
+	CAIFLOG_ENTER("chnl_net_init:\n");
+	dev->netdev_ops = &netdev_ops;
+#endif
+	dev->flags |= IFF_NOARP;
+	dev->needed_headroom = CAIF_NEEDED_HEADROOM;
+	dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
+	dev->mtu = SIZE_MTU;
+
+	priv = (struct chnl_net *)netdev_priv(dev);
+	priv->chnl.receive = chnl_recv_cb;
+	priv->chnl.ctrlcmd = chnl_flowctrl_cb;
+	priv->netdev = dev;
+
+	strncpy(priv->config.name, dev->name, sizeof(priv->config.name));
+	priv->config.type = CAIF_CHTY_DATAGRAM;
+	priv->config.phy_pref = CFPHYPREF_HIGH_BW;
+	priv->config.priority = CAIF_PRIO_LOW;
+	priv->config.u.dgm.connection_id = -1; /* Insert illegal value */
+
+	priv->flowenabled = false;
+	init_waitqueue_head(&priv->netmgmt_wq);
+	strncpy(priv->name, dev->name, sizeof(priv->name));
+	netif_tx_disable(priv->netdev);
+
+	spin_lock_init(&priv->lock);
+	spin_lock(&list_lock);
+	list_add(&priv->list_field, &chnl_net_list);
+	spin_unlock(&list_lock);
+
+	CAIFLOG_EXIT("chnl_net_init:\n");
+}
+
+static int netdev_create(struct caif_channel_create_action *action)
+{
+	struct chnl_net *priv;
+	int result = -1;
+	struct net_device *netdevptr;
+
+	netdevptr = alloc_netdev(sizeof(struct chnl_net),
+				 action->name.name, chnl_net_init);
+
+	if (!netdevptr) {
+		CAIFLOG_TRACE("chnl: can't allocate netdev.\n");
+		return	-ENODEV;
+	}
+
+	priv = (struct chnl_net *)netdev_priv(netdevptr);
+	priv->config = action->config;
+
+	result = register_netdev(priv->netdev);
+	if (result < 0) {
+		CAIFLOG_TRACE("chnl: err: %d, can't register netdev.\n",
+			      result);
+		free_netdev(priv->netdev);
+		return	-ENODEV;
+	}
+	CAIFLOG_TRACE("netdev_create: Created channel: %s\n", priv->name);
+	/* Add the device to the list */
+	return 0;
+}
+
+static int delete_device(struct chnl_net *dev)
+{
+	CAIFLOG_TRACE("delete_device: Removing Device: %s\n", dev->name);
+	if (dev->netdev) {
+		unregister_netdev(dev->netdev);
+		free_netdev(dev->netdev);
+	}
+	return 0;
+}
+
+static int netdev_remove(char *name)
+{
+	struct chnl_net *dev = NULL;
+	/* Find device from name. */
+	dev = find_device(name, true);
+	if (!dev)
+		return -EBADF;
+	else
+		if (delete_device(dev) != 0)
+			return -EBUSY;
+	return 0;
+}
+
+static int netdev_mgmt(int action, union caif_action *param)
+{
+	switch (action) {
+	case CAIF_ACT_CREATE_DEVICE:
+		return netdev_create(&param->create_channel);
+	case CAIF_ACT_DELETE_DEVICE:
+		return netdev_remove(param->delete_channel.name);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct chnl_net *priv;
+	u8 loop;
+	priv = (struct chnl_net *)netdev_priv(dev);
+	NLA_PUT_U32(skb, IFLA_CAIF_IPV4_CONNID,
+		    priv->config.u.dgm.connection_id);
+	NLA_PUT_U32(skb, IFLA_CAIF_IPV6_CONNID,
+		    priv->config.u.dgm.connection_id);
+	loop = priv->config.type == CAIF_CHTY_DATAGRAM_LOOP;
+	NLA_PUT_U8(skb, IFLA_CAIF_LOOPBACK, loop);
+
+
+	return 0;
+nla_put_failure:
+	return -EMSGSIZE;
+
+}
+
+static void caif_netlink_parms(struct nlattr *data[],
+				struct caif_channel_config *parms)
+{
+	if (!data) {
+		caif_assert("caif_netlink_parms():No params data found\n");
+		return;
+	}
+	if (data[IFLA_CAIF_IPV4_CONNID])
+		parms->u.dgm.connection_id =
+			nla_get_u32(data[IFLA_CAIF_IPV4_CONNID]);
+	if (data[IFLA_CAIF_IPV6_CONNID])
+		parms->u.dgm.connection_id =
+			nla_get_u32(data[IFLA_CAIF_IPV6_CONNID]);
+	if (data[IFLA_CAIF_LOOPBACK]) {
+		if (nla_get_u8(data[IFLA_CAIF_LOOPBACK]))
+			parms->type = CAIF_CHTY_DATAGRAM_LOOP;
+		else
+			parms->type = CAIF_CHTY_DATAGRAM;
+	}
+}
+
+static int ipcaif_newlink(struct net_device *dev, struct nlattr *tb[],
+			struct nlattr *data[])
+{
+	int err;
+	struct chnl_net *caifdev;
+	caifdev = netdev_priv(dev);
+	caif_netlink_parms(data, &caifdev->config);
+	err = register_netdevice(dev);
+	if (err) {
+		caif_assert("ipcaif_newlink(): Device Reg. failed\n");
+		goto out;
+	}
+	dev_hold(dev);
+out:
+	return err;
+}
+
+static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
+				struct nlattr *data[])
+{
+	struct chnl_net *caifdev;
+	caifdev = netdev_priv(dev);
+	caif_netlink_parms(data, &caifdev->config);
+	netdev_state_change(dev);
+	return 0;
+}
+
+static void ipcaif_dellink(struct net_device *dev)
+{
+	unregister_netdevice(dev);
+	dev_put(dev);
+}
+
+static size_t ipcaif_get_size(const struct net_device *dev)
+{
+	return
+		/* IFLA_CAIF_IPV4_CONNID */
+		nla_total_size(4) +
+		/* IFLA_CAIF_IPV6_CONNID */
+		nla_total_size(4) +
+		/* IFLA_CAIF_LOOPBACK */
+		nla_total_size(2) +
+		0;
+}
+
+static const struct nla_policy caif_policy[IFLA_CAIF_MAX + 1] = {
+	[IFLA_CAIF_IPV4_CONNID]       = { .type = NLA_U32 },
+	[IFLA_CAIF_IPV6_CONNID]       = { .type = NLA_U32 },
+	[IFLA_CAIF_LOOPBACK]          = { .type = NLA_U8 }
+};
+
+
+static struct rtnl_link_ops ipcaif_link_ops __read_mostly = {
+	.kind           = "caif",
+	.priv_size      = (size_t)sizeof(struct chnl_net),
+	.setup          = chnl_net_init,
+	.maxtype        = IFLA_CAIF_MAX,
+	.policy         = caif_policy,
+	.newlink        = ipcaif_newlink,
+	.changelink	= ipcaif_changelink,
+	.dellink     	= ipcaif_dellink,
+	.get_size       = ipcaif_get_size,
+	.fill_info      = ipcaif_fill_info,
+
+};
+
+int chnl_net_ioctl(unsigned int cmd, unsigned long arg)
+{
+	struct chnl_net *priv;
+	int result = -1;
+	struct net_device *netdevptr;
+	int ret;
+	struct ifreq ifreq;
+	struct ifcaif_param param;
+	printk(KERN_INFO "Enter %s %d\n", __func__, cmd);
+
+	if (copy_from_user(&ifreq, (const void *)arg, sizeof(ifreq)))
+		return -EFAULT;
+
+	if (cmd != SIOCCAIFNETNEW)
+		return -ENOIOCTLCMD;
+
+	if (ifreq.ifr_ifru.ifru_data != NULL) {
+		ret = copy_from_user(&param,
+				   ifreq.ifr_ifru.ifru_data,
+				   sizeof(param));
+		if (ret)
+			return -EFAULT;
+		ifreq.ifr_ifru.ifru_data = &param;
+	}
+
+
+	CAIFLOG_TRACE("Allocte netdev: %s\n", ifreq.ifr_name);
+	netdevptr = alloc_netdev(sizeof(struct chnl_net),
+				 ifreq.ifr_name, chnl_net_init);
+
+	if (!netdevptr)
+		return	-ENODEV;
+
+	priv = (struct chnl_net *)netdev_priv(netdevptr);
+
+	priv->config.u.dgm.connection_id = param.ipv4_connid;
+	if (param.loop)
+		priv->config.type = CAIF_CHTY_DATAGRAM_LOOP;
+	else
+		priv->config.type = CAIF_CHTY_DATAGRAM;
+
+	result = register_netdev(priv->netdev);
+
+	if (result < 0) {
+		CAIFLOG_TRACE("chnl: err: %d, can't register netdev.\n",
+			      result);
+		free_netdev(priv->netdev);
+		return	-ENODEV;
+	}
+	CAIFLOG_TRACE("Created channel: %s\n", priv->name);
+	/* Add the device to the list */
+	return 0;
+
+};
+
+int chnl_init_module(void)
+{
+	int err = -1;
+	caif_register_netdev(netdev_mgmt);
+	caif_register_ioctl(chnl_net_ioctl);
+	err = rtnl_link_register(&ipcaif_link_ops);
+	if (err < 0) {
+		CAIFLOG_ENTER("chnl_init_module: rtnl_link_register failed\n");
+		rtnl_link_unregister(&ipcaif_link_ops);
+		return err;
+	}
+	return 0;
+}
+
+void chnl_exit_module(void)
+{
+	struct chnl_net *dev = NULL;
+
+	/* Find_device with NULL removes the first
+	 * element from the list and updates the list.
+	 */
+	while ((dev = find_device(NULL, true)) != NULL)
+		delete_device(dev);
+	caif_unregister_netdev();
+}
+
+module_init(chnl_init_module);
+module_exit(chnl_exit_module);
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  6/8] CAIF Protocol Stack
  2009-11-30 15:00         ` [RFC PATCH v3 5/8] " sjur.brandeland
@ 2009-11-30 15:00           ` sjur.brandeland
  2009-11-30 15:00             ` [RFC PATCH v3 7/8] " sjur.brandeland
  2009-11-30 16:41           ` [RFC PATCH v3 5/8] " Randy Dunlap
  1 sibling, 1 reply; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 drivers/net/caif/Kconfig       |   22 +++
 drivers/net/caif/Makefile      |   26 +++
 drivers/net/caif/caif_loop.c   |  235 +++++++++++++++++++++++
 drivers/net/caif/caif_serial.c |  406 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 689 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/caif/Kconfig
 create mode 100644 drivers/net/caif/Makefile
 create mode 100644 drivers/net/caif/caif_loop.c
 create mode 100644 drivers/net/caif/caif_serial.c

diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
new file mode 100644
index 0000000..adf6f7c
--- /dev/null
+++ b/drivers/net/caif/Kconfig
@@ -0,0 +1,22 @@
+#
+# CAIF physical drivers
+#
+
+if CAIF
+
+comment "CAIF transport drivers"
+
+config CAIF_TTY
+	tristate "CAIF TTY transport driver"
+	default n
+	---help---
+	The CAIF TTY transport driver.
+
+config CAIF_LOOPBACK
+	tristate "CAIF loopback test driver"
+	default n
+	---help---
+	Loopback test driver
+
+
+endif # CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
new file mode 100644
index 0000000..b712ccb
--- /dev/null
+++ b/drivers/net/caif/Makefile
@@ -0,0 +1,26 @@
+ifeq ($(CONFIG_CAIF_USE_PLAIN),1)
+CFPKT:=plain
+else
+CFPKT:=skbuff
+CAIF_FLAGS+=-DCAIF_USE_SKB
+endif
+
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_FLAGS+=-DCAIF_DEBUG_ON
+endif
+
+ifdef CAIF_DIR
+KBUILD_EXTRA_SYMBOLS=$(CAIF_DIR)/net/caif/Module.symvers
+endif
+
+ccflags-y :=  $(CAIF_FLAGS)
+
+clean-dirs:= .tmp_versions
+clean-files:= Module.symvers modules.order *.cmd *~ \
+
+# --- Physical drivers --
+# Serial interface
+obj-$(CONFIG_CAIF_TTY) += caif_serial.o
+
+# Loopback
+obj-$(CONFIG_CAIF_LOOPBACK) += caif_loop.o
diff --git a/drivers/net/caif/caif_loop.c b/drivers/net/caif/caif_loop.c
new file mode 100644
index 0000000..9606f0e
--- /dev/null
+++ b/drivers/net/caif/caif_loop.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland / sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/pkt_sched.h>
+#include <net/caif/caif_dev.h>
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+
+MODULE_LICENSE("GPL");
+
+struct caif_loop_dev {
+	struct caif_dev_common common;
+	struct net_device *dev;
+	int flow_on;
+	int queue_on;
+};
+#define CAIF_MAX_MTU 4096
+
+static ssize_t store_queue_on(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t len)
+{
+	unsigned long val;
+	struct net_device *netdev = to_net_dev(dev);
+	struct caif_loop_dev *loopdev = netdev_priv(netdev);
+	strict_strtoul(buf, 10, &val);
+	loopdev->queue_on = val;
+	if (loopdev && loopdev->common.flowctrl)
+		loopdev->common.flowctrl(netdev, (int)val);
+	else
+		printk(KERN_WARNING "caif_loop:flowctrl not set\n");
+	return len;
+}
+
+static ssize_t show_queue_on(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct caif_loop_dev *loopdev = netdev_priv(netdev);
+	return sprintf(buf, "%u\n", loopdev->queue_on);
+}
+
+static ssize_t store_flow_on(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf, size_t len)
+{
+	unsigned long val;
+	struct net_device *netdev = to_net_dev(dev);
+	struct caif_loop_dev *loopdev = netdev_priv(netdev);
+	strict_strtoul(buf, 10, &val);
+	loopdev->flow_on = val;
+	return len;
+}
+
+static ssize_t show_flow_on(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct caif_loop_dev *loopdev = netdev_priv(netdev);
+	return sprintf(buf, "%u\n", loopdev->flow_on);
+}
+
+static struct device_attribute attrs[] = {
+	__ATTR(flow_on, S_IRUGO | S_IWUSR, show_flow_on, store_flow_on),
+	__ATTR(queue_on, S_IRUGO | S_IWUSR, show_queue_on, store_queue_on),
+};
+
+static int sysfs_add(struct net_device *netdev)
+{
+	int i;
+	int err;
+	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+		err = device_create_file(&netdev->dev, &attrs[i]);
+		if (err)
+			goto fail;
+	}
+	return 0;
+
+ fail:
+	while (--i >= 0)
+		device_remove_file(&netdev->dev, &attrs[i]);
+	return err;
+}
+
+static void sysfs_rem(struct net_device *netdev)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(attrs); i++)
+		device_remove_file(&netdev->dev, &attrs[i]);
+}
+
+/*
+ * Send a SKB from net_device to the CAIF stack.
+ */
+static int caif_recv(struct net_device *dev, struct sk_buff *skb)
+{
+	int ret;
+	struct caif_loop_dev *caifd;
+	skb->protocol = htons(ETH_P_CAIF);
+	skb_reset_mac_header(skb);
+	skb->dev = dev;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
+	caifd = netdev_priv(dev);
+
+	if (caifd->flow_on > 0) {
+		--caifd->flow_on;
+		return NET_XMIT_DROP;
+	}
+	ret = netif_rx(skb);
+	if (ret == NET_RX_DROP)
+		return NET_XMIT_DROP;
+	return 0;
+}
+
+void debug_netdev(struct net_device *dev)
+{
+	struct netdev_queue *txq;
+	struct Qdisc *q;
+	txq = netdev_get_tx_queue(dev, 0);
+	q = rcu_dereference(txq->qdisc);
+	printk(KERN_INFO "txq:%p q:%p enqueue:%p - %s\n",
+	       txq, q, q ? q->enqueue : NULL, q->ops ? q->ops->id : "");
+}
+
+static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	return caif_recv(dev, skb);
+}
+
+static int caif_open(struct net_device *dev)
+{
+	struct caif_loop_dev *caifd;
+	netif_wake_queue(dev);
+	caifd = netdev_priv(dev);
+	caifd->flow_on = 0;
+	return 0;
+}
+
+static int caif_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static const struct net_device_ops netdev_ops = {
+	.ndo_open = caif_open,
+	.ndo_stop = caif_close,
+	.ndo_start_xmit = caif_xmit
+};
+#endif
+
+static void caifdev_setup(struct net_device *dev)
+{
+	struct caif_loop_dev *loopdev = netdev_priv(dev);
+	dev->features = 0;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28))
+	dev->open = caif_open;
+	dev->stop = caif_close;
+	dev->hard_start_xmit = caif_xmit;
+#else
+
+	dev->netdev_ops = &netdev_ops;
+#endif
+	dev->type = ARPHRD_CAIF;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu = CAIF_MAX_MTU;
+	dev->hard_header_len = CAIF_NEEDED_HEADROOM;
+	dev->tx_queue_len = 1;
+	dev->destructor = free_netdev;
+	loopdev->common.phy_type = CFPHYTYPE_SHM;
+	loopdev->common.phy_pref = CFPHYPREF_LOW_LAT;
+	loopdev->common.net_dev_module = THIS_MODULE;
+}
+
+int create_caif_phy_dev(char *ifname, struct net_device **dev)
+{
+	struct caif_loop_dev *caifd;
+	int err;
+	if (!dev)
+		return -1;
+	*dev = alloc_netdev(sizeof(*caifd), ifname, caifdev_setup);
+	if (!*dev)
+		return -ENOMEM;
+	caifd = netdev_priv(*dev);
+	caifd->flow_on = 1;
+	netif_stop_queue(*dev);
+	caifd->dev = *dev;
+	err = register_netdev(*dev);
+	sysfs_add(*dev);
+	if (err)
+		goto err;
+	return 0;
+ err:
+	printk(KERN_WARNING "Error in create_phy_loop\n");
+	free_netdev(*dev);
+	return err;
+}
+
+static void remove_caif_phy_dev(struct net_device *dev)
+{
+	sysfs_rem(dev);
+	rtnl_lock();
+	dev_close(dev);
+	/* device is freed automagically by net-sysfs */
+	unregister_netdevice(dev);
+	rtnl_unlock();
+}
+
+static struct net_device *caif_phy_dev_inst;
+static int __init phyif_loop_init(void)
+{
+	int result;
+	result = create_caif_phy_dev("loop%d", &caif_phy_dev_inst);
+	return result;
+}
+
+static void __exit phyif_loop_exit(void)
+{
+	remove_caif_phy_dev(caif_phy_dev_inst);
+}
+
+module_init(phyif_loop_init);
+module_exit(phyif_loop_exit);
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
new file mode 100644
index 0000000..bf55f6c
--- /dev/null
+++ b/drivers/net/caif/caif_serial.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2009
+ * Author:	Sjur Brendeland / sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/tty.h>
+#include <linux/file.h>
+#include <net/caif/caif_dev.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sjur Brendeland<sjur.brandeland@stericsson.com>");
+MODULE_DESCRIPTION("CAIF serial device TTY line discipline");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_CAIF);
+
+/* FIXME:Remove this when CAIF is included in tty.h */
+#ifndef N_CAIF
+#define N_CAIF N_MOUSE
+#endif
+
+#define CAIF_SENDING	1
+#define CAIF_UART_TX_COMPLETED	2
+#define CAIF_FLOW_OFF_SENT	4
+#define MAX_WRITE_CHUNK	      256
+#define ON 1
+#define OFF 0
+#define CAIF_MAX_MTU 4096
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27))
+#define tty_ldisc tty_ldisc_ops
+#endif
+
+
+
+struct net_device *device;
+char *ser_ttyname = "/dev/ttyS0";
+module_param(ser_ttyname, charp, S_IRUGO);
+MODULE_PARM_DESC(ser_ttyname, "TTY to open");
+
+int ser_loop;
+module_param(ser_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(ser_loop, "Run in simulated loopback mode.");
+
+int ser_use_stx;
+module_param(ser_use_stx, bool, S_IRUGO);
+MODULE_PARM_DESC(ser_use_stx, "STX enabled or not.");
+
+static int caif_net_open(struct net_device *dev);
+static int caif_net_close(struct net_device *dev);
+
+struct ser_device {
+	struct caif_dev_common common;
+	struct net_device *dev;
+	struct sk_buff_head head;
+	int xoff;
+	int queue_on;
+	struct tty_struct *tty;
+	int use_stx;
+	bool tx_started;
+	unsigned long state;
+	u8 buf[MAX_WRITE_CHUNK];
+	struct file *file;
+	char *tty_name;
+};
+
+static int ser_phy_tx(struct ser_device *ser, struct sk_buff *skb);
+static void caifdev_setup(struct net_device *dev);
+static void ser_tx_wakeup(struct tty_struct *tty);
+
+static void ser_receive(struct tty_struct *tty, const u8 *data,
+			char *flags, int count)
+{
+	struct sk_buff *skb = NULL;
+	struct ser_device *ser;
+	int ret;
+	ser = tty->disc_data;
+
+	/* Workaround for garbage at start of transmission,
+	 * only enable if STX handling is not enables */
+	if (!ser->use_stx && !ser->tx_started) {
+		printk(KERN_WARNING "Bytes received before first transmission."
+		       "Bytes discarded. \n");
+		return;
+	}
+
+	BUG_ON(ser->dev == NULL);
+
+	/* Get a suitable caif packet and copy in data. */
+	skb = netdev_alloc_skb(ser->dev, count+1);
+	BUG_ON(skb == NULL);
+	{
+	  u8 *p = skb_put(skb, count);
+	  memcpy(p, data, count);
+	}
+	skb->protocol = htons(ETH_P_CAIF);
+	skb_reset_mac_header(skb);
+	skb->dev = ser->dev;
+
+	/* Push received packet up the stack. */
+	ret = netif_rx(skb);
+}
+
+static int handle_tx(struct ser_device *ser)
+{
+	struct tty_struct *tty;
+	struct sk_buff *skb;
+	char *buf;
+	int tty_wr, len, room, pktlen;
+	tty = ser->tty;
+
+	/* NOTE: This workaround is not really needed when STX is enabled.
+	 *  Remove? */
+	if (ser->tx_started == false)
+		ser->tx_started = true;
+
+	if (test_and_set_bit(CAIF_SENDING, &ser->state)) {
+		set_bit(CAIF_UART_TX_COMPLETED, &ser->state);
+		return 0;
+	}
+
+	do {
+		skb = skb_peek(&ser->head);
+		if (skb != NULL && skb->len == 0) {
+			struct sk_buff *tmp;
+			tmp = skb_dequeue(&ser->head);
+			BUG_ON(tmp != skb);
+			kfree_skb(skb);
+			skb = skb_peek(&ser->head);
+		}
+
+		if (skb ==  NULL) {
+			if (test_and_clear_bit(
+				    CAIF_FLOW_OFF_SENT,
+				    &ser->state)) {
+				if (ser->common.flowctrl != NULL)
+					ser->common.flowctrl(ser->dev, ON);
+			}
+			break;
+		}
+
+
+		buf = skb->data;
+		pktlen = len = skb->len;
+
+		clear_bit(CAIF_UART_TX_COMPLETED, &ser->state);
+		room = tty_write_room(tty);
+		if (room > MAX_WRITE_CHUNK)
+			room = MAX_WRITE_CHUNK;
+
+		if (len > room)
+			len = room;
+
+		if (!ser_loop) {
+			tty_wr = tty->ops->write(tty, buf, len);
+		} else {
+			tty_wr = len;
+			ser_receive(tty, buf, 0, len);
+		}
+
+		if (tty_wr > 0)
+			skb_pull(skb, tty_wr);
+
+		if (ser_loop)
+			ser_tx_wakeup(tty);
+
+	} while (test_bit(CAIF_UART_TX_COMPLETED, &(ser->state)));
+
+	clear_bit(CAIF_SENDING, &ser->state);
+	return 0;
+}
+
+static int ser_phy_tx(struct ser_device *ser, struct sk_buff *skb)
+{
+	if (skb_peek(&ser->head) !=  NULL) {
+		if (!test_and_set_bit(CAIF_FLOW_OFF_SENT,
+					&ser->state)
+		    && ser->common.flowctrl != NULL) {
+			ser->common.flowctrl(ser->dev, OFF);
+		}
+	}
+	skb_queue_tail(&ser->head, skb);
+	if (!test_bit(CAIF_SENDING, &ser->state))
+		handle_tx(ser);
+	return 0;
+}
+
+static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ser_device *ser;
+	if (!dev)
+		return -EINVAL;
+	ser = netdev_priv(dev);
+	return ser_phy_tx(ser, skb);
+}
+
+
+static void ser_tx_wakeup(struct tty_struct *tty)
+{
+	struct ser_device *ser;
+	ser = tty->disc_data;
+	if (ser == NULL)
+		return;
+	set_bit(CAIF_UART_TX_COMPLETED, &ser->state);
+	if (ser->tty != tty)
+		return;
+	handle_tx(ser);
+}
+
+static void remove_caif_phy_dev(struct net_device *dev)
+{
+	/* Remove may be called inside or outside of rtnl_lock */
+	int islocked = rtnl_is_locked();
+	if (!islocked)
+		rtnl_lock();
+	dev_close(dev);
+	/* device is freed automagically by net-sysfs */
+	unregister_netdevice(dev);
+	if (!islocked)
+		rtnl_unlock();
+}
+
+static int ser_open(struct tty_struct *tty)
+{
+	struct ser_device *ser;
+	/* Use global device to map tty with ser */
+	ser = netdev_priv(device);
+	if (ser->file == NULL ||
+		tty != (struct tty_struct *)ser->file->private_data) {
+		printk(KERN_WARNING "Can not install ldisc from userspace!");
+		return -EINVAL;
+	}
+	tty->receive_room = 4096;
+	ser->tty = tty;
+	tty->disc_data = ser;
+	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+	return 0;
+}
+
+static void ser_close(struct tty_struct *tty)
+{
+	struct ser_device *ser;
+	ser = tty->disc_data;
+	return ;
+}
+
+static int start_ldisc(struct ser_device *ser)
+{
+	struct file *f;
+	mm_segment_t oldfs;
+	struct termios tio;
+	int ldiscnr = N_CAIF;
+	f = filp_open(ser->tty_name, 0, 0);
+	if (f == NULL ||
+		f->f_op == NULL ||
+		f->f_op->unlocked_ioctl == NULL) {
+		return -EINVAL;
+	}
+	ser->file = f;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+
+
+	f->f_op->unlocked_ioctl(f, TCFLSH, 0x2);
+	memset(&tio, 0, sizeof(tio));
+	tio.c_cflag = B115200 | CRTSCTS | CS8 | CLOCAL | CREAD;
+	f->f_op->unlocked_ioctl(f, TCSETS, (long unsigned int)&tio);
+	f->f_op->unlocked_ioctl(f, TIOCSETD, (long unsigned int)&ldiscnr);
+	set_fs(oldfs);
+
+	return 0;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc_ops caif_ldisc = {
+	.owner =        THIS_MODULE,
+	.magic =        TTY_LDISC_MAGIC,
+	.name =         "n_caif",
+	.open =         ser_open,
+	.close =        ser_close,
+	.receive_buf =  ser_receive,
+	.write_wakeup = ser_tx_wakeup
+};
+
+
+static int register_ldisc(struct ser_device *ser)
+{
+	int result;
+	result = tty_register_ldisc(N_CAIF, &caif_ldisc);
+
+	if (result < 0) {
+		printk(KERN_WARNING "caif_ser: err: %d,"
+			 "can't register ldisc.\n", result);
+		return result;
+	}
+	return result;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static const struct net_device_ops netdev_ops = {
+	.ndo_open = caif_net_open,
+	.ndo_stop = caif_net_close,
+	.ndo_start_xmit = caif_xmit
+};
+#endif
+
+static void caifdev_setup(struct net_device *dev)
+{
+	struct ser_device *serdev = netdev_priv(dev);
+	dev->features = 0;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28))
+
+	dev->open = caif_net_open;
+	dev->stop = caif_net_close;
+	dev->hard_start_xmit = caif_xmit;
+#else
+	dev->netdev_ops = &netdev_ops;
+#endif
+	dev->type = ARPHRD_CAIF;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu = CAIF_MAX_MTU;
+	dev->hard_header_len = CAIF_NEEDED_HEADROOM;
+	dev->tx_queue_len = 0;
+	dev->destructor = free_netdev;
+	skb_queue_head_init(&serdev->head);
+	serdev->common.phy_type = CFPHYTYPE_SERIAL;
+	serdev->common.phy_pref = CFPHYPREF_LOW_LAT;
+	serdev->common.net_dev_module = THIS_MODULE;
+	serdev->use_stx = ser_use_stx;
+	serdev->xoff = 0;
+	serdev->dev = dev;
+}
+
+static int caif_net_open(struct net_device *dev)
+{
+	struct ser_device *ser;
+	ser = netdev_priv(dev);
+	register_ldisc(ser);
+	start_ldisc(ser);
+	netif_wake_queue(dev);
+	ser->xoff = 0;
+	return 0;
+}
+
+static int caif_net_close(struct net_device *dev)
+{
+	struct ser_device *ser = netdev_priv(dev);
+	netif_stop_queue(dev);
+	/* Close the file handle */
+	if (ser->file)
+		fput(ser->file);
+	return tty_unregister_ldisc(N_CAIF);
+}
+
+static int register_setenv(char *ttyname,
+			   struct net_device **device)
+{
+	struct net_device *dev;
+	struct ser_device *ser;
+	int result;
+	printk(KERN_WARNING "caif_serial:ttyname=%s\n", ttyname);
+	dev = alloc_netdev(sizeof(*ser), "caifser%d", caifdev_setup);
+	if (!dev)
+		return -ENODEV;
+	ser = netdev_priv(dev);
+	ser->tty_name = ttyname;
+	netif_stop_queue(dev);
+	ser->dev = dev;
+
+	*device = dev;
+	result = register_netdev(dev);
+	if (result) {
+		free_netdev(dev);
+		*device = 0;
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int __init caif_ser_init(void)
+{
+	return register_setenv(ser_ttyname, &device);
+
+}
+
+static void __exit caif_ser_exit(void)
+{
+	remove_caif_phy_dev(device);
+}
+
+module_init(caif_ser_init);
+module_exit(caif_ser_exit);
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  7/8] CAIF Protocol Stack
  2009-11-30 15:00           ` [RFC PATCH v3 6/8] " sjur.brandeland
@ 2009-11-30 15:00             ` sjur.brandeland
  2009-11-30 15:00               ` [RFC PATCH v3 8/8] " sjur.brandeland
  2009-12-15 17:12               ` [RFC PATCH v3 7/8] " stefano babic
  0 siblings, 2 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 Documentation/CAIF/Linux-CAIF.txt    |  263 +++++++++++++++++++++++
 Documentation/CAIF/README            |   33 +++
 Documentation/CAIF/caif.man          |  387 ++++++++++++++++++++++++++++++++++
 Documentation/CAIF/caifioc/caifioc.c |   45 ++++
 4 files changed, 728 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/CAIF/Linux-CAIF.txt
 create mode 100644 Documentation/CAIF/README
 create mode 100644 Documentation/CAIF/caif.man
 create mode 100644 Documentation/CAIF/caifioc/caifioc.c

diff --git a/Documentation/CAIF/Linux-CAIF.txt b/Documentation/CAIF/Linux-CAIF.txt
new file mode 100644
index 0000000..91c058f
--- /dev/null
+++ b/Documentation/CAIF/Linux-CAIF.txt
@@ -0,0 +1,263 @@
+Linux CAIF
+===========
+
+Introduction
+------------
+CAIF is a MUX protocol used by ST-Ericsson cellular modems for
+communication
+between Modem and host. The host processes can open virtual AT
+channels, initiate GPRS Data connections, Video channels and
+Utility Channels.
+The Utility Channels are general purpose pipes between modem
+and host.
+
+ST-Ericsson modems support a number of transports between modem
+and host. Currently, UART and Loopback are available for Linux.
+
+
+Architecture:
+------------
+The implementation of CAIF is divided into:
+* CAIF Socket Layer, Kernel API, and  Net Device.
+* CAIF Generic Protocol Implementation
+* CAIF Link Layer, implemented as NET devices.
+
+
+  RTNL/IOCTL
+   !
+   !	 +------+   +------+   +------+
+   !	+------+!  +------+!  +------+!
+   !	! Sock !!  !Kernel!!  ! Net  !!
+   !	! API  !+  ! API  !+  ! Dev  !+	  <- CAIF Client APIs
+   !	+------+   +------!   +------+
+   !	   !	      !		 !
+   !	   +----------!----------+
+   !		   +------+		  <- CAIF Protocol Implementation
+   +------->	   ! CAIF !
+		   +------+
+	     +--------!--------+
+	     !		       !
+	  +------+	    +-----+
+	  !Loop	 !	    ! TTY !	  <- Link Layer (Net Devices)
+	  +------+	    +-----+
+
+
+Using CAIF (IP) Net Device
+----------------------
+CAIF Net device can be created by use of Socket IOCTLs,
+or RT Netlink.
+
+  static struct ifcaif_param param = {
+    .ipv4_connid = 1,
+    .loop = 0
+  };
+  static struct ifreq ifr = {
+    .ifr_name = "caif%d",
+    .ifr_ifru.ifru_data = &param
+
+  };
+  s = socket(AF_CAIF,SOCK_SEQPACKET,CAIFPROTO_AT);
+  ioctl(s,SIOCCAIFNETNEW,&ifr);
+
+
+Using the Kernel API
+----------------------
+The Kernel API is used for accessing CAIF channels from the
+kernel.
+The user of the API has to implement two callbacks for receive
+and control.
+The receive callback gives a CAIF packet as a SKB. The control
+callback will
+notify of channel initialization complete, and flow-on/flow-
+off.
+
+
+  struct caif_device caif_dev = {
+    .caif_config = {
+     .name = "MYDEV"
+     .type = CAIF_CHTY_AT
+    }
+   .receive_cb = my_receive,
+   .control_cb = my_control,
+  };
+  caif_add_device(&caif_dev);
+  caif_transmit(&caif_dev, skb);
+
+See the caif_kernel.h for details about the CAIF kernel API.
+
+
+I M P L E M E N T A T I O N
+===========================
+===========================
+
+GenCAIF - The Generic CAIF Protocol Layer
+=========================================
+
+GenCaif is a generic CAIF protocol implementation. It implements the CAIF
+protocol as defined by ST-Ericsson.
+GenCaif implements the CAIF protocol stack in a layered approach, where
+each layer described in the specification is implemented as a separate layer.
+The architecture is inspired by the design patterns "Protocol Layer" and
+"Protocol Packet".
+
+== CAIF structure ==
+
+The goal is to have CAIF as system independent as possible.
+All CAIF code (GenCAIF) can be found under net/caif/generic and
+include/net/caif/generic.
+The actual linux module implementation is under drivers/net/caif.
+There is also a user space program (that is not up to date) to run the stack in
+user space for testing.
+
+GenCAIF is:
+      -	Simple implementation of CAIF.
+      -	Layered architecture (a la Streams), each layer in the CAIF
+	specification is implemented in a separate c-file.
+      -	Client of GenCaif must implement PHY layer to access physical HW
+	with receive and transmit functions.
+      -	Client of GenCaif must call configuration function to add PHY layer.
+      -	Client of GenCaif must implement adaptation layer to consume/produce
+	CAIF payload with receive and transmit functions.
+      -	Client of GenCaif  must call configuration function to add adaptation
+	layer.
+      - When receiving / transmitting CAIF Packets (cfpkt), ownership is passed
+	to the called function (except for framing layers' receive functions
+	or if a transmit function returns an error, in which case the caller
+	must free the packet).
+
+Layered Architecture
+--------------------
+The CAIF protocol can be divided into two parts: Support functions and Protocol
+Implementation. The support functions include:
+
+      - CFPKT CAIF Packet. Implementation of CAIF Protocol Packet. The
+	CAIF Packet has functions for creating, destroying and adding content
+	and for adding/extracting header and trailers to protocol packets.
+
+      - CFLST CAIF list implementation.
+
+      - CFGLUE CAIF Glue. Contains OS Specifics, such as memory
+	allocation, endianness, etc.
+
+The CAIF Protocol implementation contains:
+
+      - CFCNFG CAIF Configuration layer. Configures the CAIF Protocol
+	Stack and has a Client interface for adding Link-Layer and
+	Driver interfaces on top of the CAIF Stack.
+
+      - CFCTRL CAIF Control layer. Encodes and Decodes control messages
+	such as enumeration and channel setup. Also matches request and
+	response messages.
+
+      - CFSERVL General CAIF Service Layer functionality; handles flow
+	control and remote shutdown requests.
+
+      - CFVEI CAIF VEI layer. Handles CAIF VEI layer (AT-Channel),
+	encodes/decodes VEI frames.
+
+      - CFDGML CAIF Data-gram layer. Handles CAIF Data-gram layer(IP
+	traffic), encodes/decodes Datagram frames.
+
+      - CFMUX CAIF Mux layer. Handles multiplexing between multiple
+	physical bearers and multiple channels such as VEI, Datagram, etc.
+	The MUX keeps track of the existing CAIF Channels and
+	Physical Instances and selects the apropriate instance based
+	on Channel-Id and Physical-ID.
+
+      - CFFRML CAIF Framing layer. Handles Framing i.e. Frame length
+	and frame checksum.
+
+      - CFSERL CAIF Serial layer. Handles concatenation/split of frames
+	into CAIF Frames with correct length.
+
+
+
+		    +---------+
+		    | Config  |
+		    | CFCNFG  |
+		    +---------+
+			 !
+    +---------+	    +---------+	    +---------+
+    |	AT    |	    | Control |	    | Datagram|
+    | CFVEIL  |	    | CFCTRL  |	    | CFDGML  |
+    +---------+	    +---------+	    +---------+
+	   \_____________!______________/
+			 !
+		    +---------+
+		    |	MUX   |
+		    |	      |
+		    +---------+
+		    _____!_____
+		   /	       \
+	    +---------+	    +---------+
+	    | CFFRML  |	    | CFFRML  |
+	    | Framing |	    | Framing |
+	    +---------+	    +---------+
+		 !		!
+	    +---------+	    +---------+
+	    | Loopback|	    | Serial  |
+	    |         |	    | CFSERL  |
+	    +---------+	    +---------+
+
+
+In this layered approach the following "rules" applies.
+      - All layers embedd the same structure "struct layer"
+      - A layer does not depend on any other layer's private data.
+      - Layers are stacked by setting the pointers
+		  layer->up , layer->dn
+      -	In order to send data upwards, each layer should do
+		 layer->up->receive(layer->up, packet);
+      - In order to send data downwards, each layer should do
+		 layer->dn->transmit(layer->dn, packet);
+
+
+Linux Driver Implementation
+===========================
+
+Linux GPRS Net Device and Character Devices are implemented on top of the
+Generic CAIF protocol. The Net device and Chr device have an instance of
+'struct layer', just like the generic caif protocol stack.
+Net and Chr devices implement the 'receive()' function defined by
+'struct layer', just like the rest of the CAIF stack. In this way, transmit and
+receive of packets is handled as by the rest of the layers: the 'dn->transmit()'
+function is called in order to transmit data.
+
+The layer on top of the Generic CAIF is called an "adaptation layer".
+
+
+Configuration of Drivers
+------------------------
+
+Configuration is the most complex part of the CAIF protocol.
+Configuration is controlled by the Misc device 'caifconfig'
+implemented in caif_chr. A device is created when a IOCTL
+command for creation is received that contains information about
+the CAIF Channel type to be created and the type of device to instantiate
+(Net Device or Character Device).
+
+The Net Device and Character Device will register with the 'caifconfig'
+device by calling 'caif_register_netdev' and 'caif_register_chrdev'.
+When registered, the 'caifconfig' module will keep function pointers
+to the devices used when IOCTL creates new devices.
+
+The CAIF Configuration module CFCNFG is responsible for connecting and
+setting up the entire CAIF stack.
+
+The function 'cfcnfg_add_adapt_layer' is used to connect a Linux Driver
+to the ST-Ericsson modem. This function will trigger the setup of a CAIF
+Channel by sending a "LinkSetup" message to the modem. When the
+"LinkSetupResponse" is received, the CAIF protocol for the requested
+CAIF Service will be set up.
+
+The CAIF Channel configuration parameters will be given as input.
+
+
+Configuration of Link Layer
+---------------------------
+The Link Layer is implemented as Linux net devices (struct net_device).
+Payload handling and registration is done using standard Linux mecanisms.
+
+The CAIF Protocol relies on a los-less link layer without implementing
+retransmission. This implies that packet drops must not happend.
+Therefor a flow-control mecanism is implemented where the physical
+interface can initiate flow stop for all CAIF Channels.
diff --git a/Documentation/CAIF/README b/Documentation/CAIF/README
new file mode 100644
index 0000000..ef1d51f
--- /dev/null
+++ b/Documentation/CAIF/README
@@ -0,0 +1,33 @@
+copyright (C) ST-Ericsson AB 2009
+Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+        Kim Lilliestierna Kim.xx.Lilliestierna@ericsson.com
+License terms: GNU General Public License (GPL) version 2
+
+=== Start ===
+Copy the .ko files onto the board, and do insmod:
+
+insmod caif.ko
+insmod caif_loop.ko
+insmod chnl_net.ko
+ifconfig caif0 <your-home-address> up
+
+
+=== Test Loopback on net device ===
+insmod chnl_net.ko loop=yes
+ifconfig caif0 192.168.0.1 up
+ping -c 10 -s 1000 192.168.0.2
+
+=== Preparing the setup.===
+
+Make sure that the kernel is built with module support.
+
+There are some things that need to be tweaked to get the host TTY
+correctly set up to talk to the modem.
+Since the CAIF stack is running in the kernel and we want to use the existing
+TTY, we are installing our physical serial driver as a line discipline above
+the TTY device. The TTY device used to communicate to modem must be specified
+as a module parameter to caif_ser.
+If the modem is using Start-of-frame-extension (STX) this must also be set as
+module parameter.
+
+$ insmod caif_ser.ko ser_ttyname=/dev/ttyS0 ser_use_stx=yes
diff --git a/Documentation/CAIF/caif.man b/Documentation/CAIF/caif.man
new file mode 100644
index 0000000..e411bde
--- /dev/null
+++ b/Documentation/CAIF/caif.man
@@ -0,0 +1,387 @@
+.TH  caif 7  "November, 2009" "version 0.1" "ST Ericsson"
+.SH NAME
+CAIF \- CAIF protocol family
+.SH SYNOPSIS
+.nf
+.B #include <sys/socket.h>
+.B #include <caif/caif_socket.h>
+.fi
+.SH DESCRIPTION
+CAIF socket implements the standard Linux networking
+.BR socket (7)
+mechanism for communicating with a ST-Ericsson modem using the CAIF protocol.
+
+The programming interface is BSD socket compatible.
+
+A CAIF socket is created by calling the
+.BR socket (2)
+function as
+.BR socket(PF_CAIF ,
+.IR socket_type ,
+.IB protocol ).
+
+Using
+.I socket_type
+.B SOCK_SEQPACKET
+will provide a reliable CAIF connection. The valid values for
+.I protocols
+are
+.B CAIFPROTO_AT, CAIFPROTO_DATAGRAM, CAIFPROTO_UTIL, CAIFPROTO_RFM.
+When a client wants to open a CAIF connection it must call
+.BR connect (2).
+CAIF socket supports
+.BR getsockopt (2),
+.BR setsockopt (2),
+.BR poll (2),
+.BR select (2),
+.BR ioctrl (2),
+.BR read (2),
+.BR write (2),
+.BR recv (2),
+.BR send (2),
+.BR recvmsg (2),
+.BR sendmsg (2).
+
+.SH LIMITATIONS
+.BR listen (2),
+.BR accept (2),
+.BR bind (2)
+are not supported because CAIF socket only can initiate connections,
+but not accept connections.
+
+The error code
+.B EMSGSIZE
+is returned by the functions
+.BR read (2),
+.BR recv (2),
+.BR recvmsg (2)
+if the provided buffer is too small to hold the received CAIF message.
+The length can be retrived by using socket option
+.BR CAIFSO_PACKET_LEN .
+
+.B EMSGSIZE
+is returned for
+.BR write (2),
+.BR send (2),
+.BR sendmsg (2)
+if trying to send a message larger than
+.BR CAIF_MAX_PACKET_SIZE .
+
+.SH OVERVIEW
+In order to use CAIF socket the function
+.BR socket (2)
+must be called initially.
+Then optionally socket operations
+can be set with
+.BR setsockopt (2),
+if no socket options are set default
+values will be used. Relevant options are
+.BR CAIFSO_CHANNEL_CONFIG,
+and for
+the utility protocol the socket option
+.BR CAIFSO_REQ_PARAM .
+
+The
+.BR connect (2)
+will send a CAIF channel connect request to the modem.
+In blocking mode connect will also wait for the response from the modem.
+The CAIF channel connect request is build based on the arguments to
+.BR socket (2),
+.BR setsockopt(2),
+and
+.BR connect (2).
+
+After a successfull connect, information about the CAIF Connection
+can be read by using getsockopt. Relevant options for getsockopt are
+.B CAIFSO_CONN_ID
+to read the unique CAIF channel ID.
+For a CAIF utility link
+.RB ( CAIFPROTO_UTIL )
+.B CAIFSO_RSP_PARAM
+can be used to read response parameters.
+
+After a successfull connect, CAIF packets can be sent with
+.BR send (2),
+.BR sendmsg (2),
+.BR recvmsg (2),
+and read with
+.BR read (2),
+.BR recv (2),
+.BR recvmsg (2).
+
+.SH ADDRESS FORMAT
+CAIF is a connection oriented protocol where the address is used to specify
+a modem service.
+.I family
+must always be set to
+.BR AF_CAIF .
+CAIF addressing is dependent of the protocol specified in the initial
+.BR socket (2)
+call. The union
+.I u
+is used according to this.
+
+.nf
+struct sockaddr_caif {
+	sa_family_t  family;
+	union {
+		struct {
+			u_int8_t type; 	/* type: enum caif_at_type */
+		}at;				/* CAIFPROTO_AT */
+		union {
+			u_int32_t connection_id;
+			u_int8_t  nsapi;
+		} dgm;				/* CAIFPROTO_DATAGRAM */
+		struct {
+			char service[16];
+		} util;				/* CAIFPROTO_UTIL */
+		struct {
+			u_int32_t connection_id;
+			char      volume[16];
+		} rfm;				/* CAIFPROTO_RFM */
+	} u;
+};
+.fi
+
+.SH PROTOCOL TYPES
+.TP
+.B CAIFPROTO_AT
+Specifies an AT channel type.
+.B caif_at_type
+enum value
+.B CAIF_ATTYPE_PLAIN (0)
+is the only enpoint type supported.
+
+.TP
+.B CAIFPROTO_RFM
+Specifies a RFM channel type.
+.I connection_id
+and
+.I volume[16]
+must be supplied.
+.TP
+.B CAIFPROTO_UTIL
+Specifies a utility channel type that will connect to a utility service.
+.I service[16]
+identifies the remote process implementing the service.
+.TP
+.B CAIFPROTO_DATAGRAM
+Specifies a datagram channel type.
+.I connection_id
+specifies the PDP context connection ID.
+.I nsapi
+is future functionality.
+.TP
+.B CAIFPROTO_DATAGRAM_LOOP
+Specifies a datagram loopback channel type (packet reflector).
+This only to be used for test purposes.
+
+.SH SOCKET OPTIONS
+CAIF supports some protocol specific socket options that can be set with
+.BR setsockopt (2)
+and read with
+.BR getsockopt (2).
+The
+.I level
+parameter to
+.BR setsockopt (2)
+or
+.BR getsockopt (2)
+must be one of the supported protocols defined by the
+.B CAIFPROTO_*
+enum.
+
+.TP
+.B CAIFSO_CHANNEL_CONFIG
+When connecting a CAIF socket, the address given in sockaddr_caif is not
+the only parameters in the
+actual CAIF connect message. It also contains priority on the connection
+and specification of which physical link to use for the connection.
+If this options is not set default values will be used for the connection.
+
+.nf
+struct caif_channel_opt {
+        u_int16_t  priority;
+        u_int16_t  link_selector;
+        char       link_name[16];
+};
+.fi
+The structure
+.B caif_channel_opt
+is used for the socket option
+.B CAIFSO_CHANNEL_CONFIG.
+When setting up a CAIF connection the socket option can be used to specify the
+priority and the physical link to use for the specific connection.
+.I priority
+is a number between 0 and 31 where 0 is the lowest priority of the channel.
+If
+.I link_name[16]
+is specified, the connection will use the specified physical link.
+Otherwise
+.I link_selector
+should be set to
+.B CAIF_LINK_LOW_LATENCY
+for low latency connections and
+.B CAIF_LINK_HIGH_BANDW
+for high bandwitdh connections.
+.TP
+.B CAIFSO_REQ_PARAM
+Connections of type
+.B CAIFPROTO_UTIL
+supply request parameters which optionally can be sent to the modem in
+the connect request.
+
+.nf
+struct caif_param {
+        u_int16_t size;
+        u_int8_t  data[256];
+};
+.fi
+.I size
+and
+.I data
+specifies the request parameter lenght and value.
+.TP
+.B CAIFSO_RSP_PARAM
+Connections of type
+.B CAIFPROTO_UTIL
+may supply response parameters in the connect response.
+The response is returned in struct
+.IR caif_param .
+.TP
+.B CAIFSO_CONN_ID
+Every open connection has a unique CAIF connection ID.
+This is assigned by the modem and is unique for every CAIF connection in the system.
+This socket option allows connection ID (u_int32_t) to be read after a successfull connect.
+.TP
+.B CAIFSO_PACKET_LEN
+The packet length can be read using the socket option
+.BR CAIFSO_PACKET_LEN .
+The type is u_int32_t.
+
+.SH ERROR CODES
+.TP
+.B [ENOTSUP]
+Generally used when using unsupported functionality in the CAIF socket layer.
+.TP
+.B [EINVAL]
+Invalid argument passed.
+.TP
+.B [EPIPE]
+Connection is closed.
+.TP
+.B [EAGAIN]
+Only valid for non-blocking sockets.
+Operation would either block or a receive timeout had been
+set and the timeout expired before any data were received.
+E.g. used for send operations when CAIF channel is in state FLOW-OFF.
+.TP
+.B [EMSGSIZE]
+Sending
+.RB ( write (2),
+.BR send (2),
+.BR sendmsg (2))
+fails with this error code if the message length is less than or equal to 0 or greater than maximum CAIF packet size.
+
+Receiving
+.RB ( read (2),
+.BR recv (2),
+.BR recvmsg (2))
+fails with this error code if the CAIF packet size is larger than the provided buffer.
+
+.TP
+.B [EBADF]
+ The argument socket is an invalid descriptor.
+.TP
+.B [EFAULT]
+ The receive buffer pointer(s) points outside the address space of the process.
+.TP
+.B [EINTR]
+ The receive was interrupted by delivery of a signal
+ before any data were available.
+.TP
+.B [ENOBUFS]
+The CAIF link layer cannot send packets due to full packet queues or
+flow stop. This may indicate that the link layer has stopped sending,
+but may be caused by transient congestion.
+.TP
+.B [ENOTCONN]
+ The CAIF socket is not connected (see
+.BR connect (2)).
+.TP
+.B [ENOTSOCK]
+ The argument socket does not refer to a socket.
+.TP
+.B [EOPNOTSUPP]
+ The type and/or protocol of the socket does not support the option(s) specified in the flags.
+.TP
+.B [ENOMEM]
+ Insufficient memory is available.
+
+
+.SH EXAMPLES (1)
+.nf
+  ...
+  struct sockaddr_caif addr = {
+    .family = AF_CAIF,
+    .u.at.type = CAIF_ATTYPE_PLAIN
+  };
+  /* Create a CAIF socket for AT Service */
+  s = socket(AF_CAIF, SOCK_SEQPACKET, CAIFPROTO_AT);
+
+  /* Connect to the AT Service at the modem */
+  connect(s, (struct sockaddr *) &addr, sizeof(addr));
+  ...
+.fi
+
+.SH EXAMPLES (2)
+
+.nf
+ struct sockaddr_caif addr = {
+    .family = AF_CAIF,
+    .u.util.service = "psock_test",
+  };
+  struct caif_channel_opt conf = {
+    .priority = 10,
+    .link_selector = CAIF_LINK_HIGH_BANDW,
+  };
+  struct caif_param rsp,req = {
+    .size = 1,
+    .data = {1}
+  };
+  u_int32_t connid;
+
+  /* Create a CAIF socket for Utility Service */
+  s = socket(PF_CAIF, SOCK_SEQPACKET, CAIFPROTO_UTIL);
+
+  /* Set the Channel Options */
+  setsockopt(s, SOL_CAIF, CAIFSO_CHANNEL, &conf, sizeof(conf));
+
+  /* Set the Request Parameters on the Utility Link */
+  setsockopt(s, SOL_CAIF, CAIFSO_REQ_PARAM, &req, sizeof(req));
+
+  /* Connect to the Utility Service */
+  connect(s, (struct sockaddr *) &addr, sizeof(addr));
+
+  /* Read out Parameter Responses and CAIF Connection ID */
+  len = sizeof(rsp);
+  getsockopt(s, SOL_CAIF, CAIFSO_RSP_PARAM, &rsp, &len);
+  len = sizeof(connid);
+  getsockopt(s, SOL_CAIF, CAIFSO_CONN_ID, &connid, &len);
+.fi
+.PP
+.SH AUTHOR
+Sjur Brandeland <sjur.brandeland@stericsson.com>
+.SH COPYRIGHT
+Copyright (C) ST-Ericsson AB 2009
+.SH SEE ALSO
+.BR socket (2),
+.BR connect (2),
+.BR setsockopt (2),
+.BR getsockopt (2),
+.BR read (2),
+.BR write (2),
+.BR recv (2),
+.BR recvmsg (2),
+.BR send (2),
+.BR sendmsg (2)
diff --git a/Documentation/CAIF/caifioc/caifioc.c b/Documentation/CAIF/caifioc/caifioc.c
new file mode 100644
index 0000000..5d6dbda
--- /dev/null
+++ b/Documentation/CAIF/caifioc/caifioc.c
@@ -0,0 +1,45 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/caif/caif_socket.h>
+#include <linux/caif/if_caif.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * Example program creating and configuring CAIF IP Interface
+ * by use of IOCTLs.
+ */
+main()
+{
+  int s;
+  int r;
+
+  /* Set CAIF IP Inteface config parameters */
+  static struct ifcaif_param param = {
+    .ipv4_connid = 1,
+    .loop = 1
+
+  };
+
+  /* Populate ifreq parameters */
+  static struct ifreq ifr = {
+    .ifr_name = "caifioc%d",
+    .ifr_ifru.ifru_data = (void *) &param
+
+  };
+
+  /* Create a CAIF socket */
+  s = socket(AF_CAIF, SOCK_SEQPACKET, CAIFPROTO_AT);
+
+  /* Create new IP Interface */
+  r = ioctl(s, SIOCCAIFNETNEW, &ifr);
+  printf("Result=%d\n", r);
+
+  /* General Interface IOC are available, e.g. find ifindex */
+  strcpy(ifr.ifr_name, "caifioc0");
+  r = ioctl(s, SIOCGIFINDEX, &ifr);
+
+  printf("res=%d, ifindex=%d\n", r, ifr.ifr_ifindex);
+}
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH v3  8/8] CAIF Protocol Stack
  2009-11-30 15:00             ` [RFC PATCH v3 7/8] " sjur.brandeland
@ 2009-11-30 15:00               ` sjur.brandeland
  2009-12-15 17:12               ` [RFC PATCH v3 7/8] " stefano babic
  1 sibling, 0 replies; 25+ messages in thread
From: sjur.brandeland @ 2009-11-30 15:00 UTC (permalink / raw)
  To: netdev, stefano.babic
  Cc: randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 drivers/net/Makefile |    1 +
 net/Kconfig          |    1 +
 net/Makefile         |    1 +
 3 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 246323d..17796f9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -285,3 +285,4 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
 
 obj-$(CONFIG_WIMAX) += wimax/
+obj-$(CONFIG_CAIF) += caif/
diff --git a/net/Kconfig b/net/Kconfig
index 041c35e..1c3890f 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -275,5 +275,6 @@ source "net/wimax/Kconfig"
 
 source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
+source "net/caif/Kconfig"
 
 endif   # if NET
diff --git a/net/Makefile b/net/Makefile
index 1542e72..a5eae27 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_NETLABEL)		+= netlabel/
 obj-$(CONFIG_IUCV)		+= iucv/
 obj-$(CONFIG_RFKILL)		+= rfkill/
 obj-$(CONFIG_NET_9P)		+= 9p/
+obj-$(CONFIG_CAIF)		+= caif/
 ifneq ($(CONFIG_DCB),)
 obj-y				+= dcb/
 endif
-- 
1.6.2.2.1669.g7eaf8


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3 0/8] CAIF Protocol Stack
  2009-11-30 15:00 [RFC PATCH v3 0/8] CAIF Protocol Stack sjur.brandeland
  2009-11-30 15:00 ` [RFC PATCH v3 1/8] " sjur.brandeland
@ 2009-11-30 16:08 ` Patrick McHardy
  2009-11-30 18:26   ` Sjur Brændeland
  2009-12-02 17:02 ` Stefano Babic
  2 siblings, 1 reply; 25+ messages in thread
From: Patrick McHardy @ 2009-11-30 16:08 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> Change Log:
> 
> General:
> * Sockets has replaced the character device implementation,
>   when accessing the modem. AT channels has to open sockets.
> * CAIF Link layer is now implemented as net-devices.
> * Cleanup of asserts no using caif_assert everywhere.
> * Style cleanups, spacing, typedefs etc.
> 
> Documentation/CAIF
> * Removed tool chardevconfig for configuration.
>   Instead  CAIF NET device can be configured with RTNL or socket IOCTL.
> * Removed replaced user space tool ldiscd to configure TTY.
>   TTY is now opened from kernel when loading caif_serial.ko
> * Added caif socket MAN page to Documentation (Will be moved later on).
> * Added example on CAIF NET device configuration.
> * Removed reference to  Doc No: 155 19-CRH 109 913.
> 
> include/linux
> * Added caif_socket.h defining CAIF Socket interface.
> * Added if_caif.h define CAIF IP Net Device configuration
> 
> include/net
> * Added caif_dev.h defining interface between driver and caif-core.
> 
> include/net/generic
> * Updated assert statement
> * Removed typedefs
> 
> net/caif
> * Added socket implementation and removed character device.
> * General removed typedefs and fixed CHECKPATCH warnings
> * Minor change on error handling in cfcnfg.c
> * chnl_net.c Added RTNL support and IOCTL
> * Fixed typos in Kconfig

Please add the changelog to the respective patches and give them
meaningful subjects. Its impossible to review patches if you
don't even know what they're supposed to do.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  5/8] CAIF Protocol Stack
  2009-11-30 15:00         ` [RFC PATCH v3 5/8] " sjur.brandeland
  2009-11-30 15:00           ` [RFC PATCH v3 6/8] " sjur.brandeland
@ 2009-11-30 16:41           ` Randy Dunlap
  2009-12-10 13:05             ` Sjur Brændeland
  1 sibling, 1 reply; 25+ messages in thread
From: Randy Dunlap @ 2009-11-30 16:41 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, stefano.babic, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>

what Patrick said:
patch description should be here and each email subject should be different
and describe what that patch does.
Please read Documentation/SubmittingPatches.

(more below)

> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
> ---
>  net/caif/Kconfig            |   51 ++
>  net/caif/Makefile           |   51 ++
>  net/caif/caif_chnlif.c      |  205 ++++++
>  net/caif/caif_config_util.c |  163 +++++
>  net/caif/caif_dev.c         |  520 ++++++++++++++
>  net/caif/caif_socket.c      | 1560 +++++++++++++++++++++++++++++++++++++++++++
>  net/caif/chnl_net.c         |  655 ++++++++++++++++++
>  7 files changed, 3205 insertions(+), 0 deletions(-)
>  create mode 100644 net/caif/Kconfig
>  create mode 100644 net/caif/Makefile
>  create mode 100644 net/caif/caif_chnlif.c
>  create mode 100644 net/caif/caif_config_util.c
>  create mode 100644 net/caif/caif_dev.c
>  create mode 100644 net/caif/caif_socket.c
>  create mode 100644 net/caif/chnl_net.c
> 
> diff --git a/net/caif/Kconfig b/net/caif/Kconfig
> new file mode 100644
> index 0000000..9349123
> --- /dev/null
> +++ b/net/caif/Kconfig
> @@ -0,0 +1,51 @@
> +#
> +# CAIF net configurations
> +#
> +
> +#menu "CAIF Support"
> +comment "CAIF Support"
> +
> +menuconfig CAIF
> +	tristate "Enable CAIF support"
> +	default n
> +	---help---

Tell us what CAIF means, probably in the help text.

> +	Say Y here if you need to use a phone modem that uses CAIF as transport.
> +	You will also need to say yes to any CAIF physical devices that your platform
> +	supports.
> +	This can be either built-in or a loadable module; if you select to build it as module
> +	then the rest of CAIF also needs to built as modules.
> +	See Documentation/CAIF for a further explanation on how to use and configure.
> +
> +if CAIF
> +
> +config CAIF_NETDEV
> +	tristate "CAIF Network device"
> +	default CAIF
> +	---help---
> +	Say Y if you will be using the CAIF based network device.

	                           a (or any) CAIF-based

> +	This can be either built-in or a loadable module.
> +	If you select to build it as a built-in then the main CAIF device must also be a built-in.
> +	If unsure say Y.
> +
> +config CAIF_SOCK
> +	tristate "CAIF Sockets"
> +	default CAIF
> +	---help---
> +	Say Y if you will be using the CAIF Sockets.

	drop "the" ----------------^^^

> +	This can be either built-in or a loadable module.
> +	If you select to build it as a built-in then the main CAIF device mist also be a built-in.

s/mist/must/

> +	If unsure say Y.
> +
> +config  CAIF_DEBUG
> +	bool "Enable Debug"
> +	default n
> +	--- help ---
> +	Enable the inclusion of debug code in the CAIF stack.
> +	Be aware that doing this will impact performance.
> +	If unsure say N.
> +
> +
> +# Include physical drivers
> +source "drivers/net/caif/Kconfig"
> +endif
> +#endmenu

> diff --git a/net/caif/caif_chnlif.c b/net/caif/caif_chnlif.c
> new file mode 100644
> index 0000000..9c8a656
> --- /dev/null
> +++ b/net/caif/caif_chnlif.c
> @@ -0,0 +1,205 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/skbuff.h>
> +#include <net/caif/caif_kernel.h>
> +#include <net/caif/generic/caif_layer.h>
> +#include <net/caif/caif_config_util.h>
> +#include <net/caif/caif_log.h>
> +#include <net/caif/generic/cfpkt.h>
> +#include <net/caif/generic/cfcnfg.h>
> +#include <net/caif/generic/cfglue.h>
> +#include <net/caif/caif_chr.h>
> +struct caif_kernelif {
> +	struct layer layer;
> +	struct caif_device *dev;
> +	struct cfctrl_link_param param;
> +};
> +
> +
> +/**
> + * func caif_create_skb - Creates a CAIF SKB buffer

Use documented/expected kernel-doc notation, please.  I.e., drop "func".

> + * @data:		data to add to buffer
> + * @data_length:	length of data
> + */
> +struct sk_buff *caif_create_skb(unsigned char *data, unsigned int data_length)
> +{
> +	/* NOTE: Make room for CAIF headers when using SKB inside CAIF. */
> +	struct sk_buff *skb =
> +	    alloc_skb(data_length + CAIF_SKB_HEAD_RESERVE +
> +		      CAIF_SKB_TAIL_RESERVE, GFP_ATOMIC);
> +	if (skb == NULL)
> +		return NULL;
> +	skb_reserve(skb, CAIF_SKB_HEAD_RESERVE);
> +
> +	memcpy(skb_put(skb, data_length), data, data_length);
> +	return skb;
> +}
> +EXPORT_SYMBOL(caif_create_skb);
> +
...

> +
> +module_init(caif_device_init);
> +module_exit(caif_device_exit);
> +
> +
> +
> +
> +
> +
> +
> +
> +

delete all of those trailing empty lines.

> diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
> new file mode 100644
> index 0000000..492fcfb
> --- /dev/null
> +++ b/net/caif/caif_socket.c
> @@ -0,0 +1,1560 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Sjur Brændeland sjur.brandlenad@stericsson.com
> + *              Per Sigmond / Per.Sigmond@stericsson.com
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +#include <linux/mutex.h>
> +#include <linux/list.h>
> +#include <linux/wait.h>
> +#include <linux/poll.h>
> +#include <linux/tcp.h>
> +#include <asm/uaccess.h>
> +#include <asm/atomic.h>
> +
> +/* Caif header files. */
> +#include <linux/caif/caif_socket.h>
> +#include <net/caif/generic/caif_layer.h>
> +#include <linux/caif/caif_config.h>
> +#include <net/caif/caif_log.h>
> +#include <net/caif/caif_chr.h>
> +
> +MODULE_LICENSE("GPL");
> +
> +#define CHNL_SKT_READ_QUEUE_HIGH 2000
> +#define CHNL_SKT_READ_QUEUE_LOW 100
> +
> +#ifdef CAIF_USE_CACHE
> +int caif_max_links = 32;
> +#endif
> +
> +int caif_sockbuf_size = 40000; /* FIXME: Check this value! */
> +static struct kmem_cache *caif_sk_cachep;
> +static atomic_t caif_nr_socks = ATOMIC_INIT(0);
> +
> +#define CONN_STATE_OPEN_BIT           1
> +#define CONN_STATE_PENDING_BIT        2
> +#define CONN_STATE_PEND_DESTROY_BIT   3
> +#define CONN_REMOTE_SHUTDOWN_BIT      4
> +
> +#define TX_FLOW_ON_BIT                1
> +#define RX_FLOW_ON_BIT                2
> +
> +#define STATE_IS_OPEN(cf_sk) test_bit(CONN_STATE_OPEN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define STATE_IS_REMOTE_SHUTDOWN(cf_sk) test_bit(CONN_REMOTE_SHUTDOWN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define STATE_IS_PENDING(cf_sk) test_bit(CONN_STATE_PENDING_BIT,\
> +				       (void *) &(cf_sk)->conn_state)
> +#define STATE_IS_PENDING_DESTROY(cf_sk) test_bit(CONN_STATE_PEND_DESTROY_BIT,\
> +				       (void *) &(cf_sk)->conn_state)
> +
> +#define SET_STATE_PENDING_DESTROY(cf_sk) set_bit(CONN_STATE_PEND_DESTROY_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define SET_STATE_OPEN(cf_sk) set_bit(CONN_STATE_OPEN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define SET_STATE_CLOSED(cf_sk) clear_bit(CONN_STATE_OPEN_BIT,\
> +					(void *) &(cf_sk)->conn_state)
> +#define SET_PENDING_ON(cf_sk) set_bit(CONN_STATE_PENDING_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +#define SET_PENDING_OFF(cf_sk) clear_bit(CONN_STATE_PENDING_BIT,\
> +				       (void *) &(cf_sk)->conn_state)
> +#define SET_REMOTE_SHUTDOWN(cf_sk) set_bit(CONN_REMOTE_SHUTDOWN_BIT,\
> +				    (void *) &(cf_sk)->conn_state)
> +
> +#define RX_FLOW_IS_ON(cf_sk) test_bit(RX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +#define TX_FLOW_IS_ON(cf_sk) test_bit(TX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +
> +#define SET_RX_FLOW_OFF(cf_sk) clear_bit(RX_FLOW_ON_BIT,\
> +				       (void *) &(cf_sk)->flow_state)
> +#define SET_RX_FLOW_ON(cf_sk) set_bit(RX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +#define SET_TX_FLOW_OFF(cf_sk) clear_bit(TX_FLOW_ON_BIT,\
> +				       (void *) &(cf_sk)->flow_state)
> +#define SET_TX_FLOW_ON(cf_sk) set_bit(TX_FLOW_ON_BIT,\
> +				    (void *) &(cf_sk)->flow_state)
> +
> +#define SKT_READ_FLAG 0x01
> +#define SKT_WRITE_FLAG 0x02
> +
> +#define MAX_CAIF_SOCKETS	200
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct dentry *debugfsdir;
> +#include <linux/debugfs.h>
> +
> +static int max_caif_sockets = MAX_CAIF_SOCKETS;
> +#endif
> +
> +/* The AF_CAIF socket */
> +struct caifsock {
> +	struct sock sk;		/* NOTE: sk has to be the first member */
> +	struct layer layer;
> +	char name[CAIF_LAYER_NAME_SZ];
> +	u32 conn_state;
> +	u32 flow_state;
> +	struct cfpktq *pktq;
> +	int file_mode;
> +	struct caif_channel_config config;
> +	int read_queue_len;
> +	spinlock_t read_queue_len_lock;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	struct dentry *debugfs_device_dir;
> +	atomic_t num_open;
> +	atomic_t num_close;
> +	atomic_t num_init;
> +	atomic_t num_init_resp;
> +	atomic_t num_init_fail_resp;
> +	atomic_t num_deinit;
> +	atomic_t num_deinit_resp;
> +	atomic_t num_remote_shutdown_ind;
> +	atomic_t num_tx_flow_off_ind;
> +	atomic_t num_tx_flow_on_ind;
> +	atomic_t num_rx_flow_off;
> +	atomic_t num_rx_flow_on;
> +#endif
> +};
> +
> +static void drain_queue(struct caifsock *cf_sk);
> +
> +/** Packet Receive Callback function called from CAIF Stack */

Do not use /** to begin comments that are not kernel-doc notation.
(more found below, but deleted for now)

> +static int caif_sktrecv_cb(struct layer *layr, struct cfpkt *pkt)
> +{

> +/* Send a signal as a consequence of sendmsg, sendto or caif_sendmsg. */
> +static int caif_sendmsg(struct kiocb *kiocb, struct socket *sock,
> +			struct msghdr *msg, size_t len)
> +{
> +
> +	struct sock *sk = sock->sk;
> +	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
> +	void *payload;
> +	size_t payload_size = msg->msg_iov->iov_len;
> +	struct cfpkt *pkt = NULL;
> +	struct transmt_info info;
> +	unsigned char *txbuf;
> +	int err = 0;
> +	ssize_t ret = -EIO;
> +	int result;
> +	struct sk_buff *skb;
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +	caif_assert(msg->msg_iovlen == 1);
> +
> +	if (cf_sk == NULL) {
> +		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
> +			      __func__, __LINE__);
> +		ret = -EBADFD;
> +		goto write_error_no_unlock;
> +	}
> +
> +	if (unlikely(msg->msg_iov->iov_base == NULL)) {
> +		CAIFLOG_WARN("Buffer is NULL.\n");
> +		ret = -EINVAL;
> +		goto write_error_no_unlock;
> +	}
> +
> +	payload = msg->msg_iov->iov_base;
> +	if (payload_size > CAIF_MAX_PAYLOAD_SIZE) {
> +		CAIFLOG_TRACE("[%s:%d] buffer too long\n", __func__, __LINE__);
> +		ret = -EINVAL;
> +		goto write_error_no_unlock;
> +	}
> +	/* I want to be alone on cf_sk (except status and queue) */
> +	lock_sock(&(cf_sk->sk));
> +
> +	caif_assert(cf_sk->pktq);
> +
> +	if (!STATE_IS_OPEN(cf_sk)) {
> +		/* Socket is closed or closing */
> +		if (!STATE_IS_PENDING(cf_sk)) {
> +			CAIFLOG_TRACE("socket is closed (by remote end)\n");
> +			ret = -EPIPE;
> +		} else {
> +			CAIFLOG_TRACE("socket is closing...\n");
> +			ret = -EBADF;
> +		}
> +		goto write_error;
> +	}
> +
> +	/* Socket is open or opening */
> +	if (STATE_IS_PENDING(cf_sk)) {
> +		CAIFLOG_TRACE("socket is opening...\n");
> +
> +		if (msg->msg_flags & MSG_DONTWAIT) {
> +			/* We can't block */
> +			CAIFLOG_TRACE("state pending and MSG_DONTWAIT\n");
> +			ret = -EAGAIN;
> +			goto write_error;
> +		}
> +
> +		/* Let readers in */
> +		release_sock(&cf_sk->sk);
> +
> +		/* Blocking mode; state is pending and we need to wait
> +		   for its conclusion */
> +		result =
> +		    wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +					     !STATE_IS_PENDING(cf_sk));
> +
> +		/* I want to be alone on cf_sk (except status and queue) */
> +		lock_sock(&(cf_sk->sk));
> +
> +		if (result == -ERESTARTSYS) {
> +			CAIFLOG_TRACE
> +			    (" wait_event_interruptible woken by a signal (1)");
> +			ret = -ERESTARTSYS;
> +			goto write_error;
> +		}
> +	}
> +
> +	if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
> +		CAIFLOG_TRACE("received remote_shutdown indication\n");
> +		ret = -ESHUTDOWN;
> +		goto write_error;
> +	}
> +
> +	if (!TX_FLOW_IS_ON(cf_sk)) {
> +
> +		/* Flow is off. Check non-block flag */
> +		if (msg->msg_flags & MSG_DONTWAIT) {
> +			CAIFLOG_TRACE
> +			("caif_sendmsg: MSG_DONTWAIT and tx flow off");
> +			ret = -EAGAIN;
> +			goto write_error;
> +		}
> +
> +		/* release lock before waiting */
> +		release_sock(&cf_sk->sk);
> +
> +		/* Wait until flow is on or socket is closed */
> +		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +					TX_FLOW_IS_ON(cf_sk)
> +					|| !STATE_IS_OPEN(cf_sk)
> +					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
> +					) == -ERESTARTSYS) {
> +			CAIFLOG_TRACE
> +				("caif_sendmsg:"
> +				" wait_event_interruptible woken by a signal");
> +			ret = -ERESTARTSYS;
> +			goto write_error_no_unlock;
> +		}
> +
> +		/* I want to be alone on cf_sk (except status and queue) */
> +		lock_sock(&(cf_sk->sk));
> +
> +		if (!STATE_IS_OPEN(cf_sk)) {
> +			/* someone closed the link, report error */
> +			CAIFLOG_TRACE("[%s:%d] remote end shutdown!\n",
> +				      __func__, __LINE__);
> +			ret = -EPIPE;
> +			goto write_error;
> +		}
> +
> +		if (STATE_IS_REMOTE_SHUTDOWN(cf_sk)) {
> +			CAIFLOG_TRACE("received remote_shutdown indication\n");
> +			ret = -ESHUTDOWN;
> +			goto write_error;
> +		}
> +	}
> +
> +	/* Create packet, buf=NULL means no copying */
> +	skb = caif_alloc_send_skb(sk,
> +				payload_size + CAIF_NEEDED_HEADROOM +
> +				CAIF_NEEDED_TAILROOM,
> +				&err);
> +	skb_reserve(skb, CAIF_NEEDED_HEADROOM);
> +	pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
> +	caif_assert((void *)pkt == (void *)skb);
> +
> +	if (pkt == NULL) {
> +		CAIFLOG_TRACE
> +			("caif_sendmsg: cfpkt_create_pkt returned NULL\n");
> +		ret = -EIO;
> +		goto write_error;
> +	}
> +
> +	if (!cfpkt_raw_append(pkt, (void **) &txbuf, payload_size)) {
> +		CAIFLOG_TRACE("caif_sendmsg: cfpkt_raw_append failed\n");
> +		cfpkt_destroy(pkt);
> +		ret = -EINVAL;
> +		goto write_error;
> +	}
> +
> +	/* Copy data into buffer. */
> +	if (copy_from_user(txbuf, payload, payload_size)) {
> +		CAIFLOG_TRACE
> +			("caif_sendmsg: copy_from_user returned non zero.\n");
> +		cfpkt_destroy(pkt);
> +		ret = -EINVAL;
> +		goto write_error;
> +	}
> +	memset(&info, 0, sizeof(info));
> +
> +	/* Send the packet down the stack. */
> +	caif_assert(cf_sk->layer.dn);
> +	caif_assert(cf_sk->layer.dn->transmit);
> +
> +	do {
> +			ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn,
> +							&info, pkt);

odd indentation?

> +		if (likely((ret >= 0) || (ret != -EAGAIN)))
> +			break;
> +
> +		/* EAGAIN - retry */
> +		if (msg->msg_flags & MSG_DONTWAIT) {
> +			CAIFLOG_TRACE
> +			    ("NONBLOCK and transmit failed, error = %d\n",
> +			     ret);
> +			ret = -EAGAIN;
> +			goto write_error;
> +		}
> +
> +		/* Let readers in */
> +		release_sock(&cf_sk->sk);
> +
> +		/* Wait until flow is on or socket is closed */
> +		if (wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +					TX_FLOW_IS_ON(cf_sk)
> +					|| !STATE_IS_OPEN(cf_sk)
> +					|| STATE_IS_REMOTE_SHUTDOWN(cf_sk)
> +					) == -ERESTARTSYS) {
> +			CAIFLOG_TRACE
> +			    ("wait_event_interruptible woken by a signal");
> +			ret = -ERESTARTSYS;
> +			goto write_error_no_unlock;
> +		}
> +
> +		/* I want to be alone on cf_sk (except status and queue) */
> +		lock_sock(&(cf_sk->sk));
> +
> +	} while (ret == -EAGAIN);
> +
> +	if (ret < 0) {
> +		cfpkt_destroy(pkt);
> +		CAIFLOG_TRACE("transmit failed, error = %d\n",
> +			      ret);
> +
> +		goto write_error;
> +	}
> +
> +	release_sock(&cf_sk->sk);
> +	CAIFLOG_EXIT("");
> +	return payload_size;
> +
> +write_error:
> +	release_sock(&cf_sk->sk);
> +write_error_no_unlock:
> +	CAIFLOG_EXIT("");
> +	return ret;
> +}
> +

> +
> +static int setsockopt(struct socket *sock,
> +			int lvl, int opt, char __user *ov, int ol)
> +{
> +	struct sock *sk = sock->sk;
> +	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
> +	struct caif_channel_opt confopt;
> +	int res;
> +
> +	if (lvl != SOL_CAIF) {
> +		CAIFLOG_TRACE("setsockopt bad level\n");
> +			return -ENOPROTOOPT;

odd indentation.

> +	}
> +
> +	switch (opt) {
> +	case CAIF_CHANNEL_OPT:
> +		if (ol < sizeof(struct caif_channel_opt)) {
> +			CAIFLOG_TRACE("setsockopt"
> +					" CAIF_CHANNEL_CONFIG bad size\n");
> +				return -EINVAL;

odd indentation.

> +		}
> +		res = copy_from_user(&confopt, ov, sizeof(confopt));
> +		if (res)
> +			return res;
> +		lock_sock(&(cf_sk->sk));
> +		cf_sk->config.priority = confopt.priority;
> +		cf_sk->config.phy_pref = confopt.link_selector;
> +		strncpy(cf_sk->config.phy_name, confopt.link_name,
> +			sizeof(cf_sk->config.phy_name));
> +		CAIFLOG_TRACE("Setting sockopt pri=%d pref=%d name=%s\n",
> +			      cf_sk->config.priority,
> +			      cf_sk->config.phy_pref,
> +			      cf_sk->config.phy_name);
> +		release_sock(&cf_sk->sk);
> +		return 0;
> +/* TODO: Implement the remaining options:
> + *	case CAIF_REQ_PARAM_OPT:
> + *	case CAIF_RSP_PARAM_OPT:
> + *	case CAIF_UTIL_FLOW_OPT:
> + *	case CAIF_CONN_INFO_OPT:
> + *	case CAIF_CONN_ID_OPT:
> + */
> +	default:
> +		CAIFLOG_TRACE("setsockopt: unhandled option %d\n",
> +			      opt);
> +		return -EINVAL;
> +	}
> +
> +
> +}

> +int caif_connect(struct socket *sock, struct sockaddr *uservaddr,
> +	       int sockaddr_len, int flags)
> +{
> +	struct caifsock *cf_sk = NULL;
> +	int result = -1;
> +	int mode = 0;
> +	int ret = -EIO;
> +    struct sock *sk = sock->sk;

indent above line with tab, not spaces.

> +
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +
> +	BUG_ON(sk == NULL);
> +
> +	cf_sk = container_of(sk, struct caifsock, sk);
> +
> +	CAIFLOG_TRACE("cf_sk=%p OPEN=%d, TX_FLOW=%d, RX_FLOW=%d\n", cf_sk,
> +		      STATE_IS_OPEN(cf_sk),
> +		      TX_FLOW_IS_ON(cf_sk), RX_FLOW_IS_ON(cf_sk));
> +
> +	sk->sk_state    = TCP_CLOSE;
> +	sock->state     = SS_UNCONNECTED;
> +
> +	/* FIXME: SOCK_DGRAM should be removed? */
> +	if (sock->type == SOCK_DGRAM || sock->type == SOCK_SEQPACKET) {
> +		sock->state     = SS_CONNECTED;
> +		sk->sk_state    = TCP_ESTABLISHED;
> +	} else
> +		goto out;
> +
> +	/* I want to be alone on cf_sk (except status and queue) */
> +	lock_sock(&(cf_sk->sk));
> +
> +	ret = caif_channel_config(cf_sk, uservaddr, sockaddr_len,
> +				&cf_sk->config);
> +	if (ret) {
> +		CAIFLOG_TRACE
> +		    ("[%s:%d] Cannot set socket address\n",
> +		     __func__, __LINE__);
> +		goto open_error;
> +	}
> +
> +
> +#ifdef CONFIG_DEBUG_FS
> +	atomic_inc(&cf_sk->num_open);
> +#endif
> +	mode = SKT_READ_FLAG | SKT_WRITE_FLAG;
> +
> +	/* If socket is not open, make sure socket is in fully closed state */
> +	if (!STATE_IS_OPEN(cf_sk)) {
> +		/* Has link close response been received
> +		   (if we ever sent it)? */
> +		if (STATE_IS_PENDING(cf_sk)) {
> +			/* Still waiting for close response from remote.
> +			   If opened non-blocking, report "would block" */
> +			if (flags & MSG_DONTWAIT) {
> +				CAIFLOG_TRACE("MSG_DONTWAIT"
> +					" && close pending\n");
> +				ret = -EAGAIN;
> +				goto open_error;
> +			}
> +
> +			CAIFLOG_TRACE
> +			    ("wait for close response from remote...\n");
> +
> +			release_sock(&cf_sk->sk);
> +
> +			/* Blocking mode; close is pending and we need to wait
> +			   for its conclusion */
> +			result =
> +			    wait_event_interruptible(*cf_sk->sk.sk_sleep,
> +						     !STATE_IS_PENDING(cf_sk));
> +
> +			lock_sock(&(cf_sk->sk));
> +			if (result == -ERESTARTSYS) {
> +				CAIFLOG_TRACE
> +				    ("wait_event_interruptible woken"
> +				     "by a signal (1)");
> +				ret = -ERESTARTSYS;
> +				goto open_error;
> +			}
> +		}
> +	}
...
> +}

> +
> +/* This function is called as part of close. */
> +static int caif_release(struct socket *sock)
> +{
> +	struct sock *sk = sock->sk;
> +	struct caifsock *cf_sk = NULL;
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +
> +	caif_assert(sk != NULL);
> +	cf_sk = container_of(sk, struct caifsock, sk);
> +
> +	caif_shutdown(sock, SHUT_RDWR);
> +	lock_sock(&(cf_sk->sk));
> +	/* NOTE: This is how the sock->sk structure is used all over the linux
> +	 *       socket implementation. Since there is no locking protecting
> +	 *       the sock->sk pointer, the linux socket implementation do not
> +	 *       support multiple threads using the same socket descriptor,
> +	 *       since if one of the threads close the socket, the other
> +	 *       threads may end up accessing a pointer to NULL. See for
> +	 *       instance sock_setsockopt in net/socket.c, it uses sock->sk
> +	 *       without checking if its value is NULL. */

	/*
	 * Note: This is the Linux long comment
	 * style.  Please use it.
	 */

> +	sock->sk = NULL;
> +
> +	/* Unlink the socket from the hunt name table. */
> +
> +
> +	/* Trigger the pending attachs from and to the socket.  This needs to
> +	 * be done before the socket starts to be released. */
> +
> +
> +	/* Remove pending new link requests. */
> +
> +	/* Detach the socket from its process context by making it orphan. */
> +	sock_orphan(sk);
> +
> +	/* Setting SHUTDOWN_MASK means that both send and receive are shutdown
> +	 * for the socket. */
> +	sk->sk_shutdown = SHUTDOWN_MASK;
> +
> +	/* Set the socket state to closed, the TCP_CLOSE macro is used when
> +	 * closing any socket. */
> +	sk->sk_state = TCP_CLOSE;
> +
> +	/* Flush out this sockets receive queue. */
> +	drain_queue(cf_sk);
> +
> +	/* Finally release the socket. */
> +	STATE_IS_PENDING_DESTROY(cf_sk);
> +	release_sock(&cf_sk->sk);
> +	sock_put(sk);
> +
> +	return 0;
> +
> +	/* The rest of the cleanup will be handled from the
> +	 * caif_sock_destructor */
> +}

> +/* This function is called when a socket is finally destructed. */

                                                       destroyed. */

> +static void caif_sock_destructor(struct sock *sk)
> +{
> +	struct caifsock *cf_sk = NULL;
> +	CAIFLOG_TRACE("Enter %s\n", __func__);
> +	cf_sk = container_of(sk, struct caifsock, sk);
> +
> +	/* Error checks. */
> +	caif_assert(!atomic_read(&sk->sk_wmem_alloc));
> +	caif_assert(sk_unhashed(sk));
> +	caif_assert(!sk->sk_socket);
> +
> +	if (!sock_flag(sk, SOCK_DEAD)) {
> +		CAIFLOG_TRACE("Attempt to release alive caif socket: 0x%p", sk);
> +		return;
> +	}
> +
> +	lock_sock(&(cf_sk->sk));
> +
> +	if (STATE_IS_OPEN(cf_sk)) {
> +		CAIFLOG_TRACE
> +			("[%s:%d] socket is opened (cf_sk=%p)"
> +				" file_mode = 0x%x\n", __func__, __LINE__,
> +				cf_sk, cf_sk->file_mode);
> +		release_sock(&cf_sk->sk);
> +		return;
> +	}
> +
> +	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
> +	drain_queue(cf_sk);
> +	CAIFLOG_TRACE("pktq = %p \n", cf_sk->pktq);
> +
> +	cfglu_free(cf_sk->pktq);
> +
> +#ifdef CONFIG_DEBUG_FS
> +	if (cf_sk->debugfs_device_dir != NULL)
> +		debugfs_remove_recursive(cf_sk->debugfs_device_dir);
> +#endif
> +
> +	release_sock(&cf_sk->sk);
> +	CAIFLOG_WARN("caif_sock_destructor: Removing socket %s\n",
> +		cf_sk->name);
> +	/* Decrease the global caif socket counter. */
> +	atomic_dec(&caif_nr_socks);
> +	return;
> +}
> +


> diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
> new file mode 100644
> index 0000000..fbc8a64
> --- /dev/null
> +++ b/net/caif/chnl_net.c
> @@ -0,0 +1,655 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/version.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_ether.h>
> +#include <linux/moduleparam.h>
> +#include <linux/ip.h>
> +#include <linux/sched.h>
> +#include <linux/sockios.h>
> +
> +/* CAIF header files. */
> +#include <net/caif/generic/caif_layer.h>
> +#include <net/caif/generic/cfcnfg.h>
> +#include <net/caif/generic/cfpkt.h>
> +#include <net/caif/caif_chr.h>
> +#include <net/caif/caif_log.h>
> +
> +/*NetLink Header files*/
> +#include <net/rtnetlink.h>
> +#include <linux/caif/if_caif.h>
> +
> +#define CAIF_CONNECT_TIMEOUT 30
> +#define SIZE_MTU 1500
> +#define SIZE_MTU_MAX 4080
> +#define SIZE_MTU_MIN 68
> +
> +static LIST_HEAD(chnl_net_list);
> +static spinlock_t list_lock;
> +
> +MODULE_LICENSE("GPL");
> +
> +struct chnl_net {
> +	struct layer chnl;
> +	struct net_device_stats stats;
> +	spinlock_t lock;
> +	struct caif_channel_config config;
> +	struct list_head list_field;
> +	struct net_device *netdev;
> +	char name[256];
> +	wait_queue_head_t netmgmt_wq;
> +	/* Flow status to remember and control the transmission. */
> +	bool flowenabled;
> +};
> +
> +
> +static struct chnl_net *find_device(char *name, bool remove_from_list)
> +{
> +	struct list_head *list_node;
> +	struct list_head *n;
> +	struct chnl_net *dev = NULL;
> +	struct chnl_net *tmp;
> +	CAIFLOG_ENTER("");
> +	spin_lock(&list_lock);
> +	CAIFLOG_TRACE("[%s:%d] start looping \n", __func__,
> +		__LINE__);
> +	list_for_each_safe(list_node, n, &chnl_net_list) {
> +		tmp =
> +			list_entry(list_node, struct chnl_net, list_field);

Above doesn't need to be on 2 lines.

> +		/* Find from name. */
> +		if (name) {
> +			if (!strncmp(tmp->name, name, sizeof(tmp->name)))
> +				dev = tmp;
> +		} else
> +			/* Get the first element if name is not specified. */
> +			dev = tmp;
> +		if (dev) {
> +			CAIFLOG_TRACE("[%s:%d] match %s \n",
> +				__func__, __LINE__,  name);
> +			if (remove_from_list)
> +				list_del(list_node);
> +			break;
> +		}
> +	}
> +	spin_unlock(&list_lock);
> +	return dev;
> +}



-- 
~Randy

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3 0/8] CAIF Protocol Stack
  2009-11-30 16:08 ` [RFC PATCH v3 0/8] " Patrick McHardy
@ 2009-11-30 18:26   ` Sjur Brændeland
  0 siblings, 0 replies; 25+ messages in thread
From: Sjur Brændeland @ 2009-11-30 18:26 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev, stefano.babic, randy.dunlap, Kim Lilliestierna XX

Patrick McHardy wrote:
> 
> Please add the changelog to the respective patches and give them
> meaningful subjects. Its impossible to review patches if you don't
> even know what they're supposed to do.  

OK, I'll do so next time.
Patch 7/8 contains some documentation about CAIF.

BR/Sjur Brændeland

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3 0/8] CAIF Protocol Stack
  2009-11-30 15:00 [RFC PATCH v3 0/8] CAIF Protocol Stack sjur.brandeland
  2009-11-30 15:00 ` [RFC PATCH v3 1/8] " sjur.brandeland
  2009-11-30 16:08 ` [RFC PATCH v3 0/8] " Patrick McHardy
@ 2009-12-02 17:02 ` Stefano Babic
  2009-12-03 17:49   ` Sjur Brændeland
  2 siblings, 1 reply; 25+ messages in thread
From: Stefano Babic @ 2009-12-02 17:02 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:
> General:
> * Sockets has replaced the character device implementation,
>   when accessing the modem. AT channels has to open sockets.

Hi Sjur,

I would like to test your patches with real hardware (based on an ARM
processor), as I did last time before sending my comments.
I think it should easier if in the Documentation there is an example to
explain how to setup a connection, for example with AT protocol. I tried
and I get "Specified PHY type does not exists", probably because I have
not well understood the parameters.

There are some errors in the MAN page documentation (patch #7) and the
example reported does not compile (for example, CAIFSO_CHANNEL should be
CAIF_CHANNEL_OPT, and so on).

Can you provide an example for the user space to setup a connection ?

> Please check what you think of the asserts in this release and get back to be!

Yes, I will do it.

Best Regards,
Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3 0/8] CAIF Protocol Stack
  2009-12-02 17:02 ` Stefano Babic
@ 2009-12-03 17:49   ` Sjur Brændeland
  0 siblings, 0 replies; 25+ messages in thread
From: Sjur Brændeland @ 2009-12-03 17:49 UTC (permalink / raw)
  To: Stefano Babic; +Cc: netdev, randy.dunlap, Daniel Martensson

Hi Stefano,
Thank you for your effort reviewing and testing CAIF. 
I'm exited that you have been able to get into the code 
and that you got the last patch-set  up and running!

Stefano Babic wrote:
> I would like to test your patches with real hardware (based on an ARM
> processor), as I did last time before sending my comments.
Great! Looking forward to hearing your results.
We're doing a lot of testing and bug fixing on this as well, and
I've already found and fixed a couple of bugs. 

> I think it should easier if in the Documentation there is an example
> to explain how to setup a connection, for example with AT protocol.

This was the intention of the example part in caif.man. As mentione below
I will update this in next patch-set. 

> I tried and I get "Specified PHY type does not exists", probably
> because I have not well understood the parameters.
Parameters would probably look like this:

insmod caif_serial.ko ser_ttyname=/dev/ttyS0 ser_loop=no ser_use_stx=no

Most likely you get this error message because something went wrong 
when setting up the serial connection.  At opening, the following 
sequence happends: 
1) caif_serial registers a net device called "caifser0".
2) if caif.ko is insmod'ed caif_dev opens this net device.
3) caif_serial receives open and opens the TTY and registers N_CAIF line discipline. 
4) This causes caif line discipline to be opened. 
I'm not quite sure where this goes wrong. Could be the registration of the N_CAIF ldisc?
I must admit that changing to N_CAIF was a last-minute change, 
I have done most of my testing by hi-jacking N_MOUSE.

> There are some errors in the MAN page documentation (patch #7) and
> the example reported does not compile (for example, CAIFSO_CHANNEL
> should be CAIF_CHANNEL_OPT, and so on). 
OK thanks, I'll fix this in the next patch-set.

> Can you provide an example for the user space to setup a connection ?
[snip]
  int s,r;
  char buf[200],*msg = "AT\r\n";
  struct sockaddr_caif addr = {
    .family = AF_CAIF,
    .u.at.type = CAIF_ATTYPE_PLAIN
  };
  s = socket(AF_CAIF, SOCK_SEQPACKET, CAIFPROTO_AT);
  connect(s, (struct sockaddr *) &addr, sizeof(addr));
  send(s,msg,strlen(msg),0);
  r = recv(s,buf,sizeof(buf),0);
  buf[r]=0;
  printf("buf:'%s'\n",buf);
  
BR/Sjur


 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  1/8] CAIF Protocol Stack
  2009-11-30 15:00 ` [RFC PATCH v3 1/8] " sjur.brandeland
  2009-11-30 15:00   ` [RFC PATCH v3 2/8] " sjur.brandeland
@ 2009-12-08 23:42   ` stefano babic
  2009-12-10 11:11     ` Sjur Brændeland
  1 sibling, 1 reply; 25+ messages in thread
From: stefano babic @ 2009-12-08 23:42 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:

> +#define CAIF_PRIO_UNSPCEIFIED  0x0

The define is not used in code, but probably you would prefer to set
CAIF_PRIO_UNSPECIFIED


> diff --git a/include/linux/caif/caif_ioctl.h b/include/linux/caif/caif_ioctl.h
> +/*!\page  caif_ioctl.h
> + * This file defines the management interface to CAIF.
> + * It defines how CAIF channels are configured and become visible in the
> + * Linux file system, typically under "/dev".

This is not updated, you have already removed the char devices.

> + *
> + *\b Example - creating a new AT character device:
> + * \code
> +   fd = open("/dev/caifconfig",..);
> +   struct caif_channel_create_action at_config = {
> +	 .name = "cnhl2",
> +	 .config = {
> +	    .channel = CAIF_CHTY_AT,
> +	    .phy_ref = CAIF_PHY_LOW_LAT,
> +	    .priority = CAIF_PRIO_HIGH
> +	 }};
> +   ioctl(fd, CAIF_IOC_CONFIG_DEVICE,&at_config);
> +   close(fd);
> + * \endcode
> + * This will cause a new AT channel to be available in at "/dev/chnl2".
> + * This CAIF channel can then be connected by using \ref open.
> + */

This is obsolete,too.

> +/* Specifies the type of device to create: NET device or CHAR device*/
> +enum caif_dev_type {
> +	CAIF_DEV_CHR = 1,
> +	CAIF_DEV_NET = 2
> +};

You can remove this enum, it is not used anymore in your code.

> +
> +/** Used for identifying devices, PHY interfaces, etc.*/
> +struct caif_device_name {
> +	char name[DEVICE_NAME_LEN];	/*!< Device name */
> +	enum caif_dev_type devtype;	/*!< Device type */
> +};

I think this one is obsolete, too.

> +/* TODO: Move these defs to /usr/include/linux/socket.h */
> +#define AF_CAIF    37 		/* CAIF Socket Address Family */
> +#define PF_CAIF    37           /* CAIF Socket Protocol Family */
> +#define SOL_CAIF   278		/* CAIF Socket Option Level */

You sent already a patch for socket.h, I think you can safely remove
these duplicates.

> +
> +#define CAIF_DEFAULT_PRI       0xf

You have already defined CAIF_PRIO_NORMAL with the same value. Do you
need both ?

> +enum caif_link_selector {
> +	CAIF_LINK_UNSPECIFIED	= 0x00,
> +	CAIF_LINK_LOW_LATENCY	= 0xd0,
> +	CAIF_LINK_HIGH_BANDW	= 0xe0

caif_phy_preference and caif_link_selector have the same values for
priority. Should we have a single enum for both ?

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  2/8] CAIF Protocol Stack
  2009-11-30 15:00   ` [RFC PATCH v3 2/8] " sjur.brandeland
  2009-11-30 15:00     ` [RFC PATCH v3 3/8] " sjur.brandeland
@ 2009-12-09  0:18     ` stefano babic
  2009-12-10 11:20       ` Sjur Brændeland
  1 sibling, 1 reply; 25+ messages in thread
From: stefano babic @ 2009-12-09  0:18 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:
> diff --git a/include/net/caif/generic/caif_layer.h b/include/net/caif/generic/caif_layer.h

> +enum caif_ctrlcmd {
> +	/** Flow Control is OFF, transmit function should stop sending data */
> +	CAIF_CTRLCMD_FLOW_OFF_IND = 0,
> +	/** Flow Control is ON, transmit function can start sending data */
> +	CAIF_CTRLCMD_FLOW_ON_IND = 1,
> +	/** Remote end modem has decided to close down channel */
> +	CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND = 5,

Not really important, but is there some reason to not put them in order ?


> diff --git a/include/net/caif/generic/cfcnfg.h b/include/net/caif/generic/cfcnfg.h
> +/** Physical preference - HW Abstraction */
> +enum cfcnfg_phy_preference {
> +	/** Default physical interface */
> +	CFPHYPREF_UNSPECIFIED = 0xa0,
> +	/** Default physical interface for low-latency traffic */
> +	CFPHYPREF_LOW_LAT = 0xd0,
> +	/** Default physical interface for high-bandwidth traffic */
> +	CFPHYPREF_HIGH_BW = 0xe0,
> +	/** \b TEST \b ONLY Loopback interface simulating modem responses */
> +	CFPHYPREF_LOOP = 0x70,
> +	/** \b TEST \b ONLY Raw loopback interface */
> +	CFPHYPREF_RAW_LOOP = 0x80
> +};

Different context, but preferences have always the same values. Could we
remove the duplicates ?

> +/** Configuration parameters for a physical layer (e.g. serial) */
> +struct cfcnfg_phy_param {
> +	int foo;
> +};

This structure is obsolete and can be safely dropped.

> +/**
> + * These variable is used as a global flag, in order to configure padding on SPI communication.
> + * NOTE: This is not a fully future-proof solution.
> + */

I understand that the padding is due to the fact that a lot of spi
controller can send only words and not bytes. However, this is very
processor specific. Probably when you will add the SPI layer you will
need to add a way to set up this issue.

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3  1/8] CAIF Protocol Stack
  2009-12-08 23:42   ` [RFC PATCH v3 1/8] " stefano babic
@ 2009-12-10 11:11     ` Sjur Brændeland
  0 siblings, 0 replies; 25+ messages in thread
From: Sjur Brændeland @ 2009-12-10 11:11 UTC (permalink / raw)
  To: stefano.babic
  Cc: netdev, randy.dunlap, Kim Lilliestierna XX, Christian Bejram,
	Daniel Martensson

Hi Stefano.

Thank you for good feedback.

stefano babic wrote:
>> +#define CAIF_PRIO_UNSPCEIFIED  0x0
> 
> The define is not used in code, but probably you would prefer to set
> CAIF_PRIO_UNSPECIFIED 

I'll remove this one.

> 
> 
>> diff --git a/include/linux/caif/caif_ioctl.h
>> b/include/linux/caif/caif_ioctl.h
>> +/*!\page  caif_ioctl.h
>> + * This file defines the management interface to CAIF.
>> + * It defines how CAIF channels are configured and become visible
>> in +the + * Linux file system, typically under "/dev".
> 
> This is not updated, you have already removed the char devices.
Right - agree. I'll remove this.
> 
>> + *
>> + *\b Example - creating a new AT character device: + * \code
>> +   fd = open("/dev/caifconfig",..);
>> +   struct caif_channel_create_action at_config = { +	 .name =
>> "cnhl2", +	 .config = {
>> +	    .channel = CAIF_CHTY_AT,
>> +	    .phy_ref = CAIF_PHY_LOW_LAT,
>> +	    .priority = CAIF_PRIO_HIGH
>> +	 }};
>> +   ioctl(fd, CAIF_IOC_CONFIG_DEVICE,&at_config);
>> +   close(fd);
>> + * \endcode
>> + * This will cause a new AT channel to be available in at
>> "/dev/chnl2". + * This CAIF channel can then be connected by using
>> \ref open. + */
> 
> This is obsolete,too.

Yes, Thanks.

> 
>> +/* Specifies the type of device to create: NET device or CHAR
>> +device*/ enum caif_dev_type {
>> +	CAIF_DEV_CHR = 1,
>> +	CAIF_DEV_NET = 2
>> +};
> 
> You can remove this enum, it is not used anymore in your code.

Yes, I'll do it.

> 
>> +
>> +/** Used for identifying devices, PHY interfaces, etc.*/ struct
>> +caif_device_name { +	char name[DEVICE_NAME_LEN];	/*!< Device name */
>> +	enum caif_dev_type devtype;	/*!< Device type */
>> +};
> 
> I think this one is obsolete, too.

Yes, this is obsolete.

> 
>> +/* TODO: Move these defs to /usr/include/linux/socket.h */
>> +#define AF_CAIF    37 		/* CAIF Socket Address Family */
>> +#define PF_CAIF    37           /* CAIF Socket Protocol Family */
>> +#define SOL_CAIF   278		/* CAIF Socket Option Level */
> 
> You sent already a patch for socket.h, I think you can safely remove
> these duplicates. 
Yes they should be moved to include/linux/socket.h.
> 
>> +
>> +#define CAIF_DEFAULT_PRI       0xf
> 
> You have already defined CAIF_PRIO_NORMAL with the same value. Do you
> need both ? 
Hmm good question. My initial thinking was to have two self-contained
header files:caif_socket.h and caif_config.h. The first is used for
sockets and the second for modules using the kernel API (caif_kernel.h).
Perhaps I should look into the option of letting caif_config.h include
caif_socket.h allowing removal of duplicate types.

> 
>> +enum caif_link_selector {
>> +	CAIF_LINK_UNSPECIFIED	= 0x00,
>> +	CAIF_LINK_LOW_LATENCY	= 0xd0,
>> +	CAIF_LINK_HIGH_BANDW	= 0xe0
> 
> caif_phy_preference and caif_link_selector have the same values for
> priority. Should we have a single enum for both ? 
I'll remove the assignment to 0xd0 and 0xe0.
Link selection and priority are two fundamental different things.
Link Selectors are used to select the physical link such as SPI or UART,
while priority is about the channel's priority used for CAIF-packet
scheduling in the modem.

BR/Sjur


^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3  2/8] CAIF Protocol Stack
  2009-12-09  0:18     ` [RFC PATCH v3 2/8] " stefano babic
@ 2009-12-10 11:20       ` Sjur Brændeland
  0 siblings, 0 replies; 25+ messages in thread
From: Sjur Brændeland @ 2009-12-10 11:20 UTC (permalink / raw)
  To: stefano.babic
  Cc: netdev, randy.dunlap, Kim Lilliestierna XX, Christian Bejram,
	Daniel Martensson

Hi Stefano.

stefano babic wrote:
>> +enum caif_ctrlcmd {
>> +	/** Flow Control is OFF, transmit function should stop sending
>> data */ +	CAIF_CTRLCMD_FLOW_OFF_IND = 0,
>> +	/** Flow Control is ON, transmit function can start sending data */
>> +	CAIF_CTRLCMD_FLOW_ON_IND = 1,
>> +	/** Remote end modem has decided to close down channel */
>> +	CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND = 5,
> 
> Not really important, but is there some reason to not put them in
> order ? 
Good question, I don't remember why it ended up like this. I'll fix this up by
removing the assignment in the enum.
> 
> 
>> diff --git a/include/net/caif/generic/cfcnfg.h
>> b/include/net/caif/generic/cfcnfg.h
>> +/** Physical preference - HW Abstraction */ enum
>> +cfcnfg_phy_preference {
>> +	/** Default physical interface */
>> +	CFPHYPREF_UNSPECIFIED = 0xa0,
>> +	/** Default physical interface for low-latency traffic */
>> +	CFPHYPREF_LOW_LAT = 0xd0, +	/** Default physical interface for
>> high-bandwidth traffic */ +	CFPHYPREF_HIGH_BW = 0xe0, +	/** \b TEST
>> \b ONLY Loopback interface simulating modem responses */
>> +	CFPHYPREF_LOOP = 0x70, +	/** \b TEST \b ONLY Raw loopback
>> interface */ +	CFPHYPREF_RAW_LOOP = 0x80 +};
> 
> Different context, but preferences have always the same values. Could
> we remove the duplicates ? 
At some point I was thinking on or-ing preferences together.
This is no longer done and I think I'd rather skip the assignment
of values.

However on the subject of duplications, I have found some issues.
When I e.g. grep for UNSPECIFIED I get:
include/linux/caif/caif_socket.h:	CAIF_LINK_UNSPECIFIED	= 0x00,
include/linux/caif/caif_config.h:	CAIF_PHYPREF_UNSPECIFIED = 0x00,
include/net/caif/caif_actions.h:	CAIF_PHY_UNSPECIFIED = 0x00,
include/net/caif/generic/cfcnfg.h:	CFPHYPREF_UNSPECIFIED = 0xa0,

There are some types that are duplicated in different places for CAIF, 
but this is done for a reason.
* caif_socket.h header file is self-contained and defines types needed for
  setting up CAIF Connections.
* caif_kernel.h provides a interface for CAIF connections from kernel modules.
* The modules inside net/caif/generic include/net/caif/generic are designed to 
  be a generic CAIF Stack. 

As you might have noticed the CAIF stack residing in "generic" is designed to
be a generic CAIF implementation. This implies that if must be self-contained 
and not depend on caif_socket.h and caif_kernel.h. This allows CAIF protocol
implementation to be tested in user space test-applications and CAIF to be 
portable. The file cfglue.h contains wrappers for the Kernel Specific functions. 

Due to this you'll find duplicated information in structs like caif_channel_config, 
sockaddr_caif, cfctrl_link_param. One example of the effect of this is the following:

[snip from caif_dev.c]
int caifdev_adapt_register(struct caif_channel_config *config,
			   struct layer *adap_layer)
{
	struct cfctrl_link_param param;
	if (channel_config_2_link_param(get_caif_conf(), config, &param) == 0) <--
									-- Convert from caif_channel_config
									-- to cfctrl_link_param  
		if (cfcnfg_add_adaptation_layer(get_caif_conf(), <-- Wrap the generic function
						&param, adap_layer))
			return 0;
	return -EINVAL;
}

> 
>> +/** Configuration parameters for a physical layer (e.g. serial) */
>> +struct cfcnfg_phy_param { +	int foo;
>> +};
> 
> This structure is obsolete and can be safely dropped.
Yes you're right. Thanks for pointing this out, I have forgotten to remove some
obsolete functions and types here. I need to clean this up.

> 
>> +/**
>> + * These variable is used as a global flag, in order to configure
>> padding on SPI communication. + * NOTE: This is not a fully
>> future-proof solution. + */
> 
> I understand that the padding is due to the fact that a lot of spi
> controller can send only words and not bytes. However, this is very
> processor specific. Probably when you will add the SPI layer you will
> need to add a way to set up this issue. 
Yes, these parameters are module parameters to the SPI physical driver,
and they change on different platforms due to DMA specifics etc.
As mentioned before we're moving all SPI handling down to the SPI driver, 
so all SPI related code will be gone in the next patch-set.

BR/Sjur

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3  5/8] CAIF Protocol Stack
  2009-11-30 16:41           ` [RFC PATCH v3 5/8] " Randy Dunlap
@ 2009-12-10 13:05             ` Sjur Brændeland
  2009-12-10 16:44               ` Randy Dunlap
  0 siblings, 1 reply; 25+ messages in thread
From: Sjur Brændeland @ 2009-12-10 13:05 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: netdev, stefano.babic, Kim Lilliestierna XX, Christian Bejram,
	Daniel Martensson

Hi Randy.
Thank you for helping out on style issues, and my English writing.
As you probably have figured English is not my mother tongue.

Randy Dunlap wrote:
> sjur.brandeland@stericsson.com wrote:
>> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 
> what Patrick said:
> patch description should be here and each email subject should be
> different and describe what that patch does. Please read
> Documentation/SubmittingPatches. 
OK I'll read carefully through Submitting Patches. Do you recon this will be ok?
Subject: [PATCH X/Y] net-caif: Add CAIF Protocol Stack in net/caif/generic

>> +menuconfig CAIF
>> +	tristate "Enable CAIF support"
>> +	default n
>> +	---help---
> 
> Tell us what CAIF means, probably in the help text.

I have rephrased this a bit, what do you think about this:
[snip]
menuconfig CAIF
	tristate "Enable CAIF support"
	default n
	---help---
	The "Communication CPU to Application CPU Interface" (CAIF) is a packet based
	connection-oriented MUX protocol developed by ST-Ericsson for use with its modems.

	Say Y (or M) here if you build for a phone product (e.g. Android) that uses
	CAIF as transport, if unsure say N. 

	If you select to build it as module then CAIF_SOCK and CAIF_NETDEV also needs to 
	be built as modules. You will also need to say yes to any CAIF physical devices that
	your platform requires.

	See Documentation/net/CAIF for a further explanation on how to use and configure CAIF.


>> +	default CAIF
>> +	---help---
>> +	Say Y if you will be using the CAIF based network device.
> 
> 	                           a (or any) CAIF-based
Changed to:
	Say Y if you will be using a CAIF based GPRS network device.

>> +	Say Y if you will be using the CAIF Sockets.
> 	drop "the" ----------------^^^
> s/mist/must/
OK, I'll fix this.
> 
>> +/**
>> + * func caif_create_skb - Creates a CAIF SKB buffer
> 
> Use documented/expected kernel-doc notation, please.  I.e., drop
> "func". 
I realize I have some work to do run kernel-doc and update formatting of 
comments. I'll try to find time for this before submitting next patch-set.
> 
> 
>> +
>> +module_init(caif_device_init);
>> +module_exit(caif_device_exit);
>> +
>> +
>> +
>> +
>> +
>> +
>> +
>> +
>> +
> 
> delete all of those trailing empty lines.
Yes I will, thanks.
> 
>> +/** Packet Receive Callback function called from CAIF Stack */
> 
> Do not use /** to begin comments that are not kernel-doc notation.
> (more found below, but deleted for now)
OK, thank you for pointing this out.
It seems like caif_socket.c has a number of style problems.
I'll try to go through the file more carefully before next patch-set.

> 
>> +static int caif_sktrecv_cb(struct layer *layr, struct cfpkt *pkt) {
> 
...
>> +	do {
>> +			ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn,
>> +							&info, pkt);
> 
> odd indentation?
Yes, I'll update this.
> 
>> +
>> +static int setsockopt(struct socket *sock,
>> +			int lvl, int opt, char __user *ov, int ol) {
>> +	struct sock *sk = sock->sk;
>> +	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
>> +	struct caif_channel_opt confopt;
>> +	int res;
>> +
>> +	if (lvl != SOL_CAIF) {
>> +		CAIFLOG_TRACE("setsockopt bad level\n");
>> +			return -ENOPROTOOPT;
> 
> odd indentation.

And this.

> 
...
>> +	}
>> +
>> +	switch (opt) {
>> +	case CAIF_CHANNEL_OPT:
>> +		if (ol < sizeof(struct caif_channel_opt)) {
>> +			CAIFLOG_TRACE("setsockopt"
>> +					" CAIF_CHANNEL_CONFIG bad size\n");
>> +				return -EINVAL;
> 
> odd indentation.

and this,

> 
...
>>
>> +int caif_connect(struct socket *sock, struct sockaddr *uservaddr,
>> +	       int sockaddr_len, int flags)
>> +{
>> +	struct caifsock *cf_sk = NULL;
>> +	int result = -1;
>> +	int mode = 0;
>> +	int ret = -EIO;
>> +    struct sock *sk = sock->sk;
> 
> indent above line with tab, not spaces.

and this,

> 
...
>> +	lock_sock(&(cf_sk->sk));
>> +	/* NOTE: This is how the sock->sk structure is used all over the
>> linux +	 *       socket implementation. Since there is no locking
>> protecting +	 *       the sock->sk pointer, the linux socket
>> implementation do not +	 *       support multiple threads using the
>> same socket descriptor, +	 *       since if one of the threads close
>> the socket, the other +	 *       threads may end up accessing a
>> pointer to NULL. See for +	 *       instance sock_setsockopt in
>> net/socket.c, it uses sock->sk +	 *       without checking if its
>> value is NULL. */ 
> 
> 	/*
> 	 * Note: This is the Linux long comment
> 	 * style.  Please use it.
> 	 */

Yes, I will.

> 
>> +	/* The rest of the cleanup will be handled from the +	 *
>> caif_sock_destructor */ +}
> 
>> +/* This function is called when a socket is finally destructed. */
> 
>                                                        destroyed. */
> 

> 
...
>> +static struct chnl_net *find_device(char *name, bool
>> +remove_from_list) { +	struct list_head *list_node;
>> +	struct list_head *n;
>> +	struct chnl_net *dev = NULL;
>> +	struct chnl_net *tmp;
>> +	CAIFLOG_ENTER("");
>> +	spin_lock(&list_lock);
>> +	CAIFLOG_TRACE("[%s:%d] start looping \n", __func__, +		__LINE__);
>> +	list_for_each_safe(list_node, n, &chnl_net_list) { +		tmp =
>> +			list_entry(list_node, struct chnl_net, list_field);
> 
> Above doesn't need to be on 2 lines.

Agree, I'll fix this.

> 

Thank you Randy for your feedback, I appreciate it.

BR/Sjur

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  5/8] CAIF Protocol Stack
  2009-12-10 13:05             ` Sjur Brændeland
@ 2009-12-10 16:44               ` Randy Dunlap
  0 siblings, 0 replies; 25+ messages in thread
From: Randy Dunlap @ 2009-12-10 16:44 UTC (permalink / raw)
  To: Sjur Brændeland
  Cc: netdev, stefano.babic, Kim Lilliestierna XX, Christian Bejram,
	Daniel Martensson

On Thu, 10 Dec 2009 14:05:13 +0100 Sjur Brændeland wrote:

> Randy Dunlap wrote:
> > sjur.brandeland@stericsson.com wrote:
> >> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> > 
> > what Patrick said:
> > patch description should be here and each email subject should be
> > different and describe what that patch does. Please read
> > Documentation/SubmittingPatches. 
> OK I'll read carefully through Submitting Patches. Do you recon this will be ok?
> Subject: [PATCH X/Y] net-caif: Add CAIF Protocol Stack in net/caif/generic

One big point is that the subject line shouldn't be the same
for all of the patches (disregarding PATCH X/Y).
They should be like (e.g.):

[PATCH 1/5] net-caif: add header files
[PATCH 2/5] net-caif: add caif protocol
[PATCH 3/5] net-caif: add caif devices
[PATCH 4/5] net-caif: documentation
[PATCH 5/5] net-caif: Kconfig and Makefile




> >> +menuconfig CAIF
> >> +	tristate "Enable CAIF support"
> >> +	default n
> >> +	---help---
> > 
> > Tell us what CAIF means, probably in the help text.
> 
> I have rephrased this a bit, what do you think about this:
> [snip]
> menuconfig CAIF
> 	tristate "Enable CAIF support"
> 	default n
> 	---help---
> 	The "Communication CPU to Application CPU Interface" (CAIF) is a packet based
> 	connection-oriented MUX protocol developed by ST-Ericsson for use with its modems.
> 
> 	Say Y (or M) here if you build for a phone product (e.g. Android) that uses
> 	CAIF as transport, if unsure say N. 
> 
> 	If you select to build it as module then CAIF_SOCK and CAIF_NETDEV also needs to 
> 	be built as modules. You will also need to say yes to any CAIF physical devices that
> 	your platform requires.
> 
> 	See Documentation/net/CAIF for a further explanation on how to use and configure CAIF.


That looks good, thanks.

---
~Randy

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  3/8] CAIF Protocol Stack
  2009-11-30 15:00     ` [RFC PATCH v3 3/8] " sjur.brandeland
  2009-11-30 15:00       ` [RFC PATCH v3 4/8] " sjur.brandeland
@ 2009-12-15 16:00       ` stefano babic
  2009-12-16 16:15         ` Sjur Brændeland
  1 sibling, 1 reply; 25+ messages in thread
From: stefano babic @ 2009-12-15 16:00 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:
> diff --git a/include/net/caif/caif_chr.h b/include/net/caif/caif_chr.h
> new file mode 100644
> index 0000000..ebd89f8
> --- /dev/null
> +++ b/include/net/caif/caif_chr.h

Only a question of taste, but there is no chr device anymore, maybe
another name for the file should be more appropriate.

> +struct caif_service_config;
> +
> +enum cf_chr_dev_type {
> +	CFDEVTYPE_CHR,
> +	CFDEVTYPE_TTY,
> +	CFDEVTYPE_NET
> +};
> +
> +extern int serial_use_stx;
> +extern int (*netdev_mgmt_func) (int action, union caif_action *param);
> +int caifdev_phy_reg(struct layer *phyif, struct cfcnfg_phy_mgmt *mgmt);
> +int caifdev_phy_instanciate(struct cfcnfg_phy_config *phy_config);
> +int caifdev_phy_register(struct layer *phyif,
> +			 enum cfcnfg_phy_type phy_type,
> +			 enum cfcnfg_phy_preference phy_pref);
> +int caifdev_phy_unregister(struct layer *phyif);
> +int caifdev_phy_loop_register(struct layer *phyif,
> +			      enum cfcnfg_phy_type phy_type);
> +int caifdev_phy_spi_xmitlen(struct cfspil *layr);
> +struct cfpkt *caifdev_phy_spi_getxmitpkt(struct cfspil *layr);

All these functions seem obsolete.

> +int caif_register_chrdev(int (*chrdev_mgmt)
> +			(int action, union caif_action *param));
> +void caif_unregister_chrdev(void);

Obsolete, too.

> diff --git a/include/net/caif/caif_config_util.h b/include/net/caif/caif_config_util.h
> new file mode 100644
> index 0000000..cdc1443
> --- /dev/null
> +++ b/include/net/caif/caif_config_util.h
> @@ -0,0 +1,20 @@
> +/*
> + * Copyright (C) ST-Ericsson AB 2009
> + * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#ifndef CAIF_CONFIG_UTIL_H_
> +#define CAIF_CONFIG_UTIL_H_
> +
> +#include <linux/caif/caif_config.h>
> +#include <linux/caif/caif_ioctl.h>
> +#include <net/caif/generic/cfcnfg.h>
> +#include <net/caif/generic/cfctrl.h>
> +#include <net/caif/caif_actions.h>
> +
> +int channel_config_2_link_param(struct cfcnfg *cnfg,
> +				struct caif_channel_config *s,
> +				struct cfctrl_link_param *l);
> +
> +#endif

Do we need an extra-header only to set the prototype of a single
function ? Probably can we move it into another header file.

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  4/8] CAIF Protocol Stack
  2009-11-30 15:00       ` [RFC PATCH v3 4/8] " sjur.brandeland
  2009-11-30 15:00         ` [RFC PATCH v3 5/8] " sjur.brandeland
@ 2009-12-15 16:47         ` stefano babic
  2009-12-16 16:16           ` Sjur Brændeland
  1 sibling, 1 reply; 25+ messages in thread
From: stefano babic @ 2009-12-15 16:47 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:
> +struct cfcnfg *cfcnfg_create()
> +{
> +	struct cfcnfg *this;
> +	struct cfctrl_rsp resp;
> +	/* Initiate response functions */
> +	resp.enum_rsp = cfctrl_enum_resp;
> +	resp.linkerror_ind = cfctrl_resp_func;
> +	resp.linkdestroy_rsp = cncfg_linkdestroy_rsp;
> +	resp.sleep_rsp = cfctrl_resp_func;
> +	resp.wake_rsp = cfctrl_resp_func;
> +	resp.restart_rsp = cfctrl_resp_func;
> +	resp.radioset_rsp = cfctrl_resp_func;
> +	resp.linksetup_rsp = cncfg_linkup_rsp;
> +	resp.reject_rsp = cncfg_reject_rsp;
> +	/* Initiate this layer */
> +	this = cfglu_alloc(sizeof(struct cfcnfg));
> +	memset(this, 0, sizeof(struct cfcnfg));
> +	this->mux = cfmuxl_create();
> +	this->ctrl = cfctrl_create();
> +	this->last_phyid = 1;
> +	cfctrl_set_respfuncs(this->ctrl, &resp);

Is this correct ? resp is on the stack of the function and
cfctrl_set_respfuncs sets only the pointer. After returning from this
function, the memory used by resp could be reused again. Am I right ?

> +static void cfctrl_resp_func(void)
> +{
> +	CFLOG_ENTER(("cfcnfg: cfctrl_resp_func\n"));
> +	CFLOG_EXIT(("cfcnfg: cfctrl_resp_func\n"));
> +}

Not really useful..

Stefano
-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH v3  7/8] CAIF Protocol Stack
  2009-11-30 15:00             ` [RFC PATCH v3 7/8] " sjur.brandeland
  2009-11-30 15:00               ` [RFC PATCH v3 8/8] " sjur.brandeland
@ 2009-12-15 17:12               ` stefano babic
  1 sibling, 0 replies; 25+ messages in thread
From: stefano babic @ 2009-12-15 17:12 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, randy.dunlap, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

sjur.brandeland@stericsson.com wrote:

> +Linux GPRS Net Device and Character Devices

We have now only net devices

> +Configuration of Drivers
> +------------------------
> +
> +Configuration is the most complex part of the CAIF protocol.
> +Configuration is controlled by the Misc device 'caifconfig'
> +implemented in caif_chr.

This documentation was not updated, you get rid of 'caifconfig'

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3  3/8] CAIF Protocol Stack
  2009-12-15 16:00       ` [RFC PATCH v3 3/8] " stefano babic
@ 2009-12-16 16:15         ` Sjur Brændeland
  0 siblings, 0 replies; 25+ messages in thread
From: Sjur Brændeland @ 2009-12-16 16:15 UTC (permalink / raw)
  To: stefano babic
  Cc: netdev, randy.dunlap, Kim Lilliestierna XX, Christian Bejram,
	Daniel Martensson

stefano babic wrote:
> sjur.brandeland@stericsson.com wrote:
>> diff --git a/include/net/caif/caif_chr.h
>> b/include/net/caif/caif_chr.h 
>> new file mode 100644 index 0000000..ebd89f8
>> --- /dev/null
>> +++ b/include/net/caif/caif_chr.h
> 
> Only a question of taste, but there is no chr device anymore, maybe
> another name for the file should be more appropriate.

Yes, I'll rename to caif_dev.h

>> +struct caif_service_config;
>> +enum cf_chr_dev_type {
...
>> +extern int serial_use_stx;
>> +extern int (*netdev_mgmt_func) (int action, union caif_action
>> *param); +int caifdev_phy_reg(struct layer *phyif, struct
>> cfcnfg_phy_mgmt *mgmt); +int caifdev_phy_instanciate(struct
>> cfcnfg_phy_config *phy_config); +int caifdev_phy_register(struct
>> layer *phyif, +			 enum cfcnfg_phy_type phy_type,
>> +			 enum cfcnfg_phy_preference phy_pref);
>> +int caifdev_phy_unregister(struct layer *phyif);
>> +int caifdev_phy_loop_register(struct layer *phyif,
>> +			      enum cfcnfg_phy_type phy_type);
>> +int caifdev_phy_spi_xmitlen(struct cfspil *layr);
>> +struct cfpkt *caifdev_phy_spi_getxmitpkt(struct cfspil *layr);
> 
> All these functions seem obsolete.
> 
>> +int caif_register_chrdev(int (*chrdev_mgmt)
>> +			(int action, union caif_action *param));
>> +void caif_unregister_chrdev(void);
> 
> Obsolete, too.

Yes, I agree. This header file needs some serious cleanup.
I'll rename it to caif_dev.h add config_util and strip it down 
to something like this:
[snip]
struct caif_service_config;
int caifdev_adapt_register(struct caif_channel_config *config,
			   struct layer *adap_layer);
int caifdev_adapt_unregister(struct layer *adap_layer);
struct cfcnfg *get_caif_conf(void);
void caif_register_ioctl(int (*ioctl)(unsigned int cmd,
				      unsigned long arg,
				      bool));
int caif_ioctl(unsigned int cmd, unsigned long arg, bool from_use_land);
void caif_unregister_netdev(void);
int channel_config_2_link_param(struct cfcnfg *cnfg,
				struct caif_channel_config *s,
				struct cfctrl_link_param *l);


>> diff --git a/include/net/caif/caif_config_util.h
... 
> Do we need an extra-header only to set the prototype of a single
> function ? Probably can we move it into another header file.

You're right, I'll move this into caif_dev.h (see above). 

BR/Sjur

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [RFC PATCH v3  4/8] CAIF Protocol Stack
  2009-12-15 16:47         ` [RFC PATCH v3 4/8] " stefano babic
@ 2009-12-16 16:16           ` Sjur Brændeland
  0 siblings, 0 replies; 25+ messages in thread
From: Sjur Brændeland @ 2009-12-16 16:16 UTC (permalink / raw)
  To: stefano babic
  Cc: netdev, randy.dunlap, Kim Lilliestierna XX, Christian Bejram,
	Daniel Martensson

stefano babic wrote:
> sjur.brandeland@stericsson.com wrote:
>> +struct cfcnfg *cfcnfg_create()
>> +{
>> +	struct cfcnfg *this;
>> +	struct cfctrl_rsp resp;
>> +	/* Initiate response functions */
>> +	resp.enum_rsp = cfctrl_enum_resp;
>> +	resp.linkerror_ind = cfctrl_resp_func;
>> +	resp.linkdestroy_rsp = cncfg_linkdestroy_rsp;
...
>> +	cfctrl_set_respfuncs(this->ctrl, &resp);
> 
> Is this correct ? resp is on the stack of the function and
> cfctrl_set_respfuncs sets only the pointer. After returning from this
> function, the memory used by resp could be reused again. Am I right ?
> 
Yes it is correct. But it sure looks odd, so I'll change this. 
But it's actually working because the content is copied by the statement 
this->res = *respfuncs; in cfctrl.c.

I'll change this code to something like this:
[snip]
	resp = cfctrl_get_respfuncs(this->ctrl);
	resp->enum_rsp = cfctrl_enum_resp;
	resp->linkerror_ind = cfctrl_resp_func;
	resp->linkdestroy_rsp = cncfg_linkdestroy_rsp;
	...
BR/Sjur


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2009-12-16 16:21 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-30 15:00 [RFC PATCH v3 0/8] CAIF Protocol Stack sjur.brandeland
2009-11-30 15:00 ` [RFC PATCH v3 1/8] " sjur.brandeland
2009-11-30 15:00   ` [RFC PATCH v3 2/8] " sjur.brandeland
2009-11-30 15:00     ` [RFC PATCH v3 3/8] " sjur.brandeland
2009-11-30 15:00       ` [RFC PATCH v3 4/8] " sjur.brandeland
2009-11-30 15:00         ` [RFC PATCH v3 5/8] " sjur.brandeland
2009-11-30 15:00           ` [RFC PATCH v3 6/8] " sjur.brandeland
2009-11-30 15:00             ` [RFC PATCH v3 7/8] " sjur.brandeland
2009-11-30 15:00               ` [RFC PATCH v3 8/8] " sjur.brandeland
2009-12-15 17:12               ` [RFC PATCH v3 7/8] " stefano babic
2009-11-30 16:41           ` [RFC PATCH v3 5/8] " Randy Dunlap
2009-12-10 13:05             ` Sjur Brændeland
2009-12-10 16:44               ` Randy Dunlap
2009-12-15 16:47         ` [RFC PATCH v3 4/8] " stefano babic
2009-12-16 16:16           ` Sjur Brændeland
2009-12-15 16:00       ` [RFC PATCH v3 3/8] " stefano babic
2009-12-16 16:15         ` Sjur Brændeland
2009-12-09  0:18     ` [RFC PATCH v3 2/8] " stefano babic
2009-12-10 11:20       ` Sjur Brændeland
2009-12-08 23:42   ` [RFC PATCH v3 1/8] " stefano babic
2009-12-10 11:11     ` Sjur Brændeland
2009-11-30 16:08 ` [RFC PATCH v3 0/8] " Patrick McHardy
2009-11-30 18:26   ` Sjur Brændeland
2009-12-02 17:02 ` Stefano Babic
2009-12-03 17:49   ` Sjur Brændeland

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.