hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/net/ncsi/ncsi-cmd.c
....@@ -1,10 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * 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.
84 */
95
106 #include <linux/module.h>
....@@ -17,9 +13,12 @@
1713 #include <net/ncsi.h>
1814 #include <net/net_namespace.h>
1915 #include <net/sock.h>
16
+#include <net/genetlink.h>
2017
2118 #include "internal.h"
2219 #include "ncsi-pkt.h"
20
+
21
+static const int padding_bytes = 26;
2322
2423 u32 ncsi_calculate_checksum(unsigned char *data, int len)
2524 {
....@@ -57,7 +56,7 @@
5756 checksum = ncsi_calculate_checksum((unsigned char *)h,
5857 sizeof(*h) + nca->payload);
5958 pchecksum = (__be32 *)((void *)h + sizeof(struct ncsi_pkt_hdr) +
60
- nca->payload);
59
+ ALIGN(nca->payload, 4));
6160 *pchecksum = htonl(checksum);
6261 }
6362
....@@ -211,6 +210,30 @@
211210 return 0;
212211 }
213212
213
+static int ncsi_cmd_handler_oem(struct sk_buff *skb,
214
+ struct ncsi_cmd_arg *nca)
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 8.2.2.2
220
+ * requires payload to be padded with 0 to
221
+ * 32-bit boundary before the checksum field.
222
+ * Ensure the padding bytes are accounted for in
223
+ * skb allocation
224
+ */
225
+
226
+ payload = ALIGN(nca->payload, 4);
227
+ len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
228
+ len += max(payload, padding_bytes);
229
+
230
+ cmd = skb_put_zero(skb, len);
231
+ memcpy(&cmd->mfr_id, nca->data, nca->payload);
232
+ ncsi_cmd_build_header(&cmd->cmd.common, nca);
233
+
234
+ return 0;
235
+}
236
+
214237 static struct ncsi_cmd_handler {
215238 unsigned char type;
216239 int payload;
....@@ -244,7 +267,7 @@
244267 { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
245268 { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
246269 { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
247
- { NCSI_PKT_CMD_OEM, 0, NULL },
270
+ { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
248271 { NCSI_PKT_CMD_PLDM, 0, NULL },
249272 { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
250273 };
....@@ -256,6 +279,7 @@
256279 struct net_device *dev = nd->dev;
257280 int hlen = LL_RESERVED_SPACE(dev);
258281 int tlen = dev->needed_tailroom;
282
+ int payload;
259283 int len = hlen + tlen;
260284 struct sk_buff *skb;
261285 struct ncsi_request *nr;
....@@ -265,14 +289,14 @@
265289 return NULL;
266290
267291 /* NCSI command packet has 16-bytes header, payload, 4 bytes checksum.
292
+ * Payload needs padding so that the checksum field following payload is
293
+ * aligned to 32-bit boundary.
268294 * The packet needs padding if its payload is less than 26 bytes to
269295 * meet 64 bytes minimal ethernet frame length.
270296 */
271297 len += sizeof(struct ncsi_cmd_pkt_hdr) + 4;
272
- if (nca->payload < 26)
273
- len += 26;
274
- else
275
- len += nca->payload;
298
+ payload = ALIGN(nca->payload, 4);
299
+ len += max(payload, padding_bytes);
276300
277301 /* Allocate skb */
278302 skb = alloc_skb(len, GFP_ATOMIC);
....@@ -293,14 +317,21 @@
293317
294318 int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
295319 {
296
- struct ncsi_request *nr;
297
- struct ethhdr *eh;
298320 struct ncsi_cmd_handler *nch = NULL;
321
+ struct ncsi_request *nr;
322
+ unsigned char type;
323
+ struct ethhdr *eh;
299324 int i, ret;
325
+
326
+ /* Use OEM generic handler for Netlink request */
327
+ if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN)
328
+ type = NCSI_PKT_CMD_OEM;
329
+ else
330
+ type = nca->type;
300331
301332 /* Search for the handler */
302333 for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
303
- if (ncsi_cmd_handlers[i].type == nca->type) {
334
+ if (ncsi_cmd_handlers[i].type == type) {
304335 if (ncsi_cmd_handlers[i].handler)
305336 nch = &ncsi_cmd_handlers[i];
306337 else
....@@ -316,11 +347,23 @@
316347 return -ENOENT;
317348 }
318349
319
- /* Get packet payload length and allocate the request */
320
- nca->payload = nch->payload;
350
+ /* Get packet payload length and allocate the request
351
+ * It is expected that if length set as negative in
352
+ * handler structure means caller is initializing it
353
+ * and setting length in nca before calling xmit function
354
+ */
355
+ if (nch->payload >= 0)
356
+ nca->payload = nch->payload;
321357 nr = ncsi_alloc_command(nca);
322358 if (!nr)
323359 return -ENOMEM;
360
+
361
+ /* track netlink information */
362
+ if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
363
+ nr->snd_seq = nca->info->snd_seq;
364
+ nr->snd_portid = nca->info->snd_portid;
365
+ nr->nlhdr = *nca->info->nlhdr;
366
+ }
324367
325368 /* Prepare the packet */
326369 nca->id = nr->id;
....@@ -334,7 +377,15 @@
334377 eh = skb_push(nr->cmd, sizeof(*eh));
335378 eh->h_proto = htons(ETH_P_NCSI);
336379 eth_broadcast_addr(eh->h_dest);
337
- eth_broadcast_addr(eh->h_source);
380
+
381
+ /* If mac address received from device then use it for
382
+ * source address as unicast address else use broadcast
383
+ * address as source address
384
+ */
385
+ if (nca->ndp->gma_flag == 1)
386
+ memcpy(eh->h_source, nca->ndp->ndev.dev->dev_addr, ETH_ALEN);
387
+ else
388
+ eth_broadcast_addr(eh->h_source);
338389
339390 /* Start the timer for the request that might not have
340391 * corresponding response. Given NCSI is an internal