|
19 | 19 | #include "ncsi-pkt.h" |
20 | 20 | #include "ncsi-netlink.h" |
21 | 21 |
|
| 22 | +/* Nibbles within [0xA, 0xF] add zero "0" to the returned value. |
| 23 | + * Optional fields (encoded as 0xFF) will default to zero. |
| 24 | + */ |
| 25 | +static u8 decode_bcd_u8(u8 x) |
| 26 | +{ |
| 27 | + int lo = x & 0xF; |
| 28 | + int hi = x >> 4; |
| 29 | + |
| 30 | + lo = lo < 0xA ? lo : 0; |
| 31 | + hi = hi < 0xA ? hi : 0; |
| 32 | + return lo + hi * 10; |
| 33 | +} |
| 34 | + |
22 | 35 | static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, |
23 | 36 | unsigned short payload) |
24 | 37 | { |
@@ -755,9 +768,18 @@ static int ncsi_rsp_handler_gvi(struct ncsi_request *nr) |
755 | 768 | if (!nc) |
756 | 769 | return -ENODEV; |
757 | 770 |
|
758 | | - /* Update to channel's version info */ |
| 771 | + /* Update channel's version info |
| 772 | + * |
| 773 | + * Major, minor, and update fields are supposed to be |
| 774 | + * unsigned integers encoded as packed BCD. |
| 775 | + * |
| 776 | + * Alpha1 and alpha2 are ISO/IEC 8859-1 characters. |
| 777 | + */ |
759 | 778 | ncv = &nc->version; |
760 | | - ncv->version = ntohl(rsp->ncsi_version); |
| 779 | + ncv->major = decode_bcd_u8(rsp->major); |
| 780 | + ncv->minor = decode_bcd_u8(rsp->minor); |
| 781 | + ncv->update = decode_bcd_u8(rsp->update); |
| 782 | + ncv->alpha1 = rsp->alpha1; |
761 | 783 | ncv->alpha2 = rsp->alpha2; |
762 | 784 | memcpy(ncv->fw_name, rsp->fw_name, 12); |
763 | 785 | ncv->fw_version = ntohl(rsp->fw_version); |
@@ -1069,6 +1091,44 @@ static int ncsi_rsp_handler_netlink(struct ncsi_request *nr) |
1069 | 1091 | return ret; |
1070 | 1092 | } |
1071 | 1093 |
|
| 1094 | +static int ncsi_rsp_handler_gmcma(struct ncsi_request *nr) |
| 1095 | +{ |
| 1096 | + struct ncsi_dev_priv *ndp = nr->ndp; |
| 1097 | + struct net_device *ndev = ndp->ndev.dev; |
| 1098 | + struct ncsi_rsp_gmcma_pkt *rsp; |
| 1099 | + struct sockaddr saddr; |
| 1100 | + int ret = -1; |
| 1101 | + int i; |
| 1102 | + |
| 1103 | + rsp = (struct ncsi_rsp_gmcma_pkt *)skb_network_header(nr->rsp); |
| 1104 | + saddr.sa_family = ndev->type; |
| 1105 | + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
| 1106 | + |
| 1107 | + netdev_info(ndev, "NCSI: Received %d provisioned MAC addresses\n", |
| 1108 | + rsp->address_count); |
| 1109 | + for (i = 0; i < rsp->address_count; i++) { |
| 1110 | + netdev_info(ndev, "NCSI: MAC address %d: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| 1111 | + i, rsp->addresses[i][0], rsp->addresses[i][1], |
| 1112 | + rsp->addresses[i][2], rsp->addresses[i][3], |
| 1113 | + rsp->addresses[i][4], rsp->addresses[i][5]); |
| 1114 | + } |
| 1115 | + |
| 1116 | + for (i = 0; i < rsp->address_count; i++) { |
| 1117 | + memcpy(saddr.sa_data, &rsp->addresses[i], ETH_ALEN); |
| 1118 | + ret = ndev->netdev_ops->ndo_set_mac_address(ndev, &saddr); |
| 1119 | + if (ret < 0) { |
| 1120 | + netdev_warn(ndev, "NCSI: Unable to assign %pM to device\n", |
| 1121 | + saddr.sa_data); |
| 1122 | + continue; |
| 1123 | + } |
| 1124 | + netdev_warn(ndev, "NCSI: Set MAC address to %pM\n", saddr.sa_data); |
| 1125 | + break; |
| 1126 | + } |
| 1127 | + |
| 1128 | + ndp->gma_flag = ret == 0; |
| 1129 | + return ret; |
| 1130 | +} |
| 1131 | + |
1072 | 1132 | static struct ncsi_rsp_handler { |
1073 | 1133 | unsigned char type; |
1074 | 1134 | int payload; |
@@ -1105,7 +1165,8 @@ static struct ncsi_rsp_handler { |
1105 | 1165 | { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm }, |
1106 | 1166 | { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }, |
1107 | 1167 | { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm }, |
1108 | | - { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm } |
| 1168 | + { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm }, |
| 1169 | + { NCSI_PKT_RSP_GMCMA, -1, ncsi_rsp_handler_gmcma }, |
1109 | 1170 | }; |
1110 | 1171 |
|
1111 | 1172 | int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, |
|
0 commit comments