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+ 
39295static  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+ 
72344static  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 = {
81353static  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