2222#include <net/pkt_sched.h>
2323#include <linux/tc_act/tc_pedit.h>
2424#include <net/tc_act/tc_pedit.h>
25+ #include <uapi/linux/tc_act/tc_pedit.h>
2526
2627#define PEDIT_TAB_MASK 15
2728
@@ -30,18 +31,112 @@ static struct tc_action_ops act_pedit_ops;
3031
3132static const struct nla_policy pedit_policy [TCA_PEDIT_MAX + 1 ] = {
3233 [TCA_PEDIT_PARMS ] = { .len = sizeof (struct tc_pedit ) },
34+ [TCA_PEDIT_KEYS_EX ] = { .type = NLA_NESTED },
3335};
3436
37+ static const struct nla_policy pedit_key_ex_policy [TCA_PEDIT_KEY_EX_MAX + 1 ] = {
38+ [TCA_PEDIT_KEY_EX_HTYPE ] = { .type = NLA_U16 },
39+ };
40+
41+ static struct tcf_pedit_key_ex * tcf_pedit_keys_ex_parse (struct nlattr * nla ,
42+ u8 n )
43+ {
44+ struct tcf_pedit_key_ex * keys_ex ;
45+ struct tcf_pedit_key_ex * k ;
46+ const struct nlattr * ka ;
47+ int err = - EINVAL ;
48+ int rem ;
49+
50+ if (!nla || !n )
51+ return NULL ;
52+
53+ keys_ex = kcalloc (n , sizeof (* k ), GFP_KERNEL );
54+ if (!keys_ex )
55+ return ERR_PTR (- ENOMEM );
56+
57+ k = keys_ex ;
58+
59+ nla_for_each_nested (ka , nla , rem ) {
60+ struct nlattr * tb [TCA_PEDIT_KEY_EX_MAX + 1 ];
61+
62+ if (!n ) {
63+ err = - EINVAL ;
64+ goto err_out ;
65+ }
66+ n -- ;
67+
68+ if (nla_type (ka ) != TCA_PEDIT_KEY_EX ) {
69+ err = - EINVAL ;
70+ goto err_out ;
71+ }
72+
73+ err = nla_parse_nested (tb , TCA_PEDIT_KEY_EX_MAX , ka ,
74+ pedit_key_ex_policy );
75+ if (err )
76+ goto err_out ;
77+
78+ if (!tb [TCA_PEDIT_KEY_EX_HTYPE ]) {
79+ err = - EINVAL ;
80+ goto err_out ;
81+ }
82+
83+ k -> htype = nla_get_u16 (tb [TCA_PEDIT_KEY_EX_HTYPE ]);
84+
85+ if (k -> htype > TCA_PEDIT_HDR_TYPE_MAX ) {
86+ err = - EINVAL ;
87+ goto err_out ;
88+ }
89+
90+ k ++ ;
91+ }
92+
93+ if (n )
94+ goto err_out ;
95+
96+ return keys_ex ;
97+
98+ err_out :
99+ kfree (keys_ex );
100+ return ERR_PTR (err );
101+ }
102+
103+ static int tcf_pedit_key_ex_dump (struct sk_buff * skb ,
104+ struct tcf_pedit_key_ex * keys_ex , int n )
105+ {
106+ struct nlattr * keys_start = nla_nest_start (skb , TCA_PEDIT_KEYS_EX );
107+
108+ for (; n > 0 ; n -- ) {
109+ struct nlattr * key_start ;
110+
111+ key_start = nla_nest_start (skb , TCA_PEDIT_KEY_EX );
112+
113+ if (nla_put_u16 (skb , TCA_PEDIT_KEY_EX_HTYPE , keys_ex -> htype )) {
114+ nlmsg_trim (skb , keys_start );
115+ return - EINVAL ;
116+ }
117+
118+ nla_nest_end (skb , key_start );
119+
120+ keys_ex ++ ;
121+ }
122+
123+ nla_nest_end (skb , keys_start );
124+
125+ return 0 ;
126+ }
127+
35128static int tcf_pedit_init (struct net * net , struct nlattr * nla ,
36129 struct nlattr * est , struct tc_action * * a ,
37130 int ovr , int bind )
38131{
39132 struct tc_action_net * tn = net_generic (net , pedit_net_id );
40133 struct nlattr * tb [TCA_PEDIT_MAX + 1 ];
134+ struct nlattr * pattr ;
41135 struct tc_pedit * parm ;
42136 int ret = 0 , err ;
43137 struct tcf_pedit * p ;
44138 struct tc_pedit_key * keys = NULL ;
139+ struct tcf_pedit_key_ex * keys_ex ;
45140 int ksize ;
46141
47142 if (nla == NULL )
@@ -51,13 +146,21 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
51146 if (err < 0 )
52147 return err ;
53148
54- if (tb [TCA_PEDIT_PARMS ] == NULL )
149+ pattr = tb [TCA_PEDIT_PARMS ];
150+ if (!pattr )
151+ pattr = tb [TCA_PEDIT_PARMS_EX ];
152+ if (!pattr )
55153 return - EINVAL ;
56- parm = nla_data (tb [TCA_PEDIT_PARMS ]);
154+
155+ parm = nla_data (pattr );
57156 ksize = parm -> nkeys * sizeof (struct tc_pedit_key );
58- if (nla_len (tb [ TCA_PEDIT_PARMS ] ) < sizeof (* parm ) + ksize )
157+ if (nla_len (pattr ) < sizeof (* parm ) + ksize )
59158 return - EINVAL ;
60159
160+ keys_ex = tcf_pedit_keys_ex_parse (tb [TCA_PEDIT_KEYS_EX ], parm -> nkeys );
161+ if (IS_ERR (keys_ex ))
162+ return PTR_ERR (keys_ex );
163+
61164 if (!tcf_hash_check (tn , parm -> index , a , bind )) {
62165 if (!parm -> nkeys )
63166 return - EINVAL ;
@@ -69,6 +172,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
69172 keys = kmalloc (ksize , GFP_KERNEL );
70173 if (keys == NULL ) {
71174 tcf_hash_cleanup (* a , est );
175+ kfree (keys_ex );
72176 return - ENOMEM ;
73177 }
74178 ret = ACT_P_CREATED ;
@@ -81,8 +185,10 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
81185 p = to_pedit (* a );
82186 if (p -> tcfp_nkeys && p -> tcfp_nkeys != parm -> nkeys ) {
83187 keys = kmalloc (ksize , GFP_KERNEL );
84- if (keys == NULL )
188+ if (!keys ) {
189+ kfree (keys_ex );
85190 return - ENOMEM ;
191+ }
86192 }
87193 }
88194
@@ -95,6 +201,10 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
95201 p -> tcfp_nkeys = parm -> nkeys ;
96202 }
97203 memcpy (p -> tcfp_keys , parm -> keys , ksize );
204+
205+ kfree (p -> tcfp_keys_ex );
206+ p -> tcfp_keys_ex = keys_ex ;
207+
98208 spin_unlock_bh (& p -> tcf_lock );
99209 if (ret == ACT_P_CREATED )
100210 tcf_hash_insert (tn , * a );
@@ -106,6 +216,7 @@ static void tcf_pedit_cleanup(struct tc_action *a, int bind)
106216 struct tcf_pedit * p = to_pedit (a );
107217 struct tc_pedit_key * keys = p -> tcfp_keys ;
108218 kfree (keys );
219+ kfree (p -> tcfp_keys_ex );
109220}
110221
111222static bool offset_valid (struct sk_buff * skb , int offset )
@@ -119,38 +230,84 @@ static bool offset_valid(struct sk_buff *skb, int offset)
119230 return true;
120231}
121232
233+ static int pedit_skb_hdr_offset (struct sk_buff * skb ,
234+ enum pedit_header_type htype , int * hoffset )
235+ {
236+ int ret = - EINVAL ;
237+
238+ switch (htype ) {
239+ case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH :
240+ if (skb_mac_header_was_set (skb )) {
241+ * hoffset = skb_mac_offset (skb );
242+ ret = 0 ;
243+ }
244+ break ;
245+ case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK :
246+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 :
247+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 :
248+ * hoffset = skb_network_offset (skb );
249+ ret = 0 ;
250+ break ;
251+ case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP :
252+ case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP :
253+ if (skb_transport_header_was_set (skb )) {
254+ * hoffset = skb_transport_offset (skb );
255+ ret = 0 ;
256+ }
257+ break ;
258+ default :
259+ ret = - EINVAL ;
260+ break ;
261+ };
262+
263+ return ret ;
264+ }
265+
122266static int tcf_pedit (struct sk_buff * skb , const struct tc_action * a ,
123267 struct tcf_result * res )
124268{
125269 struct tcf_pedit * p = to_pedit (a );
126270 int i ;
127- unsigned int off ;
128271
129272 if (skb_unclone (skb , GFP_ATOMIC ))
130273 return p -> tcf_action ;
131274
132- off = skb_network_offset (skb );
133-
134275 spin_lock (& p -> tcf_lock );
135276
136277 tcf_lastuse_update (& p -> tcf_tm );
137278
138279 if (p -> tcfp_nkeys > 0 ) {
139280 struct tc_pedit_key * tkey = p -> tcfp_keys ;
281+ struct tcf_pedit_key_ex * tkey_ex = p -> tcfp_keys_ex ;
282+ enum pedit_header_type htype = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK ;
140283
141284 for (i = p -> tcfp_nkeys ; i > 0 ; i -- , tkey ++ ) {
142285 u32 * ptr , _data ;
143286 int offset = tkey -> off ;
287+ int hoffset ;
288+ int rc ;
289+
290+ if (tkey_ex ) {
291+ htype = tkey_ex -> htype ;
292+ tkey_ex ++ ;
293+ }
294+
295+ rc = pedit_skb_hdr_offset (skb , htype , & hoffset );
296+ if (rc ) {
297+ pr_info ("tc filter pedit bad header type specified (0x%x)\n" ,
298+ htype );
299+ goto bad ;
300+ }
144301
145302 if (tkey -> offmask ) {
146303 char * d , _d ;
147304
148- if (!offset_valid (skb , off + tkey -> at )) {
305+ if (!offset_valid (skb , hoffset + tkey -> at )) {
149306 pr_info ("tc filter pedit 'at' offset %d out of bounds\n" ,
150- off + tkey -> at );
307+ hoffset + tkey -> at );
151308 goto bad ;
152309 }
153- d = skb_header_pointer (skb , off + tkey -> at , 1 ,
310+ d = skb_header_pointer (skb , hoffset + tkey -> at , 1 ,
154311 & _d );
155312 if (!d )
156313 goto bad ;
@@ -163,19 +320,19 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
163320 goto bad ;
164321 }
165322
166- if (!offset_valid (skb , off + offset )) {
323+ if (!offset_valid (skb , hoffset + offset )) {
167324 pr_info ("tc filter pedit offset %d out of bounds\n" ,
168- offset );
325+ hoffset + offset );
169326 goto bad ;
170327 }
171328
172- ptr = skb_header_pointer (skb , off + offset , 4 , & _data );
329+ ptr = skb_header_pointer (skb , hoffset + offset , 4 , & _data );
173330 if (!ptr )
174331 goto bad ;
175332 /* just do it, baby */
176333 * ptr = ((* ptr & tkey -> mask ) ^ tkey -> val );
177334 if (ptr == & _data )
178- skb_store_bits (skb , off + offset , ptr , 4 );
335+ skb_store_bits (skb , hoffset + offset , ptr , 4 );
179336 }
180337
181338 goto done ;
@@ -215,8 +372,15 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
215372 opt -> refcnt = p -> tcf_refcnt - ref ;
216373 opt -> bindcnt = p -> tcf_bindcnt - bind ;
217374
218- if (nla_put (skb , TCA_PEDIT_PARMS , s , opt ))
219- goto nla_put_failure ;
375+ if (p -> tcfp_keys_ex ) {
376+ tcf_pedit_key_ex_dump (skb , p -> tcfp_keys_ex , p -> tcfp_nkeys );
377+
378+ if (nla_put (skb , TCA_PEDIT_PARMS_EX , s , opt ))
379+ goto nla_put_failure ;
380+ } else {
381+ if (nla_put (skb , TCA_PEDIT_PARMS , s , opt ))
382+ goto nla_put_failure ;
383+ }
220384
221385 tcf_tm_dump (& t , & p -> tcf_tm );
222386 if (nla_put_64bit (skb , TCA_PEDIT_TM , sizeof (t ), & t , TCA_PEDIT_PAD ))
0 commit comments