ER in6_set_header (T_NET_BUF *nbuf, uint_t len, T_IN6_ADDR *dstaddr, T_IN6_ADDR *srcaddr, uint8_t next, uint8_t hlim) { T_IFNET *ifp = IF_GET_IFNET(); T_IP6_HDR *ip6h; T_IN6_IFADDR *ia; /* * 宛先アドレスにふさわしい送信元アドレスを、 * ネットワークインタフェースから探索して利用する。 */ if (srcaddr == NULL || !IN6_IS_ADDR_UNSPECIFIED(srcaddr)) ; else if ((ia = in6_ifawithifp(ifp, dstaddr)) == NULL) return E_SYS; else srcaddr = &ia->addr; /* IPv6 ヘッダを設定する。*/ ip6h = GET_IP6_HDR(nbuf); ip6h->vcf = htonl(IP6_MAKE_VCF(IPV6_VERSION, 0)); ip6h->plen = htons(len); ip6h->next = next; ip6h->hlim = hlim; if (dstaddr == NULL) memset(&ip6h->dst, 0, sizeof(T_IN6_ADDR)); else ip6h->dst = *dstaddr; if (srcaddr == NULL) memset(&ip6h->src, 0, sizeof(T_IN6_ADDR)); else ip6h->src = *srcaddr; return E_OK; }
/* * Output an Neighbor Solicitation Message. Caller specifies: * - ICMP6 header source IP6 address * - ND6 header target IP6 address * - ND6 header source datalink address * * Based on RFC 2461 * Based on RFC 2462 (duplicated address detection) */ void nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, const struct in6_addr *taddr6, struct llinfo_nd6 *ln, /* for source address determination */ int dad) /* duplicated address detection */ { struct mbuf *m; struct ip6_hdr *ip6; struct nd_neighbor_solicit *nd_ns; struct in6_ifaddr *ia = NULL; struct ip6_moptions im6o; int icmp6len; int maxlen; caddr_t mac; struct ifnet *outif = NULL; if (IN6_IS_ADDR_MULTICAST(taddr6)) return; /* estimate the size of message */ maxlen = sizeof(*ip6) + sizeof(*nd_ns); maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; if (max_linkhdr + maxlen >= MCLBYTES) { #ifdef DIAGNOSTIC kprintf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES " "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES); #endif return; } m = m_getb(max_linkhdr + maxlen, MB_DONTWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return; if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { m->m_flags |= M_MCAST; im6o.im6o_multicast_ifp = ifp; im6o.im6o_multicast_hlim = 255; im6o.im6o_multicast_loop = 0; } icmp6len = sizeof(*nd_ns); m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */ /* fill neighbor solicitation packet */ ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_flow = 0; ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc |= IPV6_VERSION; /* ip6->ip6_plen will be set later */ ip6->ip6_nxt = IPPROTO_ICMPV6; ip6->ip6_hlim = 255; if (daddr6) ip6->ip6_dst = *daddr6; else { ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL; ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index); ip6->ip6_dst.s6_addr32[1] = 0; ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE; ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3]; ip6->ip6_dst.s6_addr8[12] = 0xff; } if (!dad) { #if 0 /* KAME way, exact address scope match */ /* * Select a source whose scope is the same as that of the dest. * Typically, the dest is link-local solicitation multicast * (i.e. neighbor discovery) or link-local/global unicast * (i.e. neighbor un-reachability detection). */ ia = in6_ifawithifp(ifp, &ip6->ip6_dst); if (ia == NULL) { m_freem(m); return; } ip6->ip6_src = ia->ia_addr.sin6_addr; #else /* spec-wise correct */ /* * RFC2461 7.2.2: * "If the source address of the packet prompting the * solicitation is the same as one of the addresses assigned * to the outgoing interface, that address SHOULD be placed * in the IP Source Address of the outgoing solicitation. * Otherwise, any one of the addresses assigned to the * interface should be used." * * We use the source address for the prompting packet * (saddr6), if: * - saddr6 is given from the caller (by giving "ln"), and * - saddr6 belongs to the outgoing interface. * Otherwise, we perform a scope-wise match. */ struct ip6_hdr *hip6; /* hold ip6 */ struct in6_addr *saddr6; if (ln && ln->ln_hold) { hip6 = mtod(ln->ln_hold, struct ip6_hdr *); /* XXX pullup? */ if (sizeof(*hip6) < ln->ln_hold->m_len) saddr6 = &hip6->ip6_src; else saddr6 = NULL; } else