Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 158975
b: refs/heads/master
c: 1dacc76
h: refs/heads/master
i:
  158973: 20d1edb
  158971: 61d3616
  158967: 47f0c31
  158959: b27a7ee
  158943: 69b292d
  158911: dc516af
  158847: 3f0657e
  158719: 1301b2d
v: v3
  • Loading branch information
Johannes Berg authored and David S. Miller committed Jul 15, 2009
1 parent 3e20df0 commit 2166ca2
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4f45b2cd4e78b5e49d7d41548345b879d3fdfeae
refs/heads/master: 1dacc76d0014a034b8aca14237c127d7c19d7726
2 changes: 1 addition & 1 deletion trunk/arch/mips/kernel/scall64-n32.S
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ EXPORT(sysn32_call_table)
PTR sys_connect
PTR sys_accept
PTR sys_sendto
PTR sys_recvfrom
PTR compat_sys_recvfrom
PTR compat_sys_sendmsg /* 6045 */
PTR compat_sys_recvmsg
PTR sys_shutdown
Expand Down
4 changes: 2 additions & 2 deletions trunk/arch/mips/kernel/scall64-o32.S
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ sys_call_table:
PTR sys_getsockname
PTR sys_getsockopt
PTR sys_listen
PTR sys_recv /* 4175 */
PTR sys_recvfrom
PTR compat_sys_recv /* 4175 */
PTR compat_sys_recvfrom
PTR compat_sys_recvmsg
PTR sys_send
PTR compat_sys_sendmsg
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/sparc/kernel/sys32.S
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ SIGN2(sys32_syslog, sys_syslog, %o0, %o2)
SIGN1(sys32_umask, sys_umask, %o0)
SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2)
SIGN1(sys32_sendto, sys_sendto, %o0)
SIGN1(sys32_recvfrom, sys_recvfrom, %o0)
SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0)
SIGN3(sys32_socket, sys_socket, %o0, %o1, %o2)
SIGN2(sys32_connect, sys_connect, %o0, %o2)
SIGN2(sys32_bind, sys_bind, %o0, %o2)
Expand Down
8 changes: 8 additions & 0 deletions trunk/include/linux/wireless.h
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,14 @@ struct __compat_iw_event {
};
#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)

/* Size of the various events for compat */
#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ)
#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32))
#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq))
#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param))
#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr))
#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality))
#define IW_EV_COMPAT_POINT_LEN \
(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
IW_EV_COMPAT_POINT_OFF)
Expand Down
20 changes: 20 additions & 0 deletions trunk/net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ menuconfig NET

if NET

config WANT_COMPAT_NETLINK_MESSAGES
bool
help
This option can be selected by other options that need compat
netlink messages.

config COMPAT_NETLINK_MESSAGES
def_bool y
depends on COMPAT
depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES
help
This option makes it possible to send different netlink messages
to tasks depending on whether the task is a compat task or not. To
achieve this, you need to set skb_shinfo(skb)->frag_list to the
compat skb before sending the skb, the netlink code will sort out
which message to actually pass to the task.

Newly written code should NEVER need this option but do
compat-independent messages instead!

menu "Networking options"

source "net/packet/Kconfig"
Expand Down
17 changes: 15 additions & 2 deletions trunk/net/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,18 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}

asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags)
{
return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
}

asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
unsigned flags, struct sockaddr __user *addr,
int __user *addrlen)
{
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}

asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
{
int ret;
Expand Down Expand Up @@ -788,10 +800,11 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
break;
case SYS_RECV:
ret = sys_recv(a0, compat_ptr(a1), a[2], a[3]);
ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]);
break;
case SYS_RECVFROM:
ret = sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), compat_ptr(a[5]));
ret = compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
compat_ptr(a[4]), compat_ptr(a[5]));
break;
case SYS_SHUTDOWN:
ret = sys_shutdown(a0,a1);
Expand Down
36 changes: 35 additions & 1 deletion trunk/net/netlink/af_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
struct netlink_sock *nlk = nlk_sk(sk);
int noblock = flags&MSG_DONTWAIT;
size_t copied;
struct sk_buff *skb;
struct sk_buff *skb, *frag __maybe_unused = NULL;
int err;

if (flags&MSG_OOB)
Expand All @@ -1373,6 +1373,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
if (skb == NULL)
goto out;

#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
if (unlikely(skb_shinfo(skb)->frag_list)) {
bool need_compat = !!(flags & MSG_CMSG_COMPAT);

/*
* If this skb has a frag_list, then here that means that
* we will have to use the frag_list skb for compat tasks
* and the regular skb for non-compat tasks.
*
* The skb might (and likely will) be cloned, so we can't
* just reset frag_list and go on with things -- we need to
* keep that. For the compat case that's easy -- simply get
* a reference to the compat skb and free the regular one
* including the frag. For the non-compat case, we need to
* avoid sending the frag to the user -- so assign NULL but
* restore it below before freeing the skb.
*/
if (need_compat) {
struct sk_buff *compskb = skb_shinfo(skb)->frag_list;
skb_get(compskb);
kfree_skb(skb);
skb = compskb;
} else {
frag = skb_shinfo(skb)->frag_list;
skb_shinfo(skb)->frag_list = NULL;
}
}
#endif

msg->msg_namelen = 0;

copied = skb->len;
Expand Down Expand Up @@ -1403,6 +1432,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
siocb->scm->creds = *NETLINK_CREDS(skb);
if (flags & MSG_TRUNC)
copied = skb->len;

#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
skb_shinfo(skb)->frag_list = frag;
#endif

skb_free_datagram(sk, skb);

if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
Expand Down
78 changes: 78 additions & 0 deletions trunk/net/wireless/wext.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,21 @@ static const int event_type_size[] = {
IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
};

#ifdef CONFIG_COMPAT
static const int compat_event_type_size[] = {
IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */
0,
IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
0,
IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */
IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
0,
IW_EV_COMPAT_POINT_LEN, /* Without variable payload */
IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
};
#endif

/************************ COMMON SUBROUTINES ************************/
/*
Expand Down Expand Up @@ -1348,6 +1363,22 @@ void wireless_send_event(struct net_device * dev,
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct nlattr *nla;
#ifdef CONFIG_COMPAT
struct __compat_iw_event *compat_event;
struct compat_iw_point compat_wrqu;
struct sk_buff *compskb;
#endif

/*
* Nothing in the kernel sends scan events with data, be safe.
* This is necessary because we cannot fix up scan event data
* for compat, due to being contained in 'extra', but normally
* applications are required to retrieve the scan data anyway
* and no data is included in the event, this codifies that
* practice.
*/
if (WARN_ON(cmd == SIOCGIWSCAN && extra))
extra = NULL;

/* Get the description of the Event */
if (cmd <= SIOCIWLAST) {
Expand Down Expand Up @@ -1446,7 +1477,54 @@ void wireless_send_event(struct net_device * dev,
memcpy(((char *) event) + hdr_len, extra, extra_len);

nlmsg_end(skb, nlh);
#ifdef CONFIG_COMPAT
hdr_len = compat_event_type_size[descr->header_type];
event_len = hdr_len + extra_len;

compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!compskb) {
kfree_skb(skb);
return;
}

/* Send via the RtNetlink event channel */
nlh = rtnetlink_ifinfo_prep(dev, compskb);
if (WARN_ON(!nlh)) {
kfree_skb(skb);
kfree_skb(compskb);
return;
}

/* Add the wireless events in the netlink packet */
nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
if (!nla) {
kfree_skb(skb);
kfree_skb(compskb);
return;
}
compat_event = nla_data(nla);

compat_event->len = event_len;
compat_event->cmd = cmd;
if (descr->header_type == IW_HEADER_TYPE_POINT) {
compat_wrqu.length = wrqu->data.length;
compat_wrqu.flags = wrqu->data.flags;
memcpy(&compat_event->pointer,
((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
hdr_len - IW_EV_COMPAT_LCP_LEN);
if (extra_len)
memcpy(((char *) compat_event) + hdr_len,
extra, extra_len);
} else {
/* extra_len must be zero, so no if (extra) needed */
memcpy(&compat_event->pointer, wrqu,
hdr_len - IW_EV_COMPAT_LCP_LEN);
}

nlmsg_end(compskb, nlh);

skb_shinfo(skb)->frag_list = compskb;
#endif
skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
schedule_work(&wireless_nlevent_work);
}
Expand Down

0 comments on commit 2166ca2

Please sign in to comment.