]>
Commit | Line | Data |
---|---|---|
47bb83ca CLG |
1 | /* |
2 | * NC-SI (Network Controller Sideband Interface) "echo" model | |
3 | * | |
4 | * Copyright (C) 2016 IBM Corp. | |
5 | * | |
6 | * This code is licensed under the GPL version 2 or later. See the | |
7 | * COPYING file in the top-level directory. | |
8 | */ | |
9 | #include "qemu/osdep.h" | |
10 | #include "slirp.h" | |
11 | ||
12 | #include "ncsi-pkt.h" | |
13 | ||
14 | /* Get Capabilities */ | |
15 | static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh) | |
16 | { | |
17 | struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *) rnh; | |
18 | ||
19 | rsp->cap = htonl(~0); | |
20 | rsp->bc_cap = htonl(~0); | |
21 | rsp->mc_cap = htonl(~0); | |
22 | rsp->buf_cap = htonl(~0); | |
23 | rsp->aen_cap = htonl(~0); | |
24 | rsp->vlan_mode = 0xff; | |
25 | rsp->uc_cnt = 2; | |
26 | return 0; | |
27 | } | |
28 | ||
29 | /* Get Link status */ | |
30 | static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh) | |
31 | { | |
32 | struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *) rnh; | |
33 | ||
34 | rsp->status = htonl(0x1); | |
35 | return 0; | |
36 | } | |
37 | ||
38 | static const struct ncsi_rsp_handler { | |
39 | unsigned char type; | |
40 | int payload; | |
41 | int (*handler)(struct ncsi_rsp_pkt_hdr *rnh); | |
42 | } ncsi_rsp_handlers[] = { | |
43 | { NCSI_PKT_RSP_CIS, 4, NULL }, | |
44 | { NCSI_PKT_RSP_SP, 4, NULL }, | |
45 | { NCSI_PKT_RSP_DP, 4, NULL }, | |
46 | { NCSI_PKT_RSP_EC, 4, NULL }, | |
47 | { NCSI_PKT_RSP_DC, 4, NULL }, | |
48 | { NCSI_PKT_RSP_RC, 4, NULL }, | |
49 | { NCSI_PKT_RSP_ECNT, 4, NULL }, | |
50 | { NCSI_PKT_RSP_DCNT, 4, NULL }, | |
51 | { NCSI_PKT_RSP_AE, 4, NULL }, | |
52 | { NCSI_PKT_RSP_SL, 4, NULL }, | |
53 | { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls }, | |
54 | { NCSI_PKT_RSP_SVF, 4, NULL }, | |
55 | { NCSI_PKT_RSP_EV, 4, NULL }, | |
56 | { NCSI_PKT_RSP_DV, 4, NULL }, | |
57 | { NCSI_PKT_RSP_SMA, 4, NULL }, | |
58 | { NCSI_PKT_RSP_EBF, 4, NULL }, | |
59 | { NCSI_PKT_RSP_DBF, 4, NULL }, | |
60 | { NCSI_PKT_RSP_EGMF, 4, NULL }, | |
61 | { NCSI_PKT_RSP_DGMF, 4, NULL }, | |
62 | { NCSI_PKT_RSP_SNFC, 4, NULL }, | |
63 | { NCSI_PKT_RSP_GVI, 36, NULL }, | |
64 | { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc }, | |
65 | { NCSI_PKT_RSP_GP, -1, NULL }, | |
66 | { NCSI_PKT_RSP_GCPS, 172, NULL }, | |
67 | { NCSI_PKT_RSP_GNS, 172, NULL }, | |
68 | { NCSI_PKT_RSP_GNPTS, 172, NULL }, | |
69 | { NCSI_PKT_RSP_GPS, 8, NULL }, | |
70 | { NCSI_PKT_RSP_OEM, 0, NULL }, | |
71 | { NCSI_PKT_RSP_PLDM, 0, NULL }, | |
72 | { NCSI_PKT_RSP_GPUUID, 20, NULL } | |
73 | }; | |
74 | ||
75 | /* | |
76 | * packet format : ncsi header + payload + checksum | |
77 | */ | |
78 | #define NCSI_MAX_PAYLOAD 172 | |
79 | #define NCSI_MAX_LEN (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4) | |
80 | ||
81 | void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) | |
82 | { | |
83 | struct ncsi_pkt_hdr *nh = (struct ncsi_pkt_hdr *)(pkt + ETH_HLEN); | |
84 | uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN]; | |
85 | struct ethhdr *reh = (struct ethhdr *)ncsi_reply; | |
86 | struct ncsi_rsp_pkt_hdr *rnh = (struct ncsi_rsp_pkt_hdr *) | |
87 | (ncsi_reply + ETH_HLEN); | |
88 | const struct ncsi_rsp_handler *handler = NULL; | |
89 | int i; | |
90 | ||
91 | memset(ncsi_reply, 0, sizeof(ncsi_reply)); | |
92 | ||
93 | memset(reh->h_dest, 0xff, ETH_ALEN); | |
94 | memset(reh->h_source, 0xff, ETH_ALEN); | |
95 | reh->h_proto = htons(ETH_P_NCSI); | |
96 | ||
97 | for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) { | |
98 | if (ncsi_rsp_handlers[i].type == nh->type + 0x80) { | |
99 | handler = &ncsi_rsp_handlers[i]; | |
100 | break; | |
101 | } | |
102 | } | |
103 | ||
104 | rnh->common.mc_id = nh->mc_id; | |
105 | rnh->common.revision = NCSI_PKT_REVISION; | |
106 | rnh->common.id = nh->id; | |
107 | rnh->common.type = nh->type + 0x80; | |
108 | rnh->common.channel = nh->channel; | |
109 | ||
110 | if (handler) { | |
111 | rnh->common.length = htons(handler->payload); | |
112 | rnh->code = htons(NCSI_PKT_RSP_C_COMPLETED); | |
113 | rnh->reason = htons(NCSI_PKT_RSP_R_NO_ERROR); | |
114 | ||
115 | if (handler->handler) { | |
116 | /* TODO: handle errors */ | |
117 | handler->handler(rnh); | |
118 | } | |
119 | } else { | |
120 | rnh->common.length = 0; | |
121 | rnh->code = htons(NCSI_PKT_RSP_C_UNAVAILABLE); | |
122 | rnh->reason = htons(NCSI_PKT_RSP_R_UNKNOWN); | |
123 | } | |
124 | ||
125 | /* TODO: add a checksum at the end of the frame but the specs | |
126 | * allows it to be zero */ | |
127 | ||
128 | slirp_output(slirp->opaque, ncsi_reply, ETH_HLEN + sizeof(*nh) + | |
129 | (handler ? handler->payload : 0) + 4); | |
130 | } |