Commit 339bf98f authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[NETLINK]: Do precise netlink message allocations where possible

Account for the netlink message header size directly in nlmsg_new()
instead of relying on the caller calculate it correctly.

Replaces error handling of message construction functions when
constructing notifications with bug traps since a failure implies
a bug in calculating the size of the skb.
Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Acked-by: default avatarPaul Moore <paul.moore@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a94f723d
...@@ -174,6 +174,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); ...@@ -174,6 +174,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
*/ */
#define NLMSG_GOODORDER 0 #define NLMSG_GOODORDER 0
#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER)) #define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
struct netlink_callback struct netlink_callback
......
...@@ -52,6 +52,7 @@ struct fib_rules_ops ...@@ -52,6 +52,7 @@ struct fib_rules_ops
struct nlmsghdr *, struct nlmsghdr *,
struct fib_rule_hdr *); struct fib_rule_hdr *);
u32 (*default_pref)(void); u32 (*default_pref)(void);
size_t (*nlmsg_payload)(struct fib_rule *);
int nlgroup; int nlgroup;
struct nla_policy *policy; struct nla_policy *policy;
......
...@@ -500,14 +500,15 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, ...@@ -500,14 +500,15 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb,
/** /**
* nlmsg_new - Allocate a new netlink message * nlmsg_new - Allocate a new netlink message
* @size: maximum size of message * @payload: size of the message payload
* @flags: the type of memory to allocate. * @flags: the type of memory to allocate.
* *
* Use NLMSG_GOODSIZE if size isn't know and you need a good default size. * Use NLMSG_DEFAULT_SIZE if the size of the payload isn't known
* and a good default is needed.
*/ */
static inline struct sk_buff *nlmsg_new(int size, gfp_t flags) static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags)
{ {
return alloc_skb(size, flags); return alloc_skb(nlmsg_total_size(payload), flags);
} }
/** /**
......
...@@ -77,8 +77,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, ...@@ -77,8 +77,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
/* /*
* If new attributes are added, please revisit this allocation * If new attributes are added, please revisit this allocation
*/ */
size = nlmsg_total_size(genlmsg_total_size(size)); skb = nlmsg_new(genlmsg_total_size(size), GFP_KERNEL);
skb = nlmsg_new(size, GFP_KERNEL);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
......
...@@ -15,6 +15,18 @@ ...@@ -15,6 +15,18 @@
#include <net/netlink.h> #include <net/netlink.h>
#include "br_private.h" #include "br_private.h"
static inline size_t br_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+ nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(4) /* IFLA_MTU */
+ nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(1) /* IFLA_OPERSTATE */
+ nla_total_size(1); /* IFLA_PROTINFO */
}
/* /*
* Create one netlink message for one interface * Create one netlink message for one interface
* Contains port and master info as well as carrier and bridge state. * Contains port and master info as well as carrier and bridge state.
...@@ -77,19 +89,16 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por ...@@ -77,19 +89,16 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
void br_ifinfo_notify(int event, struct net_bridge_port *port) void br_ifinfo_notify(int event, struct net_bridge_port *port)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int payload = sizeof(struct ifinfomsg) + 128;
int err = -ENOBUFS; int err = -ENOBUFS;
pr_debug("bridge notify event=%d\n", event); pr_debug("bridge notify event=%d\n", event);
skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = br_fill_ifinfo(skb, port, 0, 0, event, 0); err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
if (err < 0) { /* failure implies BUG in br_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
errout: errout:
......
...@@ -306,6 +306,22 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -306,6 +306,22 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
return err; return err;
} }
static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
struct fib_rule *rule)
{
size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr))
+ nla_total_size(IFNAMSIZ) /* FRA_IFNAME */
+ nla_total_size(4) /* FRA_PRIORITY */
+ nla_total_size(4) /* FRA_TABLE */
+ nla_total_size(4) /* FRA_FWMARK */
+ nla_total_size(4); /* FRA_FWMASK */
if (ops->nlmsg_payload)
payload += ops->nlmsg_payload(rule);
return payload;
}
static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
u32 pid, u32 seq, int type, int flags, u32 pid, u32 seq, int type, int flags,
struct fib_rules_ops *ops) struct fib_rules_ops *ops)
...@@ -384,15 +400,13 @@ static void notify_rule_change(int event, struct fib_rule *rule, ...@@ -384,15 +400,13 @@ static void notify_rule_change(int event, struct fib_rule *rule,
struct sk_buff *skb; struct sk_buff *skb;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); skb = nlmsg_new(fib_rule_nlmsg_size(ops, rule), GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops); err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops);
if (err < 0) { /* failure implies BUG in fib_rule_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL); err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL);
errout: errout:
......
...@@ -2410,20 +2410,27 @@ static struct file_operations neigh_stat_seq_fops = { ...@@ -2410,20 +2410,27 @@ static struct file_operations neigh_stat_seq_fops = {
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
#ifdef CONFIG_ARPD #ifdef CONFIG_ARPD
static inline size_t neigh_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ndmsg))
+ nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
+ nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
+ nla_total_size(sizeof(struct nda_cacheinfo))
+ nla_total_size(4); /* NDA_PROBES */
}
static void __neigh_notify(struct neighbour *n, int type, int flags) static void __neigh_notify(struct neighbour *n, int type, int flags)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = neigh_fill_info(skb, n, 0, 0, type, flags); err = neigh_fill_info(skb, n, 0, 0, type, flags);
if (err < 0) { /* failure implies BUG in neigh_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
errout: errout:
......
...@@ -273,6 +273,25 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, ...@@ -273,6 +273,25 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->tx_compressed = b->tx_compressed; a->tx_compressed = b->tx_compressed;
}; };
static inline size_t if_nlmsg_size(int iwbuflen)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+ nla_total_size(IFNAMSIZ) /* IFLA_QDISC */
+ nla_total_size(sizeof(struct rtnl_link_ifmap))
+ nla_total_size(sizeof(struct rtnl_link_stats))
+ nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+ nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */
+ nla_total_size(4) /* IFLA_TXQLEN */
+ nla_total_size(4) /* IFLA_WEIGHT */
+ nla_total_size(4) /* IFLA_MTU */
+ nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(1) /* IFLA_OPERSTATE */
+ nla_total_size(1) /* IFLA_LINKMODE */
+ nla_total_size(iwbuflen);
}
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
void *iwbuf, int iwbuflen, int type, u32 pid, void *iwbuf, int iwbuflen, int type, u32 pid,
u32 seq, u32 change, unsigned int flags) u32 seq, u32 change, unsigned int flags)
...@@ -558,7 +577,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -558,7 +577,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
struct sk_buff *nskb; struct sk_buff *nskb;
char *iw_buf = NULL, *iw = NULL; char *iw_buf = NULL, *iw = NULL;
int iw_buf_len = 0; int iw_buf_len = 0;
int err, payload; int err;
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
if (err < 0) if (err < 0)
...@@ -587,9 +606,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -587,9 +606,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
} }
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */ #endif /* CONFIG_NET_WIRELESS_RTNETLINK */
payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) + nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL);
nla_total_size(iw_buf_len));
nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
if (nskb == NULL) { if (nskb == NULL) {
err = -ENOBUFS; err = -ENOBUFS;
goto errout; goto errout;
...@@ -597,10 +614,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -597,10 +614,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
if (err <= 0) { /* failure impilies BUG in if_nlmsg_size or wireless_rtnetlink_get */
kfree_skb(nskb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout: errout:
...@@ -639,15 +654,13 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) ...@@ -639,15 +654,13 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
struct sk_buff *skb; struct sk_buff *skb;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); skb = nlmsg_new(if_nlmsg_size(0), GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0); err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0);
if (err < 0) { /* failure implies BUG in if_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
errout: errout:
......
...@@ -241,6 +241,12 @@ static u32 dn_fib_rule_default_pref(void) ...@@ -241,6 +241,12 @@ static u32 dn_fib_rule_default_pref(void)
return 0; return 0;
} }
static size_t dn_fib_rule_nlmsg_payload(struct fib_rule *rule)
{
return nla_total_size(2) /* dst */
+ nla_total_size(2); /* src */
}
int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
{ {
return fib_rules_dump(skb, cb, AF_DECnet); return fib_rules_dump(skb, cb, AF_DECnet);
......
...@@ -263,6 +263,32 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern ...@@ -263,6 +263,32 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern
return 0; return 0;
} }
static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi)
{
size_t payload = NLMSG_ALIGN(struct rtmsg)
+ nla_total_size(4) /* RTA_TABLE */
+ nla_total_size(2) /* RTA_DST */
+ nla_total_size(4); /* RTA_PRIORITY */
/* space for nested metrics */
payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
if (fi->fib_nhs) {
/* Also handles the special case fib_nhs == 1 */
/* each nexthop is packed in an attribute */
size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
/* may contain a gateway attribute */
nhsize += nla_total_size(4);
/* all nexthops are packed in a nested attribute */
payload += nla_total_size(fi->fib_nhs * nhsize);
}
return payload;
}
static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
u32 tb_id, u8 type, u8 scope, void *dst, int dst_len, u32 tb_id, u8 type, u8 scope, void *dst, int dst_len,
struct dn_fib_info *fi, unsigned int flags) struct dn_fib_info *fi, unsigned int flags)
...@@ -335,17 +361,15 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id, ...@@ -335,17 +361,15 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
u32 pid = req ? req->pid : 0; u32 pid = req ? req->pid : 0;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f), GFP_KERNEL));
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
f->fn_type, f->fn_scope, &f->fn_key, z, f->fn_type, f->fn_scope, &f->fn_key, z,
DN_FIB_INFO(f), 0); DN_FIB_INFO(f), 0);
if (err < 0) { /* failure implies BUG in dn_fib_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
errout: errout:
......
...@@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = { ...@@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = {
.notifier_call =inetdev_event, .notifier_call =inetdev_event,
}; };
static inline size_t inet_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
+ nla_total_size(4) /* IFA_ADDRESS */
+ nla_total_size(4) /* IFA_LOCAL */
+ nla_total_size(4) /* IFA_BROADCAST */
+ nla_total_size(4) /* IFA_ANYCAST */
+ nla_total_size(IFNAMSIZ); /* IFA_LABEL */
}
static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
u32 pid, u32 seq, int event, unsigned int flags) u32 pid, u32 seq, int event, unsigned int flags)
{ {
...@@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, ...@@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
u32 seq = nlh ? nlh->nlmsg_seq : 0; u32 seq = nlh ? nlh->nlmsg_seq : 0;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
if (err < 0) { /* failure implies BUG in inet_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
errout: errout:
......
...@@ -299,6 +299,13 @@ static u32 fib4_rule_default_pref(void) ...@@ -299,6 +299,13 @@ static u32 fib4_rule_default_pref(void)
return 0; return 0;
} }
static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
{
return nla_total_size(4) /* dst */
+ nla_total_size(4) /* src */
+ nla_total_size(4); /* flow */
}
static struct fib_rules_ops fib4_rules_ops = { static struct fib_rules_ops fib4_rules_ops = {
.family = AF_INET, .family = AF_INET,
.rule_size = sizeof(struct fib4_rule), .rule_size = sizeof(struct fib4_rule),
...@@ -308,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = { ...@@ -308,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = {
.compare = fib4_rule_compare, .compare = fib4_rule_compare,
.fill = fib4_rule_fill, .fill = fib4_rule_fill,
.default_pref = fib4_rule_default_pref, .default_pref = fib4_rule_default_pref,
.nlmsg_payload = fib4_rule_nlmsg_payload,
.nlgroup = RTNLGRP_IPV4_RULE, .nlgroup = RTNLGRP_IPV4_RULE,
.policy = fib4_rule_policy, .policy = fib4_rule_policy,
.rules_list = &fib4_rules, .rules_list = &fib4_rules,
......
...@@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev) ...@@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev)
return -1; return -1;
} }
static inline size_t fib_nlmsg_size(struct fib_info *fi)
{
size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
+ nla_total_size(4) /* RTA_TABLE */
+ nla_total_size(4) /* RTA_DST */
+ nla_total_size(4) /* RTA_PRIORITY */
+ nla_total_size(4); /* RTA_PREFSRC */
/* space for nested metrics */
payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
if (fi->fib_nhs) {
/* Also handles the special case fib_nhs == 1 */
/* each nexthop is packed in an attribute */
size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
/* may contain flow and gateway attribute */
nhsize += 2 * nla_total_size(4);
/* all nexthops are packed in a nested attribute */
payload += nla_total_size(fi->fib_nhs * nhsize);
}
return payload;
}
void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
int dst_len, u32 tb_id, struct nl_info *info) int dst_len, u32 tb_id, struct nl_info *info)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int payload = sizeof(struct rtmsg) + 256;
u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = fib_dump_info(skb, info->pid, seq, event, tb_id, err = fib_dump_info(skb, info->pid, seq, event, tb_id,
fa->fa_type, fa->fa_scope, key, dst_len, fa->fa_type, fa->fa_scope, key, dst_len,
fa->fa_tos, fa->fa_info, 0); fa->fa_tos, fa->fa_info, 0);
if (err < 0) { /* failure implies BUG in fib_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL); info->nlh, GFP_KERNEL);
......
...@@ -3098,10 +3098,9 @@ static inline int rt_scope(int ifa_scope) ...@@ -3098,10 +3098,9 @@ static inline int rt_scope(int ifa_scope)
static inline int inet6_ifaddr_msgsize(void) static inline int inet6_ifaddr_msgsize(void)
{ {
return nlmsg_total_size(sizeof(struct ifaddrmsg) + return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
nla_total_size(16) + + nla_total_size(16) /* IFA_ADDRESS */
nla_total_size(sizeof(struct ifa_cacheinfo)) + + nla_total_size(sizeof(struct ifa_cacheinfo));
128);
} }
static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
...@@ -3329,10 +3328,8 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, ...@@ -3329,10 +3328,8 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, RTM_NEWADDR, 0); nlh->nlmsg_seq, RTM_NEWADDR, 0);
if (err < 0) { /* failure implies BUG in inet6_ifaddr_msgsize() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout_ifa;
}
err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
errout_ifa: errout_ifa:
...@@ -3351,10 +3348,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) ...@@ -3351,10 +3348,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
goto errout; goto errout;
err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0);
if (err < 0) { /* failure implies BUG in inet6_ifaddr_msgsize() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout: errout:
...@@ -3397,16 +3392,19 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, ...@@ -3397,16 +3392,19 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
} }
/* Maximum length of ifinfomsg attributes */ static inline size_t inet6_if_nlmsg_size(void)
#define INET6_IFINFO_RTA_SPACE \ {
RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \ return NLMSG_ALIGN(sizeof(struct ifinfomsg))
RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \ + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
RTA_SPACE(sizeof(u32)) /* MTU */ + \ + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
RTA_SPACE(sizeof(int)) /* LINK */ + \ + nla_total_size(4) /* IFLA_MTU */
RTA_SPACE(0) /* PROTINFO */ + \ + nla_total_size(4) /* IFLA_LINK */
RTA_SPACE(sizeof(u32)) /* FLAGS */ + \ + nla_total_size( /* IFLA_PROTINFO */
RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \ nla_total_size(4) /* IFLA_INET6_FLAGS */
RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */ + nla_total_size(sizeof(struct ifla_cacheinfo))
+ nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
);
}
static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
u32 pid, u32 seq, int event, unsigned int flags) u32 pid, u32 seq, int event, unsigned int flags)
...@@ -3501,18 +3499,15 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -3501,18 +3499,15 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
void inet6_ifinfo_notify(int event, struct inet6_dev *idev) void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0);
if (err < 0) { /* failure implies BUG in inet6_if_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout: errout:
...@@ -3520,10 +3515,12 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) ...@@ -3520,10 +3515,12 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
} }
/* Maximum length of prefix_cacheinfo attributes */ static inline size_t inet6_prefix_nlmsg_size(void)
#define INET6_PREFIX_RTA_SPACE \ {
RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \ return NLMSG_ALIGN(sizeof(struct prefixmsg))
RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */ + nla_total_size(sizeof(struct in6_addr))
+ nla_total_size(sizeof(struct prefix_cacheinfo));
}
static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
struct prefix_info *pinfo, u32 pid, u32 seq, struct prefix_info *pinfo, u32 pid, u32 seq,
...@@ -3569,18 +3566,15 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, ...@@ -3569,18 +3566,15 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
struct prefix_info *pinfo) struct prefix_info *pinfo)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE;
int err = -ENOBUFS; int err = -ENOBUFS;
skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0);
if (err < 0) { /* failure implies BUG in inet6_prefix_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
errout: errout:
......
...@@ -232,6 +232,12 @@ static u32 fib6_rule_default_pref(void) ...@@ -232,6 +232,12 @@ static u32 fib6_rule_default_pref(void)
return 0x3FFF; return 0x3FFF;
} }
static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
{
return nla_total_size(16) /* dst */
+ nla_total_size(16); /* src */
}
static struct fib_rules_ops fib6_rules_ops = { static struct fib_rules_ops fib6_rules_ops = {
.family = AF_INET6, .family = AF_INET6,
.rule_size = sizeof(struct fib6_rule), .rule_size = sizeof(struct fib6_rule),
...@@ -241,6 +247,7 @@ static struct fib_rules_ops fib6_rules_ops = { ...@@ -241,6 +247,7 @@ static struct fib_rules_ops fib6_rules_ops = {
.compare = fib6_rule_compare, .compare = fib6_rule_compare,
.fill = fib6_rule_fill, .fill = fib6_rule_fill,
.default_pref = fib6_rule_default_pref, .default_pref = fib6_rule_default_pref,
.nlmsg_payload = fib6_rule_nlmsg_payload,
.nlgroup = RTNLGRP_IPV6_RULE, .nlgroup = RTNLGRP_IPV6_RULE,
.policy = fib6_rule_policy, .policy = fib6_rule_policy,
.rules_list = &fib6_rules, .rules_list = &fib6_rules,
......
...@@ -2006,6 +2006,20 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -2006,6 +2006,20 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
return ip6_route_add(&cfg); return ip6_route_add(&cfg);
} }
static inline size_t rt6_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct rtmsg))
+ nla_total_size(16) /* RTA_SRC */
+ nla_total_size(16) /* RTA_DST */
+ nla_total_size(16) /* RTA_GATEWAY */
+ nla_total_size(16) /* RTA_PREFSRC */
+ nla_total_size(4) /* RTA_TABLE */
+ nla_total_size(4) /* RTA_IIF */
+ nla_total_size(4) /* RTA_OIF */
+ nla_total_size(4) /* RTA_PRIORITY */
+ nla_total_size(sizeof(struct rta_cacheinfo));
}
static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
struct in6_addr *dst, struct in6_addr *src, struct in6_addr *dst, struct in6_addr *src,
int iif, int type, u32 pid, u32 seq, int iif, int type, u32 pid, u32 seq,
...@@ -2200,7 +2214,6 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) ...@@ -2200,7 +2214,6 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
struct sk_buff *skb; struct sk_buff *skb;
u32 pid = 0, seq = 0; u32 pid = 0, seq = 0;
struct nlmsghdr *nlh = NULL; struct nlmsghdr *nlh = NULL;
int payload = sizeof(struct rtmsg) + 256;
int err = -ENOBUFS; int err = -ENOBUFS;
if (info) { if (info) {
...@@ -2210,15 +2223,13 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) ...@@ -2210,15 +2223,13 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
seq = nlh->nlmsg_seq; seq = nlh->nlmsg_seq;
} }
skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0); err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0);
if (err < 0) { /* failure implies BUG in rt6_nlmsg_size() */
kfree_skb(skb); BUG_ON(err < 0);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any());
errout: errout:
......
...@@ -452,7 +452,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) ...@@ -452,7 +452,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
} }
list_start: list_start:
ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL); ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
if (ans_skb == NULL) { if (ans_skb == NULL) {
ret_val = -ENOMEM; ret_val = -ENOMEM;
goto list_failure; goto list_failure;
......
...@@ -356,7 +356,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) ...@@ -356,7 +356,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
void *data; void *data;
struct netlbl_dom_map *entry; struct netlbl_dom_map *entry;
ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (ans_skb == NULL) if (ans_skb == NULL)
return -ENOMEM; return -ENOMEM;
data = netlbl_netlink_hdr_put(ans_skb, data = netlbl_netlink_hdr_put(ans_skb,
...@@ -492,7 +492,7 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) ...@@ -492,7 +492,7 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
struct sk_buff *ans_skb = NULL; struct sk_buff *ans_skb = NULL;
void *data; void *data;
ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (ans_skb == NULL) if (ans_skb == NULL)
return -ENOMEM; return -ENOMEM;
data = netlbl_netlink_hdr_put(ans_skb, data = netlbl_netlink_hdr_put(ans_skb,
......
...@@ -138,7 +138,7 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) ...@@ -138,7 +138,7 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
struct sk_buff *ans_skb; struct sk_buff *ans_skb;
void *data; void *data;
ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (ans_skb == NULL) if (ans_skb == NULL)
goto list_failure; goto list_failure;
data = netlbl_netlink_hdr_put(ans_skb, data = netlbl_netlink_hdr_put(ans_skb,
......
...@@ -1148,7 +1148,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -1148,7 +1148,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (len > sk->sk_sndbuf - 32) if (len > sk->sk_sndbuf - 32)
goto out; goto out;
err = -ENOBUFS; err = -ENOBUFS;
skb = nlmsg_new(len, GFP_KERNEL); skb = alloc_skb(len, GFP_KERNEL);
if (skb==NULL) if (skb==NULL)
goto out; goto out;
...@@ -1435,14 +1435,13 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) ...@@ -1435,14 +1435,13 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
struct sk_buff *skb; struct sk_buff *skb;
struct nlmsghdr *rep; struct nlmsghdr *rep;
struct nlmsgerr *errmsg; struct nlmsgerr *errmsg;
int size; size_t payload = sizeof(*errmsg);
if (err == 0) /* error messages get the original request appened */
size = nlmsg_total_size(sizeof(*errmsg)); if (err)
else payload += nlmsg_len(nlh);
size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh));
skb = nlmsg_new(size, GFP_KERNEL); skb = nlmsg_new(payload, GFP_KERNEL);
if (!skb) { if (!skb) {
struct sock *sk; struct sock *sk;
......
...@@ -480,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, ...@@ -480,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
return ERR_PTR(-ENOBUFS); return ERR_PTR(-ENOBUFS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment