Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e7cb837 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki
Browse files

ipv6 mcast: Introduce include/net/mld.h for MLD definitions.

parent efe91932
Loading
Loading
Loading
Loading

include/net/mld.h

0 → 100644
+75 −0
Original line number Original line Diff line number Diff line
#ifndef LINUX_MLD_H
#define LINUX_MLD_H

#include <linux/in6.h>
#include <linux/icmpv6.h>

/* MLDv1 Query/Report/Done */
struct mld_msg {
	struct icmp6hdr		mld_hdr;
	struct in6_addr		mld_mca;
};

#define mld_type		mld_hdr.icmp6_type
#define mld_code		mld_hdr.icmp6_code
#define mld_cksum		mld_hdr.icmp6_cksum
#define mld_maxdelay		mld_hdr.icmp6_maxdelay
#define mld_reserved		mld_hdr.icmp6_dataun.un_data16[1]

/* Multicast Listener Discovery version 2 headers */
/* MLDv2 Report */
struct mld2_grec {
	__u8		grec_type;
	__u8		grec_auxwords;
	__be16		grec_nsrcs;
	struct in6_addr	grec_mca;
	struct in6_addr	grec_src[0];
};

struct mld2_report {
	struct icmp6hdr		mld2r_hdr;
	struct mld2_grec	mld2r_grec[0];
};

#define mld2r_type		mld2r_hdr.icmp6_type
#define mld2r_resv1		mld2r_hdr.icmp6_code
#define mld2r_cksum		mld2r_hdr.icmp6_cksum
#define mld2r_resv2		mld2r_hdr.icmp6_dataun.un_data16[0]
#define mld2r_ngrec		mld2r_hdr.icmp6_dataun.un_data16[1]

/* MLDv2 Query */
struct mld2_query {
	struct icmp6hdr		mld2q_hdr;
	struct in6_addr		mld2q_mca;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8			mld2q_qrv:3,
				mld2q_suppress:1,
				mld2q_resv2:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u8			mld2q_resv2:4,
				mld2q_suppress:1,
				mld2q_qrv:3;
#else
#error "Please fix <asm/byteorder.h>"
#endif
	__u8			mld2q_qqic;
	__be16			mld2q_nsrcs;
	struct in6_addr		mld2q_srcs[0];
};

#define mld2q_type		mld2q_hdr.icmp6_type
#define mld2q_code		mld2q_hdr.icmp6_code
#define mld2q_cksum		mld2q_hdr.icmp6_cksum
#define mld2q_mrc		mld2q_hdr.icmp6_maxdelay
#define mld2q_resv1		mld2q_hdr.icmp6_dataun.un_data16[1]

/* Max Response Code */
#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
	((value) < (thresh) ? (value) : \
	((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
	(MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))

#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)

#endif
+40 −95
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <net/mld.h>


#include <linux/netfilter.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter_ipv6.h>
@@ -71,54 +72,11 @@
#define MDBG(x)
#define MDBG(x)
#endif
#endif


/*
/* Ensure that we have struct in6_addr aligned on 32bit word. */
 *  These header formats should be in a separate include file, but icmpv6.h
static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
 *  doesn't have in6_addr defined in all cases, there is no __u128, and no
	BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4),
 *  other files reference these.
	BUILD_BUG_ON_NULL(offsetof(struct mld2_report, mld2r_grec) % 4),
 *
	BUILD_BUG_ON_NULL(offsetof(struct mld2_grec, grec_mca) % 4)
 *  			+-DLS 4/14/03
 */

/* Multicast Listener Discovery version 2 headers */

struct mld2_grec {
	__u8		grec_type;
	__u8		grec_auxwords;
	__be16		grec_nsrcs;
	struct in6_addr	grec_mca;
	struct in6_addr	grec_src[0];
};

struct mld2_report {
	__u8	type;
	__u8	resv1;
	__sum16	csum;
	__be16	resv2;
	__be16	ngrec;
	struct mld2_grec grec[0];
};

struct mld2_query {
	__u8 type;
	__u8 code;
	__sum16 csum;
	__be16 mrc;
	__be16 resv1;
	struct in6_addr mca;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8 qrv:3,
	     suppress:1,
	     resv2:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u8 resv2:4,
	     suppress:1,
	     qrv:3;
#else
#error "Please fix <asm/byteorder.h>"
#endif
	__u8 qqic;
	__be16 nsrcs;
	struct in6_addr srcs[0];
};
};


static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
@@ -157,14 +115,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
		((idev)->mc_v1_seen && \
		((idev)->mc_v1_seen && \
		time_before(jiffies, (idev)->mc_v1_seen)))
		time_before(jiffies, (idev)->mc_v1_seen)))


#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
	((value) < (thresh) ? (value) : \
	((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
	(MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))

#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)

#define IPV6_MLD_MAX_MSF	64
#define IPV6_MLD_MAX_MSF	64


int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
@@ -1161,7 +1111,7 @@ int igmp6_event_query(struct sk_buff *skb)
	struct in6_addr *group;
	struct in6_addr *group;
	unsigned long max_delay;
	unsigned long max_delay;
	struct inet6_dev *idev;
	struct inet6_dev *idev;
	struct icmp6hdr *hdr;
	struct mld_msg *mld;
	int group_type;
	int group_type;
	int mark = 0;
	int mark = 0;
	int len;
	int len;
@@ -1182,8 +1132,8 @@ int igmp6_event_query(struct sk_buff *skb)
	if (idev == NULL)
	if (idev == NULL)
		return 0;
		return 0;


	hdr = icmp6_hdr(skb);
	mld = (struct mld_msg *)icmp6_hdr(skb);
	group = (struct in6_addr *) (hdr + 1);
	group = &mld->mld_mca;
	group_type = ipv6_addr_type(group);
	group_type = ipv6_addr_type(group);


	if (group_type != IPV6_ADDR_ANY &&
	if (group_type != IPV6_ADDR_ANY &&
@@ -1197,7 +1147,7 @@ int igmp6_event_query(struct sk_buff *skb)
		/* MLDv1 router present */
		/* MLDv1 router present */


		/* Translate milliseconds to jiffies */
		/* Translate milliseconds to jiffies */
		max_delay = (ntohs(hdr->icmp6_maxdelay)*HZ)/1000;
		max_delay = (ntohs(mld->mld_maxdelay)*HZ)/1000;


		switchback = (idev->mc_qrv + 1) * max_delay;
		switchback = (idev->mc_qrv + 1) * max_delay;
		idev->mc_v1_seen = jiffies + switchback;
		idev->mc_v1_seen = jiffies + switchback;
@@ -1216,14 +1166,14 @@ int igmp6_event_query(struct sk_buff *skb)
			return -EINVAL;
			return -EINVAL;
		}
		}
		mlh2 = (struct mld2_query *)skb_transport_header(skb);
		mlh2 = (struct mld2_query *)skb_transport_header(skb);
		max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000;
		max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
		if (!max_delay)
		if (!max_delay)
			max_delay = 1;
			max_delay = 1;
		idev->mc_maxdelay = max_delay;
		idev->mc_maxdelay = max_delay;
		if (mlh2->qrv)
		if (mlh2->mld2q_qrv)
			idev->mc_qrv = mlh2->qrv;
			idev->mc_qrv = mlh2->mld2q_qrv;
		if (group_type == IPV6_ADDR_ANY) { /* general query */
		if (group_type == IPV6_ADDR_ANY) { /* general query */
			if (mlh2->nsrcs) {
			if (mlh2->mld2q_nsrcs) {
				in6_dev_put(idev);
				in6_dev_put(idev);
				return -EINVAL; /* no sources allowed */
				return -EINVAL; /* no sources allowed */
			}
			}
@@ -1232,9 +1182,9 @@ int igmp6_event_query(struct sk_buff *skb)
			return 0;
			return 0;
		}
		}
		/* mark sources to include, if group & source-specific */
		/* mark sources to include, if group & source-specific */
		if (mlh2->nsrcs != 0) {
		if (mlh2->mld2q_nsrcs != 0) {
			if (!pskb_may_pull(skb, srcs_offset +
			if (!pskb_may_pull(skb, srcs_offset +
			    ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) {
			    ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
				in6_dev_put(idev);
				in6_dev_put(idev);
				return -EINVAL;
				return -EINVAL;
			}
			}
@@ -1270,7 +1220,7 @@ int igmp6_event_query(struct sk_buff *skb)
					ma->mca_flags &= ~MAF_GSQUERY;
					ma->mca_flags &= ~MAF_GSQUERY;
			}
			}
			if (!(ma->mca_flags & MAF_GSQUERY) ||
			if (!(ma->mca_flags & MAF_GSQUERY) ||
			    mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
			    mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs))
				igmp6_group_queried(ma, max_delay);
				igmp6_group_queried(ma, max_delay);
			spin_unlock_bh(&ma->mca_lock);
			spin_unlock_bh(&ma->mca_lock);
			break;
			break;
@@ -1286,9 +1236,8 @@ int igmp6_event_query(struct sk_buff *skb)
int igmp6_event_report(struct sk_buff *skb)
int igmp6_event_report(struct sk_buff *skb)
{
{
	struct ifmcaddr6 *ma;
	struct ifmcaddr6 *ma;
	struct in6_addr *addrp;
	struct inet6_dev *idev;
	struct inet6_dev *idev;
	struct icmp6hdr *hdr;
	struct mld_msg *mld;
	int addr_type;
	int addr_type;


	/* Our own report looped back. Ignore it. */
	/* Our own report looped back. Ignore it. */
@@ -1300,10 +1249,10 @@ int igmp6_event_report(struct sk_buff *skb)
	    skb->pkt_type != PACKET_BROADCAST)
	    skb->pkt_type != PACKET_BROADCAST)
		return 0;
		return 0;


	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
	if (!pskb_may_pull(skb, sizeof(*mld) - sizeof(struct icmp6hdr)))
		return -EINVAL;
		return -EINVAL;


	hdr = icmp6_hdr(skb);
	mld = (struct mld_msg *)icmp6_hdr(skb);


	/* Drop reports with not link local source */
	/* Drop reports with not link local source */
	addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr);
	addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr);
@@ -1311,8 +1260,6 @@ int igmp6_event_report(struct sk_buff *skb)
	    !(addr_type&IPV6_ADDR_LINKLOCAL))
	    !(addr_type&IPV6_ADDR_LINKLOCAL))
		return -EINVAL;
		return -EINVAL;


	addrp = (struct in6_addr *) (hdr + 1);

	idev = in6_dev_get(skb->dev);
	idev = in6_dev_get(skb->dev);
	if (idev == NULL)
	if (idev == NULL)
		return -ENODEV;
		return -ENODEV;
@@ -1323,7 +1270,7 @@ int igmp6_event_report(struct sk_buff *skb)


	read_lock_bh(&idev->lock);
	read_lock_bh(&idev->lock);
	for (ma = idev->mc_list; ma; ma=ma->next) {
	for (ma = idev->mc_list; ma; ma=ma->next) {
		if (ipv6_addr_equal(&ma->mca_addr, addrp)) {
		if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
			spin_lock(&ma->mca_lock);
			spin_lock(&ma->mca_lock);
			if (del_timer(&ma->mca_timer))
			if (del_timer(&ma->mca_timer))
				atomic_dec(&ma->mca_refcnt);
				atomic_dec(&ma->mca_refcnt);
@@ -1432,11 +1379,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
	skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data);
	skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data);
	skb_put(skb, sizeof(*pmr));
	skb_put(skb, sizeof(*pmr));
	pmr = (struct mld2_report *)skb_transport_header(skb);
	pmr = (struct mld2_report *)skb_transport_header(skb);
	pmr->type = ICMPV6_MLD2_REPORT;
	pmr->mld2r_type = ICMPV6_MLD2_REPORT;
	pmr->resv1 = 0;
	pmr->mld2r_resv1 = 0;
	pmr->csum = 0;
	pmr->mld2r_cksum = 0;
	pmr->resv2 = 0;
	pmr->mld2r_resv2 = 0;
	pmr->ngrec = 0;
	pmr->mld2r_ngrec = 0;
	return skb;
	return skb;
}
}


@@ -1458,8 +1405,9 @@ static void mld_sendpack(struct sk_buff *skb)
	mldlen = skb->tail - skb->transport_header;
	mldlen = skb->tail - skb->transport_header;
	pip6->payload_len = htons(payload_len);
	pip6->payload_len = htons(payload_len);


	pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
	pmr->mld2r_cksum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
		IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
					   IPPROTO_ICMPV6,
					   csum_partial(skb_transport_header(skb),
							mldlen, 0));
							mldlen, 0));


	dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
	dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
@@ -1521,7 +1469,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
	pgr->grec_nsrcs = 0;
	pgr->grec_nsrcs = 0;
	pgr->grec_mca = pmc->mca_addr;	/* structure copy */
	pgr->grec_mca = pmc->mca_addr;	/* structure copy */
	pmr = (struct mld2_report *)skb_transport_header(skb);
	pmr = (struct mld2_report *)skb_transport_header(skb);
	pmr->ngrec = htons(ntohs(pmr->ngrec)+1);
	pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1);
	*ppgr = pgr;
	*ppgr = pgr;
	return skb;
	return skb;
}
}
@@ -1557,7 +1505,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,


	/* EX and TO_EX get a fresh packet, if needed */
	/* EX and TO_EX get a fresh packet, if needed */
	if (truncate) {
	if (truncate) {
		if (pmr && pmr->ngrec &&
		if (pmr && pmr->mld2r_ngrec &&
		    AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
		    AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
			if (skb)
			if (skb)
				mld_sendpack(skb);
				mld_sendpack(skb);
@@ -1770,9 +1718,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
	struct sock *sk = net->ipv6.igmp_sk;
	struct sock *sk = net->ipv6.igmp_sk;
	struct inet6_dev *idev;
	struct inet6_dev *idev;
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct icmp6hdr *hdr;
	struct mld_msg *hdr;
	const struct in6_addr *snd_addr, *saddr;
	const struct in6_addr *snd_addr, *saddr;
	struct in6_addr *addrp;
	struct in6_addr addr_buf;
	struct in6_addr addr_buf;
	int err, len, payload_len, full_len;
	int err, len, payload_len, full_len;
	u8 ra[8] = { IPPROTO_ICMPV6, 0,
	u8 ra[8] = { IPPROTO_ICMPV6, 0,
@@ -1820,14 +1767,12 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)


	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));


	hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
	hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg));
	memset(hdr, 0, sizeof(struct icmp6hdr));
	memset(hdr, 0, sizeof(struct mld_msg));
	hdr->icmp6_type = type;
	hdr->mld_type = type;

	ipv6_addr_copy(&hdr->mld_mca, addr);
	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
	ipv6_addr_copy(addrp, addr);


	hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len,
	hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len,
					 IPPROTO_ICMPV6,
					 IPPROTO_ICMPV6,
					 csum_partial(hdr, len, 0));
					 csum_partial(hdr, len, 0));