linux/net/caif/cffrml.c
<<
>>
Prefs
   1/*
   2 * CAIF Framing Layer.
   3 *
   4 * Copyright (C) ST-Ericsson AB 2010
   5 * Author:      Sjur Brendeland/sjur.brandeland@stericsson.com
   6 * License terms: GNU General Public License (GPL) version 2
   7 */
   8
   9#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
  10
  11#include <linux/stddef.h>
  12#include <linux/spinlock.h>
  13#include <linux/slab.h>
  14#include <linux/crc-ccitt.h>
  15#include <net/caif/caif_layer.h>
  16#include <net/caif/cfpkt.h>
  17#include <net/caif/cffrml.h>
  18
  19#define container_obj(layr) container_of(layr, struct cffrml, layer)
  20
  21struct cffrml {
  22        struct cflayer layer;
  23        bool dofcs;             /* !< FCS active */
  24};
  25
  26static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt);
  27static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt);
  28static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  29                                int phyid);
  30
  31static u32 cffrml_rcv_error;
  32static u32 cffrml_rcv_checsum_error;
  33struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
  34{
  35        struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
  36        if (!this) {
  37                pr_warn("Out of memory\n");
  38                return NULL;
  39        }
  40        caif_assert(offsetof(struct cffrml, layer) == 0);
  41
  42        memset(this, 0, sizeof(struct cflayer));
  43        this->layer.receive = cffrml_receive;
  44        this->layer.transmit = cffrml_transmit;
  45        this->layer.ctrlcmd = cffrml_ctrlcmd;
  46        snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid);
  47        this->dofcs = use_fcs;
  48        this->layer.id = phyid;
  49        return (struct cflayer *) this;
  50}
  51
  52void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up)
  53{
  54        this->up = up;
  55}
  56
  57void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn)
  58{
  59        this->dn = dn;
  60}
  61
  62static u16 cffrml_checksum(u16 chks, void *buf, u16 len)
  63{
  64        /* FIXME: FCS should be moved to glue in order to use OS-Specific
  65         * solutions
  66         */
  67        return crc_ccitt(chks, buf, len);
  68}
  69
  70static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
  71{
  72        u16 tmp;
  73        u16 len;
  74        u16 hdrchks;
  75        u16 pktchks;
  76        struct cffrml *this;
  77        this = container_obj(layr);
  78
  79        cfpkt_extr_head(pkt, &tmp, 2);
  80        len = le16_to_cpu(tmp);
  81
  82        /* Subtract for FCS on length if FCS is not used. */
  83        if (!this->dofcs)
  84                len -= 2;
  85
  86        if (cfpkt_setlen(pkt, len) < 0) {
  87                ++cffrml_rcv_error;
  88                pr_err("Framing length error (%d)\n", len);
  89                cfpkt_destroy(pkt);
  90                return -EPROTO;
  91        }
  92        /*
  93         * Don't do extract if FCS is false, rather do setlen - then we don't
  94         * get a cache-miss.
  95         */
  96        if (this->dofcs) {
  97                cfpkt_extr_trail(pkt, &tmp, 2);
  98                hdrchks = le16_to_cpu(tmp);
  99                pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
 100                if (pktchks != hdrchks) {
 101                        cfpkt_add_trail(pkt, &tmp, 2);
 102                        ++cffrml_rcv_error;
 103                        ++cffrml_rcv_checsum_error;
 104                        pr_info("Frame checksum error (0x%x != 0x%x)\n",
 105                                hdrchks, pktchks);
 106                        return -EILSEQ;
 107                }
 108        }
 109        if (cfpkt_erroneous(pkt)) {
 110                ++cffrml_rcv_error;
 111                pr_err("Packet is erroneous!\n");
 112                cfpkt_destroy(pkt);
 113                return -EPROTO;
 114        }
 115        return layr->up->receive(layr->up, pkt);
 116}
 117
 118static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
 119{
 120        int tmp;
 121        u16 chks;
 122        u16 len;
 123        int ret;
 124        struct cffrml *this = container_obj(layr);
 125        if (this->dofcs) {
 126                chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
 127                tmp = cpu_to_le16(chks);
 128                cfpkt_add_trail(pkt, &tmp, 2);
 129        } else {
 130                cfpkt_pad_trail(pkt, 2);
 131        }
 132        len = cfpkt_getlen(pkt);
 133        tmp = cpu_to_le16(len);
 134        cfpkt_add_head(pkt, &tmp, 2);
 135        cfpkt_info(pkt)->hdr_len += 2;
 136        if (cfpkt_erroneous(pkt)) {
 137                pr_err("Packet is erroneous!\n");
 138                return -EPROTO;
 139        }
 140        ret = layr->dn->transmit(layr->dn, pkt);
 141        if (ret < 0) {
 142                /* Remove header on faulty packet. */
 143                cfpkt_extr_head(pkt, &tmp, 2);
 144        }
 145        return ret;
 146}
 147
 148static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
 149                                        int phyid)
 150{
 151        if (layr->up->ctrlcmd)
 152                layr->up->ctrlcmd(layr->up, ctrl, layr->id);
 153}
 154