@@ -149,6 +149,21 @@ struct xfrm_pol_inexact_candidates {
149
149
struct hlist_head * res [XFRM_POL_CAND_MAX ];
150
150
};
151
151
152
+ struct xfrm_flow_keys {
153
+ struct flow_dissector_key_basic basic ;
154
+ struct flow_dissector_key_control control ;
155
+ union {
156
+ struct flow_dissector_key_ipv4_addrs ipv4 ;
157
+ struct flow_dissector_key_ipv6_addrs ipv6 ;
158
+ } addrs ;
159
+ struct flow_dissector_key_ip ip ;
160
+ struct flow_dissector_key_icmp icmp ;
161
+ struct flow_dissector_key_ports ports ;
162
+ struct flow_dissector_key_keyid gre ;
163
+ };
164
+
165
+ static struct flow_dissector xfrm_session_dissector __ro_after_init ;
166
+
152
167
static DEFINE_SPINLOCK (xfrm_if_cb_lock );
153
168
static struct xfrm_if_cb const __rcu * xfrm_if_cb __read_mostly ;
154
169
@@ -3367,191 +3382,74 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
3367
3382
}
3368
3383
3369
3384
static void
3370
- decode_session4 (struct sk_buff * skb , struct flowi * fl , bool reverse )
3385
+ decode_session4 (const struct xfrm_flow_keys * flkeys , struct flowi * fl , bool reverse )
3371
3386
{
3372
- const struct iphdr * iph = ip_hdr (skb );
3373
- int ihl = iph -> ihl ;
3374
- u8 * xprth = skb_network_header (skb ) + ihl * 4 ;
3375
3387
struct flowi4 * fl4 = & fl -> u .ip4 ;
3376
3388
3377
3389
memset (fl4 , 0 , sizeof (struct flowi4 ));
3378
3390
3379
- fl4 -> flowi4_proto = iph -> protocol ;
3380
- fl4 -> daddr = reverse ? iph -> saddr : iph -> daddr ;
3381
- fl4 -> saddr = reverse ? iph -> daddr : iph -> saddr ;
3382
- fl4 -> flowi4_tos = iph -> tos & ~INET_ECN_MASK ;
3383
-
3384
- if (!ip_is_fragment (iph )) {
3385
- switch (iph -> protocol ) {
3386
- case IPPROTO_UDP :
3387
- case IPPROTO_UDPLITE :
3388
- case IPPROTO_TCP :
3389
- case IPPROTO_SCTP :
3390
- case IPPROTO_DCCP :
3391
- if (xprth + 4 < skb -> data ||
3392
- pskb_may_pull (skb , xprth + 4 - skb -> data )) {
3393
- __be16 * ports ;
3394
-
3395
- xprth = skb_network_header (skb ) + ihl * 4 ;
3396
- ports = (__be16 * )xprth ;
3397
-
3398
- fl4 -> fl4_sport = ports [!!reverse ];
3399
- fl4 -> fl4_dport = ports [!reverse ];
3400
- }
3401
- break ;
3402
- case IPPROTO_ICMP :
3403
- if (xprth + 2 < skb -> data ||
3404
- pskb_may_pull (skb , xprth + 2 - skb -> data )) {
3405
- u8 * icmp ;
3406
-
3407
- xprth = skb_network_header (skb ) + ihl * 4 ;
3408
- icmp = xprth ;
3409
-
3410
- fl4 -> fl4_icmp_type = icmp [0 ];
3411
- fl4 -> fl4_icmp_code = icmp [1 ];
3412
- }
3413
- break ;
3414
- case IPPROTO_GRE :
3415
- if (xprth + 12 < skb -> data ||
3416
- pskb_may_pull (skb , xprth + 12 - skb -> data )) {
3417
- __be16 * greflags ;
3418
- __be32 * gre_hdr ;
3419
-
3420
- xprth = skb_network_header (skb ) + ihl * 4 ;
3421
- greflags = (__be16 * )xprth ;
3422
- gre_hdr = (__be32 * )xprth ;
3423
-
3424
- if (greflags [0 ] & GRE_KEY ) {
3425
- if (greflags [0 ] & GRE_CSUM )
3426
- gre_hdr ++ ;
3427
- fl4 -> fl4_gre_key = gre_hdr [1 ];
3428
- }
3429
- }
3430
- break ;
3431
- default :
3432
- break ;
3433
- }
3391
+ if (reverse ) {
3392
+ fl4 -> saddr = flkeys -> addrs .ipv4 .dst ;
3393
+ fl4 -> daddr = flkeys -> addrs .ipv4 .src ;
3394
+ fl4 -> fl4_sport = flkeys -> ports .dst ;
3395
+ fl4 -> fl4_dport = flkeys -> ports .src ;
3396
+ } else {
3397
+ fl4 -> saddr = flkeys -> addrs .ipv4 .src ;
3398
+ fl4 -> daddr = flkeys -> addrs .ipv4 .dst ;
3399
+ fl4 -> fl4_sport = flkeys -> ports .src ;
3400
+ fl4 -> fl4_dport = flkeys -> ports .dst ;
3434
3401
}
3402
+
3403
+ fl4 -> flowi4_proto = flkeys -> basic .ip_proto ;
3404
+ fl4 -> flowi4_tos = flkeys -> ip .tos ;
3405
+ fl4 -> fl4_icmp_type = flkeys -> icmp .type ;
3406
+ fl4 -> fl4_icmp_type = flkeys -> icmp .code ;
3407
+ fl4 -> fl4_gre_key = flkeys -> gre .keyid ;
3435
3408
}
3436
3409
3437
3410
#if IS_ENABLED (CONFIG_IPV6 )
3438
3411
static void
3439
- decode_session6 (struct sk_buff * skb , struct flowi * fl , bool reverse )
3412
+ decode_session6 (const struct xfrm_flow_keys * flkeys , struct flowi * fl , bool reverse )
3440
3413
{
3441
3414
struct flowi6 * fl6 = & fl -> u .ip6 ;
3442
- int onlyproto = 0 ;
3443
- const struct ipv6hdr * hdr = ipv6_hdr (skb );
3444
- u32 offset = sizeof (* hdr );
3445
- struct ipv6_opt_hdr * exthdr ;
3446
- const unsigned char * nh = skb_network_header (skb );
3447
- u16 nhoff = IP6CB (skb )-> nhoff ;
3448
- u8 nexthdr ;
3449
-
3450
- if (!nhoff )
3451
- nhoff = offsetof(struct ipv6hdr , nexthdr );
3452
-
3453
- nexthdr = nh [nhoff ];
3454
3415
3455
3416
memset (fl6 , 0 , sizeof (struct flowi6 ));
3456
3417
3457
- fl6 -> daddr = reverse ? hdr -> saddr : hdr -> daddr ;
3458
- fl6 -> saddr = reverse ? hdr -> daddr : hdr -> saddr ;
3459
-
3460
- while (nh + offset + sizeof (* exthdr ) < skb -> data ||
3461
- pskb_may_pull (skb , nh + offset + sizeof (* exthdr ) - skb -> data )) {
3462
- nh = skb_network_header (skb );
3463
- exthdr = (struct ipv6_opt_hdr * )(nh + offset );
3464
-
3465
- switch (nexthdr ) {
3466
- case NEXTHDR_FRAGMENT :
3467
- onlyproto = 1 ;
3468
- fallthrough ;
3469
- case NEXTHDR_ROUTING :
3470
- case NEXTHDR_HOP :
3471
- case NEXTHDR_DEST :
3472
- offset += ipv6_optlen (exthdr );
3473
- nexthdr = exthdr -> nexthdr ;
3474
- break ;
3475
- case IPPROTO_UDP :
3476
- case IPPROTO_UDPLITE :
3477
- case IPPROTO_TCP :
3478
- case IPPROTO_SCTP :
3479
- case IPPROTO_DCCP :
3480
- if (!onlyproto && (nh + offset + 4 < skb -> data ||
3481
- pskb_may_pull (skb , nh + offset + 4 - skb -> data ))) {
3482
- __be16 * ports ;
3483
-
3484
- nh = skb_network_header (skb );
3485
- ports = (__be16 * )(nh + offset );
3486
- fl6 -> fl6_sport = ports [!!reverse ];
3487
- fl6 -> fl6_dport = ports [!reverse ];
3488
- }
3489
- fl6 -> flowi6_proto = nexthdr ;
3490
- return ;
3491
- case IPPROTO_ICMPV6 :
3492
- if (!onlyproto && (nh + offset + 2 < skb -> data ||
3493
- pskb_may_pull (skb , nh + offset + 2 - skb -> data ))) {
3494
- u8 * icmp ;
3495
-
3496
- nh = skb_network_header (skb );
3497
- icmp = (u8 * )(nh + offset );
3498
- fl6 -> fl6_icmp_type = icmp [0 ];
3499
- fl6 -> fl6_icmp_code = icmp [1 ];
3500
- }
3501
- fl6 -> flowi6_proto = nexthdr ;
3502
- return ;
3503
- case IPPROTO_GRE :
3504
- if (!onlyproto &&
3505
- (nh + offset + 12 < skb -> data ||
3506
- pskb_may_pull (skb , nh + offset + 12 - skb -> data ))) {
3507
- struct gre_base_hdr * gre_hdr ;
3508
- __be32 * gre_key ;
3509
-
3510
- nh = skb_network_header (skb );
3511
- gre_hdr = (struct gre_base_hdr * )(nh + offset );
3512
- gre_key = (__be32 * )(gre_hdr + 1 );
3513
-
3514
- if (gre_hdr -> flags & GRE_KEY ) {
3515
- if (gre_hdr -> flags & GRE_CSUM )
3516
- gre_key ++ ;
3517
- fl6 -> fl6_gre_key = * gre_key ;
3518
- }
3519
- }
3520
- fl6 -> flowi6_proto = nexthdr ;
3521
- return ;
3522
-
3523
- #if IS_ENABLED (CONFIG_IPV6_MIP6 )
3524
- case IPPROTO_MH :
3525
- offset += ipv6_optlen (exthdr );
3526
- if (!onlyproto && (nh + offset + 3 < skb -> data ||
3527
- pskb_may_pull (skb , nh + offset + 3 - skb -> data ))) {
3528
- struct ip6_mh * mh ;
3529
-
3530
- nh = skb_network_header (skb );
3531
- mh = (struct ip6_mh * )(nh + offset );
3532
- fl6 -> fl6_mh_type = mh -> ip6mh_type ;
3533
- }
3534
- fl6 -> flowi6_proto = nexthdr ;
3535
- return ;
3536
- #endif
3537
- default :
3538
- fl6 -> flowi6_proto = nexthdr ;
3539
- return ;
3540
- }
3418
+ if (reverse ) {
3419
+ fl6 -> saddr = flkeys -> addrs .ipv6 .dst ;
3420
+ fl6 -> daddr = flkeys -> addrs .ipv6 .src ;
3421
+ fl6 -> fl6_sport = flkeys -> ports .dst ;
3422
+ fl6 -> fl6_dport = flkeys -> ports .src ;
3423
+ } else {
3424
+ fl6 -> saddr = flkeys -> addrs .ipv6 .src ;
3425
+ fl6 -> daddr = flkeys -> addrs .ipv6 .dst ;
3426
+ fl6 -> fl6_sport = flkeys -> ports .src ;
3427
+ fl6 -> fl6_dport = flkeys -> ports .dst ;
3541
3428
}
3429
+
3430
+ fl6 -> flowi6_proto = flkeys -> basic .ip_proto ;
3431
+ fl6 -> fl6_icmp_type = flkeys -> icmp .type ;
3432
+ fl6 -> fl6_icmp_type = flkeys -> icmp .code ;
3433
+ fl6 -> fl6_gre_key = flkeys -> gre .keyid ;
3542
3434
}
3543
3435
#endif
3544
3436
3545
3437
int __xfrm_decode_session (struct net * net , struct sk_buff * skb , struct flowi * fl ,
3546
3438
unsigned int family , int reverse )
3547
3439
{
3440
+ struct xfrm_flow_keys flkeys ;
3441
+
3442
+ memset (& flkeys , 0 , sizeof (flkeys ));
3443
+ __skb_flow_dissect (net , skb , & xfrm_session_dissector , & flkeys ,
3444
+ NULL , 0 , 0 , 0 , FLOW_DISSECTOR_F_STOP_AT_ENCAP );
3445
+
3548
3446
switch (family ) {
3549
3447
case AF_INET :
3550
- decode_session4 (skb , fl , reverse );
3448
+ decode_session4 (& flkeys , fl , reverse );
3551
3449
break ;
3552
3450
#if IS_ENABLED (CONFIG_IPV6 )
3553
3451
case AF_INET6 :
3554
- decode_session6 (skb , fl , reverse );
3452
+ decode_session6 (& flkeys , fl , reverse );
3555
3453
break ;
3556
3454
#endif
3557
3455
default :
@@ -4253,8 +4151,47 @@ static struct pernet_operations __net_initdata xfrm_net_ops = {
4253
4151
.exit = xfrm_net_exit ,
4254
4152
};
4255
4153
4154
+ static const struct flow_dissector_key xfrm_flow_dissector_keys [] = {
4155
+ {
4156
+ .key_id = FLOW_DISSECTOR_KEY_CONTROL ,
4157
+ .offset = offsetof(struct xfrm_flow_keys , control ),
4158
+ },
4159
+ {
4160
+ .key_id = FLOW_DISSECTOR_KEY_BASIC ,
4161
+ .offset = offsetof(struct xfrm_flow_keys , basic ),
4162
+ },
4163
+ {
4164
+ .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS ,
4165
+ .offset = offsetof(struct xfrm_flow_keys , addrs .ipv4 ),
4166
+ },
4167
+ {
4168
+ .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS ,
4169
+ .offset = offsetof(struct xfrm_flow_keys , addrs .ipv6 ),
4170
+ },
4171
+ {
4172
+ .key_id = FLOW_DISSECTOR_KEY_PORTS ,
4173
+ .offset = offsetof(struct xfrm_flow_keys , ports ),
4174
+ },
4175
+ {
4176
+ .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID ,
4177
+ .offset = offsetof(struct xfrm_flow_keys , gre ),
4178
+ },
4179
+ {
4180
+ .key_id = FLOW_DISSECTOR_KEY_IP ,
4181
+ .offset = offsetof(struct xfrm_flow_keys , ip ),
4182
+ },
4183
+ {
4184
+ .key_id = FLOW_DISSECTOR_KEY_ICMP ,
4185
+ .offset = offsetof(struct xfrm_flow_keys , icmp ),
4186
+ },
4187
+ };
4188
+
4256
4189
void __init xfrm_init (void )
4257
4190
{
4191
+ skb_flow_dissector_init (& xfrm_session_dissector ,
4192
+ xfrm_flow_dissector_keys ,
4193
+ ARRAY_SIZE (xfrm_flow_dissector_keys ));
4194
+
4258
4195
register_pernet_subsys (& xfrm_net_ops );
4259
4196
xfrm_dev_init ();
4260
4197
xfrm_input_init ();
0 commit comments