diff options
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r-- | net/bridge/br_netlink.c | 113 |
1 files changed, 53 insertions, 60 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 8f661195d09d..a9139682c49b 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -15,6 +15,18 @@ | |||
15 | #include <net/netlink.h> | 15 | #include <net/netlink.h> |
16 | #include "br_private.h" | 16 | #include "br_private.h" |
17 | 17 | ||
18 | static inline size_t br_nlmsg_size(void) | ||
19 | { | ||
20 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | ||
21 | + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ | ||
22 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ | ||
23 | + nla_total_size(4) /* IFLA_MASTER */ | ||
24 | + nla_total_size(4) /* IFLA_MTU */ | ||
25 | + nla_total_size(4) /* IFLA_LINK */ | ||
26 | + nla_total_size(1) /* IFLA_OPERSTATE */ | ||
27 | + nla_total_size(1); /* IFLA_PROTINFO */ | ||
28 | } | ||
29 | |||
18 | /* | 30 | /* |
19 | * Create one netlink message for one interface | 31 | * Create one netlink message for one interface |
20 | * Contains port and master info as well as carrier and bridge state. | 32 | * Contains port and master info as well as carrier and bridge state. |
@@ -24,51 +36,43 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por | |||
24 | { | 36 | { |
25 | const struct net_bridge *br = port->br; | 37 | const struct net_bridge *br = port->br; |
26 | const struct net_device *dev = port->dev; | 38 | const struct net_device *dev = port->dev; |
27 | struct ifinfomsg *r; | 39 | struct ifinfomsg *hdr; |
28 | struct nlmsghdr *nlh; | 40 | struct nlmsghdr *nlh; |
29 | unsigned char *b = skb->tail; | ||
30 | u32 mtu = dev->mtu; | ||
31 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; | 41 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
32 | u8 portstate = port->state; | ||
33 | 42 | ||
34 | pr_debug("br_fill_info event %d port %s master %s\n", | 43 | pr_debug("br_fill_info event %d port %s master %s\n", |
35 | event, dev->name, br->dev->name); | 44 | event, dev->name, br->dev->name); |
36 | 45 | ||
37 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); | 46 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); |
38 | r = NLMSG_DATA(nlh); | 47 | if (nlh == NULL) |
39 | r->ifi_family = AF_BRIDGE; | 48 | return -ENOBUFS; |
40 | r->__ifi_pad = 0; | ||
41 | r->ifi_type = dev->type; | ||
42 | r->ifi_index = dev->ifindex; | ||
43 | r->ifi_flags = dev_get_flags(dev); | ||
44 | r->ifi_change = 0; | ||
45 | 49 | ||
46 | RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); | 50 | hdr = nlmsg_data(nlh); |
51 | hdr->ifi_family = AF_BRIDGE; | ||
52 | hdr->__ifi_pad = 0; | ||
53 | hdr->ifi_type = dev->type; | ||
54 | hdr->ifi_index = dev->ifindex; | ||
55 | hdr->ifi_flags = dev_get_flags(dev); | ||
56 | hdr->ifi_change = 0; | ||
47 | 57 | ||
48 | RTA_PUT(skb, IFLA_MASTER, sizeof(int), &br->dev->ifindex); | 58 | NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); |
59 | NLA_PUT_U32(skb, IFLA_MASTER, br->dev->ifindex); | ||
60 | NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); | ||
61 | NLA_PUT_U8(skb, IFLA_OPERSTATE, operstate); | ||
49 | 62 | ||
50 | if (dev->addr_len) | 63 | if (dev->addr_len) |
51 | RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); | 64 | NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); |
52 | 65 | ||
53 | RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu); | ||
54 | if (dev->ifindex != dev->iflink) | 66 | if (dev->ifindex != dev->iflink) |
55 | RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink); | 67 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); |
56 | |||
57 | |||
58 | RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate); | ||
59 | 68 | ||
60 | if (event == RTM_NEWLINK) | 69 | if (event == RTM_NEWLINK) |
61 | RTA_PUT(skb, IFLA_PROTINFO, sizeof(portstate), &portstate); | 70 | NLA_PUT_U8(skb, IFLA_PROTINFO, port->state); |
62 | |||
63 | nlh->nlmsg_len = skb->tail - b; | ||
64 | |||
65 | return skb->len; | ||
66 | 71 | ||
67 | nlmsg_failure: | 72 | return nlmsg_end(skb, nlh); |
68 | rtattr_failure: | ||
69 | 73 | ||
70 | skb_trim(skb, b - skb->data); | 74 | nla_put_failure: |
71 | return -EINVAL; | 75 | return nlmsg_cancel(skb, nlh); |
72 | } | 76 | } |
73 | 77 | ||
74 | /* | 78 | /* |
@@ -77,19 +81,16 @@ rtattr_failure: | |||
77 | void br_ifinfo_notify(int event, struct net_bridge_port *port) | 81 | void br_ifinfo_notify(int event, struct net_bridge_port *port) |
78 | { | 82 | { |
79 | struct sk_buff *skb; | 83 | struct sk_buff *skb; |
80 | int payload = sizeof(struct ifinfomsg) + 128; | ||
81 | int err = -ENOBUFS; | 84 | int err = -ENOBUFS; |
82 | 85 | ||
83 | pr_debug("bridge notify event=%d\n", event); | 86 | pr_debug("bridge notify event=%d\n", event); |
84 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); | 87 | skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); |
85 | if (skb == NULL) | 88 | if (skb == NULL) |
86 | goto errout; | 89 | goto errout; |
87 | 90 | ||
88 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0); | 91 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0); |
89 | if (err < 0) { | 92 | /* failure implies BUG in br_nlmsg_size() */ |
90 | kfree_skb(skb); | 93 | BUG_ON(err < 0); |
91 | goto errout; | ||
92 | } | ||
93 | 94 | ||
94 | err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); | 95 | err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); |
95 | errout: | 96 | errout: |
@@ -104,25 +105,18 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
104 | { | 105 | { |
105 | struct net_device *dev; | 106 | struct net_device *dev; |
106 | int idx; | 107 | int idx; |
107 | int s_idx = cb->args[0]; | ||
108 | int err = 0; | ||
109 | 108 | ||
110 | read_lock(&dev_base_lock); | 109 | read_lock(&dev_base_lock); |
111 | for (dev = dev_base, idx = 0; dev; dev = dev->next) { | 110 | for (dev = dev_base, idx = 0; dev; dev = dev->next) { |
112 | struct net_bridge_port *p = dev->br_port; | ||
113 | |||
114 | /* not a bridge port */ | 111 | /* not a bridge port */ |
115 | if (!p) | 112 | if (dev->br_port == NULL || idx < cb->args[0]) |
116 | continue; | 113 | goto skip; |
117 | |||
118 | if (idx < s_idx) | ||
119 | goto cont; | ||
120 | 114 | ||
121 | err = br_fill_ifinfo(skb, p, NETLINK_CB(cb->skb).pid, | 115 | if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid, |
122 | cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI); | 116 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
123 | if (err <= 0) | 117 | NLM_F_MULTI) < 0) |
124 | break; | 118 | break; |
125 | cont: | 119 | skip: |
126 | ++idx; | 120 | ++idx; |
127 | } | 121 | } |
128 | read_unlock(&dev_base_lock); | 122 | read_unlock(&dev_base_lock); |
@@ -138,26 +132,27 @@ cont: | |||
138 | */ | 132 | */ |
139 | static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 133 | static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
140 | { | 134 | { |
141 | struct rtattr **rta = arg; | 135 | struct ifinfomsg *ifm; |
142 | struct ifinfomsg *ifm = NLMSG_DATA(nlh); | 136 | struct nlattr *protinfo; |
143 | struct net_device *dev; | 137 | struct net_device *dev; |
144 | struct net_bridge_port *p; | 138 | struct net_bridge_port *p; |
145 | u8 new_state; | 139 | u8 new_state; |
146 | 140 | ||
141 | if (nlmsg_len(nlh) < sizeof(*ifm)) | ||
142 | return -EINVAL; | ||
143 | |||
144 | ifm = nlmsg_data(nlh); | ||
147 | if (ifm->ifi_family != AF_BRIDGE) | 145 | if (ifm->ifi_family != AF_BRIDGE) |
148 | return -EPFNOSUPPORT; | 146 | return -EPFNOSUPPORT; |
149 | 147 | ||
150 | /* Must pass valid state as PROTINFO */ | 148 | protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); |
151 | if (rta[IFLA_PROTINFO-1]) { | 149 | if (!protinfo || nla_len(protinfo) < sizeof(u8)) |
152 | u8 *pstate = RTA_DATA(rta[IFLA_PROTINFO-1]); | ||
153 | new_state = *pstate; | ||
154 | } else | ||
155 | return -EINVAL; | 150 | return -EINVAL; |
156 | 151 | ||
152 | new_state = nla_get_u8(protinfo); | ||
157 | if (new_state > BR_STATE_BLOCKING) | 153 | if (new_state > BR_STATE_BLOCKING) |
158 | return -EINVAL; | 154 | return -EINVAL; |
159 | 155 | ||
160 | /* Find bridge port */ | ||
161 | dev = __dev_get_by_index(ifm->ifi_index); | 156 | dev = __dev_get_by_index(ifm->ifi_index); |
162 | if (!dev) | 157 | if (!dev) |
163 | return -ENODEV; | 158 | return -ENODEV; |
@@ -170,10 +165,8 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
170 | if (p->br->stp_enabled) | 165 | if (p->br->stp_enabled) |
171 | return -EBUSY; | 166 | return -EBUSY; |
172 | 167 | ||
173 | if (!netif_running(dev)) | 168 | if (!netif_running(dev) || |
174 | return -ENETDOWN; | 169 | (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)) |
175 | |||
176 | if (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED) | ||
177 | return -ENETDOWN; | 170 | return -ENETDOWN; |
178 | 171 | ||
179 | p->state = new_state; | 172 | p->state = new_state; |