qemu/slirp/src/ncsi.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause */
   2/*
   3 * NC-SI (Network Controller Sideband Interface) "echo" model
   4 *
   5 * Copyright (C) 2016-2018 IBM Corp.
   6 *
   7 * Redistribution and use in source and binary forms, with or without
   8 * modification, are permitted provided that the following conditions
   9 * are met:
  10 *
  11 * 1. Redistributions of source code must retain the above
  12 * copyright notice, this list of conditions and the following
  13 * disclaimer.
  14 *
  15 * 2. Redistributions in binary form must reproduce the above
  16 * copyright notice, this list of conditions and the following
  17 * disclaimer in the documentation and/or other materials provided
  18 * with the distribution.
  19 *
  20 * 3. Neither the name of the copyright holder nor the names of its
  21 * contributors may be used to endorse or promote products derived
  22 * from this software without specific prior written permission.
  23 *
  24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  28 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  35 * OF THE POSSIBILITY OF SUCH DAMAGE.
  36 */
  37#include "slirp.h"
  38
  39#include "ncsi-pkt.h"
  40
  41static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
  42{
  43    uint32_t checksum = 0;
  44    int i;
  45
  46    /*
  47     * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
  48     * payload interpreted as a series of 16-bit unsigned integer values.
  49     */
  50    for (i = 0; i < len; i++) {
  51        checksum += htons(data[i]);
  52    }
  53
  54    checksum = (~checksum + 1);
  55    return checksum;
  56}
  57
  58/* Get Capabilities */
  59static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
  60{
  61    struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *) rnh;
  62
  63    rsp->cap = htonl(~0);
  64    rsp->bc_cap = htonl(~0);
  65    rsp->mc_cap = htonl(~0);
  66    rsp->buf_cap = htonl(~0);
  67    rsp->aen_cap = htonl(~0);
  68    rsp->vlan_mode = 0xff;
  69    rsp->uc_cnt = 2;
  70    return 0;
  71}
  72
  73/* Get Link status */
  74static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
  75{
  76    struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *) rnh;
  77
  78    rsp->status = htonl(0x1);
  79    return 0;
  80}
  81
  82/* Get Parameters */
  83static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
  84{
  85    struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *) rnh;
  86
  87    /* no MAC address filters or VLAN filters on the channel */
  88    rsp->mac_cnt = 0;
  89    rsp->mac_enable = 0;
  90    rsp->vlan_cnt = 0;
  91    rsp->vlan_enable = 0;
  92
  93    return 0;
  94}
  95
  96static const struct ncsi_rsp_handler {
  97        unsigned char   type;
  98        int             payload;
  99        int             (*handler)(struct ncsi_rsp_pkt_hdr *rnh);
 100} ncsi_rsp_handlers[] = {
 101        { NCSI_PKT_RSP_CIS,     4, NULL },
 102        { NCSI_PKT_RSP_SP,      4, NULL },
 103        { NCSI_PKT_RSP_DP,      4, NULL },
 104        { NCSI_PKT_RSP_EC,      4, NULL },
 105        { NCSI_PKT_RSP_DC,      4, NULL },
 106        { NCSI_PKT_RSP_RC,      4, NULL },
 107        { NCSI_PKT_RSP_ECNT,    4, NULL },
 108        { NCSI_PKT_RSP_DCNT,    4, NULL },
 109        { NCSI_PKT_RSP_AE,      4, NULL },
 110        { NCSI_PKT_RSP_SL,      4, NULL },
 111        { NCSI_PKT_RSP_GLS,    16, ncsi_rsp_handler_gls },
 112        { NCSI_PKT_RSP_SVF,     4, NULL },
 113        { NCSI_PKT_RSP_EV,      4, NULL },
 114        { NCSI_PKT_RSP_DV,      4, NULL },
 115        { NCSI_PKT_RSP_SMA,     4, NULL },
 116        { NCSI_PKT_RSP_EBF,     4, NULL },
 117        { NCSI_PKT_RSP_DBF,     4, NULL },
 118        { NCSI_PKT_RSP_EGMF,    4, NULL },
 119        { NCSI_PKT_RSP_DGMF,    4, NULL },
 120        { NCSI_PKT_RSP_SNFC,    4, NULL },
 121        { NCSI_PKT_RSP_GVI,    40, NULL },
 122        { NCSI_PKT_RSP_GC,     32, ncsi_rsp_handler_gc },
 123        { NCSI_PKT_RSP_GP,     40, ncsi_rsp_handler_gp },
 124        { NCSI_PKT_RSP_GCPS,  172, NULL },
 125        { NCSI_PKT_RSP_GNS,   172, NULL },
 126        { NCSI_PKT_RSP_GNPTS, 172, NULL },
 127        { NCSI_PKT_RSP_GPS,     8, NULL },
 128        { NCSI_PKT_RSP_OEM,     0, NULL },
 129        { NCSI_PKT_RSP_PLDM,    0, NULL },
 130        { NCSI_PKT_RSP_GPUUID, 20, NULL }
 131};
 132
 133/*
 134 * packet format : ncsi header + payload + checksum
 135 */
 136#define NCSI_MAX_PAYLOAD 172
 137#define NCSI_MAX_LEN     (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4)
 138
 139void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
 140{
 141    struct ncsi_pkt_hdr *nh = (struct ncsi_pkt_hdr *)(pkt + ETH_HLEN);
 142    uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN];
 143    struct ethhdr *reh = (struct ethhdr *)ncsi_reply;
 144    struct ncsi_rsp_pkt_hdr *rnh = (struct ncsi_rsp_pkt_hdr *)
 145        (ncsi_reply + ETH_HLEN);
 146    const struct ncsi_rsp_handler *handler = NULL;
 147    int i;
 148    int ncsi_rsp_len = sizeof(*nh);
 149    uint32_t checksum;
 150    uint32_t *pchecksum;
 151
 152    memset(ncsi_reply, 0, sizeof(ncsi_reply));
 153
 154    memset(reh->h_dest, 0xff, ETH_ALEN);
 155    memset(reh->h_source, 0xff, ETH_ALEN);
 156    reh->h_proto = htons(ETH_P_NCSI);
 157
 158    for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) {
 159        if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
 160            handler = &ncsi_rsp_handlers[i];
 161            break;
 162        }
 163    }
 164
 165    rnh->common.mc_id      = nh->mc_id;
 166    rnh->common.revision   = NCSI_PKT_REVISION;
 167    rnh->common.id         = nh->id;
 168    rnh->common.type       = nh->type + 0x80;
 169    rnh->common.channel    = nh->channel;
 170
 171    if (handler) {
 172        rnh->common.length = htons(handler->payload);
 173        rnh->code          = htons(NCSI_PKT_RSP_C_COMPLETED);
 174        rnh->reason        = htons(NCSI_PKT_RSP_R_NO_ERROR);
 175
 176        if (handler->handler) {
 177            /* TODO: handle errors */
 178            handler->handler(rnh);
 179        }
 180        ncsi_rsp_len += handler->payload;
 181    } else {
 182        rnh->common.length = 0;
 183        rnh->code          = htons(NCSI_PKT_RSP_C_UNAVAILABLE);
 184        rnh->reason        = htons(NCSI_PKT_RSP_R_UNKNOWN);
 185    }
 186
 187    /* Add the optional checksum at the end of the frame. */
 188    checksum = ncsi_calculate_checksum((uint16_t *) rnh, ncsi_rsp_len);
 189    pchecksum = (uint32_t *)((void *) rnh + ncsi_rsp_len);
 190    *pchecksum = htonl(checksum);
 191    ncsi_rsp_len += 4;
 192
 193    slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
 194}
 195