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