* MLD input path. * * Assume query messages which fit in a single ICMPv6 message header * have been pulled up. * Assume that userland will want to see the message, even if it * otherwise fails kernel input validation; do not free it. * Pullup may however free the mbuf chain m if it fails. * * Return IPPROTO_DONE if we freed m. Otherwise, return 0. */
| 1249 | * Return IPPROTO_DONE if we freed m. Otherwise, return 0. |
| 1250 | */ |
| 1251 | int |
| 1252 | mld_input(struct mbuf **mp, int off, int icmp6len) |
| 1253 | { |
| 1254 | struct ifnet *ifp; |
| 1255 | struct ip6_hdr *ip6; |
| 1256 | struct mbuf *m; |
| 1257 | struct mld_hdr *mld; |
| 1258 | int mldlen; |
| 1259 | |
| 1260 | m = *mp; |
| 1261 | CTR3(KTR_MLD, "%s: called w/mbuf (%p,%d)", __func__, m, off); |
| 1262 | |
| 1263 | ifp = m->m_pkthdr.rcvif; |
| 1264 | |
| 1265 | /* Pullup to appropriate size. */ |
| 1266 | if (m->m_len < off + sizeof(*mld)) { |
| 1267 | m = m_pullup(m, off + sizeof(*mld)); |
| 1268 | if (m == NULL) { |
| 1269 | ICMP6STAT_INC(icp6s_badlen); |
| 1270 | return (IPPROTO_DONE); |
| 1271 | } |
| 1272 | } |
| 1273 | mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); |
| 1274 | if (mld->mld_type == MLD_LISTENER_QUERY && |
| 1275 | icmp6len >= sizeof(struct mldv2_query)) { |
| 1276 | mldlen = sizeof(struct mldv2_query); |
| 1277 | } else { |
| 1278 | mldlen = sizeof(struct mld_hdr); |
| 1279 | } |
| 1280 | if (m->m_len < off + mldlen) { |
| 1281 | m = m_pullup(m, off + mldlen); |
| 1282 | if (m == NULL) { |
| 1283 | ICMP6STAT_INC(icp6s_badlen); |
| 1284 | return (IPPROTO_DONE); |
| 1285 | } |
| 1286 | } |
| 1287 | *mp = m; |
| 1288 | ip6 = mtod(m, struct ip6_hdr *); |
| 1289 | mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); |
| 1290 | |
| 1291 | /* |
| 1292 | * Userland needs to see all of this traffic for implementing |
| 1293 | * the endpoint discovery portion of multicast routing. |
| 1294 | */ |
| 1295 | switch (mld->mld_type) { |
| 1296 | case MLD_LISTENER_QUERY: |
| 1297 | icmp6_ifstat_inc(ifp, ifs6_in_mldquery); |
| 1298 | if (icmp6len == sizeof(struct mld_hdr)) { |
| 1299 | if (mld_v1_input_query(ifp, ip6, mld) != 0) |
| 1300 | return (0); |
| 1301 | } else if (icmp6len >= sizeof(struct mldv2_query)) { |
| 1302 | if (mld_v2_input_query(ifp, ip6, m, |
| 1303 | (struct mldv2_query *)mld, off, icmp6len) != 0) |
| 1304 | return (0); |
| 1305 | } |
| 1306 | break; |
| 1307 | case MLD_LISTENER_REPORT: |
| 1308 | icmp6_ifstat_inc(ifp, ifs6_in_mldreport); |
no test coverage detected