* Receive Router Solicitation Message - just for routers. * Router solicitation/advertisement is mostly managed by userland program * (rtadvd) so here we have no function like nd6_ra_output(). * * Based on RFC 2461 */
| 150 | * Based on RFC 2461 |
| 151 | */ |
| 152 | void |
| 153 | nd6_rs_input(struct mbuf *m, int off, int icmp6len) |
| 154 | { |
| 155 | struct ifnet *ifp; |
| 156 | struct ip6_hdr *ip6; |
| 157 | struct nd_router_solicit *nd_rs; |
| 158 | struct in6_addr saddr6; |
| 159 | union nd_opts ndopts; |
| 160 | char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; |
| 161 | char *lladdr; |
| 162 | int lladdrlen; |
| 163 | |
| 164 | ifp = m->m_pkthdr.rcvif; |
| 165 | |
| 166 | /* |
| 167 | * Accept RS only when V_ip6_forwarding=1 and the interface has |
| 168 | * no ND6_IFF_ACCEPT_RTADV. |
| 169 | */ |
| 170 | if (!V_ip6_forwarding || ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) |
| 171 | goto freeit; |
| 172 | |
| 173 | /* RFC 6980: Nodes MUST silently ignore fragments */ |
| 174 | if(m->m_flags & M_FRAGMENTED) |
| 175 | goto freeit; |
| 176 | |
| 177 | /* Sanity checks */ |
| 178 | ip6 = mtod(m, struct ip6_hdr *); |
| 179 | if (__predict_false(ip6->ip6_hlim != 255)) { |
| 180 | ICMP6STAT_INC(icp6s_invlhlim); |
| 181 | nd6log((LOG_ERR, |
| 182 | "%s: invalid hlim (%d) from %s to %s on %s\n", __func__, |
| 183 | ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), |
| 184 | ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); |
| 185 | goto bad; |
| 186 | } |
| 187 | |
| 188 | /* |
| 189 | * Don't update the neighbor cache, if src = ::. |
| 190 | * This indicates that the src has no IP address assigned yet. |
| 191 | */ |
| 192 | saddr6 = ip6->ip6_src; |
| 193 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) |
| 194 | goto freeit; |
| 195 | |
| 196 | if (m->m_len < off + icmp6len) { |
| 197 | m = m_pullup(m, off + icmp6len); |
| 198 | if (m == NULL) { |
| 199 | IP6STAT_INC(ip6s_exthdrtoolong); |
| 200 | return; |
| 201 | } |
| 202 | } |
| 203 | ip6 = mtod(m, struct ip6_hdr *); |
| 204 | nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); |
| 205 | |
| 206 | icmp6len -= sizeof(*nd_rs); |
| 207 | nd6_option_init(nd_rs + 1, icmp6len, &ndopts); |
| 208 | if (nd6_options(&ndopts) < 0) { |
| 209 | nd6log((LOG_INFO, |
no test coverage detected