Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ncsi-cmd.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright Gavin Shan, IBM Corporation 2016.
 */


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>

#include <net/ncsi.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/genetlink.h>

#include "internal.h"
#include "ncsi-pkt.h"

static const int padding_bytes = 26;

u32 ncsi_calculate_checksum(unsigned char *data, int len)
{
 u32 checksum = 0;
 int i;

 for (i = 0; i < len; i += 2)
  checksum += (((u32)data[i] << 8) | data[i + 1]);

 checksum = (~checksum + 1);
 return checksum;
}

/* This function should be called after the data area has been
 * populated completely.
 */

static void ncsi_cmd_build_header(struct ncsi_pkt_hdr *h,
      struct ncsi_cmd_arg *nca)
{
 u32 checksum;
 __be32 *pchecksum;

 h->mc_id        = 0;
 h->revision     = NCSI_PKT_REVISION;
 h->reserved     = 0;
 h->id           = nca->id;
 h->type         = nca->type;
 h->channel      = NCSI_TO_CHANNEL(nca->package,
       nca->channel);
 h->length       = htons(nca->payload);
 h->reserved1[0] = 0;
 h->reserved1[1] = 0;

 /* Fill with calculated checksum */
 checksum = ncsi_calculate_checksum((unsigned char *)h,
        sizeof(*h) + nca->payload);
 pchecksum = (__be32 *)((void *)h + sizeof(struct ncsi_pkt_hdr) +
      ALIGN(nca->payload, 4));
 *pchecksum = htonl(checksum);
}

static int ncsi_cmd_handler_default(struct sk_buff *skb,
        struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_sp(struct sk_buff *skb,
          struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_sp_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->hw_arbitration = nca->bytes[0];
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_dc(struct sk_buff *skb,
          struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_dc_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->ald = nca->bytes[0];
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_rc(struct sk_buff *skb,
          struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_rc_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_ae(struct sk_buff *skb,
          struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_ae_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->mc_id = nca->bytes[0];
 cmd->mode = htonl(nca->dwords[1]);
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_sl(struct sk_buff *skb,
          struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_sl_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->mode = htonl(nca->dwords[0]);
 cmd->oem_mode = htonl(nca->dwords[1]);
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_svf(struct sk_buff *skb,
    struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_svf_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->vlan = htons(nca->words[1]);
 cmd->index = nca->bytes[6];
 cmd->enable = nca->bytes[7];
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_ev(struct sk_buff *skb,
          struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_ev_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->mode = nca->bytes[3];
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_sma(struct sk_buff *skb,
    struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_sma_pkt *cmd;
 int i;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 for (i = 0; i < 6; i++)
  cmd->mac[i] = nca->bytes[i];
 cmd->index = nca->bytes[6];
 cmd->at_e = nca->bytes[7];
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_ebf(struct sk_buff *skb,
    struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_ebf_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->mode = htonl(nca->dwords[0]);
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_egmf(struct sk_buff *skb,
     struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_egmf_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->mode = htonl(nca->dwords[0]);
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
     struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_snfc_pkt *cmd;

 cmd = skb_put_zero(skb, sizeof(*cmd));
 cmd->mode = nca->bytes[0];
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static int ncsi_cmd_handler_oem(struct sk_buff *skb,
    struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_oem_pkt *cmd;
 unsigned int len;
 int payload;
 /* NC-SI spec DSP_0222_1.2.0, section 8.2.2.2
 * requires payload to be padded with 0 to
 * 32-bit boundary before the checksum field.
 * Ensure the padding bytes are accounted for in
 * skb allocation
 */


 payload = ALIGN(nca->payload, 4);
 len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
 len += max(payload, padding_bytes);

 cmd = skb_put_zero(skb, len);
 unsafe_memcpy(&cmd->mfr_id, nca->data, nca->payload,
        /* skb allocated with enough to load the payload */);
 ncsi_cmd_build_header(&cmd->cmd.common, nca);

 return 0;
}

static struct ncsi_cmd_handler {
 unsigned char type;
 int           payload;
 int           (*handler)(struct sk_buff *skb,
     struct ncsi_cmd_arg *nca);
} ncsi_cmd_handlers[] = {
 { NCSI_PKT_CMD_CIS,    0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_SP,     4, ncsi_cmd_handler_sp      },
 { NCSI_PKT_CMD_DP,     0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_EC,     0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_DC,     4, ncsi_cmd_handler_dc      },
 { NCSI_PKT_CMD_RC,     4, ncsi_cmd_handler_rc      },
 { NCSI_PKT_CMD_ECNT,   0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_DCNT,   0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_AE,     8, ncsi_cmd_handler_ae      },
 { NCSI_PKT_CMD_SL,     8, ncsi_cmd_handler_sl      },
 { NCSI_PKT_CMD_GLS,    0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_SVF,    8, ncsi_cmd_handler_svf     },
 { NCSI_PKT_CMD_EV,     4, ncsi_cmd_handler_ev      },
 { NCSI_PKT_CMD_DV,     0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_SMA,    8, ncsi_cmd_handler_sma     },
 { NCSI_PKT_CMD_EBF,    4, ncsi_cmd_handler_ebf     },
 { NCSI_PKT_CMD_DBF,    0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_EGMF,   4, ncsi_cmd_handler_egmf    },
 { NCSI_PKT_CMD_DGMF,   0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_SNFC,   4, ncsi_cmd_handler_snfc    },
 { NCSI_PKT_CMD_GVI,    0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GC,     0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GP,     0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GCPS,   0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GNS,    0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GNPTS,  0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GPS,    0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_OEM,   -1, ncsi_cmd_handler_oem     },
 { NCSI_PKT_CMD_PLDM,   0, NULL                     },
 { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default },
 { NCSI_PKT_CMD_GMCMA,  0, ncsi_cmd_handler_default }
};

static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
{
 struct ncsi_dev_priv *ndp = nca->ndp;
 struct ncsi_dev *nd = &ndp->ndev;
 struct net_device *dev = nd->dev;
 int hlen = LL_RESERVED_SPACE(dev);
 int tlen = dev->needed_tailroom;
 int payload;
 int len = hlen + tlen;
 struct sk_buff *skb;
 struct ncsi_request *nr;

 nr = ncsi_alloc_request(ndp, nca->req_flags);
 if (!nr)
  return NULL;

 /* NCSI command packet has 16-bytes header, payload, 4 bytes checksum.
 * Payload needs padding so that the checksum field following payload is
 * aligned to 32-bit boundary.
 * The packet needs padding if its payload is less than 26 bytes to
 * meet 64 bytes minimal ethernet frame length.
 */

 len += sizeof(struct ncsi_cmd_pkt_hdr) + 4;
 payload = ALIGN(nca->payload, 4);
 len += max(payload, padding_bytes);

 /* Allocate skb */
 skb = alloc_skb(len, GFP_ATOMIC);
 if (!skb) {
  ncsi_free_request(nr);
  return NULL;
 }

 nr->cmd = skb;
 skb_reserve(skb, hlen);
 skb_reset_network_header(skb);

 skb->dev = dev;
 skb->protocol = htons(ETH_P_NCSI);

 return nr;
}

int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
{
 struct ncsi_cmd_handler *nch = NULL;
 struct ncsi_request *nr;
 unsigned char type;
 struct ethhdr *eh;
 int i, ret;

 /* Use OEM generic handler for Netlink request */
 if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN)
  type = NCSI_PKT_CMD_OEM;
 else
  type = nca->type;

 /* Search for the handler */
 for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
  if (ncsi_cmd_handlers[i].type == type) {
   if (ncsi_cmd_handlers[i].handler)
    nch = &ncsi_cmd_handlers[i];
   else
    nch = NULL;

   break;
  }
 }

 if (!nch) {
  netdev_err(nca->ndp->ndev.dev,
      "Cannot send packet with type 0x%02x\n", nca->type);
  return -ENOENT;
 }

 /* Get packet payload length and allocate the request
 * It is expected that if length set as negative in
 * handler structure means caller is initializing it
 * and setting length in nca before calling xmit function
 */

 if (nch->payload >= 0)
  nca->payload = nch->payload;
 nr = ncsi_alloc_command(nca);
 if (!nr)
  return -ENOMEM;

 /* track netlink information */
 if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
  nr->snd_seq = nca->info->snd_seq;
  nr->snd_portid = nca->info->snd_portid;
  nr->nlhdr = *nca->info->nlhdr;
 }

 /* Prepare the packet */
 nca->id = nr->id;
 ret = nch->handler(nr->cmd, nca);
 if (ret) {
  ncsi_free_request(nr);
  return ret;
 }

 /* Fill the ethernet header */
 eh = skb_push(nr->cmd, sizeof(*eh));
 eh->h_proto = htons(ETH_P_NCSI);
 eth_broadcast_addr(eh->h_dest);

 /* If mac address received from device then use it for
 * source address as unicast address else use broadcast
 * address as source address
 */

 if (nca->ndp->gma_flag == 1)
  memcpy(eh->h_source, nca->ndp->ndev.dev->dev_addr, ETH_ALEN);
 else
  eth_broadcast_addr(eh->h_source);

 /* Start the timer for the request that might not have
 * corresponding response. Given NCSI is an internal
 * connection a 1 second delay should be sufficient.
 */

 nr->enabled = true;
 mod_timer(&nr->timer, jiffies + 1 * HZ);

 /* Send NCSI packet */
 skb_get(nr->cmd);
 ret = dev_queue_xmit(nr->cmd);
 if (ret < 0) {
  ncsi_free_request(nr);
  return ret;
 }

 return 0;
}

Messung V0.5
C=96 H=98 G=96

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge