1919#include <linux/kernel.h>
2020#include <linux/string.h>
2121#include <linux/errno.h>
22+ #include <linux/err.h>
2223#include <linux/skbuff.h>
2324#include <linux/init.h>
2425#include <linux/kmod.h>
@@ -38,14 +39,14 @@ static DEFINE_RWLOCK(cls_mod_lock);
3839
3940/* Find classifier type by string name */
4041
41- static const struct tcf_proto_ops * tcf_proto_lookup_ops (struct nlattr * kind )
42+ static const struct tcf_proto_ops * tcf_proto_lookup_ops (const char * kind )
4243{
4344 const struct tcf_proto_ops * t , * res = NULL ;
4445
4546 if (kind ) {
4647 read_lock (& cls_mod_lock );
4748 list_for_each_entry (t , & tcf_proto_base , head ) {
48- if (nla_strcmp (kind , t -> kind ) == 0 ) {
49+ if (strcmp (kind , t -> kind ) == 0 ) {
4950 if (try_module_get (t -> owner ))
5051 res = t ;
5152 break ;
@@ -127,6 +128,77 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
127128 return first ;
128129}
129130
131+ static struct tcf_proto * tcf_proto_create (const char * kind , u32 protocol ,
132+ u32 prio , u32 parent , struct Qdisc * q )
133+ {
134+ struct tcf_proto * tp ;
135+ int err ;
136+
137+ tp = kzalloc (sizeof (* tp ), GFP_KERNEL );
138+ if (!tp )
139+ return ERR_PTR (- ENOBUFS );
140+
141+ err = - ENOENT ;
142+ tp -> ops = tcf_proto_lookup_ops (kind );
143+ if (!tp -> ops ) {
144+ #ifdef CONFIG_MODULES
145+ rtnl_unlock ();
146+ request_module ("cls_%s" , kind );
147+ rtnl_lock ();
148+ tp -> ops = tcf_proto_lookup_ops (kind );
149+ /* We dropped the RTNL semaphore in order to perform
150+ * the module load. So, even if we succeeded in loading
151+ * the module we have to replay the request. We indicate
152+ * this using -EAGAIN.
153+ */
154+ if (tp -> ops ) {
155+ module_put (tp -> ops -> owner );
156+ err = - EAGAIN ;
157+ } else {
158+ err = - ENOENT ;
159+ }
160+ goto errout ;
161+ #endif
162+ }
163+ tp -> classify = tp -> ops -> classify ;
164+ tp -> protocol = protocol ;
165+ tp -> prio = prio ;
166+ tp -> classid = parent ;
167+ tp -> q = q ;
168+
169+ err = tp -> ops -> init (tp );
170+ if (err ) {
171+ module_put (tp -> ops -> owner );
172+ goto errout ;
173+ }
174+ return tp ;
175+
176+ errout :
177+ kfree (tp );
178+ return ERR_PTR (err );
179+ }
180+
181+ static bool tcf_proto_destroy (struct tcf_proto * tp , bool force )
182+ {
183+ if (tp -> ops -> destroy (tp , force )) {
184+ module_put (tp -> ops -> owner );
185+ kfree_rcu (tp , rcu );
186+ return true;
187+ }
188+ return false;
189+ }
190+
191+ void tcf_destroy_chain (struct tcf_proto __rcu * * fl )
192+ {
193+ struct tcf_proto * tp ;
194+
195+ while ((tp = rtnl_dereference (* fl )) != NULL ) {
196+ RCU_INIT_POINTER (* fl , tp -> next );
197+ tcf_proto_destroy (tp , true);
198+ }
199+ }
200+ EXPORT_SYMBOL (tcf_destroy_chain );
201+
130202/* Add/change/delete/get a filter node */
131203
132204static int tc_ctl_tfilter (struct sk_buff * skb , struct nlmsghdr * n )
@@ -142,8 +214,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
142214 struct Qdisc * q ;
143215 struct tcf_proto __rcu * * back ;
144216 struct tcf_proto __rcu * * chain ;
217+ struct tcf_proto * next ;
145218 struct tcf_proto * tp ;
146- const struct tcf_proto_ops * tp_ops ;
147219 const struct Qdisc_class_ops * cops ;
148220 unsigned long cl ;
149221 unsigned long fh ;
@@ -222,9 +294,10 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
222294
223295 /* And the last stroke */
224296 chain = cops -> tcf_chain (q , cl );
225- err = - EINVAL ;
226- if ( chain == NULL )
297+ if ( chain == NULL ) {
298+ err = - EINVAL ;
227299 goto errout ;
300+ }
228301 if (n -> nlmsg_type == RTM_DELTFILTER && prio == 0 ) {
229302 tfilter_notify_chain (net , skb , n , chain , RTM_DELTFILTER );
230303 tcf_destroy_chain (chain );
@@ -239,121 +312,83 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
239312 if (tp -> prio >= prio ) {
240313 if (tp -> prio == prio ) {
241314 if (!nprio ||
242- (tp -> protocol != protocol && protocol ))
315+ (tp -> protocol != protocol && protocol )) {
316+ err = - EINVAL ;
243317 goto errout ;
244- } else
318+ }
319+ } else {
245320 tp = NULL ;
321+ }
246322 break ;
247323 }
248324 }
249325
250326 if (tp == NULL ) {
251327 /* Proto-tcf does not exist, create new one */
252328
253- if (tca [TCA_KIND ] == NULL || !protocol )
329+ if (tca [TCA_KIND ] == NULL || !protocol ) {
330+ err = - EINVAL ;
254331 goto errout ;
332+ }
255333
256- err = - ENOENT ;
257334 if (n -> nlmsg_type != RTM_NEWTFILTER ||
258- !(n -> nlmsg_flags & NLM_F_CREATE ))
335+ !(n -> nlmsg_flags & NLM_F_CREATE )) {
336+ err = - ENOENT ;
259337 goto errout ;
338+ }
260339
340+ if (!nprio )
341+ nprio = TC_H_MAJ (tcf_auto_prio (rtnl_dereference (* back )));
261342
262- /* Create new proto tcf */
263-
264- err = - ENOBUFS ;
265- tp = kzalloc (sizeof (* tp ), GFP_KERNEL );
266- if (tp == NULL )
267- goto errout ;
268- err = - ENOENT ;
269- tp_ops = tcf_proto_lookup_ops (tca [TCA_KIND ]);
270- if (tp_ops == NULL ) {
271- #ifdef CONFIG_MODULES
272- struct nlattr * kind = tca [TCA_KIND ];
273- char name [IFNAMSIZ ];
274-
275- if (kind != NULL &&
276- nla_strlcpy (name , kind , IFNAMSIZ ) < IFNAMSIZ ) {
277- rtnl_unlock ();
278- request_module ("cls_%s" , name );
279- rtnl_lock ();
280- tp_ops = tcf_proto_lookup_ops (kind );
281- /* We dropped the RTNL semaphore in order to
282- * perform the module load. So, even if we
283- * succeeded in loading the module we have to
284- * replay the request. We indicate this using
285- * -EAGAIN.
286- */
287- if (tp_ops != NULL ) {
288- module_put (tp_ops -> owner );
289- err = - EAGAIN ;
290- }
291- }
292- #endif
293- kfree (tp );
343+ tp = tcf_proto_create (nla_data (tca [TCA_KIND ]),
344+ protocol , nprio , parent , q );
345+ if (IS_ERR (tp )) {
346+ err = PTR_ERR (tp );
294347 goto errout ;
295348 }
296- tp -> ops = tp_ops ;
297- tp -> protocol = protocol ;
298- tp -> prio = nprio ? :
299- TC_H_MAJ (tcf_auto_prio (rtnl_dereference (* back )));
300- tp -> q = q ;
301- tp -> classify = tp_ops -> classify ;
302- tp -> classid = parent ;
303-
304- err = tp_ops -> init (tp );
305- if (err != 0 ) {
306- module_put (tp_ops -> owner );
307- kfree (tp );
308- goto errout ;
309- }
310-
311349 tp_created = 1 ;
312-
313- } else if ( tca [ TCA_KIND ] && nla_strcmp ( tca [ TCA_KIND ], tp -> ops -> kind ))
350+ } else if ( tca [ TCA_KIND ] && nla_strcmp ( tca [ TCA_KIND ], tp -> ops -> kind )) {
351+ err = - EINVAL ;
314352 goto errout ;
353+ }
315354
316355 fh = tp -> ops -> get (tp , t -> tcm_handle );
317356
318357 if (fh == 0 ) {
319358 if (n -> nlmsg_type == RTM_DELTFILTER && t -> tcm_handle == 0 ) {
320- struct tcf_proto * next = rtnl_dereference (tp -> next );
321-
359+ next = rtnl_dereference (tp -> next );
322360 RCU_INIT_POINTER (* back , next );
323-
324361 tfilter_notify (net , skb , n , tp , fh ,
325362 RTM_DELTFILTER , false);
326- tcf_destroy (tp , true);
363+ tcf_proto_destroy (tp , true);
327364 err = 0 ;
328365 goto errout ;
329366 }
330367
331- err = - ENOENT ;
332368 if (n -> nlmsg_type != RTM_NEWTFILTER ||
333- !(n -> nlmsg_flags & NLM_F_CREATE ))
369+ !(n -> nlmsg_flags & NLM_F_CREATE )) {
370+ err = - ENOENT ;
334371 goto errout ;
372+ }
335373 } else {
336374 switch (n -> nlmsg_type ) {
337375 case RTM_NEWTFILTER :
338- err = - EEXIST ;
339376 if (n -> nlmsg_flags & NLM_F_EXCL ) {
340377 if (tp_created )
341- tcf_destroy (tp , true);
378+ tcf_proto_destroy (tp , true);
379+ err = - EEXIST ;
342380 goto errout ;
343381 }
344382 break ;
345383 case RTM_DELTFILTER :
346384 err = tp -> ops -> delete (tp , fh );
347- if (err == 0 ) {
348- struct tcf_proto * next = rtnl_dereference (tp -> next );
349-
350- tfilter_notify (net , skb , n , tp ,
351- t -> tcm_handle ,
352- RTM_DELTFILTER , false);
353- if (tcf_destroy (tp , false))
354- RCU_INIT_POINTER (* back , next );
355- }
356- goto errout ;
385+ if (err )
386+ goto errout ;
387+ next = rtnl_dereference (tp -> next );
388+ tfilter_notify (net , skb , n , tp , t -> tcm_handle ,
389+ RTM_DELTFILTER , false);
390+ if (tcf_proto_destroy (tp , false))
391+ RCU_INIT_POINTER (* back , next );
357392 case RTM_GETTFILTER :
358393 err = tfilter_notify (net , skb , n , tp , fh ,
359394 RTM_NEWTFILTER , true);
@@ -374,7 +409,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
374409 tfilter_notify (net , skb , n , tp , fh , RTM_NEWTFILTER , false);
375410 } else {
376411 if (tp_created )
377- tcf_destroy (tp , true);
412+ tcf_proto_destroy (tp , true);
378413 }
379414
380415errout :
0 commit comments