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