cregit-Linux how code gets into the kernel

Release 4.11 net/caif/cfrfml.c

Directory: net/caif
/*
 * Copyright (C) ST-Ericsson AB 2010
 * Author:      Sjur Brendeland
 * License terms: GNU General Public License (GPL) version 2
 */


#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__

#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfsrvl.h>
#include <net/caif/cfpkt.h>


#define container_obj(layr) container_of(layr, struct cfrfml, serv.layer)

#define RFM_SEGMENTATION_BIT 0x01

#define RFM_HEAD_SIZE 7

static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);


struct cfrfml {
	
struct cfsrvl serv;
	
struct cfpkt *incomplete_frm;
	
int fragment_size;
	
u8  seghead[6];
	
u16 pdu_size;
	/* Protects serialized processing of packets */
	
spinlock_t sync;
};


static void cfrfml_release(struct cflayer *layer) { struct cfsrvl *srvl = container_of(layer, struct cfsrvl, layer); struct cfrfml *rfml = container_obj(&srvl->layer); if (rfml->incomplete_frm) cfpkt_destroy(rfml->incomplete_frm); kfree(srvl); }

Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland57100.00%2100.00%
Total57100.00%2100.00%


struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info, int mtu_size) { int tmp; struct cfrfml *this = kzalloc(sizeof(struct cfrfml), GFP_ATOMIC); if (!this) return NULL; cfsrvl_init(&this->serv, channel_id, dev_info, false); this->serv.release = cfrfml_release; this->serv.layer.receive = cfrfml_receive; this->serv.layer.transmit = cfrfml_transmit; /* Round down to closest multiple of 16 */ tmp = (mtu_size - RFM_HEAD_SIZE - 6) / 16; tmp *= 16; this->fragment_size = tmp; spin_lock_init(&this->sync); snprintf(this->serv.layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id); return &this->serv.layer; }

Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland143100.00%3100.00%
Total143100.00%3100.00%


static struct cfpkt *rfm_append(struct cfrfml *rfml, char *seghead, struct cfpkt *pkt, int *err) { struct cfpkt *tmppkt; *err = -EPROTO; /* n-th but not last segment */ if (cfpkt_extr_head(pkt, seghead, 6) < 0) return NULL; /* Verify correct header */ if (memcmp(seghead, rfml->seghead, 6) != 0) return NULL; tmppkt = cfpkt_append(rfml->incomplete_frm, pkt, rfml->pdu_size + RFM_HEAD_SIZE); /* If cfpkt_append failes input pkts are not freed */ *err = -ENOMEM; if (tmppkt == NULL) return NULL; *err = 0; return tmppkt; }

Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland114100.00%2100.00%
Total114100.00%2100.00%


static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt) { u8 tmp; bool segmented; int err; u8 seghead[6]; struct cfrfml *rfml; struct cfpkt *tmppkt = NULL; caif_assert(layr->up != NULL); caif_assert(layr->receive != NULL); rfml = container_obj(layr); spin_lock(&rfml->sync); err = -EPROTO; if (cfpkt_extr_head(pkt, &tmp, 1) < 0) goto out; segmented = tmp & RFM_SEGMENTATION_BIT; if (segmented) { if (rfml->incomplete_frm == NULL) { /* Initial Segment */ if (cfpkt_peek_head(pkt, rfml->seghead, 6) < 0) goto out; rfml->pdu_size = get_unaligned_le16(rfml->seghead+4); if (cfpkt_erroneous(pkt)) goto out; rfml->incomplete_frm = pkt; pkt = NULL; } else { tmppkt = rfm_append(rfml, seghead, pkt, &err); if (tmppkt == NULL) goto out; if (cfpkt_erroneous(tmppkt)) goto out; rfml->incomplete_frm = tmppkt; if (cfpkt_erroneous(tmppkt)) goto out; } err = 0; goto out; } if (rfml->incomplete_frm) { /* Last Segment */ tmppkt = rfm_append(rfml, seghead, pkt, &err); if (tmppkt == NULL) goto out; if (cfpkt_erroneous(tmppkt)) goto out; rfml->incomplete_frm = NULL; pkt = tmppkt; tmppkt = NULL; /* Verify that length is correct */ err = -EPROTO; if (rfml->pdu_size != cfpkt_getlen(pkt) - RFM_HEAD_SIZE + 1) goto out; } err = rfml->serv.layer.up->receive(rfml->serv.layer.up, pkt); out: if (err != 0) { if (tmppkt) cfpkt_destroy(tmppkt); if (pkt) cfpkt_destroy(pkt); if (rfml->incomplete_frm) cfpkt_destroy(rfml->incomplete_frm); rfml->incomplete_frm = NULL; pr_info("Connection error %d triggered on RFM link\n", err); /* Trigger connection error upon failure.*/ layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, rfml->serv.dev_info.id); } spin_unlock(&rfml->sync); if (unlikely(err == -EAGAIN)) /* It is not possible to recover after drop of a fragment */ err = -EIO; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland42096.11%250.00%
Dmitry Tarnyagin163.66%125.00%
Anton Protopopov10.23%125.00%
Total437100.00%4100.00%


static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt) { caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size + RFM_HEAD_SIZE); /* Add info for MUX-layer to route the packet out. */ cfpkt_info(pkt)->channel_id = rfml->serv.layer.id; /* * To optimize alignment, we add up the size of CAIF header before * payload. */ cfpkt_info(pkt)->hdr_len = RFM_HEAD_SIZE; cfpkt_info(pkt)->dev_info = &rfml->serv.dev_info; return rfml->serv.layer.dn->transmit(rfml->serv.layer.dn, pkt); }

Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland9198.91%266.67%
André Carvalho de Matos11.09%133.33%
Total92100.00%3100.00%


static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) { int err; u8 seg; u8 head[6]; struct cfpkt *rearpkt = NULL; struct cfpkt *frontpkt = pkt; struct cfrfml *rfml = container_obj(layr); caif_assert(layr->dn != NULL); caif_assert(layr->dn->transmit != NULL); if (!cfsrvl_ready(&rfml->serv, &err)) goto out; err = -EPROTO; if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1) goto out; err = 0; if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE) err = cfpkt_peek_head(pkt, head, 6); if (err < 0) goto out; while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) { seg = 1; err = -EPROTO; if (cfpkt_add_head(frontpkt, &seg, 1) < 0) goto out; /* * On OOM error cfpkt_split returns NULL. * * NOTE: Segmented pdu is not correctly aligned. * This has negative performance impact. */ rearpkt = cfpkt_split(frontpkt, rfml->fragment_size); if (rearpkt == NULL) goto out; err = cfrfml_transmit_segment(rfml, frontpkt); if (err != 0) { frontpkt = NULL; goto out; } frontpkt = rearpkt; rearpkt = NULL; err = -ENOMEM; if (frontpkt == NULL) goto out; err = -EPROTO; if (cfpkt_add_head(frontpkt, head, 6) < 0) goto out; } seg = 0; err = -EPROTO; if (cfpkt_add_head(frontpkt, &seg, 1) < 0) goto out; err = cfrfml_transmit_segment(rfml, frontpkt); frontpkt = NULL; out: if (err != 0) { pr_info("Connection error %d triggered on RFM link\n", err); /* Trigger connection error upon failure.*/ layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, rfml->serv.dev_info.id); if (rearpkt) cfpkt_destroy(rearpkt); if (frontpkt) cfpkt_destroy(frontpkt); } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland36497.59%266.67%
Dmitry Tarnyagin92.41%133.33%
Total373100.00%3100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Sjur Brændeland128597.35%654.55%
Dmitry Tarnyagin251.89%19.09%
Joe Perches70.53%19.09%
Anton Protopopov10.08%19.09%
André Carvalho de Matos10.08%19.09%
Jeff Mahoney10.08%19.09%
Total1320100.00%11100.00%
Directory: net/caif
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.