diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2010-04-17 23:42:05 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2010-04-23 00:35:55 -0400 |
commit | 6e7cb8370760ec17e10098399822292def8d84f3 (patch) | |
tree | 879ad4284b71e6095bb0128de5b2f02007f27f30 | |
parent | efe91932e79cfe59a562b70d8eb18049b36debc6 (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.h | 75 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 135 |
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 */ | ||
8 | struct 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 */ | ||
21 | struct 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 | |||
29 | struct 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 */ | ||
41 | struct 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 | 76 | static 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 | |||
84 | struct 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 | |||
92 | struct 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 | |||
101 | struct 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 | ||
124 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | 82 | 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, | |||
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 | ||
170 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; | 120 | int 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) | |||
1286 | int igmp6_event_report(struct sk_buff *skb) | 1236 | int 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 | ||