cregit-Linux how code gets into the kernel

Release 4.8 net/ncsi/ncsi-rsp.c

Directory: net/ncsi
/*
 * Copyright Gavin Shan, IBM Corporation 2016.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

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

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

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


static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, unsigned short payload) { struct ncsi_rsp_pkt_hdr *h; u32 checksum; __be32 *pchecksum; /* Check NCSI packet header. We don't need validate * the packet type, which should have been checked * before calling this function. */ h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp); if (h->common.revision != NCSI_PKT_REVISION) return -EINVAL; if (ntohs(h->common.length) != payload) return -EINVAL; /* Check on code and reason */ if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) return -EINVAL; /* Validate checksum, which might be zeroes if the * sender doesn't support checksum according to NCSI * specification. */ pchecksum = (__be32 *)((void *)(h + 1) + payload - 4); if (ntohl(*pchecksum) == 0) return 0; checksum = ncsi_calculate_checksum((unsigned char *)h, sizeof(*h) + payload - 4); if (*pchecksum != htonl(checksum)) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan173100.00%1100.00%
Total173100.00%1100.00%


static int ncsi_rsp_handler_cis(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_package *np; struct ncsi_channel *nc; unsigned char id; rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc); if (!nc) { if (ndp->flags & NCSI_DEV_PROBED) return -ENXIO; id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel); nc = ncsi_add_channel(np, id); } return nc ? 0 : -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan121100.00%2100.00%
Total121100.00%2100.00%


static int ncsi_rsp_handler_sp(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_package *np; unsigned char id; /* Add the package if it's not existing. Otherwise, * to change the state of its child channels. */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, NULL); if (!np) { if (ndp->flags & NCSI_DEV_PROBED) return -ENXIO; id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel); np = ncsi_add_package(ndp, id); if (!np) return -ENODEV; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan120100.00%2100.00%
Total120100.00%2100.00%


static int ncsi_rsp_handler_dp(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_package *np; struct ncsi_channel *nc; unsigned long flags; /* Find the package */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, NULL); if (!np) return -ENODEV; /* Change state of all channels attached to the package */ NCSI_FOR_EACH_CHANNEL(np, nc) { spin_lock_irqsave(&nc->lock, flags); nc->state = NCSI_CHANNEL_INACTIVE; spin_unlock_irqrestore(&nc->lock, flags); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan119100.00%1100.00%
Total119100.00%1100.00%


static int ncsi_rsp_handler_ec(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; ncm = &nc->modes[NCSI_MODE_ENABLE]; if (ncm->enable) return -EBUSY; ncm->enable = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan106100.00%1100.00%
Total106100.00%1100.00%


static int ncsi_rsp_handler_dc(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; int ret; ret = ncsi_validate_rsp_pkt(nr, 4); if (ret) return ret; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; ncm = &nc->modes[NCSI_MODE_ENABLE]; if (!ncm->enable) return -EBUSY; ncm->enable = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan126100.00%1100.00%
Total126100.00%1100.00%


static int ncsi_rsp_handler_rc(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; unsigned long flags; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Update state for the specified channel */ spin_lock_irqsave(&nc->lock, flags); nc->state = NCSI_CHANNEL_INACTIVE; spin_unlock_irqrestore(&nc->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan106100.00%1100.00%
Total106100.00%1100.00%


static int ncsi_rsp_handler_ecnt(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; if (ncm->enable) return -EBUSY; ncm->enable = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan106100.00%1100.00%
Total106100.00%1100.00%


static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; if (!ncm->enable) return -EBUSY; ncm->enable = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan107100.00%1100.00%
Total107100.00%1100.00%


static int ncsi_rsp_handler_ae(struct ncsi_request *nr) { struct ncsi_cmd_ae_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if the AEN has been enabled */ ncm = &nc->modes[NCSI_MODE_AEN]; if (ncm->enable) return -EBUSY; /* Update to AEN configuration */ cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd); ncm->enable = 1; ncm->data[0] = cmd->mc_id; ncm->data[1] = ntohl(cmd->mode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan152100.00%1100.00%
Total152100.00%1100.00%


static int ncsi_rsp_handler_sl(struct ncsi_request *nr) { struct ncsi_cmd_sl_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd); ncm = &nc->modes[NCSI_MODE_LINK]; ncm->data[0] = ntohl(cmd->mode); ncm->data[1] = ntohl(cmd->oem_mode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan137100.00%1100.00%
Total137100.00%1100.00%


static int ncsi_rsp_handler_gls(struct ncsi_request *nr) { struct ncsi_rsp_gls_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; unsigned long flags; /* Find the package and channel */ rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; ncm = &nc->modes[NCSI_MODE_LINK]; ncm->data[2] = ntohl(rsp->status); ncm->data[3] = ntohl(rsp->other); ncm->data[4] = ntohl(rsp->oem_status); if (nr->driven) return 0; /* Reset the channel monitor if it has been enabled */ spin_lock_irqsave(&nc->lock, flags); nc->timeout = 0; spin_unlock_irqrestore(&nc->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan172100.00%2100.00%
Total172100.00%2100.00%


static int ncsi_rsp_handler_svf(struct ncsi_request *nr) { struct ncsi_cmd_svf_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_filter *ncf; unsigned short vlan; int ret; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd); ncf = nc->filters[NCSI_FILTER_VLAN]; if (!ncf) return -ENOENT; if (cmd->index >= ncf->total) return -ERANGE; /* Add or remove the VLAN filter */ if (!(cmd->enable & 0x1)) { ret = ncsi_remove_filter(nc, NCSI_FILTER_VLAN, cmd->index); } else { vlan = ntohs(cmd->vlan); ret = ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan189100.00%1100.00%
Total189100.00%1100.00%


static int ncsi_rsp_handler_ev(struct ncsi_request *nr) { struct ncsi_cmd_ev_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if VLAN mode has been enabled */ ncm = &nc->modes[NCSI_MODE_VLAN]; if (ncm->enable) return -EBUSY; /* Update to VLAN mode */ cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd); ncm->enable = 1; ncm->data[0] = ntohl(cmd->mode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan141100.00%1100.00%
Total141100.00%1100.00%


static int ncsi_rsp_handler_dv(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if VLAN mode has been enabled */ ncm = &nc->modes[NCSI_MODE_VLAN]; if (!ncm->enable) return -EBUSY; /* Update to VLAN mode */ ncm->enable = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan109100.00%1100.00%
Total109100.00%1100.00%


static int ncsi_rsp_handler_sma(struct ncsi_request *nr) { struct ncsi_cmd_sma_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_filter *ncf; void *bitmap; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* According to NCSI spec 1.01, the mixed filter table * isn't supported yet. */ cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd); switch (cmd->at_e >> 5) { case 0x0: /* UC address */ ncf = nc->filters[NCSI_FILTER_UC]; break; case 0x1: /* MC address */ ncf = nc->filters[NCSI_FILTER_MC]; break; default: return -EINVAL; } /* Sanity check on the filter */ if (!ncf) return -ENOENT; else if (cmd->index >= ncf->total) return -ERANGE; bitmap = &ncf->bitmap; if (cmd->at_e & 0x1) { if (test_and_set_bit(cmd->index, bitmap)) return -EBUSY; memcpy(ncf->data + 6 * cmd->index, cmd->mac, 6); } else { if (!test_and_clear_bit(cmd->index, bitmap)) return -EBUSY; memset(ncf->data + 6 * cmd->index, 0, 6); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan259100.00%1100.00%
Total259100.00%1100.00%


static int ncsi_rsp_handler_ebf(struct ncsi_request *nr) { struct ncsi_cmd_ebf_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the package and channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if broadcast filter has been enabled */ ncm = &nc->modes[NCSI_MODE_BC]; if (ncm->enable) return -EBUSY; /* Update to broadcast filter mode */ cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd); ncm->enable = 1; ncm->data[0] = ntohl(cmd->mode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan141100.00%1100.00%
Total141100.00%1100.00%


static int ncsi_rsp_handler_dbf(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if broadcast filter isn't enabled */ ncm = &nc->modes[NCSI_MODE_BC]; if (!ncm->enable) return -EBUSY; /* Update to broadcast filter mode */ ncm->enable = 0; ncm->data[0] = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan117100.00%1100.00%
Total117100.00%1100.00%


static int ncsi_rsp_handler_egmf(struct ncsi_request *nr) { struct ncsi_cmd_egmf_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if multicast filter has been enabled */ ncm = &nc->modes[NCSI_MODE_MC]; if (ncm->enable) return -EBUSY; /* Update to multicast filter mode */ cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd); ncm->enable = 1; ncm->data[0] = ntohl(cmd->mode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan141100.00%1100.00%
Total141100.00%1100.00%


static int ncsi_rsp_handler_dgmf(struct ncsi_request *nr) { struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if multicast filter has been enabled */ ncm = &nc->modes[NCSI_MODE_MC]; if (!ncm->enable) return -EBUSY; /* Update to multicast filter mode */ ncm->enable = 0; ncm->data[0] = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan117100.00%1100.00%
Total117100.00%1100.00%


static int ncsi_rsp_handler_snfc(struct ncsi_request *nr) { struct ncsi_cmd_snfc_pkt *cmd; struct ncsi_rsp_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_mode *ncm; /* Find the channel */ rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Check if flow control has been enabled */ ncm = &nc->modes[NCSI_MODE_FC]; if (ncm->enable) return -EBUSY; /* Update to flow control mode */ cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd); ncm->enable = 1; ncm->data[0] = cmd->mode; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
gavin shangavin shan138100.00%1100.00%
Total138100.00%1100.00%


static int ncsi_rsp_handler_gvi(struct ncsi_request *nr) { struct ncsi_rsp_gvi_pkt *rsp; struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_channel *nc; struct ncsi_channel_version *ncv; int i; /* Find the channel */ rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp); ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); if (!nc) return -ENODEV; /* Update to channel's version info */ ncv = &nc->version; ncv->version = ntohl(rsp->ncsi_version); ncv->alpha2 = rsp->alpha2; memcpy(ncv->fw_name, rsp->fw_name, 12); ncv