diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index ccce2ad74128..ffbcf11e4e68 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -42,6 +42,7 @@ static struct dentry *wwan_debugfs_dir; /* WWAN port flags */ #define WWAN_PORT_TX_OFF 0 +#define WWAN_PORT_EXCLUSIVE 1 /** * struct wwan_device - The structure that defines a WWAN device @@ -748,6 +749,12 @@ static int wwan_port_op_start(struct wwan_port *port) goto out_unlock; } + if (test_bit(WWAN_PORT_EXCLUSIVE, &port->flags) && + !capable(CAP_SYS_ADMIN)) { + ret = -EBUSY; + goto out_unlock; + } + /* If port is already started, don't start again */ if (!port->start_count) ret = port->ops->start(port); @@ -769,6 +776,7 @@ static void wwan_port_op_stop(struct wwan_port *port) if (port->ops) port->ops->stop(port); skb_queue_purge(&port->rxq); + clear_bit(WWAN_PORT_EXCLUSIVE, &port->flags); } mutex_unlock(&port->ops_lock); } @@ -1031,6 +1039,22 @@ static long wwan_port_fops_at_ioctl(struct wwan_port *port, unsigned int cmd, break; } + case TIOCEXCL: + set_bit(WWAN_PORT_EXCLUSIVE, &port->flags); + break; + + case TIOCNXCL: + clear_bit(WWAN_PORT_EXCLUSIVE, &port->flags); + break; + + case TIOCGEXCL: + { + int excl = test_bit(WWAN_PORT_EXCLUSIVE, &port->flags); + + ret = put_user(excl, (int __user *)arg); + break; + } + default: ret = -ENOIOCTLCMD; } @@ -1046,7 +1070,8 @@ static long wwan_port_fops_ioctl(struct file *filp, unsigned int cmd, struct wwan_port *port = filp->private_data; int res; - if (port->type == WWAN_PORT_AT) { /* AT port specific IOCTLs */ + if (port->type == WWAN_PORT_AT || port->type == WWAN_PORT_QCDM) { + /* AT and QCDM port specific IOCTLs */ res = wwan_port_fops_at_ioctl(port, cmd, arg); if (res != -ENOIOCTLCMD) return res;