irda: Remove BKL instances from af_irda.c

Most of the times, lock_kernel() was pointless or could simply be replaced
by lock_sock().

Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
This commit is contained in:
Samuel Ortiz 2010-10-11 00:46:51 +02:00 committed by Samuel Ortiz
parent 7b738b55b2
commit 5b40964ead

View file

@ -715,14 +715,11 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
struct sockaddr_irda saddr; struct sockaddr_irda saddr;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct irda_sock *self = irda_sk(sk); struct irda_sock *self = irda_sk(sk);
int err;
lock_kernel();
memset(&saddr, 0, sizeof(saddr)); memset(&saddr, 0, sizeof(saddr));
if (peer) { if (peer) {
err = -ENOTCONN;
if (sk->sk_state != TCP_ESTABLISHED) if (sk->sk_state != TCP_ESTABLISHED)
goto out; return -ENOTCONN;
saddr.sir_family = AF_IRDA; saddr.sir_family = AF_IRDA;
saddr.sir_lsap_sel = self->dtsap_sel; saddr.sir_lsap_sel = self->dtsap_sel;
@ -739,10 +736,8 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
/* uaddr_len come to us uninitialised */ /* uaddr_len come to us uninitialised */
*uaddr_len = sizeof (struct sockaddr_irda); *uaddr_len = sizeof (struct sockaddr_irda);
memcpy(uaddr, &saddr, *uaddr_len); memcpy(uaddr, &saddr, *uaddr_len);
err = 0;
out: return 0;
unlock_kernel();
return err;
} }
/* /*
@ -758,7 +753,8 @@ static int irda_listen(struct socket *sock, int backlog)
IRDA_DEBUG(2, "%s()\n", __func__); IRDA_DEBUG(2, "%s()\n", __func__);
lock_kernel(); lock_sock(sk);
if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
(sk->sk_type != SOCK_DGRAM)) (sk->sk_type != SOCK_DGRAM))
goto out; goto out;
@ -770,7 +766,7 @@ static int irda_listen(struct socket *sock, int backlog)
err = 0; err = 0;
} }
out: out:
unlock_kernel(); release_sock(sk);
return err; return err;
} }
@ -793,7 +789,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (addr_len != sizeof(struct sockaddr_irda)) if (addr_len != sizeof(struct sockaddr_irda))
return -EINVAL; return -EINVAL;
lock_kernel(); lock_sock(sk);
#ifdef CONFIG_IRDA_ULTRA #ifdef CONFIG_IRDA_ULTRA
/* Special care for Ultra sockets */ /* Special care for Ultra sockets */
if ((sk->sk_type == SOCK_DGRAM) && if ((sk->sk_type == SOCK_DGRAM) &&
@ -836,7 +832,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
err = 0; err = 0;
out: out:
unlock_kernel(); release_sock(sk);
return err; return err;
} }
@ -856,12 +852,13 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
IRDA_DEBUG(2, "%s()\n", __func__); IRDA_DEBUG(2, "%s()\n", __func__);
lock_kernel();
err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0); err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0);
if (err) if (err)
goto out; return err;
err = -EINVAL; err = -EINVAL;
lock_sock(sk);
if (sock->state != SS_UNCONNECTED) if (sock->state != SS_UNCONNECTED)
goto out; goto out;
@ -947,7 +944,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
irda_connect_response(new); irda_connect_response(new);
err = 0; err = 0;
out: out:
unlock_kernel(); release_sock(sk);
return err; return err;
} }
@ -981,7 +978,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
IRDA_DEBUG(2, "%s(%p)\n", __func__, self); IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
lock_kernel(); lock_sock(sk);
/* Don't allow connect for Ultra sockets */ /* Don't allow connect for Ultra sockets */
err = -ESOCKTNOSUPPORT; err = -ESOCKTNOSUPPORT;
if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))
@ -1072,6 +1069,8 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->sk_state != TCP_ESTABLISHED) { if (sk->sk_state != TCP_ESTABLISHED) {
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
if (sk->sk_prot->disconnect(sk, flags))
sock->state = SS_DISCONNECTING;
err = sock_error(sk); err = sock_error(sk);
if (!err) if (!err)
err = -ECONNRESET; err = -ECONNRESET;
@ -1084,7 +1083,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
self->saddr = irttp_get_saddr(self->tsap); self->saddr = irttp_get_saddr(self->tsap);
err = 0; err = 0;
out: out:
unlock_kernel(); release_sock(sk);
return err; return err;
} }
@ -1231,7 +1230,6 @@ static int irda_release(struct socket *sock)
if (sk == NULL) if (sk == NULL)
return 0; return 0;
lock_kernel();
lock_sock(sk); lock_sock(sk);
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_shutdown |= SEND_SHUTDOWN;
@ -1250,7 +1248,6 @@ static int irda_release(struct socket *sock)
/* Destroy networking socket if we are the last reference on it, /* Destroy networking socket if we are the last reference on it,
* i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */ * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */
sock_put(sk); sock_put(sk);
unlock_kernel();
/* Notes on socket locking and deallocation... - Jean II /* Notes on socket locking and deallocation... - Jean II
* In theory we should put pairs of sock_hold() / sock_put() to * In theory we should put pairs of sock_hold() / sock_put() to
@ -1298,7 +1295,6 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
lock_kernel();
/* Note : socket.c set MSG_EOR on SEQPACKET sockets */ /* Note : socket.c set MSG_EOR on SEQPACKET sockets */
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
MSG_NOSIGNAL)) { MSG_NOSIGNAL)) {
@ -1306,6 +1302,8 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out; goto out;
} }
lock_sock(sk);
if (sk->sk_shutdown & SEND_SHUTDOWN) if (sk->sk_shutdown & SEND_SHUTDOWN)
goto out_err; goto out_err;
@ -1361,14 +1359,14 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out_err; goto out_err;
} }
unlock_kernel(); release_sock(sk);
/* Tell client how much data we actually sent */ /* Tell client how much data we actually sent */
return len; return len;
out_err: out_err:
err = sk_stream_error(sk, msg->msg_flags, err); err = sk_stream_error(sk, msg->msg_flags, err);
out: out:
unlock_kernel(); release_sock(sk);
return err; return err;
} }
@ -1390,14 +1388,10 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s()\n", __func__); IRDA_DEBUG(4, "%s()\n", __func__);
lock_kernel();
if ((err = sock_error(sk)) < 0)
goto out;
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err); flags & MSG_DONTWAIT, &err);
if (!skb) if (!skb)
goto out; return err;
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
copied = skb->len; copied = skb->len;
@ -1425,12 +1419,8 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
irttp_flow_request(self->tsap, FLOW_START); irttp_flow_request(self->tsap, FLOW_START);
} }
} }
unlock_kernel();
return copied;
out: return copied;
unlock_kernel();
return err;
} }
/* /*
@ -1448,17 +1438,15 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(3, "%s()\n", __func__); IRDA_DEBUG(3, "%s()\n", __func__);
lock_kernel();
if ((err = sock_error(sk)) < 0) if ((err = sock_error(sk)) < 0)
goto out; return err;
err = -EINVAL;
if (sock->flags & __SO_ACCEPTCON) if (sock->flags & __SO_ACCEPTCON)
goto out; return -EINVAL;
err =-EOPNOTSUPP; err =-EOPNOTSUPP;
if (flags & MSG_OOB) if (flags & MSG_OOB)
goto out; return -EOPNOTSUPP;
err = 0; err = 0;
target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
@ -1500,7 +1488,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
finish_wait(sk_sleep(sk), &wait); finish_wait(sk_sleep(sk), &wait);
if (err) if (err)
goto out; return err;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
break; break;
@ -1553,9 +1541,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
} }
} }
out: return copied;
unlock_kernel();
return err ? : copied;
} }
/* /*
@ -1573,13 +1559,12 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
lock_kernel();
IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
err = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
goto out; return -EINVAL;
lock_sock(sk);
if (sk->sk_shutdown & SEND_SHUTDOWN) { if (sk->sk_shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0); send_sig(SIGPIPE, current, 0);
@ -1630,10 +1615,12 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
goto out; goto out;
} }
unlock_kernel();
release_sock(sk);
return len; return len;
out: out:
unlock_kernel(); release_sock(sk);
return err; return err;
} }
@ -1656,10 +1643,11 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
lock_kernel();
err = -EINVAL; err = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
goto out; return -EINVAL;
lock_sock(sk);
err = -EPIPE; err = -EPIPE;
if (sk->sk_shutdown & SEND_SHUTDOWN) { if (sk->sk_shutdown & SEND_SHUTDOWN) {
@ -1732,7 +1720,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
if (err) if (err)
IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
out: out:
unlock_kernel(); release_sock(sk);
return err ? : len; return err ? : len;
} }
#endif /* CONFIG_IRDA_ULTRA */ #endif /* CONFIG_IRDA_ULTRA */
@ -1747,7 +1735,7 @@ static int irda_shutdown(struct socket *sock, int how)
IRDA_DEBUG(1, "%s(%p)\n", __func__, self); IRDA_DEBUG(1, "%s(%p)\n", __func__, self);
lock_kernel(); lock_sock(sk);
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_shutdown |= SEND_SHUTDOWN;
@ -1769,7 +1757,7 @@ static int irda_shutdown(struct socket *sock, int how)
self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */
self->saddr = 0x0; /* so IrLMP assign us any link */ self->saddr = 0x0; /* so IrLMP assign us any link */
unlock_kernel(); release_sock(sk);
return 0; return 0;
} }
@ -1786,7 +1774,6 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
IRDA_DEBUG(4, "%s()\n", __func__); IRDA_DEBUG(4, "%s()\n", __func__);
lock_kernel();
poll_wait(file, sk_sleep(sk), wait); poll_wait(file, sk_sleep(sk), wait);
mask = 0; mask = 0;
@ -1834,22 +1821,10 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
default: default:
break; break;
} }
unlock_kernel();
return mask; return mask;
} }
static unsigned int irda_datagram_poll(struct file *file, struct socket *sock,
poll_table *wait)
{
int err;
lock_kernel();
err = datagram_poll(file, sock, wait);
unlock_kernel();
return err;
}
/* /*
* Function irda_ioctl (sock, cmd, arg) * Function irda_ioctl (sock, cmd, arg)
*/ */
@ -1860,7 +1835,6 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd); IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd);
lock_kernel();
err = -EINVAL; err = -EINVAL;
switch (cmd) { switch (cmd) {
case TIOCOUTQ: { case TIOCOUTQ: {
@ -1903,7 +1877,6 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__); IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__);
err = -ENOIOCTLCMD; err = -ENOIOCTLCMD;
} }
unlock_kernel();
return err; return err;
} }
@ -1927,7 +1900,7 @@ static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
* Set some options for the socket * Set some options for the socket
* *
*/ */
static int __irda_setsockopt(struct socket *sock, int level, int optname, static int irda_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen) char __user *optval, unsigned int optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
@ -1935,13 +1908,15 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
struct irda_ias_set *ias_opt; struct irda_ias_set *ias_opt;
struct ias_object *ias_obj; struct ias_object *ias_obj;
struct ias_attrib * ias_attr; /* Attribute in IAS object */ struct ias_attrib * ias_attr; /* Attribute in IAS object */
int opt, free_ias = 0; int opt, free_ias = 0, err = 0;
IRDA_DEBUG(2, "%s(%p)\n", __func__, self); IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
if (level != SOL_IRLMP) if (level != SOL_IRLMP)
return -ENOPROTOOPT; return -ENOPROTOOPT;
lock_sock(sk);
switch (optname) { switch (optname) {
case IRLMP_IAS_SET: case IRLMP_IAS_SET:
/* The user want to add an attribute to an existing IAS object /* The user want to add an attribute to an existing IAS object
@ -1951,17 +1926,22 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
* create the right attribute... * create the right attribute...
*/ */
if (optlen != sizeof(struct irda_ias_set)) if (optlen != sizeof(struct irda_ias_set)) {
return -EINVAL; err = -EINVAL;
goto out;
}
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
if (ias_opt == NULL) if (ias_opt == NULL) {
return -ENOMEM; err = -ENOMEM;
goto out;
}
/* Copy query to the driver. */ /* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, optlen)) { if (copy_from_user(ias_opt, optval, optlen)) {
kfree(ias_opt); kfree(ias_opt);
return -EFAULT; err = -EFAULT;
goto out;
} }
/* Find the object we target. /* Find the object we target.
@ -1971,7 +1951,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
if(ias_opt->irda_class_name[0] == '\0') { if(ias_opt->irda_class_name[0] == '\0') {
if(self->ias_obj == NULL) { if(self->ias_obj == NULL) {
kfree(ias_opt); kfree(ias_opt);
return -EINVAL; err = -EINVAL;
goto out;
} }
ias_obj = self->ias_obj; ias_obj = self->ias_obj;
} else } else
@ -1983,7 +1964,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
if((!capable(CAP_NET_ADMIN)) && if((!capable(CAP_NET_ADMIN)) &&
((ias_obj == NULL) || (ias_obj != self->ias_obj))) { ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
kfree(ias_opt); kfree(ias_opt);
return -EPERM; err = -EPERM;
goto out;
} }
/* If the object doesn't exist, create it */ /* If the object doesn't exist, create it */
@ -1993,7 +1975,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
jiffies); jiffies);
if (ias_obj == NULL) { if (ias_obj == NULL) {
kfree(ias_opt); kfree(ias_opt);
return -ENOMEM; err = -ENOMEM;
goto out;
} }
free_ias = 1; free_ias = 1;
} }
@ -2005,7 +1988,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_obj->name); kfree(ias_obj->name);
kfree(ias_obj); kfree(ias_obj);
} }
return -EINVAL; err = -EINVAL;
goto out;
} }
/* Look at the type */ /* Look at the type */
@ -2028,7 +2012,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_obj); kfree(ias_obj);
} }
return -EINVAL; err = -EINVAL;
goto out;
} }
/* Add an octet sequence attribute */ /* Add an octet sequence attribute */
irias_add_octseq_attrib( irias_add_octseq_attrib(
@ -2060,7 +2045,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_obj->name); kfree(ias_obj->name);
kfree(ias_obj); kfree(ias_obj);
} }
return -EINVAL; err = -EINVAL;
goto out;
} }
irias_insert_object(ias_obj); irias_insert_object(ias_obj);
kfree(ias_opt); kfree(ias_opt);
@ -2071,17 +2057,22 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
* object is not owned by the kernel and delete it. * object is not owned by the kernel and delete it.
*/ */
if (optlen != sizeof(struct irda_ias_set)) if (optlen != sizeof(struct irda_ias_set)) {
return -EINVAL; err = -EINVAL;
goto out;
}
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
if (ias_opt == NULL) if (ias_opt == NULL) {
return -ENOMEM; err = -ENOMEM;
goto out;
}
/* Copy query to the driver. */ /* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, optlen)) { if (copy_from_user(ias_opt, optval, optlen)) {
kfree(ias_opt); kfree(ias_opt);
return -EFAULT; err = -EFAULT;
goto out;
} }
/* Find the object we target. /* Find the object we target.
@ -2094,7 +2085,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
ias_obj = irias_find_object(ias_opt->irda_class_name); ias_obj = irias_find_object(ias_opt->irda_class_name);
if(ias_obj == (struct ias_object *) NULL) { if(ias_obj == (struct ias_object *) NULL) {
kfree(ias_opt); kfree(ias_opt);
return -EINVAL; err = -EINVAL;
goto out;
} }
/* Only ROOT can mess with the global IAS database. /* Only ROOT can mess with the global IAS database.
@ -2103,7 +2095,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
if((!capable(CAP_NET_ADMIN)) && if((!capable(CAP_NET_ADMIN)) &&
((ias_obj == NULL) || (ias_obj != self->ias_obj))) { ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
kfree(ias_opt); kfree(ias_opt);
return -EPERM; err = -EPERM;
goto out;
} }
/* Find the attribute (in the object) we target */ /* Find the attribute (in the object) we target */
@ -2111,14 +2104,16 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
ias_opt->irda_attrib_name); ias_opt->irda_attrib_name);
if(ias_attr == (struct ias_attrib *) NULL) { if(ias_attr == (struct ias_attrib *) NULL) {
kfree(ias_opt); kfree(ias_opt);
return -EINVAL; err = -EINVAL;
goto out;
} }
/* Check is the user space own the object */ /* Check is the user space own the object */
if(ias_attr->value->owner != IAS_USER_ATTR) { if(ias_attr->value->owner != IAS_USER_ATTR) {
IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__); IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__);
kfree(ias_opt); kfree(ias_opt);
return -EPERM; err = -EPERM;
goto out;
} }
/* Remove the attribute (and maybe the object) */ /* Remove the attribute (and maybe the object) */
@ -2126,11 +2121,15 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_opt); kfree(ias_opt);
break; break;
case IRLMP_MAX_SDU_SIZE: case IRLMP_MAX_SDU_SIZE:
if (optlen < sizeof(int)) if (optlen < sizeof(int)) {
return -EINVAL; err = -EINVAL;
goto out;
}
if (get_user(opt, (int __user *)optval)) if (get_user(opt, (int __user *)optval)) {
return -EFAULT; err = -EFAULT;
goto out;
}
/* Only possible for a seqpacket service (TTP with SAR) */ /* Only possible for a seqpacket service (TTP with SAR) */
if (sk->sk_type != SOCK_SEQPACKET) { if (sk->sk_type != SOCK_SEQPACKET) {
@ -2140,16 +2139,21 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
} else { } else {
IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n", IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
__func__); __func__);
return -ENOPROTOOPT; err = -ENOPROTOOPT;
goto out;
} }
break; break;
case IRLMP_HINTS_SET: case IRLMP_HINTS_SET:
if (optlen < sizeof(int)) if (optlen < sizeof(int)) {
return -EINVAL; err = -EINVAL;
goto out;
}
/* The input is really a (__u8 hints[2]), easier as an int */ /* The input is really a (__u8 hints[2]), easier as an int */
if (get_user(opt, (int __user *)optval)) if (get_user(opt, (int __user *)optval)) {
return -EFAULT; err = -EFAULT;
goto out;
}
/* Unregister any old registration */ /* Unregister any old registration */
if (self->skey) if (self->skey)
@ -2163,12 +2167,16 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
* making a discovery (nodes which don't match any hint * making a discovery (nodes which don't match any hint
* bit in the mask are not reported). * bit in the mask are not reported).
*/ */
if (optlen < sizeof(int)) if (optlen < sizeof(int)) {
return -EINVAL; err = -EINVAL;
goto out;
}
/* The input is really a (__u8 hints[2]), easier as an int */ /* The input is really a (__u8 hints[2]), easier as an int */
if (get_user(opt, (int __user *)optval)) if (get_user(opt, (int __user *)optval)) {
return -EFAULT; err = -EFAULT;
goto out;
}
/* Set the new hint mask */ /* Set the new hint mask */
self->mask.word = (__u16) opt; self->mask.word = (__u16) opt;
@ -2180,19 +2188,12 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
break; break;
default: default:
return -ENOPROTOOPT; err = -ENOPROTOOPT;
break;
} }
return 0;
}
static int irda_setsockopt(struct socket *sock, int level, int optname, out:
char __user *optval, unsigned int optlen) release_sock(sk);
{
int err;
lock_kernel();
err = __irda_setsockopt(sock, level, optname, optval, optlen);
unlock_kernel();
return err; return err;
} }
@ -2249,7 +2250,7 @@ static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
/* /*
* Function irda_getsockopt (sock, level, optname, optval, optlen) * Function irda_getsockopt (sock, level, optname, optval, optlen)
*/ */
static int __irda_getsockopt(struct socket *sock, int level, int optname, static int irda_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
@ -2262,7 +2263,7 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */ int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */
int val = 0; int val = 0;
int len = 0; int len = 0;
int err; int err = 0;
int offset, total; int offset, total;
IRDA_DEBUG(2, "%s(%p)\n", __func__, self); IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
@ -2276,15 +2277,18 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
if(len < 0) if(len < 0)
return -EINVAL; return -EINVAL;
lock_sock(sk);
switch (optname) { switch (optname) {
case IRLMP_ENUMDEVICES: case IRLMP_ENUMDEVICES:
/* Ask lmp for the current discovery log */ /* Ask lmp for the current discovery log */
discoveries = irlmp_get_discoveries(&list.len, self->mask.word, discoveries = irlmp_get_discoveries(&list.len, self->mask.word,
self->nslots); self->nslots);
/* Check if the we got some results */ /* Check if the we got some results */
if (discoveries == NULL) if (discoveries == NULL) {
return -EAGAIN; /* Didn't find any devices */ err = -EAGAIN;
err = 0; goto out; /* Didn't find any devices */
}
/* Write total list length back to client */ /* Write total list length back to client */
if (copy_to_user(optval, &list, if (copy_to_user(optval, &list,
@ -2297,8 +2301,7 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
sizeof(struct irda_device_info); sizeof(struct irda_device_info);
/* Copy the list itself - watch for overflow */ /* Copy the list itself - watch for overflow */
if(list.len > 2048) if (list.len > 2048) {
{
err = -EINVAL; err = -EINVAL;
goto bed; goto bed;
} }
@ -2314,17 +2317,20 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
bed: bed:
/* Free up our buffer */ /* Free up our buffer */
kfree(discoveries); kfree(discoveries);
if (err)
return err;
break; break;
case IRLMP_MAX_SDU_SIZE: case IRLMP_MAX_SDU_SIZE:
val = self->max_data_size; val = self->max_data_size;
len = sizeof(int); len = sizeof(int);
if (put_user(len, optlen)) if (put_user(len, optlen)) {
return -EFAULT; err = -EFAULT;
goto out;
}
if (copy_to_user(optval, &val, len)) {
err = -EFAULT;
goto out;
}
if (copy_to_user(optval, &val, len))
return -EFAULT;
break; break;
case IRLMP_IAS_GET: case IRLMP_IAS_GET:
/* The user want an object from our local IAS database. /* The user want an object from our local IAS database.
@ -2332,17 +2338,22 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
* that we found */ * that we found */
/* Check that the user has allocated the right space for us */ /* Check that the user has allocated the right space for us */
if (len != sizeof(struct irda_ias_set)) if (len != sizeof(struct irda_ias_set)) {
return -EINVAL; err = -EINVAL;
goto out;
}
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
if (ias_opt == NULL) if (ias_opt == NULL) {
return -ENOMEM; err = -ENOMEM;
goto out;
}
/* Copy query to the driver. */ /* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, len)) { if (copy_from_user(ias_opt, optval, len)) {
kfree(ias_opt); kfree(ias_opt);
return -EFAULT; err = -EFAULT;
goto out;
} }
/* Find the object we target. /* Find the object we target.
@ -2355,7 +2366,8 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
ias_obj = irias_find_object(ias_opt->irda_class_name); ias_obj = irias_find_object(ias_opt->irda_class_name);
if(ias_obj == (struct ias_object *) NULL) { if(ias_obj == (struct ias_object *) NULL) {
kfree(ias_opt); kfree(ias_opt);
return -EINVAL; err = -EINVAL;
goto out;
} }
/* Find the attribute (in the object) we target */ /* Find the attribute (in the object) we target */
@ -2363,21 +2375,23 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
ias_opt->irda_attrib_name); ias_opt->irda_attrib_name);
if(ias_attr == (struct ias_attrib *) NULL) { if(ias_attr == (struct ias_attrib *) NULL) {
kfree(ias_opt); kfree(ias_opt);
return -EINVAL; err = -EINVAL;
goto out;
} }
/* Translate from internal to user structure */ /* Translate from internal to user structure */
err = irda_extract_ias_value(ias_opt, ias_attr->value); err = irda_extract_ias_value(ias_opt, ias_attr->value);
if(err) { if(err) {
kfree(ias_opt); kfree(ias_opt);
return err; goto out;
} }
/* Copy reply to the user */ /* Copy reply to the user */
if (copy_to_user(optval, ias_opt, if (copy_to_user(optval, ias_opt,
sizeof(struct irda_ias_set))) { sizeof(struct irda_ias_set))) {
kfree(ias_opt); kfree(ias_opt);
return -EFAULT; err = -EFAULT;
goto out;
} }
/* Note : don't need to put optlen, we checked it */ /* Note : don't need to put optlen, we checked it */
kfree(ias_opt); kfree(ias_opt);
@ -2388,17 +2402,22 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
* then wait for the answer to come back. */ * then wait for the answer to come back. */
/* Check that the user has allocated the right space for us */ /* Check that the user has allocated the right space for us */
if (len != sizeof(struct irda_ias_set)) if (len != sizeof(struct irda_ias_set)) {
return -EINVAL; err = -EINVAL;
goto out;
}
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
if (ias_opt == NULL) if (ias_opt == NULL) {
return -ENOMEM; err = -ENOMEM;
goto out;
}
/* Copy query to the driver. */ /* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, len)) { if (copy_from_user(ias_opt, optval, len)) {
kfree(ias_opt); kfree(ias_opt);
return -EFAULT; err = -EFAULT;
goto out;
} }
/* At this point, there are two cases... /* At this point, there are two cases...
@ -2419,7 +2438,8 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
daddr = ias_opt->daddr; daddr = ias_opt->daddr;
if((!daddr) || (daddr == DEV_ADDR_ANY)) { if((!daddr) || (daddr == DEV_ADDR_ANY)) {
kfree(ias_opt); kfree(ias_opt);
return -EINVAL; err = -EINVAL;
goto out;
} }
} }
@ -2428,7 +2448,8 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
IRDA_WARNING("%s: busy with a previous query\n", IRDA_WARNING("%s: busy with a previous query\n",
__func__); __func__);
kfree(ias_opt); kfree(ias_opt);
return -EBUSY; err = -EBUSY;
goto out;
} }
self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
@ -2436,7 +2457,8 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
if (self->iriap == NULL) { if (self->iriap == NULL) {
kfree(ias_opt); kfree(ias_opt);
return -ENOMEM; err = -ENOMEM;
goto out;
} }
/* Treat unexpected wakeup as disconnect */ /* Treat unexpected wakeup as disconnect */
@ -2455,7 +2477,8 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
* we can free it regardless! */ * we can free it regardless! */
kfree(ias_opt); kfree(ias_opt);
/* Treat signals as disconnect */ /* Treat signals as disconnect */
return -EHOSTUNREACH; err = -EHOSTUNREACH;
goto out;
} }
/* Check what happened */ /* Check what happened */
@ -2465,9 +2488,11 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
/* Requested object/attribute doesn't exist */ /* Requested object/attribute doesn't exist */
if((self->errno == IAS_CLASS_UNKNOWN) || if((self->errno == IAS_CLASS_UNKNOWN) ||
(self->errno == IAS_ATTRIB_UNKNOWN)) (self->errno == IAS_ATTRIB_UNKNOWN))
return -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
else else
return -EHOSTUNREACH; err = -EHOSTUNREACH;
goto out;
} }
/* Translate from internal to user structure */ /* Translate from internal to user structure */
@ -2476,14 +2501,15 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
irias_delete_value(self->ias_result); irias_delete_value(self->ias_result);
if (err) { if (err) {
kfree(ias_opt); kfree(ias_opt);
return err; goto out;
} }
/* Copy reply to the user */ /* Copy reply to the user */
if (copy_to_user(optval, ias_opt, if (copy_to_user(optval, ias_opt,
sizeof(struct irda_ias_set))) { sizeof(struct irda_ias_set))) {
kfree(ias_opt); kfree(ias_opt);
return -EFAULT; err = -EFAULT;
goto out;
} }
/* Note : don't need to put optlen, we checked it */ /* Note : don't need to put optlen, we checked it */
kfree(ias_opt); kfree(ias_opt);
@ -2504,11 +2530,15 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
*/ */
/* Check that the user is passing us an int */ /* Check that the user is passing us an int */
if (len != sizeof(int)) if (len != sizeof(int)) {
return -EINVAL; err = -EINVAL;
goto out;
}
/* Get timeout in ms (max time we block the caller) */ /* Get timeout in ms (max time we block the caller) */
if (get_user(val, (int __user *)optval)) if (get_user(val, (int __user *)optval)) {
return -EFAULT; err = -EFAULT;
goto out;
}
/* Tell IrLMP we want to be notified */ /* Tell IrLMP we want to be notified */
irlmp_update_client(self->ckey, self->mask.word, irlmp_update_client(self->ckey, self->mask.word,
@ -2520,8 +2550,6 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
/* Wait until a node is discovered */ /* Wait until a node is discovered */
if (!self->cachedaddr) { if (!self->cachedaddr) {
int ret = 0;
IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__); IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__);
/* Set watchdog timer to expire in <val> ms. */ /* Set watchdog timer to expire in <val> ms. */
@ -2534,7 +2562,7 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
/* Wait for IR-LMP to call us back */ /* Wait for IR-LMP to call us back */
__wait_event_interruptible(self->query_wait, __wait_event_interruptible(self->query_wait,
(self->cachedaddr != 0 || self->errno == -ETIME), (self->cachedaddr != 0 || self->errno == -ETIME),
ret); err);
/* If watchdog is still activated, kill it! */ /* If watchdog is still activated, kill it! */
if(timer_pending(&(self->watchdog))) if(timer_pending(&(self->watchdog)))
@ -2542,8 +2570,8 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__); IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__);
if (ret != 0) if (err != 0)
return ret; goto out;
} }
else else
IRDA_DEBUG(1, "%s(), found immediately !\n", IRDA_DEBUG(1, "%s(), found immediately !\n",
@ -2566,25 +2594,19 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
* If the user want more details, he should query * If the user want more details, he should query
* the whole discovery log and pick one device... * the whole discovery log and pick one device...
*/ */
if (put_user(daddr, (int __user *)optval)) if (put_user(daddr, (int __user *)optval)) {
return -EFAULT; err = -EFAULT;
goto out;
}
break; break;
default: default:
return -ENOPROTOOPT; err = -ENOPROTOOPT;
} }
return 0; out:
}
static int irda_getsockopt(struct socket *sock, int level, int optname, release_sock(sk);
char __user *optval, int __user *optlen)
{
int err;
lock_kernel();
err = __irda_getsockopt(sock, level, optname, optval, optlen);
unlock_kernel();
return err; return err;
} }
@ -2628,7 +2650,7 @@ static const struct proto_ops irda_seqpacket_ops = {
.socketpair = sock_no_socketpair, .socketpair = sock_no_socketpair,
.accept = irda_accept, .accept = irda_accept,
.getname = irda_getname, .getname = irda_getname,
.poll = irda_datagram_poll, .poll = datagram_poll,
.ioctl = irda_ioctl, .ioctl = irda_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = irda_compat_ioctl, .compat_ioctl = irda_compat_ioctl,
@ -2652,7 +2674,7 @@ static const struct proto_ops irda_dgram_ops = {
.socketpair = sock_no_socketpair, .socketpair = sock_no_socketpair,
.accept = irda_accept, .accept = irda_accept,
.getname = irda_getname, .getname = irda_getname,
.poll = irda_datagram_poll, .poll = datagram_poll,
.ioctl = irda_ioctl, .ioctl = irda_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = irda_compat_ioctl, .compat_ioctl = irda_compat_ioctl,
@ -2677,7 +2699,7 @@ static const struct proto_ops irda_ultra_ops = {
.socketpair = sock_no_socketpair, .socketpair = sock_no_socketpair,
.accept = sock_no_accept, .accept = sock_no_accept,
.getname = irda_getname, .getname = irda_getname,
.poll = irda_datagram_poll, .poll = datagram_poll,
.ioctl = irda_ioctl, .ioctl = irda_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = irda_compat_ioctl, .compat_ioctl = irda_compat_ioctl,