1 /* 2 * Copyright Gavin Shan, IBM Corporation 2016. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/etherdevice.h> 14 #include <linux/netdevice.h> 15 #include <linux/skbuff.h> 16 17 #include <net/ncsi.h> 18 #include <net/net_namespace.h> 19 #include <net/sock.h> 20 21 #include "internal.h" 22 #include "ncsi-pkt.h" 23 24 u32 ncsi_calculate_checksum(unsigned char *data, int len) 25 { 26 u32 checksum = 0; 27 int i; 28 29 for (i = 0; i < len; i += 2) 30 checksum += (((u32)data[i] << 8) | data[i + 1]); 31 32 checksum = (~checksum + 1); 33 return checksum; 34 } 35 36 /* This function should be called after the data area has been 37 * populated completely. 38 */ 39 static void ncsi_cmd_build_header(struct ncsi_pkt_hdr *h, 40 struct ncsi_cmd_arg *nca) 41 { 42 u32 checksum; 43 __be32 *pchecksum; 44 45 h->mc_id = 0; 46 h->revision = NCSI_PKT_REVISION; 47 h->reserved = 0; 48 h->id = nca->id; 49 h->type = nca->type; 50 h->channel = NCSI_TO_CHANNEL(nca->package, 51 nca->channel); 52 h->length = htons(nca->payload); 53 h->reserved1[0] = 0; 54 h->reserved1[1] = 0; 55 56 /* Fill with calculated checksum */ 57 checksum = ncsi_calculate_checksum((unsigned char *)h, 58 sizeof(*h) + nca->payload); 59 pchecksum = (__be32 *)((void *)h + sizeof(struct ncsi_pkt_hdr) + 60 nca->payload); 61 *pchecksum = htonl(checksum); 62 } 63 64 static int ncsi_cmd_handler_default(struct sk_buff *skb, 65 struct ncsi_cmd_arg *nca) 66 { 67 struct ncsi_cmd_pkt *cmd; 68 69 cmd = (struct ncsi_cmd_pkt *)skb_put(skb, sizeof(*cmd)); 70 memset(cmd, 0, sizeof(*cmd)); 71 ncsi_cmd_build_header(&cmd->cmd.common, nca); 72 73 return 0; 74 } 75 76 static int ncsi_cmd_handler_sp(struct sk_buff *skb, 77 struct ncsi_cmd_arg *nca) 78 { 79 struct ncsi_cmd_sp_pkt *cmd; 80 81 cmd = (struct ncsi_cmd_sp_pkt *)skb_put(skb, sizeof(*cmd)); 82 memset(cmd, 0, sizeof(*cmd)); 83 cmd->hw_arbitration = nca->bytes[0]; 84 ncsi_cmd_build_header(&cmd->cmd.common, nca); 85 86 return 0; 87 } 88 89 static int ncsi_cmd_handler_dc(struct sk_buff *skb, 90 struct ncsi_cmd_arg *nca) 91 { 92 struct ncsi_cmd_dc_pkt *cmd; 93 94 cmd = (struct ncsi_cmd_dc_pkt *)skb_put(skb, sizeof(*cmd)); 95 memset(cmd, 0, sizeof(*cmd)); 96 cmd->ald = nca->bytes[0]; 97 ncsi_cmd_build_header(&cmd->cmd.common, nca); 98 99 return 0; 100 } 101 102 static int ncsi_cmd_handler_rc(struct sk_buff *skb, 103 struct ncsi_cmd_arg *nca) 104 { 105 struct ncsi_cmd_rc_pkt *cmd; 106 107 cmd = (struct ncsi_cmd_rc_pkt *)skb_put(skb, sizeof(*cmd)); 108 memset(cmd, 0, sizeof(*cmd)); 109 ncsi_cmd_build_header(&cmd->cmd.common, nca); 110 111 return 0; 112 } 113 114 static int ncsi_cmd_handler_ae(struct sk_buff *skb, 115 struct ncsi_cmd_arg *nca) 116 { 117 struct ncsi_cmd_ae_pkt *cmd; 118 119 cmd = (struct ncsi_cmd_ae_pkt *)skb_put(skb, sizeof(*cmd)); 120 memset(cmd, 0, sizeof(*cmd)); 121 cmd->mc_id = nca->bytes[0]; 122 cmd->mode = htonl(nca->dwords[1]); 123 ncsi_cmd_build_header(&cmd->cmd.common, nca); 124 125 return 0; 126 } 127 128 static int ncsi_cmd_handler_sl(struct sk_buff *skb, 129 struct ncsi_cmd_arg *nca) 130 { 131 struct ncsi_cmd_sl_pkt *cmd; 132 133 cmd = (struct ncsi_cmd_sl_pkt *)skb_put(skb, sizeof(*cmd)); 134 memset(cmd, 0, sizeof(*cmd)); 135 cmd->mode = htonl(nca->dwords[0]); 136 cmd->oem_mode = htonl(nca->dwords[1]); 137 ncsi_cmd_build_header(&cmd->cmd.common, nca); 138 139 return 0; 140 } 141 142 static int ncsi_cmd_handler_svf(struct sk_buff *skb, 143 struct ncsi_cmd_arg *nca) 144 { 145 struct ncsi_cmd_svf_pkt *cmd; 146 147 cmd = (struct ncsi_cmd_svf_pkt *)skb_put(skb, sizeof(*cmd)); 148 memset(cmd, 0, sizeof(*cmd)); 149 cmd->vlan = htons(nca->words[0]); 150 cmd->index = nca->bytes[2]; 151 cmd->enable = nca->bytes[3]; 152 ncsi_cmd_build_header(&cmd->cmd.common, nca); 153 154 return 0; 155 } 156 157 static int ncsi_cmd_handler_ev(struct sk_buff *skb, 158 struct ncsi_cmd_arg *nca) 159 { 160 struct ncsi_cmd_ev_pkt *cmd; 161 162 cmd = (struct ncsi_cmd_ev_pkt *)skb_put(skb, sizeof(*cmd)); 163 memset(cmd, 0, sizeof(*cmd)); 164 cmd->mode = nca->bytes[0]; 165 ncsi_cmd_build_header(&cmd->cmd.common, nca); 166 167 return 0; 168 } 169 170 static int ncsi_cmd_handler_sma(struct sk_buff *skb, 171 struct ncsi_cmd_arg *nca) 172 { 173 struct ncsi_cmd_sma_pkt *cmd; 174 int i; 175 176 cmd = (struct ncsi_cmd_sma_pkt *)skb_put(skb, sizeof(*cmd)); 177 memset(cmd, 0, sizeof(*cmd)); 178 for (i = 0; i < 6; i++) 179 cmd->mac[i] = nca->bytes[i]; 180 cmd->index = nca->bytes[6]; 181 cmd->at_e = nca->bytes[7]; 182 ncsi_cmd_build_header(&cmd->cmd.common, nca); 183 184 return 0; 185 } 186 187 static int ncsi_cmd_handler_ebf(struct sk_buff *skb, 188 struct ncsi_cmd_arg *nca) 189 { 190 struct ncsi_cmd_ebf_pkt *cmd; 191 192 cmd = (struct ncsi_cmd_ebf_pkt *)skb_put(skb, sizeof(*cmd)); 193 memset(cmd, 0, sizeof(*cmd)); 194 cmd->mode = htonl(nca->dwords[0]); 195 ncsi_cmd_build_header(&cmd->cmd.common, nca); 196 197 return 0; 198 } 199 200 static int ncsi_cmd_handler_egmf(struct sk_buff *skb, 201 struct ncsi_cmd_arg *nca) 202 { 203 struct ncsi_cmd_egmf_pkt *cmd; 204 205 cmd = (struct ncsi_cmd_egmf_pkt *)skb_put(skb, sizeof(*cmd)); 206 memset(cmd, 0, sizeof(*cmd)); 207 cmd->mode = htonl(nca->dwords[0]); 208 ncsi_cmd_build_header(&cmd->cmd.common, nca); 209 210 return 0; 211 } 212 213 static int ncsi_cmd_handler_snfc(struct sk_buff *skb, 214 struct ncsi_cmd_arg *nca) 215 { 216 struct ncsi_cmd_snfc_pkt *cmd; 217 218 cmd = (struct ncsi_cmd_snfc_pkt *)skb_put(skb, sizeof(*cmd)); 219 memset(cmd, 0, sizeof(*cmd)); 220 cmd->mode = nca->bytes[0]; 221 ncsi_cmd_build_header(&cmd->cmd.common, nca); 222 223 return 0; 224 } 225 226 static struct ncsi_cmd_handler { 227 unsigned char type; 228 int payload; 229 int (*handler)(struct sk_buff *skb, 230 struct ncsi_cmd_arg *nca); 231 } ncsi_cmd_handlers[] = { 232 { NCSI_PKT_CMD_CIS, 0, ncsi_cmd_handler_default }, 233 { NCSI_PKT_CMD_SP, 4, ncsi_cmd_handler_sp }, 234 { NCSI_PKT_CMD_DP, 0, ncsi_cmd_handler_default }, 235 { NCSI_PKT_CMD_EC, 0, ncsi_cmd_handler_default }, 236 { NCSI_PKT_CMD_DC, 4, ncsi_cmd_handler_dc }, 237 { NCSI_PKT_CMD_RC, 4, ncsi_cmd_handler_rc }, 238 { NCSI_PKT_CMD_ECNT, 0, ncsi_cmd_handler_default }, 239 { NCSI_PKT_CMD_DCNT, 0, ncsi_cmd_handler_default }, 240 { NCSI_PKT_CMD_AE, 8, ncsi_cmd_handler_ae }, 241 { NCSI_PKT_CMD_SL, 8, ncsi_cmd_handler_sl }, 242 { NCSI_PKT_CMD_GLS, 0, ncsi_cmd_handler_default }, 243 { NCSI_PKT_CMD_SVF, 4, ncsi_cmd_handler_svf }, 244 { NCSI_PKT_CMD_EV, 4, ncsi_cmd_handler_ev }, 245 { NCSI_PKT_CMD_DV, 0, ncsi_cmd_handler_default }, 246 { NCSI_PKT_CMD_SMA, 8, ncsi_cmd_handler_sma }, 247 { NCSI_PKT_CMD_EBF, 4, ncsi_cmd_handler_ebf }, 248 { NCSI_PKT_CMD_DBF, 0, ncsi_cmd_handler_default }, 249 { NCSI_PKT_CMD_EGMF, 4, ncsi_cmd_handler_egmf }, 250 { NCSI_PKT_CMD_DGMF, 0, ncsi_cmd_handler_default }, 251 { NCSI_PKT_CMD_SNFC, 4, ncsi_cmd_handler_snfc }, 252 { NCSI_PKT_CMD_GVI, 0, ncsi_cmd_handler_default }, 253 { NCSI_PKT_CMD_GC, 0, ncsi_cmd_handler_default }, 254 { NCSI_PKT_CMD_GP, 0, ncsi_cmd_handler_default }, 255 { NCSI_PKT_CMD_GCPS, 0, ncsi_cmd_handler_default }, 256 { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default }, 257 { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default }, 258 { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default }, 259 { NCSI_PKT_CMD_OEM, 0, NULL }, 260 { NCSI_PKT_CMD_PLDM, 0, NULL }, 261 { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default } 262 }; 263 264 static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca) 265 { 266 struct ncsi_dev_priv *ndp = nca->ndp; 267 struct ncsi_dev *nd = &ndp->ndev; 268 struct net_device *dev = nd->dev; 269 int hlen = LL_RESERVED_SPACE(dev); 270 int tlen = dev->needed_tailroom; 271 int len = hlen + tlen; 272 struct sk_buff *skb; 273 struct ncsi_request *nr; 274 275 nr = ncsi_alloc_request(ndp, nca->driven); 276 if (!nr) 277 return NULL; 278 279 /* NCSI command packet has 16-bytes header, payload, 4 bytes checksum. 280 * The packet needs padding if its payload is less than 26 bytes to 281 * meet 64 bytes minimal ethernet frame length. 282 */ 283 len += sizeof(struct ncsi_cmd_pkt_hdr) + 4; 284 if (nca->payload < 26) 285 len += 26; 286 else 287 len += nca->payload; 288 289 /* Allocate skb */ 290 skb = alloc_skb(len, GFP_ATOMIC); 291 if (!skb) { 292 ncsi_free_request(nr); 293 return NULL; 294 } 295 296 nr->cmd = skb; 297 skb_reserve(skb, hlen); 298 skb_reset_network_header(skb); 299 300 skb->dev = dev; 301 skb->protocol = htons(ETH_P_NCSI); 302 303 return nr; 304 } 305 306 int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca) 307 { 308 struct ncsi_request *nr; 309 struct ethhdr *eh; 310 struct ncsi_cmd_handler *nch = NULL; 311 int i, ret; 312 313 /* Search for the handler */ 314 for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) { 315 if (ncsi_cmd_handlers[i].type == nca->type) { 316 if (ncsi_cmd_handlers[i].handler) 317 nch = &ncsi_cmd_handlers[i]; 318 else 319 nch = NULL; 320 321 break; 322 } 323 } 324 325 if (!nch) { 326 netdev_err(nca->ndp->ndev.dev, 327 "Cannot send packet with type 0x%02x\n", nca->type); 328 return -ENOENT; 329 } 330 331 /* Get packet payload length and allocate the request */ 332 nca->payload = nch->payload; 333 nr = ncsi_alloc_command(nca); 334 if (!nr) 335 return -ENOMEM; 336 337 /* Prepare the packet */ 338 nca->id = nr->id; 339 ret = nch->handler(nr->cmd, nca); 340 if (ret) { 341 ncsi_free_request(nr); 342 return ret; 343 } 344 345 /* Fill the ethernet header */ 346 eh = (struct ethhdr *)skb_push(nr->cmd, sizeof(*eh)); 347 eh->h_proto = htons(ETH_P_NCSI); 348 eth_broadcast_addr(eh->h_dest); 349 eth_broadcast_addr(eh->h_source); 350 351 /* Start the timer for the request that might not have 352 * corresponding response. Given NCSI is an internal 353 * connection a 1 second delay should be sufficient. 354 */ 355 nr->enabled = true; 356 mod_timer(&nr->timer, jiffies + 1 * HZ); 357 358 /* Send NCSI packet */ 359 skb_get(nr->cmd); 360 ret = dev_queue_xmit(nr->cmd); 361 if (ret < 0) { 362 ncsi_free_request(nr); 363 return ret; 364 } 365 366 return 0; 367 } 368