File Index
Files and directories
Sign in
FILE

smsgiucv.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/net/smsgiucv.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * IUCV special message driver
  4 *
  5 * Copyright IBM Corp. 2003, 2009
  6 *
  7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  8 */
  9
 10#include <linux/export.h>
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <linux/errno.h>
 14#include <linux/device.h>
 15#include <linux/slab.h>
 16#include <net/iucv/iucv.h>
 17#include <asm/machine.h>
 18#include <asm/cpcmd.h>
 19#include <asm/ebcdic.h>
 20#include "smsgiucv.h"
 21
 22struct smsg_callback {
 23	struct list_head list;
 24	const char *prefix;
 25	int len;
 26	void (*callback)(const char *from, char *str);
 27};
 28
 29MODULE_AUTHOR
 30   ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
 31MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
 32
 33static struct iucv_path *smsg_path;
 34
 35static DEFINE_SPINLOCK(smsg_list_lock);
 36static LIST_HEAD(smsg_list);
 37
 38static int smsg_path_pending(struct iucv_path *, u8 *, u8 *);
 39static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
 40
 41static struct iucv_handler smsg_handler = {
 42	.path_pending	 = smsg_path_pending,
 43	.message_pending = smsg_message_pending,
 44};
 45
 46static int smsg_path_pending(struct iucv_path *path, u8 *ipvmid, u8 *ipuser)
 47{
 48	if (strncmp(ipvmid, "*MSG    ", 8) != 0)
 49		return -EINVAL;
 50	/* Path pending from *MSG. */
 51	return iucv_path_accept(path, &smsg_handler, "SMSGIUCV        ", NULL);
 52}
 53
 54static void smsg_message_pending(struct iucv_path *path,
 55				 struct iucv_message *msg)
 56{
 57	struct smsg_callback *cb;
 58	unsigned char *buffer;
 59	unsigned char sender[9];
 60	int rc, i;
 61
 62	buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA);
 63	if (!buffer) {
 64		iucv_message_reject(path, msg);
 65		return;
 66	}
 67	rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL);
 68	if (rc == 0) {
 69		buffer[msg->length] = 0;
 70		EBCASC(buffer, msg->length);
 71		memcpy(sender, buffer, 8);
 72		sender[8] = 0;
 73		/* Remove trailing whitespace from the sender name. */
 74		for (i = 7; i >= 0; i--) {
 75			if (sender[i] != ' ' && sender[i] != '\t')
 76				break;
 77			sender[i] = 0;
 78		}
 79		spin_lock(&smsg_list_lock);
 80		list_for_each_entry(cb, &smsg_list, list)
 81			if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) {
 82				cb->callback(sender, buffer + 8);
 83				break;
 84			}
 85		spin_unlock(&smsg_list_lock);
 86	}
 87	kfree(buffer);
 88}
 89
 90int smsg_register_callback(const char *prefix,
 91			   void (*callback)(const char *from, char *str))
 92{
 93	struct smsg_callback *cb;
 94
 95	cb = kmalloc(sizeof(struct smsg_callback), GFP_KERNEL);
 96	if (!cb)
 97		return -ENOMEM;
 98	cb->prefix = prefix;
 99	cb->len = strlen(prefix);
100	cb->callback = callback;
101	spin_lock_bh(&smsg_list_lock);
102	list_add_tail(&cb->list, &smsg_list);
103	spin_unlock_bh(&smsg_list_lock);
104	return 0;
105}
106
107void smsg_unregister_callback(const char *prefix,
108			      void (*callback)(const char *from,
109					       char *str))
110{
111	struct smsg_callback *cb, *tmp;
112
113	spin_lock_bh(&smsg_list_lock);
114	cb = NULL;
115	list_for_each_entry(tmp, &smsg_list, list)
116		if (tmp->callback == callback &&
117		    strcmp(tmp->prefix, prefix) == 0) {
118			cb = tmp;
119			list_del(&cb->list);
120			break;
121		}
122	spin_unlock_bh(&smsg_list_lock);
123	kfree(cb);
124}
125
126static struct device_driver smsg_driver = {
127	.owner = THIS_MODULE,
128	.name = SMSGIUCV_DRV_NAME,
129	.bus  = &iucv_bus,
130};
131
132static void __exit smsg_exit(void)
133{
134	cpcmd("SET SMSG OFF", NULL, 0, NULL);
135	iucv_unregister(&smsg_handler, 1);
136	driver_unregister(&smsg_driver);
137}
138
139static int __init smsg_init(void)
140{
141	int rc;
142
143	if (!machine_is_vm()) {
144		rc = -EPROTONOSUPPORT;
145		goto out;
146	}
147	rc = driver_register(&smsg_driver);
148	if (rc != 0)
149		goto out;
150	rc = iucv_register(&smsg_handler, 1);
151	if (rc)
152		goto out_driver;
153	smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
154	if (!smsg_path) {
155		rc = -ENOMEM;
156		goto out_register;
157	}
158	rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
159			       NULL, NULL, NULL);
160	if (rc)
161		goto out_free_path;
162
163	cpcmd("SET SMSG IUCV", NULL, 0, NULL);
164	return 0;
165
166out_free_path:
167	iucv_path_free(smsg_path);
168	smsg_path = NULL;
169out_register:
170	iucv_unregister(&smsg_handler, 1);
171out_driver:
172	driver_unregister(&smsg_driver);
173out:
174	return rc;
175}
176
177module_init(smsg_init);
178module_exit(smsg_exit);
179MODULE_LICENSE("GPL");
180
181EXPORT_SYMBOL(smsg_register_callback);
182EXPORT_SYMBOL(smsg_unregister_callback);
~/ Read-only file preview.