aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2010-04-17 23:42:05 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2010-04-23 00:35:55 -0400
commit6e7cb8370760ec17e10098399822292def8d84f3 (patch)
tree879ad4284b71e6095bb0128de5b2f02007f27f30
parentefe91932e79cfe59a562b70d8eb18049b36debc6 (diff)
ipv6 mcast: Introduce include/net/mld.h for MLD definitions.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
-rw-r--r--include/net/mld.h75
-rw-r--r--net/ipv6/mcast.c135
2 files changed, 115 insertions, 95 deletions
diff --git a/include/net/mld.h b/include/net/mld.h
new file mode 100644
index 000000000000..467143cd4e2f
--- /dev/null
+++ b/include/net/mld.h
@@ -0,0 +1,75 @@
1#ifndef LINUX_MLD_H
2#define LINUX_MLD_H
3
4#include <linux/in6.h>
5#include <linux/icmpv6.h>
6
7/* MLDv1 Query/Report/Done */
8struct mld_msg {
9 struct icmp6hdr mld_hdr;
10 struct in6_addr mld_mca;
11};
12
13#define mld_type mld_hdr.icmp6_type
14#define mld_code mld_hdr.icmp6_code
15#define mld_cksum mld_hdr.icmp6_cksum
16#define mld_maxdelay mld_hdr.icmp6_maxdelay
17#define mld_reserved mld_hdr.icmp6_dataun.un_data16[1]
18
19/* Multicast Listener Discovery version 2 headers */
20/* MLDv2 Report */
21struct mld2_grec {
22 __u8 grec_type;
23 __u8 grec_auxwords;
24 __be16 grec_nsrcs;
25 struct in6_addr grec_mca;
26 struct in6_addr grec_src[0];
27};
28
29struct mld2_report {
30 struct icmp6hdr mld2r_hdr;
31 struct mld2_grec mld2r_grec[0];
32};
33
34#define mld2r_type mld2r_hdr.icmp6_type
35#define mld2r_resv1 mld2r_hdr.icmp6_code
36#define mld2r_cksum mld2r_hdr.icmp6_cksum
37#define mld2r_resv2 mld2r_hdr.icmp6_dataun.un_data16[0]
38#define mld2r_ngrec mld2r_hdr.icmp6_dataun.un_data16[1]
39
40/* MLDv2 Query */
41struct mld2_query {
42 struct icmp6hdr mld2q_hdr;
43 struct in6_addr mld2q_mca;
44#if defined(__LITTLE_ENDIAN_BITFIELD)
45 __u8 mld2q_qrv:3,
46 mld2q_suppress:1,
47 mld2q_resv2:4;
48#elif defined(__BIG_ENDIAN_BITFIELD)
49 __u8 mld2q_resv2:4,
50 mld2q_suppress:1,
51 mld2q_qrv:3;
52#else
53#error "Please fix <asm/byteorder.h>"
54#endif
55 __u8 mld2q_qqic;
56 __be16 mld2q_nsrcs;
57 struct in6_addr mld2q_srcs[0];
58};
59
60#define mld2q_type mld2q_hdr.icmp6_type
61#define mld2q_code mld2q_hdr.icmp6_code
62#define mld2q_cksum mld2q_hdr.icmp6_cksum
63#define mld2q_mrc mld2q_hdr.icmp6_maxdelay
64#define mld2q_resv1 mld2q_hdr.icmp6_dataun.un_data16[1]
65
66/* Max Response Code */
67#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
68#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
69 ((value) < (thresh) ? (value) : \
70 ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
71 (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
72
73#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
74
75#endif
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 62ed08213d91..006aee683a0f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -44,6 +44,7 @@
44#include <linux/proc_fs.h> 44#include <linux/proc_fs.h>
45#include <linux/seq_file.h> 45#include <linux/seq_file.h>
46#include <linux/slab.h> 46#include <linux/slab.h>
47#include <net/mld.h>
47 48
48#include <linux/netfilter.h> 49#include <linux/netfilter.h>
49#include <linux/netfilter_ipv6.h> 50#include <linux/netfilter_ipv6.h>
@@ -71,54 +72,11 @@
71#define MDBG(x) 72#define MDBG(x)
72#endif 73#endif
73 74
74/* 75/* Ensure that we have struct in6_addr aligned on 32bit word. */
75 * These header formats should be in a separate include file, but icmpv6.h 76static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
76 * doesn't have in6_addr defined in all cases, there is no __u128, and no 77 BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4),
77 * other files reference these. 78 BUILD_BUG_ON_NULL(offsetof(struct mld2_report, mld2r_grec) % 4),
78 * 79 BUILD_BUG_ON_NULL(offsetof(struct mld2_grec, grec_mca) % 4)
79 * +-DLS 4/14/03
80 */
81
82/* Multicast Listener Discovery version 2 headers */
83
84struct mld2_grec {
85 __u8 grec_type;
86 __u8 grec_auxwords;
87 __be16 grec_nsrcs;
88 struct in6_addr grec_mca;
89 struct in6_addr grec_src[0];
90};
91
92struct mld2_report {
93 __u8 type;
94 __u8 resv1;
95 __sum16 csum;
96 __be16 resv2;
97 __be16 ngrec;
98 struct mld2_grec grec[0];
99};
100
101struct mld2_query {
102 __u8 type;
103 __u8 code;
104 __sum16 csum;
105 __be16 mrc;
106 __be16 resv1;
107 struct in6_addr mca;
108#if defined(__LITTLE_ENDIAN_BITFIELD)
109 __u8 qrv:3,
110 suppress:1,
111 resv2:4;
112#elif defined(__BIG_ENDIAN_BITFIELD)
113 __u8 resv2:4,
114 suppress:1,
115 qrv:3;
116#else
117#error "Please fix <asm/byteorder.h>"
118#endif
119 __u8 qqic;
120 __be16 nsrcs;
121 struct in6_addr srcs[0];
122}; 80};
123 81
124static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; 82static 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,
157 ((idev)->mc_v1_seen && \ 115 ((idev)->mc_v1_seen && \
158 time_before(jiffies, (idev)->mc_v1_seen))) 116 time_before(jiffies, (idev)->mc_v1_seen)))
159 117
160#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
161#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
162 ((value) < (thresh) ? (value) : \
163 ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
164 (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
165
166#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
167
168#define IPV6_MLD_MAX_MSF 64 118#define IPV6_MLD_MAX_MSF 64
169 119
170int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; 120int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
@@ -1161,7 +1111,7 @@ int igmp6_event_query(struct sk_buff *skb)
1161 struct in6_addr *group; 1111 struct in6_addr *group;
1162 unsigned long max_delay; 1112 unsigned long max_delay;
1163 struct inet6_dev *idev; 1113 struct inet6_dev *idev;
1164 struct icmp6hdr *hdr; 1114 struct mld_msg *mld;
1165 int group_type; 1115 int group_type;
1166 int mark = 0; 1116 int mark = 0;
1167 int len; 1117 int len;
@@ -1182,8 +1132,8 @@ int igmp6_event_query(struct sk_buff *skb)
1182 if (idev == NULL) 1132 if (idev == NULL)
1183 return 0; 1133 return 0;
1184 1134
1185 hdr = icmp6_hdr(skb); 1135 mld = (struct mld_msg *)icmp6_hdr(skb);
1186 group = (struct in6_addr *) (hdr + 1); 1136 group = &mld->mld_mca;
1187 group_type = ipv6_addr_type(group); 1137 group_type = ipv6_addr_type(group);
1188 1138
1189 if (group_type != IPV6_ADDR_ANY && 1139 if (group_type != IPV6_ADDR_ANY &&
@@ -1197,7 +1147,7 @@ int igmp6_event_query(struct sk_buff *skb)
1197 /* MLDv1 router present */ 1147 /* MLDv1 router present */
1198 1148
1199 /* Translate milliseconds to jiffies */ 1149 /* Translate milliseconds to jiffies */
1200 max_delay = (ntohs(hdr->icmp6_maxdelay)*HZ)/1000; 1150 max_delay = (ntohs(mld->mld_maxdelay)*HZ)/1000;
1201 1151
1202 switchback = (idev->mc_qrv + 1) * max_delay; 1152 switchback = (idev->mc_qrv + 1) * max_delay;
1203 idev->mc_v1_seen = jiffies + switchback; 1153 idev->mc_v1_seen = jiffies + switchback;
@@ -1216,14 +1166,14 @@ int igmp6_event_query(struct sk_buff *skb)
1216 return -EINVAL; 1166 return -EINVAL;
1217 } 1167 }
1218 mlh2 = (struct mld2_query *)skb_transport_header(skb); 1168 mlh2 = (struct mld2_query *)skb_transport_header(skb);
1219 max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; 1169 max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
1220 if (!max_delay) 1170 if (!max_delay)
1221 max_delay = 1; 1171 max_delay = 1;
1222 idev->mc_maxdelay = max_delay; 1172 idev->mc_maxdelay = max_delay;
1223 if (mlh2->qrv) 1173 if (mlh2->mld2q_qrv)
1224 idev->mc_qrv = mlh2->qrv; 1174 idev->mc_qrv = mlh2->mld2q_qrv;
1225 if (group_type == IPV6_ADDR_ANY) { /* general query */ 1175 if (group_type == IPV6_ADDR_ANY) { /* general query */
1226 if (mlh2->nsrcs) { 1176 if (mlh2->mld2q_nsrcs) {
1227 in6_dev_put(idev); 1177 in6_dev_put(idev);
1228 return -EINVAL; /* no sources allowed */ 1178 return -EINVAL; /* no sources allowed */
1229 } 1179 }
@@ -1232,9 +1182,9 @@ int igmp6_event_query(struct sk_buff *skb)
1232 return 0; 1182 return 0;
1233 } 1183 }
1234 /* mark sources to include, if group & source-specific */ 1184 /* mark sources to include, if group & source-specific */
1235 if (mlh2->nsrcs != 0) { 1185 if (mlh2->mld2q_nsrcs != 0) {
1236 if (!pskb_may_pull(skb, srcs_offset + 1186 if (!pskb_may_pull(skb, srcs_offset +
1237 ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) { 1187 ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
1238 in6_dev_put(idev); 1188 in6_dev_put(idev);
1239 return -EINVAL; 1189 return -EINVAL;
1240 } 1190 }
@@ -1270,7 +1220,7 @@ int igmp6_event_query(struct sk_buff *skb)
1270 ma->mca_flags &= ~MAF_GSQUERY; 1220 ma->mca_flags &= ~MAF_GSQUERY;
1271 } 1221 }
1272 if (!(ma->mca_flags & MAF_GSQUERY) || 1222 if (!(ma->mca_flags & MAF_GSQUERY) ||
1273 mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) 1223 mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs))
1274 igmp6_group_queried(ma, max_delay); 1224 igmp6_group_queried(ma, max_delay);
1275 spin_unlock_bh(&ma->mca_lock); 1225 spin_unlock_bh(&ma->mca_lock);
1276 break; 1226 break;
@@ -1286,9 +1236,8 @@ int igmp6_event_query(struct sk_buff *skb)
1286int igmp6_event_report(struct sk_buff *skb) 1236int igmp6_event_report(struct sk_buff *skb)
1287{ 1237{
1288 struct ifmcaddr6 *ma; 1238 struct ifmcaddr6 *ma;
1289 struct in6_addr *addrp;
1290 struct inet6_dev *idev; 1239 struct inet6_dev *idev;
1291 struct icmp6hdr *hdr; 1240 struct mld_msg *mld;
1292 int addr_type; 1241 int addr_type;
1293 1242
1294 /* Our own report looped back. Ignore it. */ 1243 /* Our own report looped back. Ignore it. */
@@ -1300,10 +1249,10 @@ int igmp6_event_report(struct sk_buff *skb)
1300 skb->pkt_type != PACKET_BROADCAST) 1249 skb->pkt_type != PACKET_BROADCAST)
1301 return 0; 1250 return 0;
1302 1251
1303 if (!pskb_may_pull(skb, sizeof(struct in6_addr))) 1252 if (!pskb_may_pull(skb, sizeof(*mld) - sizeof(struct icmp6hdr)))
1304 return -EINVAL; 1253 return -EINVAL;
1305 1254
1306 hdr = icmp6_hdr(skb); 1255 mld = (struct mld_msg *)icmp6_hdr(skb);
1307 1256
1308 /* Drop reports with not link local source */ 1257 /* Drop reports with not link local source */
1309 addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr); 1258 addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr);
@@ -1311,8 +1260,6 @@ int igmp6_event_report(struct sk_buff *skb)
1311 !(addr_type&IPV6_ADDR_LINKLOCAL)) 1260 !(addr_type&IPV6_ADDR_LINKLOCAL))
1312 return -EINVAL; 1261 return -EINVAL;
1313 1262
1314 addrp = (struct in6_addr *) (hdr + 1);
1315
1316 idev = in6_dev_get(skb->dev); 1263 idev = in6_dev_get(skb->dev);
1317 if (idev == NULL) 1264 if (idev == NULL)
1318 return -ENODEV; 1265 return -ENODEV;
@@ -1323,7 +1270,7 @@ int igmp6_event_report(struct sk_buff *skb)
1323 1270
1324 read_lock_bh(&idev->lock); 1271 read_lock_bh(&idev->lock);
1325 for (ma = idev->mc_list; ma; ma=ma->next) { 1272 for (ma = idev->mc_list; ma; ma=ma->next) {
1326 if (ipv6_addr_equal(&ma->mca_addr, addrp)) { 1273 if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
1327 spin_lock(&ma->mca_lock); 1274 spin_lock(&ma->mca_lock);
1328 if (del_timer(&ma->mca_timer)) 1275 if (del_timer(&ma->mca_timer))
1329 atomic_dec(&ma->mca_refcnt); 1276 atomic_dec(&ma->mca_refcnt);
@@ -1432,11 +1379,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
1432 skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data); 1379 skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data);
1433 skb_put(skb, sizeof(*pmr)); 1380 skb_put(skb, sizeof(*pmr));
1434 pmr = (struct mld2_report *)skb_transport_header(skb); 1381 pmr = (struct mld2_report *)skb_transport_header(skb);
1435 pmr->type = ICMPV6_MLD2_REPORT; 1382 pmr->mld2r_type = ICMPV6_MLD2_REPORT;
1436 pmr->resv1 = 0; 1383 pmr->mld2r_resv1 = 0;
1437 pmr->csum = 0; 1384 pmr->mld2r_cksum = 0;
1438 pmr->resv2 = 0; 1385 pmr->mld2r_resv2 = 0;
1439 pmr->ngrec = 0; 1386 pmr->mld2r_ngrec = 0;
1440 return skb; 1387 return skb;
1441} 1388}
1442 1389
@@ -1458,9 +1405,10 @@ static void mld_sendpack(struct sk_buff *skb)
1458 mldlen = skb->tail - skb->transport_header; 1405 mldlen = skb->tail - skb->transport_header;
1459 pip6->payload_len = htons(payload_len); 1406 pip6->payload_len = htons(payload_len);
1460 1407
1461 pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, 1408 pmr->mld2r_cksum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
1462 IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), 1409 IPPROTO_ICMPV6,
1463 mldlen, 0)); 1410 csum_partial(skb_transport_header(skb),
1411 mldlen, 0));
1464 1412
1465 dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); 1413 dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
1466 1414
@@ -1521,7 +1469,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
1521 pgr->grec_nsrcs = 0; 1469 pgr->grec_nsrcs = 0;
1522 pgr->grec_mca = pmc->mca_addr; /* structure copy */ 1470 pgr->grec_mca = pmc->mca_addr; /* structure copy */
1523 pmr = (struct mld2_report *)skb_transport_header(skb); 1471 pmr = (struct mld2_report *)skb_transport_header(skb);
1524 pmr->ngrec = htons(ntohs(pmr->ngrec)+1); 1472 pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1);
1525 *ppgr = pgr; 1473 *ppgr = pgr;
1526 return skb; 1474 return skb;
1527} 1475}
@@ -1557,7 +1505,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
1557 1505
1558 /* EX and TO_EX get a fresh packet, if needed */ 1506 /* EX and TO_EX get a fresh packet, if needed */
1559 if (truncate) { 1507 if (truncate) {
1560 if (pmr && pmr->ngrec && 1508 if (pmr && pmr->mld2r_ngrec &&
1561 AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { 1509 AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
1562 if (skb) 1510 if (skb)
1563 mld_sendpack(skb); 1511 mld_sendpack(skb);
@@ -1770,9 +1718,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
1770 struct sock *sk = net->ipv6.igmp_sk; 1718 struct sock *sk = net->ipv6.igmp_sk;
1771 struct inet6_dev *idev; 1719 struct inet6_dev *idev;
1772 struct sk_buff *skb; 1720 struct sk_buff *skb;
1773 struct icmp6hdr *hdr; 1721 struct mld_msg *hdr;
1774 const struct in6_addr *snd_addr, *saddr; 1722 const struct in6_addr *snd_addr, *saddr;
1775 struct in6_addr *addrp;
1776 struct in6_addr addr_buf; 1723 struct in6_addr addr_buf;
1777 int err, len, payload_len, full_len; 1724 int err, len, payload_len, full_len;
1778 u8 ra[8] = { IPPROTO_ICMPV6, 0, 1725 u8 ra[8] = { IPPROTO_ICMPV6, 0,
@@ -1820,16 +1767,14 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
1820 1767
1821 memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); 1768 memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
1822 1769
1823 hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr)); 1770 hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg));
1824 memset(hdr, 0, sizeof(struct icmp6hdr)); 1771 memset(hdr, 0, sizeof(struct mld_msg));
1825 hdr->icmp6_type = type; 1772 hdr->mld_type = type;
1773 ipv6_addr_copy(&hdr->mld_mca, addr);
1826 1774
1827 addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); 1775 hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len,
1828 ipv6_addr_copy(addrp, addr); 1776 IPPROTO_ICMPV6,
1829 1777 csum_partial(hdr, len, 0));
1830 hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len,
1831 IPPROTO_ICMPV6,
1832 csum_partial(hdr, len, 0));
1833 1778
1834 idev = in6_dev_get(skb->dev); 1779 idev = in6_dev_get(skb->dev);
1835 1780