* old behaviour for all userspace, unless it explicitly opts in to the
  * rules outlined here by using the new &struct rfkill_event_ext.
  *
- * Userspace using &struct rfkill_event_ext must adhere to the following
- * rules
+ * Additionally, some other userspace (bluez, g-s-d) was reading with a
+ * large size but as streaming reads rather than message-based, or with
+ * too strict checks for the returned size. So eventually, we completely
+ * reverted this, and extended messages need to be opted in to by using
+ * an ioctl:
+ *
+ *  ioctl(fd, RFKILL_IOCTL_MAX_SIZE, sizeof(struct rfkill_event_ext));
+ *
+ * Userspace using &struct rfkill_event_ext and the ioctl must adhere to
+ * the following rules:
  *
  * 1. accept short writes, optionally using them to detect that it's
  *    running on an older kernel;
 #define RFKILL_IOC_MAGIC       'R'
 #define RFKILL_IOC_NOINPUT     1
 #define RFKILL_IOCTL_NOINPUT   _IO(RFKILL_IOC_MAGIC, RFKILL_IOC_NOINPUT)
+#define RFKILL_IOC_MAX_SIZE    2
+#define RFKILL_IOCTL_MAX_SIZE  _IOW(RFKILL_IOC_MAGIC, RFKILL_IOC_EXT_SIZE, __u32)
 
 /* and that's all userspace gets */
 
 
        struct mutex            mtx;
        wait_queue_head_t       read_wait;
        bool                    input_handler;
+       u8                      max_size;
 };
 
 
        if (!data)
                return -ENOMEM;
 
+       data->max_size = RFKILL_EVENT_SIZE_V1;
+
        INIT_LIST_HEAD(&data->events);
        mutex_init(&data->mtx);
        init_waitqueue_head(&data->read_wait);
                                list);
 
        sz = min_t(unsigned long, sizeof(ev->ev), count);
+       sz = min_t(unsigned long, sz, data->max_size);
        ret = sz;
        if (copy_to_user(buf, &ev->ev, sz))
                ret = -EFAULT;
 static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *pos)
 {
+       struct rfkill_data *data = file->private_data;
        struct rfkill *rfkill;
        struct rfkill_event_ext ev;
        int ret;
         * our API version even in a write() call, if it cares.
         */
        count = min(count, sizeof(ev));
+       count = min_t(size_t, count, data->max_size);
        if (copy_from_user(&ev, buf, count))
                return -EFAULT;
 
        return 0;
 }
 
-#ifdef CONFIG_RFKILL_INPUT
 static long rfkill_fop_ioctl(struct file *file, unsigned int cmd,
                             unsigned long arg)
 {
        struct rfkill_data *data = file->private_data;
+       int ret = -ENOSYS;
+       u32 size;
 
        if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC)
                return -ENOSYS;
 
-       if (_IOC_NR(cmd) != RFKILL_IOC_NOINPUT)
-               return -ENOSYS;
-
        mutex_lock(&data->mtx);
-
-       if (!data->input_handler) {
-               if (atomic_inc_return(&rfkill_input_disabled) == 1)
-                       printk(KERN_DEBUG "rfkill: input handler disabled\n");
-               data->input_handler = true;
+       switch (_IOC_NR(cmd)) {
+#ifdef CONFIG_RFKILL_INPUT
+       case RFKILL_IOC_NOINPUT:
+               if (!data->input_handler) {
+                       if (atomic_inc_return(&rfkill_input_disabled) == 1)
+                               printk(KERN_DEBUG "rfkill: input handler disabled\n");
+                       data->input_handler = true;
+               }
+               ret = 0;
+               break;
+#endif
+       case RFKILL_IOC_MAX_SIZE:
+               if (get_user(size, (__u32 __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (size < RFKILL_EVENT_SIZE_V1 || size > U8_MAX) {
+                       ret = -EINVAL;
+                       break;
+               }
+               data->max_size = size;
+               ret = 0;
+               break;
+       default:
+               break;
        }
-
        mutex_unlock(&data->mtx);
 
-       return 0;
+       return ret;
 }
-#endif
 
 static const struct file_operations rfkill_fops = {
        .owner          = THIS_MODULE,
        .write          = rfkill_fop_write,
        .poll           = rfkill_fop_poll,
        .release        = rfkill_fop_release,
-#ifdef CONFIG_RFKILL_INPUT
        .unlocked_ioctl = rfkill_fop_ioctl,
        .compat_ioctl   = compat_ptr_ioctl,
-#endif
        .llseek         = no_llseek,
 };