struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr, struct device *dev, int nd) { struct inet6_ifaddr * ifp; u8 hash; unsigned flags = 0; if (!nd) flags |= DAD_STATUS|ADDR_INVALID; addrconf_lock(); hash = ipv6_addr_hash(addr); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && !(ifp->flags&flags)) { if (dev == NULL || ifp->idev->dev == dev || !(ifp->scope&(IFA_LINK|IFA_HOST))) break; } } addrconf_unlock(); return ifp; }
static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) { u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); return hash_32(hash, HASH_SIZE_SHIFT); }
static bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) { int nhoff = skb_network_offset(skb); u8 ip_proto; __be16 proto = skb->protocol; memset(flow, 0, sizeof(*flow)); again: switch (proto) { case __constant_htons(ETH_P_IP): { const struct iphdr *iph; struct iphdr _iph; ip: iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); if (!iph) return false; if (ip_is_fragment(iph)) ip_proto = 0; else ip_proto = iph->protocol; iph_to_flow_copy_addrs(flow, iph); nhoff += iph->ihl * 4; break; } case __constant_htons(ETH_P_IPV6): { const struct ipv6hdr *iph; struct ipv6hdr _iph; ipv6: iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); if (!iph) return false; ip_proto = iph->nexthdr; flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); nhoff += sizeof(struct ipv6hdr); break; } case __constant_htons(ETH_P_8021AD): case __constant_htons(ETH_P_8021Q): { const struct vlan_hdr *vlan; struct vlan_hdr _vlan; vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan); if (!vlan) return false; proto = vlan->h_vlan_encapsulated_proto; nhoff += sizeof(*vlan); goto again; } case __constant_htons(ETH_P_PPP_SES): { struct { struct pppoe_hdr hdr; __be16 proto; } *hdr, _hdr; hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr); if (!hdr) return false; proto = hdr->proto; nhoff += PPPOE_SES_HLEN; switch (proto) { case __constant_htons(PPP_IP): goto ip; case __constant_htons(PPP_IPV6): goto ipv6; default: return false; } } default: return false; } switch (ip_proto) { case IPPROTO_GRE: { struct gre_hdr { __be16 flags; __be16 proto; } *hdr, _hdr; hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr); if (!hdr) return false; /* * Only look inside GRE if version zero and no * routing */ if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) { proto = hdr->proto; nhoff += 4; if (hdr->flags & GRE_CSUM) nhoff += 4; if (hdr->flags & GRE_KEY) nhoff += 4; if (hdr->flags & GRE_SEQ) nhoff += 4; if (proto == htons(ETH_P_TEB)) { const struct ethhdr *eth; struct ethhdr _eth; eth = skb_header_pointer(skb, nhoff, sizeof(_eth), &_eth); if (!eth) return false; proto = eth->h_proto; nhoff += sizeof(*eth); } goto again; } break; } case IPPROTO_IPIP: goto again; case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); goto ipv6; default: break; } flow->ip_proto = ip_proto; flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); flow->thoff = (u16) nhoff; return true; }
/** * __skb_flow_dissect - extract the flow_keys struct and return it * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified * @data: raw buffer pointer to the packet, if NULL use skb->data * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb) * @hlen: packet header length, if @data is NULL use skb_headlen(skb) * * The function will try to retrieve the struct flow_keys from either the skbuff * or a raw buffer specified by the rest parameters */ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, void *data, __be16 proto, int nhoff, int hlen) { u8 ip_proto; if (!data) { data = skb->data; proto = skb->protocol; nhoff = skb_network_offset(skb); hlen = skb_headlen(skb); } memset(flow, 0, sizeof(*flow)); again: switch (proto) { case htons(ETH_P_IP): { const struct iphdr *iph; struct iphdr _iph; ip: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); if (!iph || iph->ihl < 5) return false; nhoff += iph->ihl * 4; ip_proto = iph->protocol; if (ip_is_fragment(iph)) ip_proto = 0; /* skip the address processing if skb is NULL. The assumption * here is that if there is no skb we are not looking for flow * info but lengths and protocols. */ if (!skb) break; iph_to_flow_copy_addrs(flow, iph); break; } case htons(ETH_P_IPV6): { const struct ipv6hdr *iph; struct ipv6hdr _iph; __be32 flow_label; ipv6: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); if (!iph) return false; ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); /* see comment above in IPv4 section */ if (!skb) break; flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); flow_label = ip6_flowlabel(iph); if (flow_label) { /* Awesome, IPv6 packet has a flow label so we can * use that to represent the ports without any * further dissection. */ flow->n_proto = proto; flow->ip_proto = ip_proto; flow->ports = flow_label; flow->thoff = (u16)nhoff; return true; } break; } case htons(ETH_P_8021AD): case htons(ETH_P_8021Q): { const struct vlan_hdr *vlan; struct vlan_hdr _vlan; vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan); if (!vlan) return false; proto = vlan->h_vlan_encapsulated_proto; nhoff += sizeof(*vlan); goto again; } case htons(ETH_P_PPP_SES): { struct { struct pppoe_hdr hdr; __be16 proto; } *hdr, _hdr; hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) return false; proto = hdr->proto; nhoff += PPPOE_SES_HLEN; switch (proto) { case htons(PPP_IP): goto ip; case htons(PPP_IPV6): goto ipv6; default: return false; } } case __constant_htons(ETH_P_MAP): { struct { struct rmnet_map_header_s map; uint8_t proto; } *map, _map; unsigned int maplen; map = skb_header_pointer(skb, nhoff, sizeof(_map), &_map); if (!map) return false; /* Is MAP command? */ if (map->map.cd_bit) return false; /* Is aggregated frame? */ maplen = ntohs(map->map.pkt_len); maplen += map->map.pad_len; maplen += sizeof(struct rmnet_map_header_s); if (maplen < skb->len) return false; nhoff += sizeof(struct rmnet_map_header_s); switch (map->proto & RMNET_IP_VER_MASK) { case RMNET_IPV4: proto = htons(ETH_P_IP); goto ip; case RMNET_IPV6: proto = htons(ETH_P_IPV6); goto ipv6; default: return false; } } case htons(ETH_P_FCOE): flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN); /* fall through */ default: return false; } switch (ip_proto) { case IPPROTO_GRE: { struct gre_hdr { __be16 flags; __be16 proto; } *hdr, _hdr; hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) return false; /* * Only look inside GRE if version zero and no * routing */ if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) { proto = hdr->proto; nhoff += 4; if (hdr->flags & GRE_CSUM) nhoff += 4; if (hdr->flags & GRE_KEY) nhoff += 4; if (hdr->flags & GRE_SEQ) nhoff += 4; if (proto == htons(ETH_P_TEB)) { const struct ethhdr *eth; struct ethhdr _eth; eth = __skb_header_pointer(skb, nhoff, sizeof(_eth), data, hlen, &_eth); if (!eth) return false; proto = eth->h_proto; nhoff += sizeof(*eth); } goto again; } break; } case IPPROTO_IPIP: proto = htons(ETH_P_IP); goto ip; case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); goto ipv6; default: break; } flow->n_proto = proto; flow->ip_proto = ip_proto; flow->thoff = (u16) nhoff; /* unless skb is set we don't need to record port info */ if (skb) flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen); return true; }
static u32 HASH_ADDR(const struct in6_addr *addr) { u32 hash = ipv6_addr_hash(addr); return hash_32(hash, HASH_SIZE_SHIFT); }