5555
5656#include <linux/uaccess.h>
5757
58- /*
59- * Parsing tlv encoded headers.
60- *
61- * Parsing function "func" returns true, if parsing succeed
62- * and false, if it failed.
63- * It MUST NOT touch skb->h.
64- */
65-
66- struct tlvtype_proc {
67- int type ;
68- bool (* func )(struct sk_buff * skb , int offset );
69- };
70-
7158/*********************
7259 Generic functions
7360 *********************/
@@ -112,16 +99,23 @@ static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff,
11299 return false;
113100}
114101
102+ static bool ipv6_hop_ra (struct sk_buff * skb , int optoff );
103+ static bool ipv6_hop_ioam (struct sk_buff * skb , int optoff );
104+ static bool ipv6_hop_jumbo (struct sk_buff * skb , int optoff );
105+ static bool ipv6_hop_calipso (struct sk_buff * skb , int optoff );
106+ #if IS_ENABLED (CONFIG_IPV6_MIP6 )
107+ static bool ipv6_dest_hao (struct sk_buff * skb , int optoff );
108+ #endif
109+
115110/* Parse tlv encoded option header (hop-by-hop or destination) */
116111
117- static bool ip6_parse_tlv (const struct tlvtype_proc * procs ,
112+ static bool ip6_parse_tlv (bool hopbyhop ,
118113 struct sk_buff * skb ,
119114 int max_count )
120115{
121116 int len = (skb_transport_header (skb )[1 ] + 1 ) << 3 ;
122117 const unsigned char * nh = skb_network_header (skb );
123118 int off = skb_network_header_len (skb );
124- const struct tlvtype_proc * curr ;
125119 bool disallow_unknowns = false;
126120 int tlv_count = 0 ;
127121 int padlen = 0 ;
@@ -176,20 +170,45 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
176170 if (tlv_count > max_count )
177171 goto bad ;
178172
179- for (curr = procs ; curr -> type >= 0 ; curr ++ ) {
180- if (curr -> type == nh [off ]) {
181- /* type specific length/alignment
182- checks will be performed in the
183- func(). */
184- if (curr -> func (skb , off ) == false)
173+ if (hopbyhop ) {
174+ switch (nh [off ]) {
175+ case IPV6_TLV_ROUTERALERT :
176+ if (!ipv6_hop_ra (skb , off ))
177+ return false;
178+ break ;
179+ case IPV6_TLV_IOAM :
180+ if (!ipv6_hop_ioam (skb , off ))
181+ return false;
182+ break ;
183+ case IPV6_TLV_JUMBO :
184+ if (!ipv6_hop_jumbo (skb , off ))
185+ return false;
186+ break ;
187+ case IPV6_TLV_CALIPSO :
188+ if (!ipv6_hop_calipso (skb , off ))
189+ return false;
190+ break ;
191+ default :
192+ if (!ip6_tlvopt_unknown (skb , off ,
193+ disallow_unknowns ))
194+ return false;
195+ break ;
196+ }
197+ } else {
198+ switch (nh [off ]) {
199+ #if IS_ENABLED (CONFIG_IPV6_MIP6 )
200+ case IPV6_TLV_HAO :
201+ if (!ipv6_dest_hao (skb , off ))
202+ return false;
203+ break ;
204+ #endif
205+ default :
206+ if (!ip6_tlvopt_unknown (skb , off ,
207+ disallow_unknowns ))
185208 return false;
186209 break ;
187210 }
188211 }
189- if (curr -> type < 0 &&
190- !ip6_tlvopt_unknown (skb , off , disallow_unknowns ))
191- return false;
192-
193212 padlen = 0 ;
194213 }
195214 off += optlen ;
@@ -267,16 +286,6 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
267286}
268287#endif
269288
270- static const struct tlvtype_proc tlvprocdestopt_lst [] = {
271- #if IS_ENABLED (CONFIG_IPV6_MIP6 )
272- {
273- .type = IPV6_TLV_HAO ,
274- .func = ipv6_dest_hao ,
275- },
276- #endif
277- {-1 , NULL }
278- };
279-
280289static int ipv6_destopt_rcv (struct sk_buff * skb )
281290{
282291 struct inet6_dev * idev = __in6_dev_get (skb -> dev );
@@ -307,8 +316,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
307316 dstbuf = opt -> dst1 ;
308317#endif
309318
310- if (ip6_parse_tlv (tlvprocdestopt_lst , skb ,
311- net -> ipv6 .sysctl .max_dst_opts_cnt )) {
319+ if (ip6_parse_tlv (false, skb , net -> ipv6 .sysctl .max_dst_opts_cnt )) {
312320 skb -> transport_header += extlen ;
313321 opt = IP6CB (skb );
314322#if IS_ENABLED (CONFIG_IPV6_MIP6 )
@@ -1051,26 +1059,6 @@ static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
10511059 return false;
10521060}
10531061
1054- static const struct tlvtype_proc tlvprochopopt_lst [] = {
1055- {
1056- .type = IPV6_TLV_ROUTERALERT ,
1057- .func = ipv6_hop_ra ,
1058- },
1059- {
1060- .type = IPV6_TLV_IOAM ,
1061- .func = ipv6_hop_ioam ,
1062- },
1063- {
1064- .type = IPV6_TLV_JUMBO ,
1065- .func = ipv6_hop_jumbo ,
1066- },
1067- {
1068- .type = IPV6_TLV_CALIPSO ,
1069- .func = ipv6_hop_calipso ,
1070- },
1071- { -1 , }
1072- };
1073-
10741062int ipv6_parse_hopopts (struct sk_buff * skb )
10751063{
10761064 struct inet6_skb_parm * opt = IP6CB (skb );
@@ -1096,8 +1084,7 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
10961084 goto fail_and_free ;
10971085
10981086 opt -> flags |= IP6SKB_HOPBYHOP ;
1099- if (ip6_parse_tlv (tlvprochopopt_lst , skb ,
1100- net -> ipv6 .sysctl .max_hbh_opts_cnt )) {
1087+ if (ip6_parse_tlv (true, skb , net -> ipv6 .sysctl .max_hbh_opts_cnt )) {
11011088 skb -> transport_header += extlen ;
11021089 opt = IP6CB (skb );
11031090 opt -> nhoff = sizeof (struct ipv6hdr );
0 commit comments