linux/net/caif/cfutill.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) ST-Ericsson AB 2010
   4 * Author:      Sjur Brendeland
   5 */
   6
   7#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
   8
   9#include <linux/kernel.h>
  10#include <linux/types.h>
  11#include <linux/slab.h>
  12#include <linux/errno.h>
  13#include <net/caif/caif_layer.h>
  14#include <net/caif/cfsrvl.h>
  15#include <net/caif/cfpkt.h>
  16
  17#define container_obj(layr) ((struct cfsrvl *) layr)
  18#define UTIL_PAYLOAD  0x00
  19#define UTIL_CMD_BIT  0x80
  20#define UTIL_REMOTE_SHUTDOWN 0x82
  21#define UTIL_FLOW_OFF 0x81
  22#define UTIL_FLOW_ON  0x80
  23
  24static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt);
  25static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt);
  26
  27struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
  28{
  29        struct cfsrvl *util = kzalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
  30        if (!util)
  31                return NULL;
  32        caif_assert(offsetof(struct cfsrvl, layer) == 0);
  33        cfsrvl_init(util, channel_id, dev_info, true);
  34        util->layer.receive = cfutill_receive;
  35        util->layer.transmit = cfutill_transmit;
  36        snprintf(util->layer.name, CAIF_LAYER_NAME_SZ, "util1");
  37        return &util->layer;
  38}
  39
  40static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
  41{
  42        u8 cmd = -1;
  43        struct cfsrvl *service = container_obj(layr);
  44        caif_assert(layr != NULL);
  45        caif_assert(layr->up != NULL);
  46        caif_assert(layr->up->receive != NULL);
  47        caif_assert(layr->up->ctrlcmd != NULL);
  48        if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
  49                pr_err("Packet is erroneous!\n");
  50                cfpkt_destroy(pkt);
  51                return -EPROTO;
  52        }
  53
  54        switch (cmd) {
  55        case UTIL_PAYLOAD:
  56                return layr->up->receive(layr->up, pkt);
  57        case UTIL_FLOW_OFF:
  58                layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
  59                cfpkt_destroy(pkt);
  60                return 0;
  61        case UTIL_FLOW_ON:
  62                layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
  63                cfpkt_destroy(pkt);
  64                return 0;
  65        case UTIL_REMOTE_SHUTDOWN:      /* Remote Shutdown Request */
  66                pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n");
  67                layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
  68                service->open = false;
  69                cfpkt_destroy(pkt);
  70                return 0;
  71        default:
  72                cfpkt_destroy(pkt);
  73                pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd);
  74                return -EPROTO;
  75        }
  76}
  77
  78static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
  79{
  80        u8 zero = 0;
  81        struct caif_payload_info *info;
  82        int ret;
  83        struct cfsrvl *service = container_obj(layr);
  84        caif_assert(layr != NULL);
  85        caif_assert(layr->dn != NULL);
  86        caif_assert(layr->dn->transmit != NULL);
  87
  88        if (!cfsrvl_ready(service, &ret)) {
  89                cfpkt_destroy(pkt);
  90                return ret;
  91        }
  92
  93        cfpkt_add_head(pkt, &zero, 1);
  94        /* Add info for MUX-layer to route the packet out. */
  95        info = cfpkt_info(pkt);
  96        info->channel_id = service->layer.id;
  97        /*
  98         * To optimize alignment, we add up the size of CAIF header before
  99         * payload.
 100         */
 101        info->hdr_len = 1;
 102        info->dev_info = &service->dev_info;
 103        return layr->dn->transmit(layr->dn, pkt);
 104}
 105