33
33
34
34
#include "core.h"
35
35
#include "config.h"
36
+ #include "bearer.h"
36
37
#include <net/genetlink.h>
37
38
#include <linux/tipc_config.h>
38
39
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
+
39
295
static int handle_cmd (struct sk_buff * skb , struct genl_info * info )
40
296
{
41
297
struct net * net = genl_info_net (info );
@@ -69,6 +325,22 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
69
325
return 0 ;
70
326
}
71
327
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
+
72
344
static struct genl_family tipc_genl_compat_family = {
73
345
.id = GENL_ID_GENERATE ,
74
346
.name = TIPC_GENL_NAME ,
@@ -81,7 +353,7 @@ static struct genl_family tipc_genl_compat_family = {
81
353
static struct genl_ops tipc_genl_compat_ops [] = {
82
354
{
83
355
.cmd = TIPC_GENL_CMD ,
84
- .doit = handle_cmd ,
356
+ .doit = tipc_nl_compat_tmp_wrap ,
85
357
},
86
358
};
87
359
0 commit comments