diff options
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r-- | net/dcb/dcbnl.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 656c7c75b192..5520e431b072 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -196,6 +196,34 @@ static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { | |||
196 | static LIST_HEAD(dcb_app_list); | 196 | static LIST_HEAD(dcb_app_list); |
197 | static DEFINE_SPINLOCK(dcb_lock); | 197 | static DEFINE_SPINLOCK(dcb_lock); |
198 | 198 | ||
199 | static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, | ||
200 | u32 flags, struct nlmsghdr **nlhp) | ||
201 | { | ||
202 | struct sk_buff *skb; | ||
203 | struct dcbmsg *dcb; | ||
204 | struct nlmsghdr *nlh; | ||
205 | |||
206 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
207 | if (!skb) | ||
208 | return NULL; | ||
209 | |||
210 | nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags); | ||
211 | if (!nlh) { | ||
212 | /* header should always fit, allocation must be buggy */ | ||
213 | BUG(); | ||
214 | } | ||
215 | |||
216 | dcb = nlmsg_data(nlh); | ||
217 | dcb->dcb_family = AF_UNSPEC; | ||
218 | dcb->cmd = cmd; | ||
219 | dcb->dcb_pad = 0; | ||
220 | |||
221 | if (nlhp) | ||
222 | *nlhp = nlh; | ||
223 | |||
224 | return skb; | ||
225 | } | ||
226 | |||
199 | /* standard netlink reply call */ | 227 | /* standard netlink reply call */ |
200 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, | 228 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
201 | u32 seq, u16 flags) | 229 | u32 seq, u16 flags) |
@@ -1922,6 +1950,19 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, | |||
1922 | return err; | 1950 | return err; |
1923 | } | 1951 | } |
1924 | 1952 | ||
1953 | struct reply_func { | ||
1954 | /* reply netlink message type */ | ||
1955 | int type; | ||
1956 | |||
1957 | /* function to fill message contents */ | ||
1958 | int (*cb)(struct net_device *, struct nlmsghdr *, u32, | ||
1959 | struct nlattr **, struct sk_buff *); | ||
1960 | }; | ||
1961 | |||
1962 | static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { | ||
1963 | /* FIXME: add reply defs */ | ||
1964 | }; | ||
1965 | |||
1925 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1966 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1926 | { | 1967 | { |
1927 | struct net *net = sock_net(skb->sk); | 1968 | struct net *net = sock_net(skb->sk); |
@@ -1930,6 +1971,9 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1930 | struct nlattr *tb[DCB_ATTR_MAX + 1]; | 1971 | struct nlattr *tb[DCB_ATTR_MAX + 1]; |
1931 | u32 pid = skb ? NETLINK_CB(skb).pid : 0; | 1972 | u32 pid = skb ? NETLINK_CB(skb).pid : 0; |
1932 | int ret = -EINVAL; | 1973 | int ret = -EINVAL; |
1974 | struct sk_buff *reply_skb; | ||
1975 | struct nlmsghdr *reply_nlh; | ||
1976 | const struct reply_func *fn; | ||
1933 | 1977 | ||
1934 | if (!net_eq(net, &init_net)) | 1978 | if (!net_eq(net, &init_net)) |
1935 | return -EINVAL; | 1979 | return -EINVAL; |
@@ -1939,6 +1983,14 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1939 | if (ret < 0) | 1983 | if (ret < 0) |
1940 | return ret; | 1984 | return ret; |
1941 | 1985 | ||
1986 | if (dcb->cmd > DCB_CMD_MAX) | ||
1987 | return -EINVAL; | ||
1988 | |||
1989 | /* check if a reply function has been defined for the command */ | ||
1990 | fn = &reply_funcs[dcb->cmd]; | ||
1991 | if (!fn->cb) | ||
1992 | return -EOPNOTSUPP; | ||
1993 | |||
1942 | if (!tb[DCB_ATTR_IFNAME]) | 1994 | if (!tb[DCB_ATTR_IFNAME]) |
1943 | return -EINVAL; | 1995 | return -EINVAL; |
1944 | 1996 | ||
@@ -1949,6 +2001,25 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1949 | if (!netdev->dcbnl_ops) | 2001 | if (!netdev->dcbnl_ops) |
1950 | goto errout; | 2002 | goto errout; |
1951 | 2003 | ||
2004 | reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, pid, nlh->nlmsg_seq, | ||
2005 | nlh->nlmsg_flags, &reply_nlh); | ||
2006 | if (!reply_skb) { | ||
2007 | ret = -ENOBUFS; | ||
2008 | goto out; | ||
2009 | } | ||
2010 | |||
2011 | ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); | ||
2012 | if (ret < 0) { | ||
2013 | nlmsg_free(reply_skb); | ||
2014 | goto out; | ||
2015 | } | ||
2016 | |||
2017 | nlmsg_end(reply_skb, reply_nlh); | ||
2018 | |||
2019 | ret = rtnl_unicast(reply_skb, &init_net, pid); | ||
2020 | if (ret) | ||
2021 | goto out; | ||
2022 | |||
1952 | switch (dcb->cmd) { | 2023 | switch (dcb->cmd) { |
1953 | case DCB_CMD_GSTATE: | 2024 | case DCB_CMD_GSTATE: |
1954 | ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, | 2025 | ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, |