log.c (3120B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Greybus driver for the log protocol 4 * 5 * Copyright 2016 Google Inc. 6 */ 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/slab.h> 10#include <linux/sizes.h> 11#include <linux/uaccess.h> 12#include <linux/greybus.h> 13 14struct gb_log { 15 struct gb_connection *connection; 16}; 17 18static int gb_log_request_handler(struct gb_operation *op) 19{ 20 struct gb_connection *connection = op->connection; 21 struct device *dev = &connection->bundle->dev; 22 struct gb_log_send_log_request *receive; 23 u16 len; 24 25 if (op->type != GB_LOG_TYPE_SEND_LOG) { 26 dev_err(dev, "unknown request type 0x%02x\n", op->type); 27 return -EINVAL; 28 } 29 30 /* Verify size of payload */ 31 if (op->request->payload_size < sizeof(*receive)) { 32 dev_err(dev, "log request too small (%zu < %zu)\n", 33 op->request->payload_size, sizeof(*receive)); 34 return -EINVAL; 35 } 36 receive = op->request->payload; 37 len = le16_to_cpu(receive->len); 38 if (len != (op->request->payload_size - sizeof(*receive))) { 39 dev_err(dev, "log request wrong size %d vs %zu\n", len, 40 (op->request->payload_size - sizeof(*receive))); 41 return -EINVAL; 42 } 43 if (len == 0) { 44 dev_err(dev, "log request of 0 bytes?\n"); 45 return -EINVAL; 46 } 47 48 if (len > GB_LOG_MAX_LEN) { 49 dev_err(dev, "log request too big: %d\n", len); 50 return -EINVAL; 51 } 52 53 /* Ensure the buffer is 0 terminated */ 54 receive->msg[len - 1] = '\0'; 55 56 /* 57 * Print with dev_dbg() so that it can be easily turned off using 58 * dynamic debugging (and prevent any DoS) 59 */ 60 dev_dbg(dev, "%s", receive->msg); 61 62 return 0; 63} 64 65static int gb_log_probe(struct gb_bundle *bundle, 66 const struct greybus_bundle_id *id) 67{ 68 struct greybus_descriptor_cport *cport_desc; 69 struct gb_connection *connection; 70 struct gb_log *log; 71 int retval; 72 73 if (bundle->num_cports != 1) 74 return -ENODEV; 75 76 cport_desc = &bundle->cport_desc[0]; 77 if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LOG) 78 return -ENODEV; 79 80 log = kzalloc(sizeof(*log), GFP_KERNEL); 81 if (!log) 82 return -ENOMEM; 83 84 connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), 85 gb_log_request_handler); 86 if (IS_ERR(connection)) { 87 retval = PTR_ERR(connection); 88 goto error_free; 89 } 90 91 log->connection = connection; 92 greybus_set_drvdata(bundle, log); 93 94 retval = gb_connection_enable(connection); 95 if (retval) 96 goto error_connection_destroy; 97 98 return 0; 99 100error_connection_destroy: 101 gb_connection_destroy(connection); 102error_free: 103 kfree(log); 104 return retval; 105} 106 107static void gb_log_disconnect(struct gb_bundle *bundle) 108{ 109 struct gb_log *log = greybus_get_drvdata(bundle); 110 struct gb_connection *connection = log->connection; 111 112 gb_connection_disable(connection); 113 gb_connection_destroy(connection); 114 115 kfree(log); 116} 117 118static const struct greybus_bundle_id gb_log_id_table[] = { 119 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOG) }, 120 { } 121}; 122MODULE_DEVICE_TABLE(greybus, gb_log_id_table); 123 124static struct greybus_driver gb_log_driver = { 125 .name = "log", 126 .probe = gb_log_probe, 127 .disconnect = gb_log_disconnect, 128 .id_table = gb_log_id_table, 129}; 130module_greybus_driver(gb_log_driver); 131 132MODULE_LICENSE("GPL v2");