Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1#include <linux/skbuff.h>
  2#include <linux/export.h>
  3#include <linux/ip.h>
  4#include <linux/ipv6.h>
  5#include <linux/if_vlan.h>
  6#include <net/ip.h>
  7#include <linux/if_tunnel.h>
  8#include <linux/if_pppox.h>
  9#include <linux/ppp_defs.h>
 10#include <net/flow_keys.h>
 11
 12/* copy saddr & daddr, possibly using 64bit load/store
 13 * Equivalent to :	flow->src = iph->saddr;
 14 *			flow->dst = iph->daddr;
 15 */
 16static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *iph)
 17{
 18	BUILD_BUG_ON(offsetof(typeof(*flow), dst) !=
 19		     offsetof(typeof(*flow), src) + sizeof(flow->src));
 20	memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst));
 21}
 22
 23bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
 24{
 25	int poff, nhoff = skb_network_offset(skb);
 26	u8 ip_proto;
 27	__be16 proto = skb->protocol;
 28
 29	memset(flow, 0, sizeof(*flow));
 30
 31again:
 32	switch (proto) {
 33	case __constant_htons(ETH_P_IP): {
 34		const struct iphdr *iph;
 35		struct iphdr _iph;
 36ip:
 37		iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
 38		if (!iph)
 39			return false;
 40
 41		if (ip_is_fragment(iph))
 42			ip_proto = 0;
 43		else
 44			ip_proto = iph->protocol;
 45		iph_to_flow_copy_addrs(flow, iph);
 46		nhoff += iph->ihl * 4;
 47		break;
 48	}
 49	case __constant_htons(ETH_P_IPV6): {
 50		const struct ipv6hdr *iph;
 51		struct ipv6hdr _iph;
 52ipv6:
 53		iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
 54		if (!iph)
 55			return false;
 56
 57		ip_proto = iph->nexthdr;
 58		flow->src = iph->saddr.s6_addr32[3];
 59		flow->dst = iph->daddr.s6_addr32[3];
 60		nhoff += sizeof(struct ipv6hdr);
 61		break;
 62	}
 63	case __constant_htons(ETH_P_8021Q): {
 64		const struct vlan_hdr *vlan;
 65		struct vlan_hdr _vlan;
 66
 67		vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
 68		if (!vlan)
 69			return false;
 70
 71		proto = vlan->h_vlan_encapsulated_proto;
 72		nhoff += sizeof(*vlan);
 73		goto again;
 74	}
 75	case __constant_htons(ETH_P_PPP_SES): {
 76		struct {
 77			struct pppoe_hdr hdr;
 78			__be16 proto;
 79		} *hdr, _hdr;
 80		hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
 81		if (!hdr)
 82			return false;
 83		proto = hdr->proto;
 84		nhoff += PPPOE_SES_HLEN;
 85		switch (proto) {
 86		case __constant_htons(PPP_IP):
 87			goto ip;
 88		case __constant_htons(PPP_IPV6):
 89			goto ipv6;
 90		default:
 91			return false;
 92		}
 93	}
 94	default:
 95		return false;
 96	}
 97
 98	switch (ip_proto) {
 99	case IPPROTO_GRE: {
100		struct gre_hdr {
101			__be16 flags;
102			__be16 proto;
103		} *hdr, _hdr;
104
105		hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
106		if (!hdr)
107			return false;
108		/*
109		 * Only look inside GRE if version zero and no
110		 * routing
111		 */
112		if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) {
113			proto = hdr->proto;
114			nhoff += 4;
115			if (hdr->flags & GRE_CSUM)
116				nhoff += 4;
117			if (hdr->flags & GRE_KEY)
118				nhoff += 4;
119			if (hdr->flags & GRE_SEQ)
120				nhoff += 4;
121			goto again;
122		}
123		break;
124	}
125	case IPPROTO_IPIP:
126		goto again;
127	default:
128		break;
129	}
130
131	flow->ip_proto = ip_proto;
132	poff = proto_ports_offset(ip_proto);
133	if (poff >= 0) {
134		__be32 *ports, _ports;
135
136		nhoff += poff;
137		ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
138		if (ports)
139			flow->ports = *ports;
140	}
141
142	return true;
143}
144EXPORT_SYMBOL(skb_flow_dissect);