1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _NF_TABLES_IPV6_H_ 3 #define _NF_TABLES_IPV6_H_ 4 5 #include <linux/netfilter_ipv6/ip6_tables.h> 6 #include <net/ipv6.h> 7 8 static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt, 9 struct sk_buff *skb) 10 { 11 unsigned int flags = IP6_FH_F_AUTH; 12 int protohdr, thoff = 0; 13 unsigned short frag_off; 14 15 protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags); 16 if (protohdr < 0) { 17 nft_set_pktinfo_unspec(pkt, skb); 18 return; 19 } 20 21 pkt->tprot_set = true; 22 pkt->tprot = protohdr; 23 pkt->xt.thoff = thoff; 24 pkt->xt.fragoff = frag_off; 25 } 26 27 static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt, 28 struct sk_buff *skb) 29 { 30 #if IS_ENABLED(CONFIG_IPV6) 31 unsigned int flags = IP6_FH_F_AUTH; 32 struct ipv6hdr *ip6h, _ip6h; 33 unsigned int thoff = 0; 34 unsigned short frag_off; 35 int protohdr; 36 u32 pkt_len; 37 38 ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h), 39 &_ip6h); 40 if (!ip6h) 41 return -1; 42 43 if (ip6h->version != 6) 44 return -1; 45 46 pkt_len = ntohs(ip6h->payload_len); 47 if (pkt_len + sizeof(*ip6h) > skb->len) 48 return -1; 49 50 protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags); 51 if (protohdr < 0) 52 return -1; 53 54 pkt->tprot_set = true; 55 pkt->tprot = protohdr; 56 pkt->xt.thoff = thoff; 57 pkt->xt.fragoff = frag_off; 58 59 return 0; 60 #else 61 return -1; 62 #endif 63 } 64 65 static inline void nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt, 66 struct sk_buff *skb) 67 { 68 if (__nft_set_pktinfo_ipv6_validate(pkt, skb) < 0) 69 nft_set_pktinfo_unspec(pkt, skb); 70 } 71 72 #endif 73