qcacmn: IGMP leave message handling in MLO MCAST
IGMP leave message handling in MLO MCAST scenarios.
Change-Id: Ic0ac16dbe75b4ef2b27e97be3f42c498b503ca06
CRs-Fixed: 3359488
This commit is contained in:

committed by
Madan Koyyalamudi

parent
cbc0170b1c
commit
88dd4c6970
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
@@ -42,6 +42,8 @@
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <pld_common.h>
|
||||
#include <qdf_crypto.h>
|
||||
#include <linux/igmp.h>
|
||||
#include <net/mld.h>
|
||||
|
||||
#if defined(FEATURE_TSO)
|
||||
#include <net/ipv6.h>
|
||||
@@ -2036,6 +2038,165 @@ is_mld:
|
||||
|
||||
qdf_export_symbol(__qdf_nbuf_data_is_ipv6_igmp_pkt);
|
||||
|
||||
/**
|
||||
* __qdf_nbuf_is_ipv4_igmp_leave_pkt() - check if skb is a igmp leave packet
|
||||
* @data: Pointer to network buffer
|
||||
*
|
||||
* This api is for ipv4 packet.
|
||||
*
|
||||
* Return: true if packet is igmp packet
|
||||
* false otherwise.
|
||||
*/
|
||||
bool __qdf_nbuf_is_ipv4_igmp_leave_pkt(__qdf_nbuf_t buf)
|
||||
{
|
||||
qdf_ether_header_t *eh = NULL;
|
||||
uint16_t ether_type;
|
||||
uint8_t eth_hdr_size = sizeof(qdf_ether_header_t);
|
||||
|
||||
eh = (qdf_ether_header_t *)qdf_nbuf_data(buf);
|
||||
ether_type = eh->ether_type;
|
||||
|
||||
if (ether_type == htons(ETH_P_8021Q)) {
|
||||
struct vlan_ethhdr *veth =
|
||||
(struct vlan_ethhdr *)qdf_nbuf_data(buf);
|
||||
ether_type = veth->h_vlan_encapsulated_proto;
|
||||
eth_hdr_size = sizeof(struct vlan_ethhdr);
|
||||
}
|
||||
|
||||
if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_IPV4_ETH_TYPE)) {
|
||||
struct iphdr *iph = NULL;
|
||||
struct igmphdr *ih = NULL;
|
||||
|
||||
iph = (struct iphdr *)(qdf_nbuf_data(buf) + eth_hdr_size);
|
||||
ih = (struct igmphdr *)((uint8_t *)iph + iph->ihl * 4);
|
||||
switch (ih->type) {
|
||||
case IGMP_HOST_LEAVE_MESSAGE:
|
||||
return true;
|
||||
case IGMPV3_HOST_MEMBERSHIP_REPORT:
|
||||
{
|
||||
struct igmpv3_report *ihv3 = (struct igmpv3_report *)ih;
|
||||
struct igmpv3_grec *grec = NULL;
|
||||
int num = 0;
|
||||
int i = 0;
|
||||
int len = 0;
|
||||
int type = 0;
|
||||
|
||||
num = ntohs(ihv3->ngrec);
|
||||
for (i = 0; i < num; i++) {
|
||||
grec = (void *)((uint8_t *)(ihv3->grec) + len);
|
||||
type = grec->grec_type;
|
||||
if ((type == IGMPV3_MODE_IS_INCLUDE) ||
|
||||
(type == IGMPV3_CHANGE_TO_INCLUDE))
|
||||
return true;
|
||||
|
||||
len += sizeof(struct igmpv3_grec);
|
||||
len += ntohs(grec->grec_nsrcs) * 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdf_export_symbol(__qdf_nbuf_is_ipv4_igmp_leave_pkt);
|
||||
|
||||
/**
|
||||
* __qdf_nbuf_is_ipv6_igmp_leave_pkt() - check if skb is a igmp leave packet
|
||||
* @data: Pointer to network buffer
|
||||
*
|
||||
* This api is for ipv6 packet.
|
||||
*
|
||||
* Return: true if packet is igmp packet
|
||||
* false otherwise.
|
||||
*/
|
||||
bool __qdf_nbuf_is_ipv6_igmp_leave_pkt(__qdf_nbuf_t buf)
|
||||
{
|
||||
qdf_ether_header_t *eh = NULL;
|
||||
uint16_t ether_type;
|
||||
uint8_t eth_hdr_size = sizeof(qdf_ether_header_t);
|
||||
|
||||
eh = (qdf_ether_header_t *)qdf_nbuf_data(buf);
|
||||
ether_type = eh->ether_type;
|
||||
|
||||
if (ether_type == htons(ETH_P_8021Q)) {
|
||||
struct vlan_ethhdr *veth =
|
||||
(struct vlan_ethhdr *)qdf_nbuf_data(buf);
|
||||
ether_type = veth->h_vlan_encapsulated_proto;
|
||||
eth_hdr_size = sizeof(struct vlan_ethhdr);
|
||||
}
|
||||
|
||||
if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_IPV6_ETH_TYPE)) {
|
||||
struct ipv6hdr *ip6h = NULL;
|
||||
struct icmp6hdr *icmp6h = NULL;
|
||||
uint8_t nexthdr;
|
||||
uint16_t frag_off = 0;
|
||||
int offset;
|
||||
qdf_nbuf_t buf_copy = NULL;
|
||||
|
||||
ip6h = (struct ipv6hdr *)(qdf_nbuf_data(buf) + eth_hdr_size);
|
||||
if (ip6h->nexthdr != IPPROTO_HOPOPTS ||
|
||||
ip6h->payload_len == 0)
|
||||
return false;
|
||||
|
||||
buf_copy = qdf_nbuf_copy(buf);
|
||||
if (qdf_likely(!buf_copy))
|
||||
return false;
|
||||
|
||||
nexthdr = ip6h->nexthdr;
|
||||
offset = ipv6_skip_exthdr(buf_copy,
|
||||
eth_hdr_size + sizeof(*ip6h),
|
||||
&nexthdr,
|
||||
&frag_off);
|
||||
qdf_nbuf_free(buf_copy);
|
||||
if (offset < 0 || nexthdr != IPPROTO_ICMPV6)
|
||||
return false;
|
||||
|
||||
icmp6h = (struct icmp6hdr *)(qdf_nbuf_data(buf) + offset);
|
||||
|
||||
switch (icmp6h->icmp6_type) {
|
||||
case ICMPV6_MGM_REDUCTION:
|
||||
return true;
|
||||
case ICMPV6_MLD2_REPORT:
|
||||
{
|
||||
struct mld2_report *mh = NULL;
|
||||
struct mld2_grec *grec = NULL;
|
||||
int num = 0;
|
||||
int i = 0;
|
||||
int len = 0;
|
||||
int type = -1;
|
||||
|
||||
mh = (struct mld2_report *)icmp6h;
|
||||
num = ntohs(mh->mld2r_ngrec);
|
||||
for (i = 0; i < num; i++) {
|
||||
grec = (void *)(((uint8_t *)mh->mld2r_grec) +
|
||||
len);
|
||||
type = grec->grec_type;
|
||||
if ((type == MLD2_MODE_IS_INCLUDE) ||
|
||||
(type == MLD2_CHANGE_TO_INCLUDE))
|
||||
return true;
|
||||
else if (type == MLD2_BLOCK_OLD_SOURCES)
|
||||
return true;
|
||||
|
||||
len += sizeof(struct mld2_grec);
|
||||
len += ntohs(grec->grec_nsrcs) *
|
||||
sizeof(struct in6_addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdf_export_symbol(__qdf_nbuf_is_ipv6_igmp_leave_pkt);
|
||||
|
||||
/**
|
||||
* __qdf_nbuf_is_ipv4_tdls_pkt() - check if skb data is a tdls packet
|
||||
* @skb: Pointer to network buffer
|
||||
|
Reference in New Issue
Block a user