Line data Source code
1 : /*-
2 : * Copyright (c) 2009-2016 Microsoft Corp.
3 : * Copyright (c) 2012 NetApp Inc.
4 : * Copyright (c) 2012 Citrix Inc.
5 : * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com>
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice unmodified, this list of conditions, and the following
13 : * disclaimer.
14 : * 2. Redistributions in binary form must reproduce the above copyright
15 : * notice, this list of conditions and the following disclaimer in the
16 : * documentation and/or other materials provided with the distribution.
17 : *
18 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : */
29 :
30 : /*
31 : * The OpenBSD port was done under funding by Esdenera Networks GmbH.
32 : */
33 :
34 : #include <sys/param.h>
35 :
36 : /* Hyperv requires locked atomic operations */
37 : #ifndef MULTIPROCESSOR
38 : #define _HYPERVMPATOMICS
39 : #define MULTIPROCESSOR
40 : #endif
41 : #include <sys/atomic.h>
42 : #ifdef _HYPERVMPATOMICS
43 : #undef MULTIPROCESSOR
44 : #undef _HYPERVMPATOMICS
45 : #endif
46 :
47 : #include <sys/systm.h>
48 : #include <sys/proc.h>
49 : #include <sys/signal.h>
50 : #include <sys/signalvar.h>
51 : #include <sys/malloc.h>
52 : #include <sys/kernel.h>
53 : #include <sys/device.h>
54 : #include <sys/pool.h>
55 : #include <sys/timetc.h>
56 : #include <sys/task.h>
57 : #include <sys/syslog.h>
58 : #include <sys/socket.h>
59 :
60 : #include <machine/bus.h>
61 : #include <machine/cpu.h>
62 : #include <machine/cpufunc.h>
63 :
64 : #include <machine/i82489var.h>
65 :
66 : #include <dev/rndvar.h>
67 :
68 : #include <net/if.h>
69 : #include <net/if_dl.h>
70 : #include <netinet/in.h>
71 : #include <netinet/if_ether.h>
72 :
73 : #include <dev/pv/pvvar.h>
74 : #include <dev/pv/pvreg.h>
75 : #include <dev/pv/hypervreg.h>
76 : #include <dev/pv/hypervvar.h>
77 : #include <dev/pv/hypervicreg.h>
78 :
79 : struct hv_ic_dev;
80 :
81 : #define NKVPPOOLS 4
82 : #define MAXPOOLENTS 1023
83 :
84 : struct kvp_entry {
85 : int kpe_index;
86 : uint32_t kpe_valtype;
87 : uint8_t kpe_key[HV_KVP_MAX_KEY_SIZE / 2];
88 : uint8_t kpe_val[HV_KVP_MAX_VAL_SIZE / 2];
89 : TAILQ_ENTRY(kvp_entry) kpe_entry;
90 : };
91 : TAILQ_HEAD(kvp_list, kvp_entry);
92 :
93 : struct kvp_pool {
94 : struct kvp_list kvp_entries;
95 : struct mutex kvp_lock;
96 : u_int kvp_index;
97 : };
98 :
99 : struct pool kvp_entry_pool;
100 :
101 : struct hv_kvp {
102 : struct kvp_pool kvp_pool[NKVPPOOLS];
103 : };
104 :
105 : int hv_heartbeat_attach(struct hv_ic_dev *);
106 : void hv_heartbeat(void *);
107 : int hv_kvp_attach(struct hv_ic_dev *);
108 : void hv_kvp(void *);
109 : int hv_kvop(void *, int, char *, char *, size_t);
110 : int hv_shutdown_attach(struct hv_ic_dev *);
111 : void hv_shutdown(void *);
112 : int hv_timesync_attach(struct hv_ic_dev *);
113 : void hv_timesync(void *);
114 :
115 : static struct hv_ic_dev {
116 : const char *dv_name;
117 : const struct hv_guid *dv_type;
118 : int (*dv_attach)(struct hv_ic_dev *);
119 : void (*dv_handler)(void *);
120 : struct hv_channel *dv_ch;
121 : uint8_t *dv_buf;
122 : void *dv_priv;
123 : } hv_ic_devs[] = {
124 : {
125 : "heartbeat",
126 : &hv_guid_heartbeat,
127 : hv_heartbeat_attach,
128 : hv_heartbeat
129 : },
130 : {
131 : "kvp",
132 : &hv_guid_kvp,
133 : hv_kvp_attach,
134 : hv_kvp
135 : },
136 : {
137 : "shutdown",
138 : &hv_guid_shutdown,
139 : hv_shutdown_attach,
140 : hv_shutdown
141 : },
142 : {
143 : "timesync",
144 : &hv_guid_timesync,
145 : hv_timesync_attach,
146 : hv_timesync
147 : }
148 : };
149 :
150 : static const struct {
151 : enum hv_kvp_pool poolidx;
152 : const char *poolname;
153 : size_t poolnamelen;
154 : } kvp_pools[] = {
155 : { HV_KVP_POOL_EXTERNAL, "External", sizeof("External") },
156 : { HV_KVP_POOL_GUEST, "Guest", sizeof("Guest") },
157 : { HV_KVP_POOL_AUTO, "Auto", sizeof("Auto") },
158 : { HV_KVP_POOL_AUTO_EXTERNAL, "Guest/Parameters",
159 : sizeof("Guest/Parameters") }
160 : };
161 :
162 : static const struct {
163 : int keyidx;
164 : const char *keyname;
165 : const char *value;
166 : } kvp_pool_auto[] = {
167 : { 0, "FullyQualifiedDomainName", hostname },
168 : { 1, "IntegrationServicesVersion", "6.6.6" },
169 : { 2, "NetworkAddressIPv4", "127.0.0.1" },
170 : { 3, "NetworkAddressIPv6", "::1" },
171 : { 4, "OSBuildNumber", osversion },
172 : { 5, "OSName", ostype },
173 : { 6, "OSMajorVersion", "6" }, /* free commit for mike */
174 : { 7, "OSMinorVersion", &osrelease[2] },
175 : { 8, "OSVersion", osrelease },
176 : #ifdef __amd64__ /* As specified in SYSTEM_INFO.wProcessorArchitecture */
177 : { 9, "ProcessorArchitecture", "9" }
178 : #else
179 : { 9, "ProcessorArchitecture", "0" }
180 : #endif
181 : };
182 :
183 : void
184 0 : hv_attach_icdevs(struct hv_softc *sc)
185 : {
186 : struct hv_ic_dev *dv;
187 : struct hv_channel *ch;
188 : int i, header = 0;
189 :
190 0 : for (i = 0; i < nitems(hv_ic_devs); i++) {
191 0 : dv = &hv_ic_devs[i];
192 :
193 0 : TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
194 0 : if (ch->ch_state != HV_CHANSTATE_OFFERED)
195 : continue;
196 0 : if (ch->ch_flags & CHF_MONITOR)
197 : continue;
198 0 : if (memcmp(dv->dv_type, &ch->ch_type,
199 0 : sizeof(ch->ch_type)) == 0)
200 : break;
201 : }
202 0 : if (ch == NULL)
203 : continue;
204 :
205 0 : dv->dv_ch = ch;
206 :
207 : /*
208 : * These services are not performance critical and
209 : * do not need batched reading. Furthermore, some
210 : * services such as KVP can only handle one message
211 : * from the host at a time.
212 : */
213 0 : dv->dv_ch->ch_flags &= ~CHF_BATCHED;
214 :
215 0 : if (dv->dv_attach && dv->dv_attach(dv) != 0)
216 : continue;
217 :
218 0 : if (hv_channel_open(ch, VMBUS_IC_BUFRINGSIZE, NULL, 0,
219 0 : dv->dv_handler, dv)) {
220 0 : printf("%s: failed to open channel for %s\n",
221 0 : sc->sc_dev.dv_xname, dv->dv_name);
222 0 : continue;
223 : }
224 0 : evcount_attach(&ch->ch_evcnt, dv->dv_name, &sc->sc_idtvec);
225 :
226 0 : if (!header) {
227 0 : printf("%s: %s", sc->sc_dev.dv_xname, dv->dv_name);
228 : header = 1;
229 0 : } else
230 0 : printf(", %s", dv->dv_name);
231 : }
232 0 : if (header)
233 0 : printf("\n");
234 0 : }
235 :
236 : static inline void
237 0 : hv_ic_negotiate(struct vmbus_icmsg_hdr *hdr, uint32_t *rlen, uint32_t fwver,
238 : uint32_t msgver)
239 : {
240 : struct vmbus_icmsg_negotiate *msg;
241 : uint16_t propmin, propmaj, chosenmaj, chosenmin;
242 : int i;
243 :
244 0 : msg = (struct vmbus_icmsg_negotiate *)hdr;
245 :
246 : chosenmaj = chosenmin = 0;
247 0 : for (i = 0; i < msg->ic_fwver_cnt; i++) {
248 0 : propmaj = VMBUS_ICVER_MAJOR(msg->ic_ver[i]);
249 0 : propmin = VMBUS_ICVER_MINOR(msg->ic_ver[i]);
250 0 : if (propmaj > chosenmaj &&
251 0 : propmaj <= VMBUS_ICVER_MAJOR(fwver) &&
252 0 : propmin >= chosenmin &&
253 0 : propmin <= VMBUS_ICVER_MINOR(fwver)) {
254 : chosenmaj = propmaj;
255 : chosenmin = propmin;
256 0 : }
257 : }
258 0 : fwver = VMBUS_IC_VERSION(chosenmaj, chosenmin);
259 :
260 : chosenmaj = chosenmin = 0;
261 0 : for (; i < msg->ic_fwver_cnt + msg->ic_msgver_cnt; i++) {
262 0 : propmaj = VMBUS_ICVER_MAJOR(msg->ic_ver[i]);
263 0 : propmin = VMBUS_ICVER_MINOR(msg->ic_ver[i]);
264 0 : if (propmaj > chosenmaj &&
265 0 : propmaj <= VMBUS_ICVER_MAJOR(msgver) &&
266 0 : propmin >= chosenmin &&
267 0 : propmin <= VMBUS_ICVER_MINOR(msgver)) {
268 : chosenmaj = propmaj;
269 : chosenmin = propmin;
270 0 : }
271 : }
272 0 : msgver = VMBUS_IC_VERSION(chosenmaj, chosenmin);
273 :
274 0 : msg->ic_fwver_cnt = 1;
275 0 : msg->ic_ver[0] = fwver;
276 0 : msg->ic_msgver_cnt = 1;
277 0 : msg->ic_ver[1] = msgver;
278 0 : hdr->ic_dsize = sizeof(*msg) + 2 * sizeof(uint32_t) -
279 : sizeof(struct vmbus_icmsg_hdr);
280 0 : if (*rlen < sizeof(*msg) + 2 * sizeof(uint32_t))
281 0 : *rlen = sizeof(*msg) + 2 * sizeof(uint32_t);
282 0 : }
283 :
284 : int
285 0 : hv_heartbeat_attach(struct hv_ic_dev *dv)
286 : {
287 0 : struct hv_channel *ch = dv->dv_ch;
288 0 : struct hv_softc *sc = ch->ch_sc;
289 :
290 0 : dv->dv_buf = malloc(PAGE_SIZE, M_DEVBUF, M_ZERO |
291 0 : (cold ? M_NOWAIT : M_WAITOK));
292 0 : if (dv->dv_buf == NULL) {
293 0 : printf("%s: failed to allocate receive buffer\n",
294 0 : sc->sc_dev.dv_xname);
295 0 : return (-1);
296 : }
297 0 : return (0);
298 0 : }
299 :
300 : void
301 0 : hv_heartbeat(void *arg)
302 : {
303 0 : struct hv_ic_dev *dv = arg;
304 0 : struct hv_channel *ch = dv->dv_ch;
305 0 : struct hv_softc *sc = ch->ch_sc;
306 : struct vmbus_icmsg_hdr *hdr;
307 : struct vmbus_icmsg_heartbeat *msg;
308 0 : uint64_t rid;
309 0 : uint32_t rlen;
310 : int rv;
311 :
312 0 : rv = hv_channel_recv(ch, dv->dv_buf, PAGE_SIZE, &rlen, &rid, 0);
313 0 : if (rv || rlen == 0) {
314 : if (rv != EAGAIN)
315 : DPRINTF("%s: heartbeat rv=%d rlen=%u\n",
316 : sc->sc_dev.dv_xname, rv, rlen);
317 0 : return;
318 : }
319 0 : if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
320 : DPRINTF("%s: heartbeat short read rlen=%u\n",
321 : sc->sc_dev.dv_xname, rlen);
322 0 : return;
323 : }
324 0 : hdr = (struct vmbus_icmsg_hdr *)dv->dv_buf;
325 0 : switch (hdr->ic_type) {
326 : case VMBUS_ICMSG_TYPE_NEGOTIATE:
327 0 : hv_ic_negotiate(hdr, &rlen, VMBUS_IC_VERSION(3, 0),
328 : VMBUS_IC_VERSION(3, 0));
329 0 : break;
330 : case VMBUS_ICMSG_TYPE_HEARTBEAT:
331 0 : msg = (struct vmbus_icmsg_heartbeat *)hdr;
332 0 : msg->ic_seq += 1;
333 0 : break;
334 : default:
335 0 : printf("%s: unhandled heartbeat message type %u\n",
336 0 : sc->sc_dev.dv_xname, hdr->ic_type);
337 0 : return;
338 : }
339 0 : hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION | VMBUS_ICMSG_FLAG_RESPONSE;
340 0 : hv_channel_send(ch, dv->dv_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
341 0 : }
342 :
343 : static void
344 0 : hv_shutdown_task(void *arg)
345 : {
346 0 : struct hv_softc *sc = arg;
347 0 : pvbus_shutdown(&sc->sc_dev);
348 0 : }
349 :
350 : int
351 0 : hv_shutdown_attach(struct hv_ic_dev *dv)
352 : {
353 0 : struct hv_channel *ch = dv->dv_ch;
354 0 : struct hv_softc *sc = ch->ch_sc;
355 :
356 0 : dv->dv_buf = malloc(PAGE_SIZE, M_DEVBUF, M_ZERO |
357 0 : (cold ? M_NOWAIT : M_WAITOK));
358 0 : if (dv->dv_buf == NULL) {
359 0 : printf("%s: failed to allocate receive buffer\n",
360 0 : sc->sc_dev.dv_xname);
361 0 : return (-1);
362 : }
363 :
364 0 : task_set(&sc->sc_sdtask, hv_shutdown_task, sc);
365 :
366 0 : return (0);
367 0 : }
368 :
369 : void
370 0 : hv_shutdown(void *arg)
371 : {
372 0 : struct hv_ic_dev *dv = arg;
373 0 : struct hv_channel *ch = dv->dv_ch;
374 0 : struct hv_softc *sc = ch->ch_sc;
375 : struct vmbus_icmsg_hdr *hdr;
376 : struct vmbus_icmsg_shutdown *msg;
377 0 : uint64_t rid;
378 0 : uint32_t rlen;
379 : int rv, shutdown = 0;
380 :
381 0 : rv = hv_channel_recv(ch, dv->dv_buf, PAGE_SIZE, &rlen, &rid, 0);
382 0 : if (rv || rlen == 0) {
383 : if (rv != EAGAIN)
384 : DPRINTF("%s: shutdown rv=%d rlen=%u\n",
385 : sc->sc_dev.dv_xname, rv, rlen);
386 0 : return;
387 : }
388 0 : if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
389 : DPRINTF("%s: shutdown short read rlen=%u\n",
390 : sc->sc_dev.dv_xname, rlen);
391 0 : return;
392 : }
393 0 : hdr = (struct vmbus_icmsg_hdr *)dv->dv_buf;
394 0 : switch (hdr->ic_type) {
395 : case VMBUS_ICMSG_TYPE_NEGOTIATE:
396 0 : hv_ic_negotiate(hdr, &rlen, VMBUS_IC_VERSION(3, 0),
397 : VMBUS_IC_VERSION(3, 0));
398 0 : break;
399 : case VMBUS_ICMSG_TYPE_SHUTDOWN:
400 0 : msg = (struct vmbus_icmsg_shutdown *)hdr;
401 0 : if (msg->ic_haltflags == 0 || msg->ic_haltflags == 1) {
402 : shutdown = 1;
403 0 : hdr->ic_status = VMBUS_ICMSG_STATUS_OK;
404 0 : } else
405 0 : hdr->ic_status = VMBUS_ICMSG_STATUS_FAIL;
406 : break;
407 : default:
408 0 : printf("%s: unhandled shutdown message type %u\n",
409 0 : sc->sc_dev.dv_xname, hdr->ic_type);
410 0 : return;
411 : }
412 :
413 0 : hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION | VMBUS_ICMSG_FLAG_RESPONSE;
414 0 : hv_channel_send(ch, dv->dv_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
415 :
416 0 : if (shutdown)
417 0 : task_add(systq, &sc->sc_sdtask);
418 0 : }
419 :
420 : int
421 0 : hv_timesync_attach(struct hv_ic_dev *dv)
422 : {
423 0 : struct hv_channel *ch = dv->dv_ch;
424 0 : struct hv_softc *sc = ch->ch_sc;
425 :
426 0 : dv->dv_buf = malloc(PAGE_SIZE, M_DEVBUF, M_ZERO |
427 0 : (cold ? M_NOWAIT : M_WAITOK));
428 0 : if (dv->dv_buf == NULL) {
429 0 : printf("%s: failed to allocate receive buffer\n",
430 0 : sc->sc_dev.dv_xname);
431 0 : return (-1);
432 : }
433 :
434 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
435 : sizeof(sc->sc_sensordev.xname));
436 :
437 0 : sc->sc_sensor.type = SENSOR_TIMEDELTA;
438 0 : sc->sc_sensor.status = SENSOR_S_UNKNOWN;
439 :
440 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
441 0 : sensordev_install(&sc->sc_sensordev);
442 :
443 0 : return (0);
444 0 : }
445 :
446 : void
447 0 : hv_timesync(void *arg)
448 : {
449 0 : struct hv_ic_dev *dv = arg;
450 0 : struct hv_channel *ch = dv->dv_ch;
451 0 : struct hv_softc *sc = ch->ch_sc;
452 : struct vmbus_icmsg_hdr *hdr;
453 : struct vmbus_icmsg_timesync *msg;
454 0 : struct timespec guest, host, diff;
455 : uint64_t tns;
456 0 : uint64_t rid;
457 0 : uint32_t rlen;
458 : int rv;
459 :
460 0 : rv = hv_channel_recv(ch, dv->dv_buf, PAGE_SIZE, &rlen, &rid, 0);
461 0 : if (rv || rlen == 0) {
462 : if (rv != EAGAIN)
463 : DPRINTF("%s: timesync rv=%d rlen=%u\n",
464 : sc->sc_dev.dv_xname, rv, rlen);
465 0 : return;
466 : }
467 0 : if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
468 : DPRINTF("%s: timesync short read rlen=%u\n",
469 : sc->sc_dev.dv_xname, rlen);
470 0 : return;
471 : }
472 0 : hdr = (struct vmbus_icmsg_hdr *)dv->dv_buf;
473 0 : switch (hdr->ic_type) {
474 : case VMBUS_ICMSG_TYPE_NEGOTIATE:
475 0 : hv_ic_negotiate(hdr, &rlen, VMBUS_IC_VERSION(3, 0),
476 : VMBUS_IC_VERSION(3, 0));
477 0 : break;
478 : case VMBUS_ICMSG_TYPE_TIMESYNC:
479 0 : msg = (struct vmbus_icmsg_timesync *)hdr;
480 0 : if (msg->ic_tsflags == VMBUS_ICMSG_TS_FLAG_SAMPLE) {
481 0 : microtime(&sc->sc_sensor.tv);
482 0 : nanotime(&guest);
483 0 : tns = (msg->ic_hvtime - 116444736000000000LL) * 100;
484 0 : host.tv_sec = tns / 1000000000LL;
485 0 : host.tv_nsec = tns % 1000000000LL;
486 0 : timespecsub(&guest, &host, &diff);
487 0 : sc->sc_sensor.value = (int64_t)diff.tv_sec *
488 0 : 1000000000LL + diff.tv_nsec;
489 0 : sc->sc_sensor.status = SENSOR_S_OK;
490 0 : }
491 : break;
492 : default:
493 0 : printf("%s: unhandled timesync message type %u\n",
494 0 : sc->sc_dev.dv_xname, hdr->ic_type);
495 0 : return;
496 : }
497 :
498 0 : hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION | VMBUS_ICMSG_FLAG_RESPONSE;
499 0 : hv_channel_send(ch, dv->dv_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
500 0 : }
501 :
502 : static inline int
503 0 : copyout_utf16le(void *dst, const void *src, size_t dlen, size_t slen)
504 : {
505 : const uint8_t *sp = src;
506 : uint8_t *dp = dst;
507 : int i, j;
508 :
509 0 : KASSERT(dlen >= slen * 2);
510 :
511 0 : for (i = j = 0; i < slen; i++, j += 2) {
512 0 : dp[j] = sp[i];
513 0 : dp[j + 1] = '\0';
514 : }
515 0 : return (j);
516 : }
517 :
518 : static inline int
519 0 : copyin_utf16le(void *dst, const void *src, size_t dlen, size_t slen)
520 : {
521 : const uint8_t *sp = src;
522 : uint8_t *dp = dst;
523 : int i, j;
524 :
525 0 : KASSERT(dlen >= slen / 2);
526 :
527 0 : for (i = j = 0; i < slen; i += 2, j++)
528 0 : dp[j] = sp[i];
529 0 : return (j);
530 : }
531 :
532 : static inline int
533 0 : keycmp_utf16le(const uint8_t *key, const uint8_t *ukey, size_t ukeylen)
534 : {
535 : int i, j;
536 :
537 0 : for (i = j = 0; i < ukeylen; i += 2, j++) {
538 0 : if (key[j] != ukey[i])
539 0 : return (key[j] > ukey[i] ?
540 0 : key[j] - ukey[i] :
541 0 : ukey[i] - key[j]);
542 : }
543 0 : return (0);
544 0 : }
545 :
546 : static void
547 0 : kvp_pool_init(struct kvp_pool *kvpl)
548 : {
549 0 : TAILQ_INIT(&kvpl->kvp_entries);
550 0 : mtx_init(&kvpl->kvp_lock, IPL_NET);
551 0 : kvpl->kvp_index = 0;
552 0 : }
553 :
554 : static int
555 0 : kvp_pool_insert(struct kvp_pool *kvpl, const char *key, const char *val,
556 : uint32_t vallen, uint32_t valtype)
557 : {
558 : struct kvp_entry *kpe;
559 0 : int keylen = strlen(key);
560 :
561 0 : if (keylen > HV_KVP_MAX_KEY_SIZE / 2)
562 0 : return (ERANGE);
563 :
564 0 : mtx_enter(&kvpl->kvp_lock);
565 :
566 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
567 0 : if (strcmp(kpe->kpe_key, key) == 0) {
568 0 : mtx_leave(&kvpl->kvp_lock);
569 0 : return (EEXIST);
570 : }
571 : }
572 :
573 0 : kpe = pool_get(&kvp_entry_pool, PR_ZERO | PR_NOWAIT);
574 0 : if (kpe == NULL) {
575 0 : mtx_leave(&kvpl->kvp_lock);
576 0 : return (ENOMEM);
577 : }
578 :
579 0 : strlcpy(kpe->kpe_key, key, HV_KVP_MAX_KEY_SIZE / 2);
580 :
581 0 : if ((kpe->kpe_valtype = valtype) == HV_KVP_REG_SZ)
582 0 : strlcpy(kpe->kpe_val, val, HV_KVP_MAX_KEY_SIZE / 2);
583 : else
584 0 : memcpy(kpe->kpe_val, val, vallen);
585 :
586 0 : kpe->kpe_index = kvpl->kvp_index++ & MAXPOOLENTS;
587 :
588 0 : TAILQ_INSERT_TAIL(&kvpl->kvp_entries, kpe, kpe_entry);
589 :
590 0 : mtx_leave(&kvpl->kvp_lock);
591 :
592 0 : return (0);
593 0 : }
594 :
595 : static int
596 0 : kvp_pool_update(struct kvp_pool *kvpl, const char *key, const char *val,
597 : uint32_t vallen, uint32_t valtype)
598 : {
599 : struct kvp_entry *kpe;
600 0 : int keylen = strlen(key);
601 :
602 0 : if (keylen > HV_KVP_MAX_KEY_SIZE / 2)
603 0 : return (ERANGE);
604 :
605 0 : mtx_enter(&kvpl->kvp_lock);
606 :
607 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
608 0 : if (strcmp(kpe->kpe_key, key) == 0)
609 : break;
610 : }
611 0 : if (kpe == NULL) {
612 0 : mtx_leave(&kvpl->kvp_lock);
613 0 : return (ENOENT);
614 : }
615 :
616 0 : if ((kpe->kpe_valtype = valtype) == HV_KVP_REG_SZ)
617 0 : strlcpy(kpe->kpe_val, val, HV_KVP_MAX_KEY_SIZE / 2);
618 : else
619 0 : memcpy(kpe->kpe_val, val, vallen);
620 :
621 0 : mtx_leave(&kvpl->kvp_lock);
622 :
623 0 : return (0);
624 0 : }
625 :
626 : static int
627 0 : kvp_pool_import(struct kvp_pool *kvpl, const char *key, uint32_t keylen,
628 : const char *val, uint32_t vallen, uint32_t valtype)
629 : {
630 : struct kvp_entry *kpe;
631 :
632 0 : if (keylen > HV_KVP_MAX_KEY_SIZE ||
633 0 : vallen > HV_KVP_MAX_VAL_SIZE)
634 0 : return (ERANGE);
635 :
636 0 : mtx_enter(&kvpl->kvp_lock);
637 :
638 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
639 0 : if (keycmp_utf16le(kpe->kpe_key, key, keylen) == 0)
640 : break;
641 : }
642 0 : if (kpe == NULL) {
643 0 : kpe = pool_get(&kvp_entry_pool, PR_ZERO | PR_NOWAIT);
644 0 : if (kpe == NULL) {
645 0 : mtx_leave(&kvpl->kvp_lock);
646 0 : return (ENOMEM);
647 : }
648 :
649 0 : copyin_utf16le(kpe->kpe_key, key, HV_KVP_MAX_KEY_SIZE / 2,
650 0 : keylen);
651 :
652 0 : kpe->kpe_index = kvpl->kvp_index++ & MAXPOOLENTS;
653 :
654 0 : TAILQ_INSERT_TAIL(&kvpl->kvp_entries, kpe, kpe_entry);
655 0 : }
656 :
657 0 : copyin_utf16le(kpe->kpe_val, val, HV_KVP_MAX_VAL_SIZE / 2, vallen);
658 0 : kpe->kpe_valtype = valtype;
659 :
660 0 : mtx_leave(&kvpl->kvp_lock);
661 :
662 0 : return (0);
663 0 : }
664 :
665 : static int
666 0 : kvp_pool_export(struct kvp_pool *kvpl, uint32_t index, char *key,
667 : uint32_t *keylen, char *val, uint32_t *vallen, uint32_t *valtype)
668 : {
669 : struct kvp_entry *kpe;
670 :
671 0 : mtx_enter(&kvpl->kvp_lock);
672 :
673 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
674 0 : if (kpe->kpe_index == index)
675 : break;
676 : }
677 0 : if (kpe == NULL) {
678 0 : mtx_leave(&kvpl->kvp_lock);
679 0 : return (ENOENT);
680 : }
681 :
682 0 : *keylen = copyout_utf16le(key, kpe->kpe_key, HV_KVP_MAX_KEY_SIZE,
683 0 : strlen(kpe->kpe_key) + 1);
684 0 : *vallen = copyout_utf16le(val, kpe->kpe_val, HV_KVP_MAX_VAL_SIZE,
685 0 : strlen(kpe->kpe_val) + 1);
686 0 : *valtype = kpe->kpe_valtype;
687 :
688 0 : mtx_leave(&kvpl->kvp_lock);
689 :
690 0 : return (0);
691 0 : }
692 :
693 : static int
694 0 : kvp_pool_remove(struct kvp_pool *kvpl, const char *key, uint32_t keylen)
695 : {
696 : struct kvp_entry *kpe;
697 :
698 0 : mtx_enter(&kvpl->kvp_lock);
699 :
700 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
701 0 : if (keycmp_utf16le(kpe->kpe_key, key, keylen) == 0)
702 : break;
703 : }
704 0 : if (kpe == NULL) {
705 0 : mtx_leave(&kvpl->kvp_lock);
706 0 : return (ENOENT);
707 : }
708 :
709 0 : TAILQ_REMOVE(&kvpl->kvp_entries, kpe, kpe_entry);
710 :
711 0 : mtx_leave(&kvpl->kvp_lock);
712 :
713 0 : pool_put(&kvp_entry_pool, kpe);
714 :
715 0 : return (0);
716 0 : }
717 :
718 : static int
719 0 : kvp_pool_extract(struct kvp_pool *kvpl, const char *key, char *val,
720 : uint32_t vallen)
721 : {
722 : struct kvp_entry *kpe;
723 :
724 0 : if (vallen < HV_KVP_MAX_VAL_SIZE / 2)
725 0 : return (ERANGE);
726 :
727 0 : mtx_enter(&kvpl->kvp_lock);
728 :
729 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
730 0 : if (strcmp(kpe->kpe_key, key) == 0)
731 : break;
732 : }
733 0 : if (kpe == NULL) {
734 0 : mtx_leave(&kvpl->kvp_lock);
735 0 : return (ENOENT);
736 : }
737 :
738 0 : switch (kpe->kpe_valtype) {
739 : case HV_KVP_REG_SZ:
740 0 : strlcpy(val, kpe->kpe_val, HV_KVP_MAX_VAL_SIZE / 2);
741 0 : break;
742 : case HV_KVP_REG_U32:
743 0 : snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%u",
744 0 : *(uint32_t *)kpe->kpe_val);
745 0 : break;
746 : case HV_KVP_REG_U64:
747 0 : snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%llu",
748 0 : *(uint64_t *)kpe->kpe_val);
749 0 : break;
750 : }
751 :
752 0 : mtx_leave(&kvpl->kvp_lock);
753 :
754 0 : return (0);
755 0 : }
756 :
757 : static int
758 0 : kvp_pool_keys(struct kvp_pool *kvpl, int next, char *key, size_t *keylen)
759 : {
760 : struct kvp_entry *kpe;
761 : int iter = 0;
762 :
763 0 : TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
764 0 : if (iter++ < next)
765 : continue;
766 0 : *keylen = strlen(kpe->kpe_key) + 1;
767 0 : strlcpy(key, kpe->kpe_key, *keylen);
768 0 : return (0);
769 : }
770 :
771 0 : return (-1);
772 0 : }
773 :
774 : int
775 0 : hv_kvp_attach(struct hv_ic_dev *dv)
776 : {
777 0 : struct hv_channel *ch = dv->dv_ch;
778 0 : struct hv_softc *sc = ch->ch_sc;
779 : struct hv_kvp *kvp;
780 : int i;
781 :
782 0 : dv->dv_buf = malloc(2 * PAGE_SIZE, M_DEVBUF, M_ZERO |
783 0 : (cold ? M_NOWAIT : M_WAITOK));
784 0 : if (dv->dv_buf == NULL) {
785 0 : printf("%s: failed to allocate receive buffer\n",
786 0 : sc->sc_dev.dv_xname);
787 0 : return (-1);
788 : }
789 :
790 0 : dv->dv_priv = malloc(sizeof(struct hv_kvp), M_DEVBUF, M_ZERO |
791 0 : (cold ? M_NOWAIT : M_WAITOK));
792 0 : if (dv->dv_priv == NULL) {
793 0 : free(dv->dv_buf, M_DEVBUF, 2 * PAGE_SIZE);
794 0 : printf("%s: failed to allocate KVP private data\n",
795 0 : sc->sc_dev.dv_xname);
796 0 : return (-1);
797 : }
798 0 : kvp = dv->dv_priv;
799 :
800 0 : pool_init(&kvp_entry_pool, sizeof(struct kvp_entry), 0, IPL_NET, 0,
801 : "hvkvpl", NULL);
802 :
803 0 : for (i = 0; i < NKVPPOOLS; i++)
804 0 : kvp_pool_init(&kvp->kvp_pool[i]);
805 :
806 : /* Initialize 'Auto' pool */
807 0 : for (i = 0; i < nitems(kvp_pool_auto); i++) {
808 0 : if (kvp_pool_insert(&kvp->kvp_pool[HV_KVP_POOL_AUTO],
809 0 : kvp_pool_auto[i].keyname, kvp_pool_auto[i].value,
810 0 : strlen(kvp_pool_auto[i].value), HV_KVP_REG_SZ))
811 : DPRINTF("%s: failed to insert into 'Auto' pool\n",
812 : sc->sc_dev.dv_xname);
813 : }
814 :
815 0 : sc->sc_pvbus->hv_kvop = hv_kvop;
816 0 : sc->sc_pvbus->hv_arg = dv;
817 :
818 0 : return (0);
819 0 : }
820 :
821 : static int
822 0 : nibble(int ch)
823 : {
824 0 : if (ch >= '0' && ch <= '9')
825 0 : return (ch - '0');
826 0 : if (ch >= 'A' && ch <= 'F')
827 0 : return (10 + ch - 'A');
828 0 : if (ch >= 'a' && ch <= 'f')
829 0 : return (10 + ch - 'a');
830 0 : return (-1);
831 0 : }
832 :
833 : static int
834 0 : kvp_get_ip_info(struct hv_kvp *kvp, const uint8_t *mac, uint8_t *family,
835 : uint8_t *addr, uint8_t *netmask, size_t addrlen)
836 : {
837 : struct ifnet *ifp;
838 : struct ifaddr *ifa, *ifa6, *ifa6ll;
839 : struct sockaddr_in *sin;
840 0 : struct sockaddr_in6 *sin6, sa6;
841 0 : uint8_t enaddr[ETHER_ADDR_LEN];
842 0 : uint8_t ipaddr[INET6_ADDRSTRLEN];
843 : int i, j, lo, hi, s, af;
844 :
845 : /* Convert from the UTF-16LE string format to binary */
846 0 : for (i = 0, j = 0; j < ETHER_ADDR_LEN; i += 6) {
847 0 : if ((hi = nibble(mac[i])) == -1 ||
848 0 : (lo = nibble(mac[i+2])) == -1)
849 0 : return (-1);
850 0 : enaddr[j++] = hi << 4 | lo;
851 : }
852 :
853 0 : switch (*family) {
854 : case ADDR_FAMILY_NONE:
855 : af = AF_UNSPEC;
856 0 : break;
857 : case ADDR_FAMILY_IPV4:
858 : af = AF_INET;
859 0 : break;
860 : case ADDR_FAMILY_IPV6:
861 : af = AF_INET6;
862 0 : break;
863 : default:
864 0 : return (-1);
865 : }
866 :
867 0 : KERNEL_LOCK();
868 0 : s = splnet();
869 :
870 0 : TAILQ_FOREACH(ifp, &ifnet, if_list) {
871 0 : if (!memcmp(LLADDR(ifp->if_sadl), enaddr, ETHER_ADDR_LEN))
872 : break;
873 : }
874 0 : if (ifp == NULL) {
875 0 : splx(s);
876 0 : KERNEL_UNLOCK();
877 0 : return (-1);
878 : }
879 :
880 : ifa6 = ifa6ll = NULL;
881 :
882 : /* Try to find a best matching address, preferring IPv4 */
883 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
884 : /*
885 : * First IPv4 address is always a best match unless
886 : * we were asked for for an IPv6 address.
887 : */
888 0 : if ((af == AF_INET || af == AF_UNSPEC) &&
889 0 : (ifa->ifa_addr->sa_family == AF_INET)) {
890 : af = AF_INET;
891 0 : goto found;
892 : }
893 0 : if ((af == AF_INET6 || af == AF_UNSPEC) &&
894 0 : (ifa->ifa_addr->sa_family == AF_INET6)) {
895 0 : if (!IN6_IS_ADDR_LINKLOCAL(
896 : &satosin6(ifa->ifa_addr)->sin6_addr)) {
897 : /* Done if we're looking for an IPv6 address */
898 0 : if (af == AF_INET6)
899 : goto found;
900 : /* Stick to the first one */
901 0 : if (ifa6 == NULL)
902 0 : ifa6 = ifa;
903 : } else /* Pick the last one */
904 : ifa6ll = ifa;
905 : }
906 : }
907 : /* If we haven't found any IPv4 or IPv6 direct matches... */
908 0 : if (ifa == NULL) {
909 : /* ... try the last global IPv6 address... */
910 0 : if (ifa6 != NULL)
911 0 : ifa = ifa6;
912 : /* ... or the last link-local... */
913 0 : else if (ifa6ll != NULL)
914 : ifa = ifa6ll;
915 : else {
916 0 : splx(s);
917 0 : KERNEL_UNLOCK();
918 0 : return (-1);
919 : }
920 : }
921 : found:
922 0 : switch (af) {
923 : case AF_INET:
924 0 : sin = satosin(ifa->ifa_addr);
925 0 : inet_ntop(AF_INET, &sin->sin_addr, ipaddr, sizeof(ipaddr));
926 0 : copyout_utf16le(addr, ipaddr, addrlen, INET_ADDRSTRLEN);
927 :
928 0 : sin = satosin(ifa->ifa_netmask);
929 0 : inet_ntop(AF_INET, &sin->sin_addr, ipaddr, sizeof(ipaddr));
930 0 : copyout_utf16le(netmask, ipaddr, addrlen, INET_ADDRSTRLEN);
931 :
932 0 : *family = ADDR_FAMILY_IPV4;
933 0 : break;
934 : case AF_UNSPEC:
935 : case AF_INET6:
936 0 : sin6 = satosin6(ifa->ifa_addr);
937 0 : if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr)) {
938 0 : sa6 = *satosin6(ifa->ifa_addr);
939 0 : sa6.sin6_addr.s6_addr16[1] = 0;
940 : sin6 = &sa6;
941 0 : }
942 0 : inet_ntop(AF_INET6, &sin6->sin6_addr, ipaddr, sizeof(ipaddr));
943 0 : copyout_utf16le(addr, ipaddr, addrlen, INET6_ADDRSTRLEN);
944 :
945 0 : sin6 = satosin6(ifa->ifa_netmask);
946 0 : inet_ntop(AF_INET6, &sin6->sin6_addr, ipaddr, sizeof(ipaddr));
947 0 : copyout_utf16le(netmask, ipaddr, addrlen, INET6_ADDRSTRLEN);
948 :
949 0 : *family = ADDR_FAMILY_IPV6;
950 0 : break;
951 : }
952 :
953 0 : splx(s);
954 0 : KERNEL_UNLOCK();
955 :
956 0 : return (0);
957 0 : }
958 :
959 : static void
960 0 : hv_kvp_process(struct hv_kvp *kvp, struct vmbus_icmsg_kvp *msg)
961 : {
962 0 : union hv_kvp_hdr *kvh = &msg->ic_kvh;
963 0 : union hv_kvp_msg *kvm = &msg->ic_kvm;
964 :
965 0 : switch (kvh->kvh_op) {
966 : case HV_KVP_OP_SET:
967 0 : if (kvh->kvh_pool == HV_KVP_POOL_AUTO_EXTERNAL &&
968 0 : kvp_pool_import(&kvp->kvp_pool[HV_KVP_POOL_AUTO_EXTERNAL],
969 0 : kvm->kvm_val.kvm_key, kvm->kvm_val.kvm_keylen,
970 0 : kvm->kvm_val.kvm_val, kvm->kvm_val.kvm_vallen,
971 0 : kvm->kvm_val.kvm_valtype)) {
972 : DPRINTF("%s: failed to import into 'Guest/Parameters'"
973 : " pool\n", __func__);
974 0 : kvh->kvh_err = HV_KVP_S_CONT;
975 0 : } else if (kvh->kvh_pool == HV_KVP_POOL_EXTERNAL &&
976 0 : kvp_pool_import(&kvp->kvp_pool[HV_KVP_POOL_EXTERNAL],
977 0 : kvm->kvm_val.kvm_key, kvm->kvm_val.kvm_keylen,
978 0 : kvm->kvm_val.kvm_val, kvm->kvm_val.kvm_vallen,
979 0 : kvm->kvm_val.kvm_valtype)) {
980 : DPRINTF("%s: failed to import into 'External' pool\n",
981 : __func__);
982 0 : kvh->kvh_err = HV_KVP_S_CONT;
983 0 : } else if (kvh->kvh_pool != HV_KVP_POOL_AUTO_EXTERNAL &&
984 0 : kvh->kvh_pool != HV_KVP_POOL_EXTERNAL) {
985 0 : kvh->kvh_err = HV_KVP_S_CONT;
986 0 : } else
987 0 : kvh->kvh_err = HV_KVP_S_OK;
988 : break;
989 : case HV_KVP_OP_DELETE:
990 0 : if (kvh->kvh_pool != HV_KVP_POOL_EXTERNAL ||
991 0 : kvp_pool_remove(&kvp->kvp_pool[HV_KVP_POOL_EXTERNAL],
992 0 : kvm->kvm_del.kvm_key, kvm->kvm_del.kvm_keylen)) {
993 : DPRINTF("%s: failed to remove from 'External' pool\n",
994 : __func__);
995 0 : kvh->kvh_err = HV_KVP_S_CONT;
996 0 : } else
997 0 : kvh->kvh_err = HV_KVP_S_OK;
998 : break;
999 : case HV_KVP_OP_ENUMERATE:
1000 0 : if (kvh->kvh_pool == HV_KVP_POOL_AUTO &&
1001 0 : kvp_pool_export(&kvp->kvp_pool[HV_KVP_POOL_AUTO],
1002 0 : kvm->kvm_enum.kvm_index, kvm->kvm_enum.kvm_key,
1003 0 : &kvm->kvm_enum.kvm_keylen, kvm->kvm_enum.kvm_val,
1004 0 : &kvm->kvm_enum.kvm_vallen, &kvm->kvm_enum.kvm_valtype))
1005 0 : kvh->kvh_err = HV_KVP_S_CONT;
1006 0 : else if (kvh->kvh_pool == HV_KVP_POOL_GUEST &&
1007 0 : kvp_pool_export(&kvp->kvp_pool[HV_KVP_POOL_GUEST],
1008 0 : kvm->kvm_enum.kvm_index, kvm->kvm_enum.kvm_key,
1009 0 : &kvm->kvm_enum.kvm_keylen, kvm->kvm_enum.kvm_val,
1010 0 : &kvm->kvm_enum.kvm_vallen, &kvm->kvm_enum.kvm_valtype))
1011 0 : kvh->kvh_err = HV_KVP_S_CONT;
1012 : else
1013 0 : kvh->kvh_err = HV_KVP_S_OK;
1014 : break;
1015 : case HV_KVP_OP_GET_IP_INFO:
1016 0 : if (VMBUS_ICVER_MAJOR(msg->ic_hdr.ic_msgver) <= 4) {
1017 : struct vmbus_icmsg_kvp_addr *amsg;
1018 : struct hv_kvp_msg_addr *kva;
1019 :
1020 0 : amsg = (struct vmbus_icmsg_kvp_addr *)msg;
1021 0 : kva = &amsg->ic_kvm;
1022 :
1023 0 : if (kvp_get_ip_info(kvp, kva->kvm_mac,
1024 0 : &kva->kvm_family, kva->kvm_addr,
1025 0 : kva->kvm_netmask, sizeof(kva->kvm_addr)))
1026 0 : kvh->kvh_err = HV_KVP_S_CONT;
1027 : else
1028 0 : kvh->kvh_err = HV_KVP_S_OK;
1029 0 : } else {
1030 : DPRINTF("KVP GET_IP_INFO fw %u.%u msg %u.%u dsize=%u\n",
1031 : VMBUS_ICVER_MAJOR(msg->ic_hdr.ic_fwver),
1032 : VMBUS_ICVER_MINOR(msg->ic_hdr.ic_fwver),
1033 : VMBUS_ICVER_MAJOR(msg->ic_hdr.ic_msgver),
1034 : VMBUS_ICVER_MINOR(msg->ic_hdr.ic_msgver),
1035 : msg->ic_hdr.ic_dsize);
1036 0 : kvh->kvh_err = HV_KVP_S_CONT;
1037 : }
1038 : break;
1039 : default:
1040 : DPRINTF("KVP message op %u pool %u\n", kvh->kvh_op,
1041 : kvh->kvh_pool);
1042 0 : kvh->kvh_err = HV_KVP_S_CONT;
1043 0 : }
1044 0 : }
1045 :
1046 : void
1047 0 : hv_kvp(void *arg)
1048 : {
1049 0 : struct hv_ic_dev *dv = arg;
1050 0 : struct hv_channel *ch = dv->dv_ch;
1051 0 : struct hv_softc *sc = ch->ch_sc;
1052 0 : struct hv_kvp *kvp = dv->dv_priv;
1053 : struct vmbus_icmsg_hdr *hdr;
1054 0 : uint64_t rid;
1055 0 : uint32_t fwver, msgver, rlen;
1056 : int rv;
1057 :
1058 0 : for (;;) {
1059 0 : rv = hv_channel_recv(ch, dv->dv_buf, 2 * PAGE_SIZE,
1060 : &rlen, &rid, 0);
1061 0 : if (rv || rlen == 0) {
1062 : if (rv != EAGAIN)
1063 : DPRINTF("%s: kvp rv=%d rlen=%u\n",
1064 : sc->sc_dev.dv_xname, rv, rlen);
1065 0 : return;
1066 : }
1067 0 : if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
1068 : DPRINTF("%s: kvp short read rlen=%u\n",
1069 : sc->sc_dev.dv_xname, rlen);
1070 0 : return;
1071 : }
1072 0 : hdr = (struct vmbus_icmsg_hdr *)dv->dv_buf;
1073 0 : switch (hdr->ic_type) {
1074 : case VMBUS_ICMSG_TYPE_NEGOTIATE:
1075 0 : switch (sc->sc_proto) {
1076 : case VMBUS_VERSION_WS2008:
1077 : fwver = VMBUS_IC_VERSION(1, 0);
1078 : msgver = VMBUS_IC_VERSION(1, 0);
1079 0 : break;
1080 : case VMBUS_VERSION_WIN7:
1081 : fwver = VMBUS_IC_VERSION(3, 0);
1082 : msgver = VMBUS_IC_VERSION(3, 0);
1083 0 : break;
1084 : default:
1085 : fwver = VMBUS_IC_VERSION(3, 0);
1086 : msgver = VMBUS_IC_VERSION(4, 0);
1087 0 : }
1088 0 : hv_ic_negotiate(hdr, &rlen, fwver, msgver);
1089 0 : break;
1090 : case VMBUS_ICMSG_TYPE_KVP:
1091 0 : if (hdr->ic_dsize >= sizeof(union hv_kvp_hdr))
1092 0 : hv_kvp_process(kvp,
1093 0 : (struct vmbus_icmsg_kvp *)hdr);
1094 : else
1095 0 : printf("%s: message too short: %u\n",
1096 0 : sc->sc_dev.dv_xname, hdr->ic_dsize);
1097 : break;
1098 : default:
1099 0 : printf("%s: unhandled kvp message type %u\n",
1100 0 : sc->sc_dev.dv_xname, hdr->ic_type);
1101 0 : continue;
1102 : }
1103 0 : hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION |
1104 : VMBUS_ICMSG_FLAG_RESPONSE;
1105 0 : hv_channel_send(ch, dv->dv_buf, rlen, rid,
1106 : VMBUS_CHANPKT_TYPE_INBAND, 0);
1107 : }
1108 0 : }
1109 :
1110 : static int
1111 0 : kvp_poolname(char **key)
1112 : {
1113 : char *p;
1114 : int i, rv = -1;
1115 :
1116 0 : if ((p = strrchr(*key, '/')) == NULL)
1117 0 : return (rv);
1118 0 : *p = '\0';
1119 0 : for (i = 0; i < nitems(kvp_pools); i++) {
1120 0 : if (strncasecmp(*key, kvp_pools[i].poolname,
1121 0 : kvp_pools[i].poolnamelen) == 0) {
1122 0 : rv = kvp_pools[i].poolidx;
1123 0 : break;
1124 : }
1125 : }
1126 0 : if (rv >= 0)
1127 0 : *key = ++p;
1128 0 : return (rv);
1129 0 : }
1130 :
1131 : int
1132 0 : hv_kvop(void *arg, int op, char *key, char *val, size_t vallen)
1133 : {
1134 0 : struct hv_ic_dev *dv = arg;
1135 0 : struct hv_kvp *kvp = dv->dv_priv;
1136 : struct kvp_pool *kvpl;
1137 : int next, pool, error = 0;
1138 : char *vp = val;
1139 0 : size_t keylen;
1140 :
1141 0 : pool = kvp_poolname(&key);
1142 0 : if (pool == -1)
1143 0 : return (EINVAL);
1144 :
1145 0 : kvpl = &kvp->kvp_pool[pool];
1146 0 : if (strlen(key) == 0) {
1147 0 : for (next = 0; next < MAXPOOLENTS; next++) {
1148 0 : if ((val + vallen < vp + HV_KVP_MAX_KEY_SIZE / 2) ||
1149 0 : kvp_pool_keys(kvpl, next, vp, &keylen))
1150 : goto out;
1151 0 : if (strlcat(val, "\n", vallen) >= vallen)
1152 : goto out;
1153 0 : vp += keylen;
1154 : }
1155 : out:
1156 0 : if (vp > val)
1157 0 : *(vp - 1) = '\0';
1158 0 : return (0);
1159 : }
1160 :
1161 0 : if (op == PVBUS_KVWRITE) {
1162 0 : if (pool == HV_KVP_POOL_AUTO)
1163 0 : error = kvp_pool_update(kvpl, key, val, vallen,
1164 : HV_KVP_REG_SZ);
1165 0 : else if (pool == HV_KVP_POOL_GUEST)
1166 0 : error = kvp_pool_insert(kvpl, key, val, vallen,
1167 : HV_KVP_REG_SZ);
1168 : else
1169 : error = EINVAL;
1170 : } else
1171 0 : error = kvp_pool_extract(kvpl, key, val, vallen);
1172 :
1173 0 : return (error);
1174 0 : }
|