From 487420df79f1d9f5b9de74c9bef378609c475a39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 08:32:06 +0000 Subject: netlink: remove unused exports I added those myself in commits b4ff4f04 and 84659eb5, but I see no reason now why they should be exported, only generic netlink uses them which cannot be modular. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net/netlink/af_netlink.c') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 2936fa3b6dc..d7d1b822e82 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1541,7 +1541,6 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) kfree(old); return err; } -EXPORT_SYMBOL(netlink_change_ngroups); /** * netlink_clear_multicast_users - kick off multicast listeners @@ -1564,7 +1563,6 @@ void netlink_clear_multicast_users(struct sock *ksk, unsigned int group) netlink_table_ungrab(); } -EXPORT_SYMBOL(netlink_clear_multicast_users); void netlink_set_nonroot(int protocol, unsigned int flags) { -- cgit v1.2.3-70-g09d2 From 6c04bb18ddd633b7feac2c8fe2ae0bf61d20ca7a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 09:51:32 +0000 Subject: netlink: use call_rcu for netlink_change_ngroups For the network namespace work in generic netlink I need to be able to call this function under rcu_read_lock(), otherwise the locking becomes a nightmare and more locks would be needed. Instead, just embed a struct rcu_head (actually a struct listeners_rcu_head that also carries the pointer to the memory block) into the listeners memory so we can use call_rcu() instead of synchronising and then freeing. No rcu_barrier() is needed since this code cannot be modular. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'net/netlink/af_netlink.c') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d7d1b822e82..d46da6cb92e 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -83,6 +83,11 @@ struct netlink_sock { struct module *module; }; +struct listeners_rcu_head { + struct rcu_head rcu_head; + void *ptr; +}; + #define NETLINK_KERNEL_SOCKET 0x1 #define NETLINK_RECV_PKTINFO 0x2 #define NETLINK_BROADCAST_SEND_ERROR 0x4 @@ -1453,7 +1458,8 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, if (groups < 32) groups = 32; - listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL); + listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), + GFP_KERNEL); if (!listeners) goto out_sock_release; @@ -1501,6 +1507,14 @@ netlink_kernel_release(struct sock *sk) EXPORT_SYMBOL(netlink_kernel_release); +static void netlink_free_old_listeners(struct rcu_head *rcu_head) +{ + struct listeners_rcu_head *lrh; + + lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head); + kfree(lrh->ptr); +} + /** * netlink_change_ngroups - change number of multicast groups * @@ -1516,6 +1530,7 @@ EXPORT_SYMBOL(netlink_kernel_release); int netlink_change_ngroups(struct sock *sk, unsigned int groups) { unsigned long *listeners, *old = NULL; + struct listeners_rcu_head *old_rcu_head; struct netlink_table *tbl = &nl_table[sk->sk_protocol]; int err = 0; @@ -1524,7 +1539,9 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) netlink_table_grab(); if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { - listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC); + listeners = kzalloc(NLGRPSZ(groups) + + sizeof(struct listeners_rcu_head), + GFP_ATOMIC); if (!listeners) { err = -ENOMEM; goto out_ungrab; @@ -1532,13 +1549,22 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) old = tbl->listeners; memcpy(listeners, old, NLGRPSZ(tbl->groups)); rcu_assign_pointer(tbl->listeners, listeners); + /* + * Free the old memory after an RCU grace period so we + * don't leak it. We use call_rcu() here in order to be + * able to call this function from atomic contexts. The + * allocation of this memory will have reserved enough + * space for struct listeners_rcu_head at the end. + */ + old_rcu_head = (void *)(tbl->listeners + + NLGRPLONGS(tbl->groups)); + old_rcu_head->ptr = old; + call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners); } tbl->groups = groups; out_ungrab: netlink_table_ungrab(); - synchronize_rcu(); - kfree(old); return err; } -- cgit v1.2.3-70-g09d2 From 1dacc76d0014a034b8aca14237c127d7c19d7726 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 11:26:02 +0000 Subject: net/compat/wext: send different messages to compat tasks Wireless extensions have the unfortunate problem that events are multicast netlink messages, and are not independent of pointer size. Thus, currently 32-bit tasks on 64-bit platforms cannot properly receive events and fail with all kinds of strange problems, for instance wpa_supplicant never notices disassociations, due to the way the 64-bit event looks (to a 32-bit process), the fact that the address is all zeroes is lost, it thinks instead it is 00:00:00:00:01:00. The same problem existed with the ioctls, until David Miller fixed those some time ago in an heroic effort. A different problem caused by this is that we cannot send the ASSOCREQIE/ASSOCRESPIE events because sending them causes a 32-bit wpa_supplicant on a 64-bit system to overwrite its internal information, which is worse than it not getting the information at all -- so we currently resort to sending a custom string event that it then parses. This, however, has a severe size limitation we are frequently hitting with modern access points; this limitation would can be lifted after this patch by sending the correct binary, not custom, event. A similar problem apparently happens for some other netlink users on x86_64 with 32-bit tasks due to the alignment for 64-bit quantities. In order to fix these problems, I have implemented a way to send compat messages to tasks. When sending an event, we send the non-compat event data together with a compat event data in skb_shinfo(main_skb)->frag_list. Then, when the event is read from the socket, the netlink code makes sure to pass out only the skb that is compatible with the task. This approach was suggested by David Miller, my original approach required always sending two skbs but that had various small problems. To determine whether compat is needed or not, I have used the MSG_CMSG_COMPAT flag, and adjusted the call path for recv and recvfrom to include it, even if those calls do not have a cmsg parameter. I have not solved one small part of the problem, and I don't think it is necessary to: if a 32-bit application uses read() rather than any form of recvmsg() it will still get the wrong (64-bit) event. However, neither do applications actually do this, nor would it be a regression. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/scall64-o32.S | 4 +-- arch/sparc/kernel/sys32.S | 2 +- include/linux/wireless.h | 8 +++++ net/Kconfig | 20 +++++++++++ net/compat.c | 17 +++++++-- net/netlink/af_netlink.c | 36 ++++++++++++++++++- net/wireless/wext.c | 78 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 160 insertions(+), 7 deletions(-) (limited to 'net/netlink/af_netlink.c') diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 15874f9812c..7c4a94f4370 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -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 diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 781e0f1e953..821fc978673 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -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 diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index f061c4dda9e..3762f6c7894 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -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) diff --git a/include/linux/wireless.h b/include/linux/wireless.h index cb24204851f..5b4c6c772a9 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -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) diff --git a/net/Kconfig b/net/Kconfig index 7051b971067..041c35edb76 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -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" diff --git a/net/compat.c b/net/compat.c index 8d739053afe..12728b17a22 100644 --- a/net/compat.c +++ b/net/compat.c @@ -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; @@ -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); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d46da6cb92e..da3163d15ef 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -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) @@ -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; @@ -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) diff --git a/net/wireless/wext.c b/net/wireless/wext.c index ee35e6422f1..3fe3c2c0ce1 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -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 ************************/ /* @@ -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) { @@ -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); } -- cgit v1.2.3-70-g09d2 From 3a6c2b419b7768703cfb2cabdb894517c5065e33 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Aug 2009 16:07:40 +0200 Subject: netlink: constify nlmsghdr arguments Consitfy nlmsghdr arguments to a couple of functions as preparation for the next patch, which will constify the netlink message data in all nfnetlink users. Signed-off-by: Patrick McHardy --- include/linux/netlink.h | 15 ++++++++------- include/net/netlink.h | 4 ++-- include/net/rtnetlink.h | 2 +- net/netlink/af_netlink.c | 2 +- net/sched/act_api.c | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) (limited to 'net/netlink/af_netlink.c') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 5ba398e9030..0fbecbbe8e9 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -217,12 +217,13 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb); struct netlink_callback { - struct sk_buff *skb; - struct nlmsghdr *nlh; - int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); - int (*done)(struct netlink_callback *cb); - int family; - long args[6]; + struct sk_buff *skb; + const struct nlmsghdr *nlh; + int (*dump)(struct sk_buff * skb, + struct netlink_callback *cb); + int (*done)(struct netlink_callback *cb); + int family; + long args[6]; }; struct netlink_notify @@ -258,7 +259,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) NLMSG_NEW(skb, pid, seq, type, len, 0) extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - struct nlmsghdr *nlh, + const struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback*), int (*done)(struct netlink_callback*)); diff --git a/include/net/netlink.h b/include/net/netlink.h index 007bdb07dab..a63b2192ac1 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -365,7 +365,7 @@ static inline struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) * * See nla_parse() */ -static inline int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, +static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { @@ -414,7 +414,7 @@ static inline int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, * * Returns 1 if a report back to the application is requested. */ -static inline int nlmsg_report(struct nlmsghdr *nlh) +static inline int nlmsg_report(const struct nlmsghdr *nlh) { return !!(nlh->nlmsg_flags & NLM_F_ECHO); } diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 3c1895e54b7..85ba560332e 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -14,7 +14,7 @@ extern void rtnl_register(int protocol, int msgtype, extern int rtnl_unregister(int protocol, int msgtype); extern void rtnl_unregister_all(int protocol); -static inline int rtnl_msg_family(struct nlmsghdr *nlh) +static inline int rtnl_msg_family(const struct nlmsghdr *nlh) { if (nlmsg_len(nlh) >= sizeof(struct rtgenmsg)) return ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index da3163d15ef..d0ff382c40c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1705,7 +1705,7 @@ errout: } int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - struct nlmsghdr *nlh, + const struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback *), int (*done)(struct netlink_callback *)) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 9d03cc33b6c..2dfb3e7a040 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1011,7 +1011,7 @@ replay: } static struct nlattr * -find_dump_kind(struct nlmsghdr *n) +find_dump_kind(const struct nlmsghdr *n) { struct nlattr *tb1, *tb2[TCA_ACT_MAX+1]; struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; -- cgit v1.2.3-70-g09d2