diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-11-20 19:20:22 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:26:13 -0500 |
commit | 746859625d879688adb99f1e5e8108fea876d369 (patch) | |
tree | dc5689f41d2822b676fd812138cfcc7c358bb978 /net/bridge/br_netlink.c | |
parent | 82e3ab9dbeebd5c8d5402ad1607d22086271a56d (diff) |
[BRIDGE] netlink: Convert bridge netlink code to new netlink interface
Removes dependency on buggy rta_buf, fixes a memory corruption bug due to
a unvalidated netlink attribute, and simplifies the code.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r-- | net/bridge/br_netlink.c | 92 |
1 files changed, 38 insertions, 54 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 15d6efbe7519..a9139682c49b 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -36,51 +36,43 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por | |||
36 | { | 36 | { |
37 | const struct net_bridge *br = port->br; | 37 | const struct net_bridge *br = port->br; |
38 | const struct net_device *dev = port->dev; | 38 | const struct net_device *dev = port->dev; |
39 | struct ifinfomsg *r; | 39 | struct ifinfomsg *hdr; |
40 | struct nlmsghdr *nlh; | 40 | struct nlmsghdr *nlh; |
41 | unsigned char *b = skb->tail; | ||
42 | u32 mtu = dev->mtu; | ||
43 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; | 41 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
44 | u8 portstate = port->state; | ||
45 | 42 | ||
46 | 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", |
47 | event, dev->name, br->dev->name); | 44 | event, dev->name, br->dev->name); |
48 | 45 | ||
49 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); | 46 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); |
50 | r = NLMSG_DATA(nlh); | 47 | if (nlh == NULL) |
51 | r->ifi_family = AF_BRIDGE; | 48 | return -ENOBUFS; |
52 | r->__ifi_pad = 0; | ||
53 | r->ifi_type = dev->type; | ||
54 | r->ifi_index = dev->ifindex; | ||
55 | r->ifi_flags = dev_get_flags(dev); | ||
56 | r->ifi_change = 0; | ||
57 | 49 | ||
58 | 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; | ||
59 | 57 | ||
60 | 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); | ||
61 | 62 | ||
62 | if (dev->addr_len) | 63 | if (dev->addr_len) |
63 | RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); | 64 | NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); |
64 | 65 | ||
65 | RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu); | ||
66 | if (dev->ifindex != dev->iflink) | 66 | if (dev->ifindex != dev->iflink) |
67 | RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink); | 67 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); |
68 | |||
69 | |||
70 | RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate); | ||
71 | 68 | ||
72 | if (event == RTM_NEWLINK) | 69 | if (event == RTM_NEWLINK) |
73 | RTA_PUT(skb, IFLA_PROTINFO, sizeof(portstate), &portstate); | 70 | NLA_PUT_U8(skb, IFLA_PROTINFO, port->state); |
74 | |||
75 | nlh->nlmsg_len = skb->tail - b; | ||
76 | 71 | ||
77 | return skb->len; | 72 | return nlmsg_end(skb, nlh); |
78 | |||
79 | nlmsg_failure: | ||
80 | rtattr_failure: | ||
81 | 73 | ||
82 | skb_trim(skb, b - skb->data); | 74 | nla_put_failure: |
83 | return -EINVAL; | 75 | return nlmsg_cancel(skb, nlh); |
84 | } | 76 | } |
85 | 77 | ||
86 | /* | 78 | /* |
@@ -113,25 +105,18 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
113 | { | 105 | { |
114 | struct net_device *dev; | 106 | struct net_device *dev; |
115 | int idx; | 107 | int idx; |
116 | int s_idx = cb->args[0]; | ||
117 | int err = 0; | ||
118 | 108 | ||
119 | read_lock(&dev_base_lock); | 109 | read_lock(&dev_base_lock); |
120 | for (dev = dev_base, idx = 0; dev; dev = dev->next) { | 110 | for (dev = dev_base, idx = 0; dev; dev = dev->next) { |
121 | struct net_bridge_port *p = dev->br_port; | ||
122 | |||
123 | /* not a bridge port */ | 111 | /* not a bridge port */ |
124 | if (!p) | 112 | if (dev->br_port == NULL || idx < cb->args[0]) |
125 | continue; | 113 | goto skip; |
126 | 114 | ||
127 | if (idx < s_idx) | 115 | if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid, |
128 | goto cont; | 116 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
129 | 117 | NLM_F_MULTI) < 0) | |
130 | err = br_fill_ifinfo(skb, p, NETLINK_CB(cb->skb).pid, | ||
131 | cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI); | ||
132 | if (err <= 0) | ||
133 | break; | 118 | break; |
134 | cont: | 119 | skip: |
135 | ++idx; | 120 | ++idx; |
136 | } | 121 | } |
137 | read_unlock(&dev_base_lock); | 122 | read_unlock(&dev_base_lock); |
@@ -147,26 +132,27 @@ cont: | |||
147 | */ | 132 | */ |
148 | 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) |
149 | { | 134 | { |
150 | struct rtattr **rta = arg; | 135 | struct ifinfomsg *ifm; |
151 | struct ifinfomsg *ifm = NLMSG_DATA(nlh); | 136 | struct nlattr *protinfo; |
152 | struct net_device *dev; | 137 | struct net_device *dev; |
153 | struct net_bridge_port *p; | 138 | struct net_bridge_port *p; |
154 | u8 new_state; | 139 | u8 new_state; |
155 | 140 | ||
141 | if (nlmsg_len(nlh) < sizeof(*ifm)) | ||
142 | return -EINVAL; | ||
143 | |||
144 | ifm = nlmsg_data(nlh); | ||
156 | if (ifm->ifi_family != AF_BRIDGE) | 145 | if (ifm->ifi_family != AF_BRIDGE) |
157 | return -EPFNOSUPPORT; | 146 | return -EPFNOSUPPORT; |
158 | 147 | ||
159 | /* Must pass valid state as PROTINFO */ | 148 | protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); |
160 | if (rta[IFLA_PROTINFO-1]) { | 149 | if (!protinfo || nla_len(protinfo) < sizeof(u8)) |
161 | u8 *pstate = RTA_DATA(rta[IFLA_PROTINFO-1]); | ||
162 | new_state = *pstate; | ||
163 | } else | ||
164 | return -EINVAL; | 150 | return -EINVAL; |
165 | 151 | ||
152 | new_state = nla_get_u8(protinfo); | ||
166 | if (new_state > BR_STATE_BLOCKING) | 153 | if (new_state > BR_STATE_BLOCKING) |
167 | return -EINVAL; | 154 | return -EINVAL; |
168 | 155 | ||
169 | /* Find bridge port */ | ||
170 | dev = __dev_get_by_index(ifm->ifi_index); | 156 | dev = __dev_get_by_index(ifm->ifi_index); |
171 | if (!dev) | 157 | if (!dev) |
172 | return -ENODEV; | 158 | return -ENODEV; |
@@ -179,10 +165,8 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
179 | if (p->br->stp_enabled) | 165 | if (p->br->stp_enabled) |
180 | return -EBUSY; | 166 | return -EBUSY; |
181 | 167 | ||
182 | if (!netif_running(dev)) | 168 | if (!netif_running(dev) || |
183 | return -ENETDOWN; | 169 | (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)) |
184 | |||
185 | if (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED) | ||
186 | return -ENETDOWN; | 170 | return -ENETDOWN; |
187 | 171 | ||
188 | p->state = new_state; | 172 | p->state = new_state; |