2010-03-30 17:56:23 +04:00
/*
* Copyright ( C ) ST - Ericsson AB 2010
2013-04-23 03:57:01 +04:00
* Author : Sjur Brendeland
2010-03-30 17:56:23 +04:00
* License terms : GNU General Public License ( GPL ) version 2
*/
2010-09-06 01:31:11 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
2010-03-30 17:56:23 +04:00
# include <linux/stddef.h>
# include <linux/spinlock.h>
# include <linux/slab.h>
# include <net/caif/caif_layer.h>
# include <net/caif/cfsrvl.h>
# include <net/caif/cfpkt.h>
2011-04-11 14:11:30 +04:00
2010-03-30 17:56:23 +04:00
# define container_obj(layr) ((struct cfsrvl *) layr)
# define DGM_CMD_BIT 0x80
# define DGM_FLOW_OFF 0x81
# define DGM_FLOW_ON 0x80
2010-06-17 10:55:40 +04:00
# define DGM_MTU 1500
2010-03-30 17:56:23 +04:00
static int cfdgml_receive ( struct cflayer * layr , struct cfpkt * pkt ) ;
static int cfdgml_transmit ( struct cflayer * layr , struct cfpkt * pkt ) ;
struct cflayer * cfdgml_create ( u8 channel_id , struct dev_info * dev_info )
{
2011-08-25 17:22:24 +04:00
struct cfsrvl * dgm = kzalloc ( sizeof ( struct cfsrvl ) , GFP_ATOMIC ) ;
if ( ! dgm )
2010-03-30 17:56:23 +04:00
return NULL ;
caif_assert ( offsetof ( struct cfsrvl , layer ) = = 0 ) ;
2010-06-17 10:55:38 +04:00
cfsrvl_init ( dgm , channel_id , dev_info , true ) ;
2010-03-30 17:56:23 +04:00
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 ' ;
return & dgm - > layer ;
}
static int cfdgml_receive ( struct cflayer * layr , struct cfpkt * pkt )
{
u8 cmd = - 1 ;
u8 dgmhdr [ 3 ] ;
int ret ;
caif_assert ( layr - > up ! = NULL ) ;
caif_assert ( layr - > receive ! = NULL ) ;
caif_assert ( layr - > ctrlcmd ! = NULL ) ;
if ( cfpkt_extr_head ( pkt , & cmd , 1 ) < 0 ) {
2010-09-06 01:31:11 +04:00
pr_err ( " Packet is erroneous! \n " ) ;
2010-03-30 17:56:23 +04:00
cfpkt_destroy ( pkt ) ;
return - EPROTO ;
}
if ( ( cmd & DGM_CMD_BIT ) = = 0 ) {
if ( cfpkt_extr_head ( pkt , & dgmhdr , 3 ) < 0 ) {
2010-09-06 01:31:11 +04:00
pr_err ( " Packet is erroneous! \n " ) ;
2010-03-30 17:56:23 +04:00
cfpkt_destroy ( pkt ) ;
return - EPROTO ;
}
ret = layr - > up - > receive ( layr - > up , pkt ) ;
return ret ;
}
switch ( cmd ) {
case DGM_FLOW_OFF : /* FLOW OFF */
layr - > ctrlcmd ( layr , CAIF_CTRLCMD_FLOW_OFF_IND , 0 ) ;
cfpkt_destroy ( pkt ) ;
return 0 ;
case DGM_FLOW_ON : /* FLOW ON */
layr - > ctrlcmd ( layr , CAIF_CTRLCMD_FLOW_ON_IND , 0 ) ;
cfpkt_destroy ( pkt ) ;
return 0 ;
default :
cfpkt_destroy ( pkt ) ;
2010-09-06 01:31:11 +04:00
pr_info ( " Unknown datagram control %d (0x%x) \n " , cmd , cmd ) ;
2010-03-30 17:56:23 +04:00
return - EPROTO ;
}
}
static int cfdgml_transmit ( struct cflayer * layr , struct cfpkt * pkt )
{
2011-04-11 14:11:30 +04:00
u8 packet_type ;
2010-03-30 17:56:23 +04:00
u32 zero = 0 ;
struct caif_payload_info * info ;
struct cfsrvl * service = container_obj ( layr ) ;
int ret ;
2012-03-11 14:28:31 +04:00
if ( ! cfsrvl_ready ( service , & ret ) ) {
cfpkt_destroy ( pkt ) ;
2010-03-30 17:56:23 +04:00
return ret ;
2012-03-11 14:28:31 +04:00
}
2010-03-30 17:56:23 +04:00
2010-06-17 10:55:40 +04:00
/* STE Modem cannot handle more than 1500 bytes datagrams */
2012-03-11 14:28:31 +04:00
if ( cfpkt_getlen ( pkt ) > DGM_MTU ) {
cfpkt_destroy ( pkt ) ;
2010-06-17 10:55:40 +04:00
return - EMSGSIZE ;
2012-03-11 14:28:31 +04:00
}
2010-06-17 10:55:40 +04:00
2011-04-11 14:11:30 +04:00
cfpkt_add_head ( pkt , & zero , 3 ) ;
packet_type = 0x08 ; /* B9 set - UNCLASSIFIED */
cfpkt_add_head ( pkt , & packet_type , 1 ) ;
2010-03-30 17:56:23 +04:00
/* Add info for MUX-layer to route the packet out. */
info = cfpkt_info ( pkt ) ;
info - > channel_id = service - > layer . id ;
/* To optimize alignment, we add up the size of CAIF header
* before payload .
*/
info - > hdr_len = 4 ;
info - > dev_info = & service - > dev_info ;
2011-04-11 14:43:51 +04:00
return layr - > dn - > transmit ( layr - > dn , pkt ) ;
2010-03-30 17:56:23 +04:00
}