0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/errno.h>
0013 #include <linux/device.h>
0014 #include <linux/slab.h>
0015 #include <net/iucv/iucv.h>
0016 #include <asm/cpcmd.h>
0017 #include <asm/ebcdic.h>
0018 #include "smsgiucv.h"
0019
0020 struct smsg_callback {
0021 struct list_head list;
0022 const char *prefix;
0023 int len;
0024 void (*callback)(const char *from, char *str);
0025 };
0026
0027 MODULE_AUTHOR
0028 ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
0029 MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
0030
0031 static struct iucv_path *smsg_path;
0032
0033 static DEFINE_SPINLOCK(smsg_list_lock);
0034 static LIST_HEAD(smsg_list);
0035
0036 static int smsg_path_pending(struct iucv_path *, u8 *, u8 *);
0037 static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
0038
0039 static struct iucv_handler smsg_handler = {
0040 .path_pending = smsg_path_pending,
0041 .message_pending = smsg_message_pending,
0042 };
0043
0044 static int smsg_path_pending(struct iucv_path *path, u8 *ipvmid, u8 *ipuser)
0045 {
0046 if (strncmp(ipvmid, "*MSG ", 8) != 0)
0047 return -EINVAL;
0048
0049 return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL);
0050 }
0051
0052 static void smsg_message_pending(struct iucv_path *path,
0053 struct iucv_message *msg)
0054 {
0055 struct smsg_callback *cb;
0056 unsigned char *buffer;
0057 unsigned char sender[9];
0058 int rc, i;
0059
0060 buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA);
0061 if (!buffer) {
0062 iucv_message_reject(path, msg);
0063 return;
0064 }
0065 rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL);
0066 if (rc == 0) {
0067 buffer[msg->length] = 0;
0068 EBCASC(buffer, msg->length);
0069 memcpy(sender, buffer, 8);
0070 sender[8] = 0;
0071
0072 for (i = 7; i >= 0; i--) {
0073 if (sender[i] != ' ' && sender[i] != '\t')
0074 break;
0075 sender[i] = 0;
0076 }
0077 spin_lock(&smsg_list_lock);
0078 list_for_each_entry(cb, &smsg_list, list)
0079 if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) {
0080 cb->callback(sender, buffer + 8);
0081 break;
0082 }
0083 spin_unlock(&smsg_list_lock);
0084 }
0085 kfree(buffer);
0086 }
0087
0088 int smsg_register_callback(const char *prefix,
0089 void (*callback)(const char *from, char *str))
0090 {
0091 struct smsg_callback *cb;
0092
0093 cb = kmalloc(sizeof(struct smsg_callback), GFP_KERNEL);
0094 if (!cb)
0095 return -ENOMEM;
0096 cb->prefix = prefix;
0097 cb->len = strlen(prefix);
0098 cb->callback = callback;
0099 spin_lock_bh(&smsg_list_lock);
0100 list_add_tail(&cb->list, &smsg_list);
0101 spin_unlock_bh(&smsg_list_lock);
0102 return 0;
0103 }
0104
0105 void smsg_unregister_callback(const char *prefix,
0106 void (*callback)(const char *from,
0107 char *str))
0108 {
0109 struct smsg_callback *cb, *tmp;
0110
0111 spin_lock_bh(&smsg_list_lock);
0112 cb = NULL;
0113 list_for_each_entry(tmp, &smsg_list, list)
0114 if (tmp->callback == callback &&
0115 strcmp(tmp->prefix, prefix) == 0) {
0116 cb = tmp;
0117 list_del(&cb->list);
0118 break;
0119 }
0120 spin_unlock_bh(&smsg_list_lock);
0121 kfree(cb);
0122 }
0123
0124 static struct device_driver smsg_driver = {
0125 .owner = THIS_MODULE,
0126 .name = SMSGIUCV_DRV_NAME,
0127 .bus = &iucv_bus,
0128 };
0129
0130 static void __exit smsg_exit(void)
0131 {
0132 cpcmd("SET SMSG OFF", NULL, 0, NULL);
0133 iucv_unregister(&smsg_handler, 1);
0134 driver_unregister(&smsg_driver);
0135 }
0136
0137 static int __init smsg_init(void)
0138 {
0139 int rc;
0140
0141 if (!MACHINE_IS_VM) {
0142 rc = -EPROTONOSUPPORT;
0143 goto out;
0144 }
0145 rc = driver_register(&smsg_driver);
0146 if (rc != 0)
0147 goto out;
0148 rc = iucv_register(&smsg_handler, 1);
0149 if (rc)
0150 goto out_driver;
0151 smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
0152 if (!smsg_path) {
0153 rc = -ENOMEM;
0154 goto out_register;
0155 }
0156 rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
0157 NULL, NULL, NULL);
0158 if (rc)
0159 goto out_free_path;
0160
0161 cpcmd("SET SMSG IUCV", NULL, 0, NULL);
0162 return 0;
0163
0164 out_free_path:
0165 iucv_path_free(smsg_path);
0166 smsg_path = NULL;
0167 out_register:
0168 iucv_unregister(&smsg_handler, 1);
0169 out_driver:
0170 driver_unregister(&smsg_driver);
0171 out:
0172 return rc;
0173 }
0174
0175 module_init(smsg_init);
0176 module_exit(smsg_exit);
0177 MODULE_LICENSE("GPL");
0178
0179 EXPORT_SYMBOL(smsg_register_callback);
0180 EXPORT_SYMBOL(smsg_unregister_callback);