blob: 4cc78ac13e499cd75b1a4ecd71bed02ce4a8e45c [file] [log] [blame]
Carl van Schaik6d7b2ff2018-07-06 22:00:55 +10001/*
2 * drivers/vservices/core_client.c
3 *
4 * Copyright (c) 2012-2018 General Dynamics
5 * Copyright (c) 2014 Open Kernel Labs, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Client side core service application driver. This is responsible for:
12 *
13 * - automatically connecting to the server when it becomes ready;
14 * - sending a reset command to the server if something has gone wrong; and
15 * - enumerating all the available services.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/completion.h>
21#include <linux/workqueue.h>
22#include <linux/device.h>
23#include <linux/slab.h>
24#include <linux/list.h>
25#include <linux/err.h>
26#include <linux/module.h>
27
28#include <vservices/types.h>
29#include <vservices/transport.h>
30#include <vservices/session.h>
31#include <vservices/buffer.h>
32#include <vservices/service.h>
33
34#include <vservices/protocol/core/types.h>
35#include <vservices/protocol/core/common.h>
36#include <vservices/protocol/core/client.h>
37
38#include "session.h"
39#include "transport.h"
40#include "compat.h"
41
42struct core_client {
43 struct vs_client_core_state state;
44 struct vs_service_device *service;
45
46 struct list_head message_queue;
47 struct mutex message_queue_lock;
48 struct work_struct message_queue_work;
49};
50
51struct pending_reset {
52 struct vs_service_device *service;
53 struct list_head list;
54};
55
56#define to_core_client(x) container_of(x, struct core_client, state)
57#define dev_to_core_client(x) to_core_client(dev_get_drvdata(x))
58
59static int vs_client_core_fatal_error(struct vs_client_core_state *state)
60{
61 struct core_client *client = to_core_client(state);
62
63 /* Force a transport level reset */
64 dev_err(&client->service->dev," Fatal error - resetting session\n");
65 return -EPROTO;
66}
67
68static struct core_client *
69vs_client_session_core_client(struct vs_session_device *session)
70{
71 struct vs_service_device *core_service = session->core_service;
72
73 if (!core_service)
74 return NULL;
75
76 return dev_to_core_client(&core_service->dev);
77}
78
79static ssize_t client_core_reset_service_store(struct device *dev,
80 struct device_attribute *attr, const char *buf, size_t count)
81{
82 struct vs_service_device *core_service = to_vs_service_device(dev);
83 struct vs_session_device *session =
84 vs_service_get_session(core_service);
85 struct vs_service_device *target;
86 vs_service_id_t service_id;
87 unsigned long val;
88 int err;
89
90 /* Writing a valid service id to this file resets that service */
91 err = kstrtoul(buf, 0, &val);
92 if (err)
93 return err;
94
95 service_id = val;
96 target = vs_session_get_service(session, service_id);
97 if (!target)
98 return -ENODEV;
99
100 err = vs_service_reset(target, core_service);
101
102 vs_put_service(target);
103 return err < 0 ? err : count;
104}
105
106static DEVICE_ATTR(reset_service, S_IWUSR, NULL,
107 client_core_reset_service_store);
108
109static struct attribute *client_core_dev_attrs[] = {
110 &dev_attr_reset_service.attr,
111 NULL,
112};
113
114static const struct attribute_group client_core_attr_group = {
115 .attrs = client_core_dev_attrs,
116};
117
118/*
119 * Protocol callbacks
120 */
121static int
122vs_client_core_handle_service_removed(struct vs_client_core_state *state,
123 u32 service_id)
124{
125 struct core_client *client = to_core_client(state);
126 struct vs_session_device *session =
127 vs_service_get_session(client->service);
128 struct vs_service_device *service;
129 int ret;
130
131 service = vs_session_get_service(session, service_id);
132 if (!service)
133 return -EINVAL;
134
135 ret = vs_service_handle_delete(service);
136 vs_put_service(service);
137 return ret;
138}
139
140static int vs_client_core_create_service(struct core_client *client,
141 struct vs_session_device *session, vs_service_id_t service_id,
142 struct vs_string *protocol_name_string,
143 struct vs_string *service_name_string)
144{
145 char *protocol_name, *service_name;
146 struct vs_service_device *service;
147 int ret = 0;
148
149 protocol_name = vs_string_dup(protocol_name_string, GFP_KERNEL);
150 if (!protocol_name) {
151 ret = -ENOMEM;
152 goto out;
153 }
154
155 service_name = vs_string_dup(service_name_string, GFP_KERNEL);
156 if (!service_name) {
157 ret = -ENOMEM;
158 goto out_free_protocol_name;
159 }
160
161 service = vs_service_register(session, client->service, service_id,
162 protocol_name, service_name, NULL);
163 if (IS_ERR(service)) {
164 ret = PTR_ERR(service);
165 goto out_free_service_name;
166 }
167
168 vs_service_start(service);
169
170out_free_service_name:
171 kfree(service_name);
172out_free_protocol_name:
173 kfree(protocol_name);
174out:
175 return ret;
176}
177
178static int
179vs_client_core_handle_service_created(struct vs_client_core_state *state,
180 u32 service_id, struct vs_string service_name,
181 struct vs_string protocol_name, struct vs_mbuf *mbuf)
182{
183 struct core_client *client = to_core_client(state);
184 struct vs_session_device *session =
185 vs_service_get_session(client->service);
186 int err;
187
188 vs_dev_debug(VS_DEBUG_CLIENT_CORE,
189 vs_service_get_session(client->service),
190 &client->service->dev, "Service info for %d received\n",
191 service_id);
192
193 err = vs_client_core_create_service(client, session, service_id,
194 &protocol_name, &service_name);
195 if (err)
196 dev_err(&session->dev,
197 "Failed to create service with id %d: %d\n",
198 service_id, err);
199
200 vs_client_core_core_free_service_created(state, &service_name,
201 &protocol_name, mbuf);
202
203 return err;
204}
205
206static int
207vs_client_core_send_service_reset(struct core_client *client,
208 struct vs_service_device *service)
209{
210 return vs_client_core_core_send_service_reset(&client->state,
211 service->id, GFP_KERNEL);
212}
213
214static int
215vs_client_core_queue_service_reset(struct vs_session_device *session,
216 struct vs_service_device *service)
217{
218 struct core_client *client =
219 vs_client_session_core_client(session);
220 struct pending_reset *msg;
221
222 if (!client)
223 return -ENODEV;
224
225 vs_dev_debug(VS_DEBUG_SERVER, session, &session->dev,
226 "Sending reset for service %d\n", service->id);
227
228 msg = kzalloc(sizeof(*msg), GFP_KERNEL);
229 if (!msg)
230 return -ENOMEM;
231
232 mutex_lock(&client->message_queue_lock);
233
234 /* put by message_queue_work */
235 msg->service = vs_get_service(service);
236 list_add_tail(&msg->list, &client->message_queue);
237
238 mutex_unlock(&client->message_queue_lock);
239 queue_work(client->service->work_queue, &client->message_queue_work);
240
241 return 0;
242}
243
244static int vs_core_client_tx_ready(struct vs_client_core_state *state)
245{
246 struct core_client *client = to_core_client(state);
247
248 queue_work(client->service->work_queue, &client->message_queue_work);
249
250 return 0;
251}
252
253static void message_queue_work(struct work_struct *work)
254{
255 struct core_client *client = container_of(work, struct core_client,
256 message_queue_work);
257 struct vs_session_device *session =
258 vs_service_get_session(client->service);
259 struct pending_reset *msg;
260 int err;
261
262 vs_service_state_lock(client->service);
263 if (!VSERVICE_CORE_STATE_IS_CONNECTED(client->state.state.core)) {
264 vs_service_state_unlock(client->service);
265 return;
266 }
267
268 vs_dev_debug(VS_DEBUG_CLIENT, session, &session->dev, "tx_ready\n");
269
270 mutex_lock(&client->message_queue_lock);
271 while (!list_empty(&client->message_queue)) {
272 msg = list_first_entry(&client->message_queue,
273 struct pending_reset, list);
274
275 err = vs_client_core_send_service_reset(client, msg->service);
276
277 /* If we're out of quota there's no point continuing */
278 if (err == -ENOBUFS)
279 break;
280
281 /* Any other error is fatal */
282 if (err < 0) {
283 dev_err(&client->service->dev,
284 "Failed to send pending reset for %d (%d) - resetting session",
285 msg->service->id, err);
286 vs_service_reset_nosync(client->service);
287 break;
288 }
289
290 /*
291 * The message sent successfully - remove it from the queue.
292 * The corresponding vs_get_service() was done when the pending
293 * message was enqueued.
294 */
295 vs_put_service(msg->service);
296 list_del(&msg->list);
297 kfree(msg);
298 }
299 mutex_unlock(&client->message_queue_lock);
300 vs_service_state_unlock(client->service);
301}
302
303static int
304vs_client_core_handle_server_ready(struct vs_client_core_state *state,
305 u32 service_id, u32 in_quota, u32 out_quota, u32 in_bit_offset,
306 u32 in_num_bits, u32 out_bit_offset, u32 out_num_bits)
307{
308 struct core_client *client = to_core_client(state);
309 struct vs_session_device *session;
310 struct vs_service_device *service;
311 int ret;
312
313 if (service_id == 0)
314 return -EPROTO;
315
316 if (!in_quota || !out_quota)
317 return -EINVAL;
318
319 session = vs_service_get_session(client->service);
320 service = vs_session_get_service(session, service_id);
321 if (!service)
322 return -EINVAL;
323
324 service->send_quota = in_quota;
325 service->recv_quota = out_quota;
326 service->notify_send_offset = in_bit_offset;
327 service->notify_send_bits = in_num_bits;
328 service->notify_recv_offset = out_bit_offset;
329 service->notify_recv_bits = out_num_bits;
330
331 ret = vs_service_enable(service);
332 vs_put_service(service);
333 return ret;
334}
335
336static int
337vs_client_core_handle_service_reset(struct vs_client_core_state *state,
338 u32 service_id)
339{
340 struct core_client *client = to_core_client(state);
341 struct vs_session_device *session;
342
343 if (service_id == 0)
344 return -EPROTO;
345
346 session = vs_service_get_session(client->service);
347
348 return vs_service_handle_reset(session, service_id, true);
349}
350
351static void vs_core_client_start(struct vs_client_core_state *state)
352{
353 struct core_client *client = to_core_client(state);
354 struct vs_session_device *session =
355 vs_service_get_session(client->service);
356
357 /* FIXME - start callback should return int */
358 vs_dev_debug(VS_DEBUG_CLIENT_CORE, session, &client->service->dev,
359 "Core client start\n");
360}
361
362static void vs_core_client_reset(struct vs_client_core_state *state)
363{
364 struct core_client *client = to_core_client(state);
365 struct vs_session_device *session =
366 vs_service_get_session(client->service);
367 struct pending_reset *msg;
368
369 /* Flush the pending resets - we're about to delete everything */
370 while (!list_empty(&client->message_queue)) {
371 msg = list_first_entry(&client->message_queue,
372 struct pending_reset, list);
373 vs_put_service(msg->service);
374 list_del(&msg->list);
375 kfree(msg);
376 }
377
378 vs_session_delete_noncore(session);
379
380 /* Return to the initial quotas, until the next startup message */
381 client->service->send_quota = 0;
382 client->service->recv_quota = 1;
383}
384
385static int vs_core_client_startup(struct vs_client_core_state *state,
386 u32 core_in_quota, u32 core_out_quota)
387{
388 struct core_client *client = to_core_client(state);
389 struct vs_service_device *service = state->service;
390 struct vs_session_device *session = vs_service_get_session(service);
391 int ret;
392
393 if (!core_in_quota || !core_out_quota)
394 return -EINVAL;
395
396 /*
397 * Update the service struct with our real quotas and tell the
398 * transport about the change
399 */
400
401 service->send_quota = core_in_quota;
402 service->recv_quota = core_out_quota;
403 ret = session->transport->vt->service_start(session->transport, service);
404 if (ret < 0)
405 return ret;
406
407 WARN_ON(!list_empty(&client->message_queue));
408
409 return vs_client_core_core_req_connect(state, GFP_KERNEL);
410}
411
412static struct vs_client_core_state *
413vs_core_client_alloc(struct vs_service_device *service)
414{
415 struct core_client *client;
416 int err;
417
418 client = kzalloc(sizeof(*client), GFP_KERNEL);
419 if (!client)
420 goto fail;
421
422 client->service = service;
423 INIT_LIST_HEAD(&client->message_queue);
424 INIT_WORK(&client->message_queue_work, message_queue_work);
425 mutex_init(&client->message_queue_lock);
426
427 err = sysfs_create_group(&service->dev.kobj, &client_core_attr_group);
428 if (err)
429 goto fail_free_client;
430
431 /*
432 * Default transport resources for the core service client. The
433 * server will inform us of the real quotas in the startup message.
434 * Note that it is important that the quotas never decrease, so these
435 * numbers are as small as possible.
436 */
437 service->send_quota = 0;
438 service->recv_quota = 1;
439 service->notify_send_bits = 0;
440 service->notify_send_offset = 0;
441 service->notify_recv_bits = 0;
442 service->notify_recv_offset = 0;
443
444 return &client->state;
445
446fail_free_client:
447 kfree(client);
448fail:
449 return NULL;
450}
451
452static void vs_core_client_release(struct vs_client_core_state *state)
453{
454 struct core_client *client = to_core_client(state);
455
456 sysfs_remove_group(&client->service->dev.kobj, &client_core_attr_group);
457 kfree(client);
458}
459
460static struct vs_client_core vs_core_client_driver = {
461 .alloc = vs_core_client_alloc,
462 .release = vs_core_client_release,
463 .start = vs_core_client_start,
464 .reset = vs_core_client_reset,
465 .tx_ready = vs_core_client_tx_ready,
466
467 .core = {
468 .nack_connect = vs_client_core_fatal_error,
469
470 /* FIXME: Jira ticket SDK-3074 - ryanm. */
471 .ack_disconnect = vs_client_core_fatal_error,
472 .nack_disconnect = vs_client_core_fatal_error,
473
474 .msg_service_created = vs_client_core_handle_service_created,
475 .msg_service_removed = vs_client_core_handle_service_removed,
476
477 .msg_startup = vs_core_client_startup,
478 /* FIXME: Jira ticket SDK-3074 - philipd. */
479 .msg_shutdown = vs_client_core_fatal_error,
480 .msg_server_ready = vs_client_core_handle_server_ready,
481 .msg_service_reset = vs_client_core_handle_service_reset,
482 },
483};
484
485/*
486 * Client bus driver
487 */
488static int vs_client_bus_match(struct device *dev, struct device_driver *driver)
489{
490 struct vs_service_device *service = to_vs_service_device(dev);
491 struct vs_service_driver *vsdrv = to_vs_service_driver(driver);
492
493 /* Don't match anything to the devio driver; it's bound manually */
494 if (!vsdrv->protocol)
495 return 0;
496
497 WARN_ON_ONCE(service->is_server || vsdrv->is_server);
498
499 /* Match if the protocol strings are the same */
500 if (strcmp(service->protocol, vsdrv->protocol) == 0)
501 return 1;
502
503 return 0;
504}
505
506static ssize_t is_server_show(struct device *dev, struct device_attribute *attr,
507 char *buf)
508{
509 struct vs_service_device *service = to_vs_service_device(dev);
510
511 return scnprintf(buf, PAGE_SIZE, "%d\n", service->is_server);
512}
513
514static ssize_t id_show(struct device *dev, struct device_attribute *attr,
515 char *buf)
516{
517 struct vs_service_device *service = to_vs_service_device(dev);
518
519 return scnprintf(buf, PAGE_SIZE, "%d\n", service->id);
520}
521
522static ssize_t dev_protocol_show(struct device *dev,
523 struct device_attribute *attr, char *buf)
524{
525 struct vs_service_device *service = to_vs_service_device(dev);
526
527 return scnprintf(buf, PAGE_SIZE, "%s\n", service->protocol ?: "");
528}
529
530static ssize_t service_name_show(struct device *dev,
531 struct device_attribute *attr, char *buf)
532{
533 struct vs_service_device *service = to_vs_service_device(dev);
534
535 return scnprintf(buf, PAGE_SIZE, "%s\n", service->name);
536}
537
538static ssize_t quota_in_show(struct device *dev,
539 struct device_attribute *attr, char *buf)
540{
541 struct vs_service_device *service = to_vs_service_device(dev);
542
543 return scnprintf(buf, PAGE_SIZE, "%d\n", service->send_quota);
544}
545
546static ssize_t quota_out_show(struct device *dev,
547 struct device_attribute *attr, char *buf)
548{
549 struct vs_service_device *service = to_vs_service_device(dev);
550
551 return scnprintf(buf, PAGE_SIZE, "%d\n", service->recv_quota);
552}
553
554static struct device_attribute vs_client_dev_attrs[] = {
555 __ATTR_RO(id),
556 __ATTR_RO(is_server),
557 __ATTR(protocol, S_IRUGO, dev_protocol_show, NULL),
558 __ATTR_RO(service_name),
559 __ATTR_RO(quota_in),
560 __ATTR_RO(quota_out),
561 __ATTR_NULL
562};
563
564static ssize_t protocol_show(struct device_driver *drv, char *buf)
565{
566 struct vs_service_driver *driver = to_vs_service_driver(drv);
567
568 return scnprintf(buf, PAGE_SIZE, "%s\n", driver->protocol);
569}
570
571#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
572static struct driver_attribute vs_client_drv_attrs[] = {
573 __ATTR_RO(protocol),
574 __ATTR_NULL
575};
576#else
577static DRIVER_ATTR_RO(protocol);
578
579static struct attribute *vs_client_drv_attrs[] = {
580 &driver_attr_protocol.attr,
581 NULL,
582};
583ATTRIBUTE_GROUPS(vs_client_drv);
584#endif
585
586struct bus_type vs_client_bus_type = {
587 .name = "vservices-client",
588 .dev_attrs = vs_client_dev_attrs,
589#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
590 .drv_attrs = vs_client_drv_attrs,
591#else
592 .drv_groups = vs_client_drv_groups,
593#endif
594 .match = vs_client_bus_match,
595 .probe = vs_service_bus_probe,
596 .remove = vs_service_bus_remove,
597 .uevent = vs_service_bus_uevent,
598};
599EXPORT_SYMBOL(vs_client_bus_type);
600
601/*
602 * Client session driver
603 */
604static int vs_client_session_probe(struct device *dev)
605{
606 struct vs_session_device *session = to_vs_session_device(dev);
607 struct vs_service_device *service;
608 char *protocol, *name;
609 int ret = 0;
610
611 if (session->is_server) {
612 ret = -ENODEV;
613 goto fail;
614 }
615
616 /* create a service for the core protocol client */
617 protocol = kstrdup(VSERVICE_CORE_PROTOCOL_NAME, GFP_KERNEL);
618 if (!protocol) {
619 ret = -ENOMEM;
620 goto fail;
621 }
622
623 name = kstrdup("core", GFP_KERNEL);
624 if (!name) {
625 ret = -ENOMEM;
626 goto fail_free_protocol;
627 }
628
629 service = vs_service_register(session, NULL, 0, protocol, name, NULL);
630 if (IS_ERR(service)) {
631 ret = PTR_ERR(service);
632 goto fail_free_name;
633 }
634
635fail_free_name:
636 kfree(name);
637fail_free_protocol:
638 kfree(protocol);
639fail:
640 return ret;
641}
642
643static int
644vs_client_session_send_service_reset(struct vs_session_device *session,
645 struct vs_service_device *service)
646{
647 if (WARN_ON(service->id == 0))
648 return -EINVAL;
649
650 return vs_client_core_queue_service_reset(session, service);
651}
652
653static struct vs_session_driver vs_client_session_driver = {
654 .driver = {
655 .name = "vservices-client-session",
656 .owner = THIS_MODULE,
657 .bus = &vs_session_bus_type,
658 .probe = vs_client_session_probe,
659 .suppress_bind_attrs = true,
660 },
661 .is_server = false,
662 .service_bus = &vs_client_bus_type,
663 .service_local_reset = vs_client_session_send_service_reset,
664};
665
666static int __init vs_core_client_init(void)
667{
668 int ret;
669
670 ret = bus_register(&vs_client_bus_type);
671 if (ret)
672 goto fail_bus_register;
673
674#ifdef CONFIG_VSERVICES_CHAR_DEV
675 vs_devio_client_driver.driver.bus = &vs_client_bus_type;
676 vs_devio_client_driver.driver.owner = THIS_MODULE;
677 ret = driver_register(&vs_devio_client_driver.driver);
678 if (ret)
679 goto fail_devio_register;
680#endif
681
682 ret = driver_register(&vs_client_session_driver.driver);
683 if (ret)
684 goto fail_driver_register;
685
686 ret = vservice_core_client_register(&vs_core_client_driver,
687 "vs_core_client");
688 if (ret)
689 goto fail_core_register;
690
691 vservices_client_root = kobject_create_and_add("client-sessions",
692 vservices_root);
693 if (!vservices_client_root) {
694 ret = -ENOMEM;
695 goto fail_create_root;
696 }
697
698 return 0;
699
700fail_create_root:
701 vservice_core_client_unregister(&vs_core_client_driver);
702fail_core_register:
703 driver_unregister(&vs_client_session_driver.driver);
704fail_driver_register:
705#ifdef CONFIG_VSERVICES_CHAR_DEV
706 driver_unregister(&vs_devio_client_driver.driver);
707 vs_devio_client_driver.driver.bus = NULL;
708 vs_devio_client_driver.driver.owner = NULL;
709fail_devio_register:
710#endif
711 bus_unregister(&vs_client_bus_type);
712fail_bus_register:
713 return ret;
714}
715
716static void __exit vs_core_client_exit(void)
717{
718 kobject_put(vservices_client_root);
719 vservice_core_client_unregister(&vs_core_client_driver);
720 driver_unregister(&vs_client_session_driver.driver);
721#ifdef CONFIG_VSERVICES_CHAR_DEV
722 driver_unregister(&vs_devio_client_driver.driver);
723 vs_devio_client_driver.driver.bus = NULL;
724 vs_devio_client_driver.driver.owner = NULL;
725#endif
726 bus_unregister(&vs_client_bus_type);
727}
728
729subsys_initcall(vs_core_client_init);
730module_exit(vs_core_client_exit);
731
732MODULE_DESCRIPTION("OKL4 Virtual Services Core Client Driver");
733MODULE_AUTHOR("Open Kernel Labs, Inc");