/* * Copyright (c) 2012-2018 General Dynamics * Copyright (c) 2014 Open Kernel Labs, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * This is the generated code for the core server protocol handling. */ #include #include #include #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) #include #endif #include #include #include #include #include #include #include "../../transport.h" #define VS_MBUF_SIZE(mbuf) mbuf->size #define VS_MBUF_DATA(mbuf) mbuf->data #define VS_STATE_SERVICE_PTR(state) state->service /*** Linux driver model integration ***/ struct vs_core_server_driver { struct vs_server_core *server; struct list_head list; struct vs_service_driver vsdrv; }; #define to_server_driver(d) \ container_of(d, struct vs_core_server_driver, vsdrv) static void core_handle_start(struct vs_service_device *service) { struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server __maybe_unused = to_server_driver(vsdrv)->server; vs_service_state_lock(service); state->state = VSERVICE_CORE_PROTOCOL_RESET_STATE; if (server->start) server->start(state); vs_service_state_unlock(service); } static void core_handle_reset(struct vs_service_device *service) { struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server __maybe_unused = to_server_driver(vsdrv)->server; vs_service_state_lock(service); state->state = VSERVICE_CORE_PROTOCOL_RESET_STATE; if (server->reset) server->reset(state); vs_service_state_unlock(service); } static void core_handle_start_bh(struct vs_service_device *service) { struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server __maybe_unused = to_server_driver(vsdrv)->server; vs_service_state_lock_bh(service); state->state = VSERVICE_CORE_PROTOCOL_RESET_STATE; if (server->start) server->start(state); vs_service_state_unlock_bh(service); } static void core_handle_reset_bh(struct vs_service_device *service) { struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server __maybe_unused = to_server_driver(vsdrv)->server; vs_service_state_lock_bh(service); state->state = VSERVICE_CORE_PROTOCOL_RESET_STATE; if (server->reset) server->reset(state); vs_service_state_unlock_bh(service); } static int core_server_probe(struct vs_service_device *service); static int core_server_remove(struct vs_service_device *service); static int core_handle_message(struct vs_service_device *service, struct vs_mbuf *_mbuf); static void core_handle_notify(struct vs_service_device *service, uint32_t flags); static void core_handle_start(struct vs_service_device *service); static void core_handle_start_bh(struct vs_service_device *service); static void core_handle_reset(struct vs_service_device *service); static void core_handle_reset_bh(struct vs_service_device *service); static int core_handle_tx_ready(struct vs_service_device *service); int __vservice_core_server_register(struct vs_server_core *server, const char *name, struct module *owner) { int ret; struct vs_core_server_driver *driver; if (server->tx_atomic && !server->rx_atomic) return -EINVAL; driver = kzalloc(sizeof(*driver), GFP_KERNEL); if (!driver) { ret = -ENOMEM; goto fail_alloc_driver; } server->driver = &driver->vsdrv; driver->server = server; driver->vsdrv.protocol = VSERVICE_CORE_PROTOCOL_NAME; driver->vsdrv.is_server = true; driver->vsdrv.rx_atomic = server->rx_atomic; driver->vsdrv.tx_atomic = server->tx_atomic; /* FIXME Jira ticket SDK-2835 - philipd. */ driver->vsdrv.in_quota_min = 1; driver->vsdrv.in_quota_best = server->in_quota_best ? server->in_quota_best : driver->vsdrv.in_quota_min; /* FIXME Jira ticket SDK-2835 - philipd. */ driver->vsdrv.out_quota_min = 1; driver->vsdrv.out_quota_best = server->out_quota_best ? server->out_quota_best : driver->vsdrv.out_quota_min; driver->vsdrv.in_notify_count = VSERVICE_CORE_NBIT_IN__COUNT; driver->vsdrv.out_notify_count = VSERVICE_CORE_NBIT_OUT__COUNT; driver->vsdrv.probe = core_server_probe; driver->vsdrv.remove = core_server_remove; driver->vsdrv.receive = core_handle_message; driver->vsdrv.notify = core_handle_notify; driver->vsdrv.start = server->tx_atomic ? core_handle_start_bh : core_handle_start; driver->vsdrv.reset = server->tx_atomic ? core_handle_reset_bh : core_handle_reset; driver->vsdrv.tx_ready = core_handle_tx_ready; driver->vsdrv.out_notify_count = 0; driver->vsdrv.in_notify_count = 0; driver->vsdrv.driver.name = name; driver->vsdrv.driver.owner = owner; driver->vsdrv.driver.bus = &vs_server_bus_type; ret = driver_register(&driver->vsdrv.driver); if (ret) { goto fail_driver_register; } return 0; fail_driver_register: server->driver = NULL; kfree(driver); fail_alloc_driver: return ret; } EXPORT_SYMBOL(__vservice_core_server_register); int vservice_core_server_unregister(struct vs_server_core *server) { struct vs_core_server_driver *driver; if (!server->driver) return 0; driver = to_server_driver(server->driver); driver_unregister(&driver->vsdrv.driver); server->driver = NULL; kfree(driver); return 0; } EXPORT_SYMBOL(vservice_core_server_unregister); static int core_server_probe(struct vs_service_device *service) { struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server = to_server_driver(vsdrv)->server; struct vs_server_core_state *state; state = server->alloc(service); if (!state) return -ENOMEM; else if (IS_ERR(state)) return PTR_ERR(state); state->service = vs_get_service(service); state->state = VSERVICE_CORE_PROTOCOL_RESET_STATE; dev_set_drvdata(&service->dev, state); return 0; } static int core_server_remove(struct vs_service_device *service) { struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server = to_server_driver(vsdrv)->server; state->released = true; dev_set_drvdata(&service->dev, NULL); server->release(state); vs_put_service(service); return 0; } static int core_handle_tx_ready(struct vs_service_device *service) { struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); struct vs_server_core *server = to_server_driver(vsdrv)->server; struct vs_server_core_state *state = dev_get_drvdata(&service->dev); if (server->tx_ready) server->tx_ready(state); return 0; } struct vs_mbuf *vs_server_core_core_alloc_service_created(struct vs_server_core_state *_state, struct vs_string *service_name, struct vs_string *protocol_name, gfp_t flags) { struct vs_mbuf *_mbuf; const vs_message_id_t _msg_id = VSERVICE_CORE_CORE_MSG_SERVICE_CREATED; const uint32_t _msg_size = sizeof(vs_message_id_t) + VSERVICE_CORE_SERVICE_NAME_SIZE + VSERVICE_CORE_PROTOCOL_NAME_SIZE + 4UL; _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return _mbuf; if (!_mbuf) { WARN_ON_ONCE(1); return ERR_PTR(-ENOMEM); } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = _msg_id; if (!service_name) goto fail; service_name->ptr = (char *)(VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 4UL); service_name->max_size = VSERVICE_CORE_SERVICE_NAME_SIZE; if (!protocol_name) goto fail; protocol_name->ptr = (char *)(VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + VSERVICE_CORE_SERVICE_NAME_SIZE + 4UL); protocol_name->max_size = VSERVICE_CORE_PROTOCOL_NAME_SIZE; return _mbuf; fail: vs_service_free_mbuf(VS_STATE_SERVICE_PTR(_state), _mbuf); return NULL; } EXPORT_SYMBOL(vs_server_core_core_alloc_service_created); int vs_server_core_core_free_service_created(struct vs_server_core_state *_state, struct vs_string *service_name, struct vs_string *protocol_name, struct vs_mbuf *_mbuf) { vs_service_free_mbuf(VS_STATE_SERVICE_PTR(_state), _mbuf); return 0; } EXPORT_SYMBOL(vs_server_core_core_free_service_created); int vs_server_core_core_send_ack_connect(struct vs_server_core_state *_state, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 0UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_DISCONNECTED__CONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_ACK_CONNECT; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } _state->state.core.statenum = VSERVICE_CORE_STATE_CONNECTED; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_DISCONNECTED__CONNECT, VSERVICE_CORE_STATE_CONNECTED); return 0; } EXPORT_SYMBOL(vs_server_core_core_send_ack_connect); int vs_server_core_core_send_nack_connect(struct vs_server_core_state *_state, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 0UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_DISCONNECTED__CONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_NACK_CONNECT; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } _state->state.core.statenum = VSERVICE_CORE_STATE_DISCONNECTED; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_DISCONNECTED__CONNECT, VSERVICE_CORE_STATE_DISCONNECTED); return 0; } EXPORT_SYMBOL(vs_server_core_core_send_nack_connect); int vs_server_core_core_send_ack_disconnect(struct vs_server_core_state *_state, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 0UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED__DISCONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_ACK_DISCONNECT; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } _state->state.core.statenum = VSERVICE_CORE_STATE_DISCONNECTED; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_CONNECTED__DISCONNECT, VSERVICE_CORE_STATE_DISCONNECTED); return 0; } EXPORT_SYMBOL(vs_server_core_core_send_ack_disconnect); int vs_server_core_core_send_nack_disconnect(struct vs_server_core_state *_state, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 0UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED__DISCONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_NACK_DISCONNECT; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } _state->state.core.statenum = VSERVICE_CORE_STATE_CONNECTED; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_CONNECTED__DISCONNECT, VSERVICE_CORE_STATE_CONNECTED); return 0; } EXPORT_SYMBOL(vs_server_core_core_send_nack_disconnect); static int vs_server_core_core_handle_req_connect(const struct vs_server_core *_server, struct vs_server_core_state *_state, struct vs_mbuf *_mbuf) { const size_t _expected_size = sizeof(vs_message_id_t) + 0UL; if (VS_MBUF_SIZE(_mbuf) < _expected_size) return -EBADMSG; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_DISCONNECTED: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _state->state.core.statenum = VSERVICE_CORE_STATE_DISCONNECTED__CONNECT; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_DISCONNECTED, VSERVICE_CORE_STATE_DISCONNECTED__CONNECT); vs_service_free_mbuf(VS_STATE_SERVICE_PTR(_state), _mbuf); if (_server->core.req_connect) return _server->core.req_connect(_state); else dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: No handler registered for _server->core.req_connect, command will never be acknowledged\n", __func__, __LINE__); return 0; } EXPORT_SYMBOL(vs_server_core_core_handle_req_connect); static int vs_server_core_core_handle_req_disconnect(const struct vs_server_core *_server, struct vs_server_core_state *_state, struct vs_mbuf *_mbuf) { const size_t _expected_size = sizeof(vs_message_id_t) + 0UL; if (VS_MBUF_SIZE(_mbuf) < _expected_size) return -EBADMSG; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _state->state.core.statenum = VSERVICE_CORE_STATE_CONNECTED__DISCONNECT; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_CONNECTED, VSERVICE_CORE_STATE_CONNECTED__DISCONNECT); vs_service_free_mbuf(VS_STATE_SERVICE_PTR(_state), _mbuf); if (_server->core.req_disconnect) return _server->core.req_disconnect(_state); else dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: No handler registered for _server->core.req_disconnect, command will never be acknowledged\n", __func__, __LINE__); return 0; } EXPORT_SYMBOL(vs_server_core_core_handle_req_disconnect); int vs_server_core_core_send_startup(struct vs_server_core_state *_state, uint32_t core_in_quota, uint32_t core_out_quota, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 8UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_OFFLINE: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_MSG_STARTUP; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 0UL) = core_in_quota; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 4UL) = core_out_quota; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } _state->state.core.statenum = VSERVICE_CORE_STATE_DISCONNECTED; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_OFFLINE, VSERVICE_CORE_STATE_DISCONNECTED); return 0; } EXPORT_SYMBOL(vs_server_core_core_send_startup); int vs_server_core_core_send_shutdown(struct vs_server_core_state *_state, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 0UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_DISCONNECTED: case VSERVICE_CORE_STATE_DISCONNECTED__CONNECT: case VSERVICE_CORE_STATE_CONNECTED: case VSERVICE_CORE_STATE_CONNECTED__DISCONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_MSG_SHUTDOWN; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_DISCONNECTED: _state->state.core.statenum = VSERVICE_CORE_STATE_OFFLINE; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_DISCONNECTED, VSERVICE_CORE_STATE_OFFLINE); break; case VSERVICE_CORE_STATE_CONNECTED: _state->state.core.statenum = VSERVICE_CORE_STATE_OFFLINE; if (_server->core.state_change) _server->core.state_change(_state, VSERVICE_CORE_STATE_CONNECTED, VSERVICE_CORE_STATE_OFFLINE); break; default: break; } return 0; } EXPORT_SYMBOL(vs_server_core_core_send_shutdown); int vs_server_core_core_send_service_created(struct vs_server_core_state *_state, uint32_t service_id, struct vs_string service_name, struct vs_string protocol_name, struct vs_mbuf *_mbuf) { struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED: case VSERVICE_CORE_STATE_CONNECTED__DISCONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } if (*(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) != VSERVICE_CORE_CORE_MSG_SERVICE_CREATED) return -EINVAL; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 0UL) = service_id; { size_t _size = strnlen(service_name.ptr, service_name.max_size); if ((_size + sizeof(vs_message_id_t) + 4UL) > VS_MBUF_SIZE(_mbuf)) return -EINVAL; memset(service_name.ptr + _size, 0, service_name.max_size - _size); } { size_t _size = strnlen(protocol_name.ptr, protocol_name.max_size); if ((_size + sizeof(vs_message_id_t) + VSERVICE_CORE_SERVICE_NAME_SIZE + 4UL) > VS_MBUF_SIZE(_mbuf)) return -EINVAL; if (_size < protocol_name.max_size) VS_MBUF_SIZE(_mbuf) -= (protocol_name.max_size - _size); } { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } return 0; } EXPORT_SYMBOL(vs_server_core_core_send_service_created); int vs_server_core_core_send_service_removed(struct vs_server_core_state *_state, uint32_t service_id, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 4UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED: case VSERVICE_CORE_STATE_CONNECTED__DISCONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_MSG_SERVICE_REMOVED; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 0UL) = service_id; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } return 0; } EXPORT_SYMBOL(vs_server_core_core_send_service_removed); int vs_server_core_core_send_server_ready(struct vs_server_core_state *_state, uint32_t service_id, uint32_t in_quota, uint32_t out_quota, uint32_t in_bit_offset, uint32_t in_num_bits, uint32_t out_bit_offset, uint32_t out_num_bits, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 28UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED: case VSERVICE_CORE_STATE_CONNECTED__DISCONNECT: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_MSG_SERVER_READY; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 0UL) = service_id; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 4UL) = in_quota; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 8UL) = out_quota; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 12UL) = in_bit_offset; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 16UL) = in_num_bits; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 20UL) = out_bit_offset; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 24UL) = out_num_bits; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } return 0; } EXPORT_SYMBOL(vs_server_core_core_send_server_ready); int vs_server_core_core_send_service_reset(struct vs_server_core_state *_state, uint32_t service_id, gfp_t flags) { struct vs_mbuf *_mbuf; const size_t _msg_size = sizeof(vs_message_id_t) + 4UL; struct vs_service_driver *vsdrv = to_vs_service_driver(VS_STATE_SERVICE_PTR(_state)->dev.driver); __maybe_unused struct vs_server_core *_server = to_server_driver(vsdrv)->server; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } _mbuf = vs_service_alloc_mbuf(VS_STATE_SERVICE_PTR(_state), _msg_size, flags); if (IS_ERR(_mbuf)) return PTR_ERR(_mbuf); if (!_mbuf) { WARN_ON_ONCE(1); return -ENOMEM; } *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)) = VSERVICE_CORE_CORE_MSG_SERVICE_RESET; *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 0UL) = service_id; { int err = vs_service_send(VS_STATE_SERVICE_PTR(_state), _mbuf); if (err) { dev_warn(&_state->service->dev, "[%s:%d] Protocol warning: Error %d sending message on transport.\n", __func__, __LINE__, err); return err; } } return 0; } EXPORT_SYMBOL(vs_server_core_core_send_service_reset); static int vs_server_core_core_handle_service_reset(const struct vs_server_core *_server, struct vs_server_core_state *_state, struct vs_mbuf *_mbuf) { const size_t _expected_size = sizeof(vs_message_id_t) + 4UL; uint32_t service_id; switch (_state->state.core.statenum) { case VSERVICE_CORE_STATE_CONNECTED: break; default: dev_err(&_state->service->dev, "[%s:%d] Protocol error: In wrong protocol state %d - %s\n", __func__, __LINE__, _state->state.core.statenum, vservice_core_get_state_string(_state->state.core)); return -EPROTO; } if (VS_MBUF_SIZE(_mbuf) < _expected_size) return -EBADMSG; service_id = *(uint32_t *) (VS_MBUF_DATA(_mbuf) + sizeof(vs_message_id_t) + 0UL); vs_service_free_mbuf(VS_STATE_SERVICE_PTR(_state), _mbuf); if (_server->core.msg_service_reset) return _server->core.msg_service_reset(_state, service_id); return 0; return 0; } EXPORT_SYMBOL(vs_server_core_core_handle_service_reset); static int core_handle_message(struct vs_service_device *service, struct vs_mbuf *_mbuf) { vs_message_id_t message_id; __maybe_unused struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); __maybe_unused struct vs_server_core *server = to_server_driver(vsdrv)->server; int ret; /* Extract the message ID */ if (VS_MBUF_SIZE(_mbuf) < sizeof(message_id)) { dev_err(&state->service->dev, "[%s:%d] Protocol error: Invalid message size %zd\n", __func__, __LINE__, VS_MBUF_SIZE(_mbuf)); return -EBADMSG; } message_id = *(vs_message_id_t *) (VS_MBUF_DATA(_mbuf)); switch (message_id) { /** interface core **/ /* command in sync connect */ case VSERVICE_CORE_CORE_REQ_CONNECT: ret = vs_server_core_core_handle_req_connect(server, state, _mbuf); break; /* command in sync disconnect */ case VSERVICE_CORE_CORE_REQ_DISCONNECT: ret = vs_server_core_core_handle_req_disconnect(server, state, _mbuf); break; /* message service_reset */ case VSERVICE_CORE_CORE_MSG_SERVICE_RESET: ret = vs_server_core_core_handle_service_reset(server, state, _mbuf); break; default: dev_err(&state->service->dev, "[%s:%d] Protocol error: Unknown message type %d\n", __func__, __LINE__, (int)message_id); ret = -EPROTO; break; } if (ret) { dev_err(&state->service->dev, "[%s:%d] Protocol error: Handler for message type %d returned %d\n", __func__, __LINE__, (int)message_id, ret); } return ret; } static void core_handle_notify(struct vs_service_device *service, uint32_t notify_bits) { __maybe_unused struct vs_server_core_state *state = dev_get_drvdata(&service->dev); struct vs_service_driver *vsdrv = to_vs_service_driver(service->dev.driver); __maybe_unused struct vs_server_core *server = to_server_driver(vsdrv)->server; uint32_t bits = notify_bits; int ret; while (bits) { uint32_t not = __ffs(bits); switch (not) { /** interface core **/ default: dev_err(&state->service->dev, "[%s:%d] Protocol error: Unknown notification %d\n", __func__, __LINE__, (int)not); ret = -EPROTO; break; } bits &= ~(1 << not); if (ret) { dev_err(&state->service->dev, "[%s:%d] Protocol error: Handler for notification %d returned %d\n", __func__, __LINE__, (int)not, ret); } } } MODULE_DESCRIPTION("OKL4 Virtual Services coreServer Protocol Driver"); MODULE_AUTHOR("Open Kernel Labs, Inc");