Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Deliver z/VM CP special messages (SMSG) as uevents.
0004  *
0005  * The driver registers for z/VM CP special messages with the
0006  * "APP" prefix. Incoming messages are delivered to user space
0007  * as uevents.
0008  *
0009  * Copyright IBM Corp. 2010
0010  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
0011  *
0012  */
0013 #define KMSG_COMPONENT      "smsgiucv_app"
0014 #define pr_fmt(fmt)     KMSG_COMPONENT ": " fmt
0015 
0016 #include <linux/ctype.h>
0017 #include <linux/err.h>
0018 #include <linux/device.h>
0019 #include <linux/list.h>
0020 #include <linux/kobject.h>
0021 #include <linux/module.h>
0022 #include <linux/slab.h>
0023 #include <linux/spinlock.h>
0024 #include <linux/workqueue.h>
0025 #include <net/iucv/iucv.h>
0026 #include "smsgiucv.h"
0027 
0028 /* prefix used for SMSG registration */
0029 #define SMSG_PREFIX     "APP"
0030 
0031 /* SMSG related uevent environment variables */
0032 #define ENV_SENDER_STR      "SMSG_SENDER="
0033 #define ENV_SENDER_LEN      (strlen(ENV_SENDER_STR) + 8 + 1)
0034 #define ENV_PREFIX_STR      "SMSG_ID="
0035 #define ENV_PREFIX_LEN      (strlen(ENV_PREFIX_STR) + \
0036                  strlen(SMSG_PREFIX) + 1)
0037 #define ENV_TEXT_STR        "SMSG_TEXT="
0038 #define ENV_TEXT_LEN(msg)   (strlen(ENV_TEXT_STR) + strlen((msg)) + 1)
0039 
0040 /* z/VM user ID which is permitted to send SMSGs
0041  * If the value is undefined or empty (""), special messages are
0042  * accepted from any z/VM user ID. */
0043 static char *sender;
0044 module_param(sender, charp, 0400);
0045 MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted");
0046 
0047 /* SMSG device representation */
0048 static struct device *smsg_app_dev;
0049 
0050 /* list element for queuing received messages for delivery */
0051 struct smsg_app_event {
0052     struct list_head list;
0053     char *buf;
0054     char *envp[4];
0055 };
0056 
0057 /* queue for outgoing uevents */
0058 static LIST_HEAD(smsg_event_queue);
0059 static DEFINE_SPINLOCK(smsg_event_queue_lock);
0060 
0061 static void smsg_app_event_free(struct smsg_app_event *ev)
0062 {
0063     kfree(ev->buf);
0064     kfree(ev);
0065 }
0066 
0067 static struct smsg_app_event *smsg_app_event_alloc(const char *from,
0068                            const char *msg)
0069 {
0070     struct smsg_app_event *ev;
0071 
0072     ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
0073     if (!ev)
0074         return NULL;
0075 
0076     ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN +
0077               ENV_TEXT_LEN(msg), GFP_ATOMIC);
0078     if (!ev->buf) {
0079         kfree(ev);
0080         return NULL;
0081     }
0082 
0083     /* setting up environment pointers into buf */
0084     ev->envp[0] = ev->buf;
0085     ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN;
0086     ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN;
0087     ev->envp[3] = NULL;
0088 
0089     /* setting up environment: sender, prefix name, and message text */
0090     snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from);
0091     snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX);
0092     snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg);
0093 
0094     return ev;
0095 }
0096 
0097 static void smsg_event_work_fn(struct work_struct *work)
0098 {
0099     LIST_HEAD(event_queue);
0100     struct smsg_app_event *p, *n;
0101     struct device *dev;
0102 
0103     dev = get_device(smsg_app_dev);
0104     if (!dev)
0105         return;
0106 
0107     spin_lock_bh(&smsg_event_queue_lock);
0108     list_splice_init(&smsg_event_queue, &event_queue);
0109     spin_unlock_bh(&smsg_event_queue_lock);
0110 
0111     list_for_each_entry_safe(p, n, &event_queue, list) {
0112         list_del(&p->list);
0113         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp);
0114         smsg_app_event_free(p);
0115     }
0116 
0117     put_device(dev);
0118 }
0119 static DECLARE_WORK(smsg_event_work, smsg_event_work_fn);
0120 
0121 static void smsg_app_callback(const char *from, char *msg)
0122 {
0123     struct smsg_app_event *se;
0124 
0125     /* check if the originating z/VM user ID matches
0126      * the configured sender. */
0127     if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0)
0128         return;
0129 
0130     /* get start of message text (skip prefix and leading blanks) */
0131     msg += strlen(SMSG_PREFIX);
0132     while (*msg && isspace(*msg))
0133         msg++;
0134     if (*msg == '\0')
0135         return;
0136 
0137     /* allocate event list element and its environment */
0138     se = smsg_app_event_alloc(from, msg);
0139     if (!se)
0140         return;
0141 
0142     /* queue event and schedule work function */
0143     spin_lock(&smsg_event_queue_lock);
0144     list_add_tail(&se->list, &smsg_event_queue);
0145     spin_unlock(&smsg_event_queue_lock);
0146 
0147     schedule_work(&smsg_event_work);
0148     return;
0149 }
0150 
0151 static int __init smsgiucv_app_init(void)
0152 {
0153     struct device_driver *smsgiucv_drv;
0154     int rc;
0155 
0156     if (!MACHINE_IS_VM)
0157         return -ENODEV;
0158 
0159     smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL);
0160     if (!smsg_app_dev)
0161         return -ENOMEM;
0162 
0163     smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus);
0164     if (!smsgiucv_drv) {
0165         kfree(smsg_app_dev);
0166         return -ENODEV;
0167     }
0168 
0169     rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
0170     if (rc) {
0171         kfree(smsg_app_dev);
0172         goto fail;
0173     }
0174     smsg_app_dev->bus = &iucv_bus;
0175     smsg_app_dev->parent = iucv_root;
0176     smsg_app_dev->release = (void (*)(struct device *)) kfree;
0177     smsg_app_dev->driver = smsgiucv_drv;
0178     rc = device_register(smsg_app_dev);
0179     if (rc) {
0180         put_device(smsg_app_dev);
0181         goto fail;
0182     }
0183 
0184     /* convert sender to uppercase characters */
0185     if (sender) {
0186         int len = strlen(sender);
0187         while (len--)
0188             sender[len] = toupper(sender[len]);
0189     }
0190 
0191     /* register with the smsgiucv device driver */
0192     rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
0193     if (rc) {
0194         device_unregister(smsg_app_dev);
0195         goto fail;
0196     }
0197 
0198     rc = 0;
0199 fail:
0200     return rc;
0201 }
0202 module_init(smsgiucv_app_init);
0203 
0204 static void __exit smsgiucv_app_exit(void)
0205 {
0206     /* unregister callback */
0207     smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback);
0208 
0209     /* cancel pending work and flush any queued event work */
0210     cancel_work_sync(&smsg_event_work);
0211     smsg_event_work_fn(&smsg_event_work);
0212 
0213     device_unregister(smsg_app_dev);
0214 }
0215 module_exit(smsgiucv_app_exit);
0216 
0217 MODULE_LICENSE("GPL v2");
0218 MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents");
0219 MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");