Skip to content

Commit d0796d1

Browse files
Richard Alpedavem330
Richard Alpe
authored andcommitted
tipc: convert legacy nl bearer dump to nl compat
Introduce a framework for dumping netlink data from the new netlink API and formatting it to the old legacy API format. This is done by looping the dump data and calling a format handler for each entity, in this case a bearer. We dump until either all data is dumped or we reach the limited buffer size of the legacy API. Remember, the legacy API doesn't scale. In this commit we convert TIPC_CMD_GET_BEARER_NAMES to use the compat layer. Signed-off-by: Richard Alpe <[email protected]> Reviewed-by: Erik Hugne <[email protected]> Reviewed-by: Ying Xue <[email protected]> Reviewed-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bfb3e5d commit d0796d1

File tree

5 files changed

+278
-34
lines changed

5 files changed

+278
-34
lines changed

include/uapi/linux/tipc_config.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@ static inline int TLV_CHECK(const void *tlv, __u16 space, __u16 exp_type)
272272
(ntohs(((struct tlv_desc *)tlv)->tlv_type) == exp_type);
273273
}
274274

275+
static inline int TLV_GET_LEN(struct tlv_desc *tlv)
276+
{
277+
return ntohs(tlv->tlv_len);
278+
}
279+
275280
static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len)
276281
{
277282
struct tlv_desc *tlv_ptr;

net/tipc/bearer.c

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -205,35 +205,6 @@ struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name)
205205
return NULL;
206206
}
207207

208-
/**
209-
* tipc_bearer_get_names - record names of bearers in buffer
210-
*/
211-
struct sk_buff *tipc_bearer_get_names(struct net *net)
212-
{
213-
struct tipc_net *tn = net_generic(net, tipc_net_id);
214-
struct sk_buff *buf;
215-
struct tipc_bearer *b;
216-
int i, j;
217-
218-
buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
219-
if (!buf)
220-
return NULL;
221-
222-
for (i = 0; media_info_array[i] != NULL; i++) {
223-
for (j = 0; j < MAX_BEARERS; j++) {
224-
b = rtnl_dereference(tn->bearer_list[j]);
225-
if (!b)
226-
continue;
227-
if (b->media == media_info_array[i]) {
228-
tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
229-
b->name,
230-
strlen(b->name) + 1);
231-
}
232-
}
233-
}
234-
return buf;
235-
}
236-
237208
void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest)
238209
{
239210
struct tipc_net *tn = net_generic(net, tipc_net_id);

net/tipc/bearer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ void tipc_disable_l2_media(struct tipc_bearer *b);
205205
int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
206206
struct tipc_bearer *b, struct tipc_media_addr *dest);
207207

208-
struct sk_buff *tipc_bearer_get_names(struct net *net);
209208
void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest);
210209
void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest);
211210
struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name);

net/tipc/config.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,6 @@ struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
252252
rep_tlv_buf = tipc_nametbl_get(net, req_tlv_area,
253253
req_tlv_space);
254254
break;
255-
case TIPC_CMD_GET_BEARER_NAMES:
256-
rep_tlv_buf = tipc_bearer_get_names(net);
257-
break;
258255
case TIPC_CMD_GET_MEDIA_NAMES:
259256
rep_tlv_buf = tipc_media_get_names();
260257
break;

net/tipc/netlink_compat.c

Lines changed: 273 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,265 @@
3333

3434
#include "core.h"
3535
#include "config.h"
36+
#include "bearer.h"
3637
#include <net/genetlink.h>
3738
#include <linux/tipc_config.h>
3839

40+
/* The legacy API had an artificial message length limit called
41+
* ULTRA_STRING_MAX_LEN.
42+
*/
43+
#define ULTRA_STRING_MAX_LEN 32768
44+
45+
#define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN)
46+
47+
#define REPLY_TRUNCATED "<truncated>\n"
48+
49+
struct tipc_nl_compat_msg {
50+
u16 cmd;
51+
int rep_size;
52+
struct sk_buff *rep;
53+
struct tlv_desc *req;
54+
struct sock *dst_sk;
55+
};
56+
57+
struct tipc_nl_compat_cmd_dump {
58+
int (*dumpit)(struct sk_buff *, struct netlink_callback *);
59+
int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs);
60+
};
61+
62+
static int tipc_skb_tailroom(struct sk_buff *skb)
63+
{
64+
int tailroom;
65+
int limit;
66+
67+
tailroom = skb_tailroom(skb);
68+
limit = TIPC_SKB_MAX - skb->len;
69+
70+
if (tailroom < limit)
71+
return tailroom;
72+
73+
return limit;
74+
}
75+
76+
static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len)
77+
{
78+
struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb);
79+
80+
if (tipc_skb_tailroom(skb) < TLV_SPACE(len))
81+
return -EMSGSIZE;
82+
83+
skb_put(skb, TLV_SPACE(len));
84+
tlv->tlv_type = htons(type);
85+
tlv->tlv_len = htons(TLV_LENGTH(len));
86+
if (len && data)
87+
memcpy(TLV_DATA(tlv), data, len);
88+
89+
return 0;
90+
}
91+
92+
static struct sk_buff *tipc_tlv_alloc(int size)
93+
{
94+
int hdr_len;
95+
struct sk_buff *buf;
96+
97+
size = TLV_SPACE(size);
98+
hdr_len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
99+
100+
buf = alloc_skb(hdr_len + size, GFP_KERNEL);
101+
if (!buf)
102+
return NULL;
103+
104+
skb_reserve(buf, hdr_len);
105+
106+
return buf;
107+
}
108+
109+
static struct sk_buff *tipc_get_err_tlv(char *str)
110+
{
111+
int str_len = strlen(str) + 1;
112+
struct sk_buff *buf;
113+
114+
buf = tipc_tlv_alloc(TLV_SPACE(str_len));
115+
if (buf)
116+
tipc_add_tlv(buf, TIPC_TLV_ERROR_STRING, str, str_len);
117+
118+
return buf;
119+
}
120+
121+
static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
122+
struct tipc_nl_compat_msg *msg,
123+
struct sk_buff *arg)
124+
{
125+
int len = 0;
126+
int err;
127+
struct sk_buff *buf;
128+
struct nlmsghdr *nlmsg;
129+
struct netlink_callback cb;
130+
131+
memset(&cb, 0, sizeof(cb));
132+
cb.nlh = (struct nlmsghdr *)arg->data;
133+
cb.skb = arg;
134+
135+
buf = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
136+
if (!buf)
137+
return -ENOMEM;
138+
139+
buf->sk = msg->dst_sk;
140+
141+
do {
142+
int rem;
143+
144+
len = (*cmd->dumpit)(buf, &cb);
145+
146+
nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
147+
struct nlattr **attrs;
148+
149+
err = tipc_nlmsg_parse(nlmsg, &attrs);
150+
if (err)
151+
goto err_out;
152+
153+
err = (*cmd->format)(msg, attrs);
154+
if (err)
155+
goto err_out;
156+
157+
if (tipc_skb_tailroom(msg->rep) <= 1) {
158+
err = -EMSGSIZE;
159+
goto err_out;
160+
}
161+
}
162+
163+
skb_reset_tail_pointer(buf);
164+
buf->len = 0;
165+
166+
} while (len);
167+
168+
err = 0;
169+
170+
err_out:
171+
kfree_skb(buf);
172+
173+
if (err == -EMSGSIZE) {
174+
/* The legacy API only considered messages filling
175+
* "ULTRA_STRING_MAX_LEN" to be truncated.
176+
*/
177+
if ((TIPC_SKB_MAX - msg->rep->len) <= 1) {
178+
char *tail = skb_tail_pointer(msg->rep);
179+
180+
if (*tail != '\0')
181+
sprintf(tail - sizeof(REPLY_TRUNCATED) - 1,
182+
REPLY_TRUNCATED);
183+
}
184+
185+
return 0;
186+
}
187+
188+
return err;
189+
}
190+
191+
static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
192+
struct tipc_nl_compat_msg *msg)
193+
{
194+
int err;
195+
struct sk_buff *arg;
196+
197+
msg->rep = tipc_tlv_alloc(msg->rep_size);
198+
if (!msg->rep)
199+
return -ENOMEM;
200+
201+
arg = nlmsg_new(0, GFP_KERNEL);
202+
if (!arg) {
203+
kfree_skb(msg->rep);
204+
return -ENOMEM;
205+
}
206+
207+
err = __tipc_nl_compat_dumpit(cmd, msg, arg);
208+
if (err)
209+
kfree_skb(msg->rep);
210+
211+
kfree_skb(arg);
212+
213+
return err;
214+
}
215+
216+
static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
217+
struct nlattr **attrs)
218+
{
219+
struct nlattr *bearer[TIPC_NLA_BEARER_MAX + 1];
220+
221+
nla_parse_nested(bearer, TIPC_NLA_BEARER_MAX, attrs[TIPC_NLA_BEARER],
222+
NULL);
223+
224+
return tipc_add_tlv(msg->rep, TIPC_TLV_BEARER_NAME,
225+
nla_data(bearer[TIPC_NLA_BEARER_NAME]),
226+
nla_len(bearer[TIPC_NLA_BEARER_NAME]));
227+
}
228+
229+
static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
230+
{
231+
struct tipc_nl_compat_cmd_dump dump;
232+
233+
memset(&dump, 0, sizeof(dump));
234+
235+
switch (msg->cmd) {
236+
case TIPC_CMD_GET_BEARER_NAMES:
237+
msg->rep_size = MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME);
238+
dump.dumpit = tipc_nl_bearer_dump;
239+
dump.format = tipc_nl_compat_bearer_dump;
240+
return tipc_nl_compat_dumpit(&dump, msg);
241+
}
242+
243+
return -EOPNOTSUPP;
244+
}
245+
246+
static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
247+
{
248+
int err;
249+
int len;
250+
struct tipc_nl_compat_msg msg;
251+
struct nlmsghdr *req_nlh;
252+
struct nlmsghdr *rep_nlh;
253+
struct tipc_genlmsghdr *req_userhdr = info->userhdr;
254+
struct net *net = genl_info_net(info);
255+
256+
memset(&msg, 0, sizeof(msg));
257+
258+
req_nlh = (struct nlmsghdr *)skb->data;
259+
msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN;
260+
msg.cmd = req_userhdr->cmd;
261+
msg.dst_sk = info->dst_sk;
262+
263+
if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) {
264+
msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN);
265+
err = -EACCES;
266+
goto send;
267+
}
268+
269+
len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
270+
if (TLV_GET_LEN(msg.req) && !TLV_OK(msg.req, len)) {
271+
msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
272+
err = -EOPNOTSUPP;
273+
goto send;
274+
}
275+
276+
err = tipc_nl_compat_handle(&msg);
277+
if (err == -EOPNOTSUPP)
278+
msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
279+
else if (err == -EINVAL)
280+
msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR);
281+
send:
282+
if (!msg.rep)
283+
return err;
284+
285+
len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
286+
skb_push(msg.rep, len);
287+
rep_nlh = nlmsg_hdr(msg.rep);
288+
memcpy(rep_nlh, info->nlhdr, len);
289+
rep_nlh->nlmsg_len = msg.rep->len;
290+
genlmsg_unicast(net, msg.rep, NETLINK_CB(skb).portid);
291+
292+
return err;
293+
}
294+
39295
static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
40296
{
41297
struct net *net = genl_info_net(info);
@@ -69,6 +325,22 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
69325
return 0;
70326
}
71327

328+
/* Temporary function to keep functionality throughout the patchset
329+
* without having to mess with the global variables and other trickery
330+
* of the old API.
331+
*/
332+
static int tipc_nl_compat_tmp_wrap(struct sk_buff *skb, struct genl_info *info)
333+
{
334+
struct tipc_genlmsghdr *req = info->userhdr;
335+
336+
switch (req->cmd) {
337+
case TIPC_CMD_GET_BEARER_NAMES:
338+
return tipc_nl_compat_recv(skb, info);
339+
}
340+
341+
return handle_cmd(skb, info);
342+
}
343+
72344
static struct genl_family tipc_genl_compat_family = {
73345
.id = GENL_ID_GENERATE,
74346
.name = TIPC_GENL_NAME,
@@ -81,7 +353,7 @@ static struct genl_family tipc_genl_compat_family = {
81353
static struct genl_ops tipc_genl_compat_ops[] = {
82354
{
83355
.cmd = TIPC_GENL_CMD,
84-
.doit = handle_cmd,
356+
.doit = tipc_nl_compat_tmp_wrap,
85357
},
86358
};
87359

0 commit comments

Comments
 (0)