Re: [PATCH] Bluetooth: Add tty HCI driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 30 Apr 2015 10:48:09 +0300
Eyal Reizer <eyalreizer@xxxxxxxxx> wrote:

> tty_hci driver exposes a /dev/hci_tty character device node, that intends
> to emulate a generic /dev/ttyX device that would be used by the user-space
> Bluetooth stacks to send/receive data to/from the WL combo-connectivity
> chipsets.

We have an in kernel bluetooth stack, why do we care about this - how
will people test and debug driver interactions with binary only bluetooth
stacks in userspace ?

That aside

Either

- Use the tty layer to provide your interface with a correct "emulation",

or

- Don't pretend to be a tty device in the first place

Your code behaviour is nothing like a tty or indeed much like anything
else sane.

> +int hci_tty_open(struct inode *inod, struct file *file)
> +{
> +	int i = 0, err = 0;
> +	unsigned long timeleft;
> +	struct ti_st *hst;
> +
> +	pr_info("inside %s (%p, %p)\n", __func__, inod, file);
> +
> +	hst = kzalloc(sizeof(*hst), GFP_KERNEL);
> +	file->private_data = hst;
> +	hst = file->private_data;

Just crashed if you ran out of memory


> +		pr_debug("waiting for registration completion signal from ST");
> +		timeleft = wait_for_completion_timeout
> +			(&hst->wait_reg_completion,
> +			 msecs_to_jiffies(BT_REGISTER_TIMEOUT));
> +		if (!timeleft) {
> +			pr_err("Timeout(%d sec),didn't get reg completion signal from ST",
> +			       BT_REGISTER_TIMEOUT / 1000);
> +			err = -ETIMEDOUT;
> +			goto error;

Without de-registering stuff ?

 +
> +/** hci_tty_read Function
> + *
> + *  Parameters :
> + *  @file  : File pointer for BT char driver
> + *  @data  : Data which needs to be passed to APP
> + *  @size  : Length of the data passesd
> + *  offset :
> + *  Returns  Size of packet received -  on success
> + *           else suitable error code
> + */
> +ssize_t hci_tty_read(struct file *file, char __user *data, size_t size,
> +		     loff_t *offset)
> +{
> +	int len = 0, tout;
> +	struct sk_buff *skb = NULL, *rskb = NULL;
> +	struct ti_st	*hst;
> +
> +	pr_debug("inside %s (%p, %p, %u, %p)\n",
> +		 __func__, file, data, size, offset);
> +
> +	/* Validate input parameters */
> +	if ((NULL == file) || (((NULL == data) || (0 == size)))) {
> +		pr_err("Invalid input params passed to %s", __func__);
> +		return -EINVAL;
> +	}

Why ... if they are broken here then the kernel is already crashed.

> +
> +	hst = file->private_data;
> +
> +	/* cannot come here if poll-ed before reading
> +	 * if not poll-ed wait on the same wait_q
> +	 */
> +	tout = wait_event_interruptible_timeout(hst->data_q,
> +						!skb_queue_empty(&hst->rx_list),
> +						msecs_to_jiffies(1000));
> +	/* Check for timed out condition */
> +	if (0 == tout) {
> +		pr_err("Device Read timed out\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* hst->rx_list not empty skb already present */
> +	skb = skb_dequeue(&hst->rx_list);
> +	if (!skb) {
> +		pr_err("dequed skb is null?\n");
> +		return -EIO;
> +	}
> +
> +#ifdef VERBOSE
> +	print_hex_dump(KERN_INFO, ">in>", DUMP_PREFIX_NONE,
> +		       16, 1, skb->data, skb->len, 0);
> +#endif
> +
> +	/* Forward the data to the user */
> +	if (skb->len >= size) {
> +		pr_err("FIONREAD not done before read\n");
> +		return -ENOMEM;

Even if the user did an FIONREAD this wouldn't work with two threads.
ENOMEM is a nonsense return for it
The semantics of read/write on a tty are not those you have implemented
You don't want to allow users to fill the log with error messages


> +	}
> +	/* returning skb */
> +	rskb = alloc_skb(size, GFP_KERNEL);
> +	if (!rskb)
> +		return -ENOMEM;
> +
> +	/* cb[0] has the pkt_type 0x04 or 0x02 or 0x03 */
> +	memcpy(skb_put(rskb, 1), &skb->cb[0], 1);
> +	memcpy(skb_put(rskb, skb->len), skb->data, skb->len);
> +
> +	if (copy_to_user(data, rskb->data, rskb->len)) {
> +		pr_err("unable to copy to user space\n");

Same problem with error messages

> +		/* Queue the skb back to head */
> +		skb_queue_head(&hst->rx_list, skb);

You've just re-ordered your list if threaded


> +/** hci_tty_ioctl Function
> + *  This will peform the functions as directed by the command and command
> + *  argument.
> + *
> + *  Parameters :
> + *  @file  : File pointer for BT char driver
> + *  @cmd   : IOCTL Command
> + *  @arg   : Command argument for IOCTL command
> + *  Returns  0 on success
> + *           else suitable error code
> + */
> +static long hci_tty_ioctl(struct file *file,
> +			  unsigned int cmd, unsigned long arg)
> +{
> +	struct sk_buff *skb = NULL;
> +	int		retcode = 0;
> +	struct ti_st	*hst;
> +
> +	pr_debug("inside %s (%p, %u, %lx)", __func__, file, cmd, arg);
> +
> +	/* Validate input parameters */
> +	if ((NULL == file) || (0 == cmd)) {
> +		pr_err("invalid input parameters passed to %s", __func__);
> +		return -EINVAL;
> +	}

More nonsense validation
> +
> +	hst = file->private_data;
> +
> +	switch (cmd) {
> +	case FIONREAD:
> +		/* Deque the SKB from the head if rx_list is not empty
> +		 * update the argument with skb->len to provide amount of data
> +		 * available in the available SKB +1 for the PKT_TYPE
> +		 * field not provided in data by TI-ST.
> +		 */
> +		skb = skb_dequeue(&hst->rx_list);
> +		if (skb) {
> +			*(unsigned int *)arg = skb->len + 1;

arg is in userspace is it not - if so you've just added some interesting
holes because you should be using the proper user access functions.

> +			/* Re-Store the SKB for furtur Read operations */
> +			skb_queue_head(&hst->rx_list, skb);

Re-ordering problems again here.

> +		} else {
> +			*(unsigned int *)arg = 0;
> +		}
> +		pr_debug("returning %d\n", *(unsigned int *)arg);
> +		break;
> +	default:
> +		pr_debug("Un-Identified IOCTL %d", cmd);
> +		retcode = 0;
> +		break;
> +	}
> +
> +	return retcode;
> +}
> +
> +/** hci_tty_poll Function
> + *  This function will wait till some data is received to the hci_tty driver from ST
> + *
> + *  Parameters :
> + *  @file  : File pointer for BT char driver
> + *  @wait  : POLL wait information
> + *  Returns  status of POLL on success
> + *           else suitable error code
> + */
> +static unsigned int hci_tty_poll(struct file *file, poll_table *wait)
> +{
> +	struct ti_st	*hst = file->private_data;
> +	unsigned long mask = 0;
> +
> +	pr_debug("@ %s\n", __func__);
> +
> +	/* wait to be completed by st_receive */
> +	poll_wait(file, &hst->data_q, wait);
> +	pr_debug("poll broke\n");

Why "broke" ?

> +
> +	if (!skb_queue_empty(&hst->rx_list)) {
> +		pr_debug("rx list que !empty\n");
> +		mask |= POLLIN;	/* TODO: check app for mask */
> +	}
> +

Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux