static int handle_outgoing_nonce(struct snd_pkt_info *pi) { struct in6_addr tbuf[1], *tgt = NULL; switch (pi->icmp->icmp6_type) { case ND_ROUTER_SOLICIT: ipv6_addr_all_routers(tbuf); tgt = tbuf; break; case ND_NEIGHBOR_SOLICIT: { struct nd_neighbor_solicit *ns; ns = (struct nd_neighbor_solicit *)(pi->icmp); tgt = &ns->nd_ns_target; break; } case ND_ROUTER_ADVERT: tgt = NULL; break; case ND_NEIGHBOR_ADVERT: { struct nd_neighbor_advert *na; na = (struct nd_neighbor_advert *)(pi->icmp); tgt = &na->nd_na_target; break; } } switch (pi->icmp->icmp6_type) { case ND_ROUTER_SOLICIT: case ND_NEIGHBOR_SOLICIT: if (snd_proto_add_solicit_nonce(pi->b, tgt, pi->ifi) < 0) { return (-1); } break; case ND_ROUTER_ADVERT: case ND_NEIGHBOR_ADVERT: if (snd_proto_add_advert_nonce(pi->b, &pi->iph->ip6_dst, tgt, pi->ifi) < 0) { /* catastrophic failure */ return (-1); } break; } return (0); }
static int upd_caches(struct snd_pkt_info *pi) { struct in6_addr tbuf[1], *tgt = NULL; uint8_t *nonceopt = NULL; switch (pi->icmp->icmp6_type) { case ND_ROUTER_SOLICIT: case ND_NEIGHBOR_SOLICIT: nonceopt = (uint8_t *)pi->ndopts.opt[ND_OPT_NONCE]; if (pi->icmp->icmp6_type == ND_NEIGHBOR_SOLICIT) { struct nd_neighbor_solicit *ns; ns = (struct nd_neighbor_solicit *)(pi->icmp); tgt = &ns->nd_ns_target; } if (snd_proto_cache_nonce(&pi->iph->ip6_src, tgt, pi->ifi, nonceopt) < 0) { return (-1); } break; case ND_ROUTER_ADVERT: case ND_NEIGHBOR_ADVERT: if (!pi->ndopts.opt[ND_OPT_NONCE]) { break; } if (pi->icmp->icmp6_type == ND_NEIGHBOR_ADVERT) { struct nd_neighbor_advert *na; na = (struct nd_neighbor_advert *)(pi->icmp); tgt = &na->nd_na_target; } else { /* RA */ ipv6_addr_all_routers(tbuf); tgt = tbuf; } snd_del_solicit_ent(tgt, pi->ifi); break; } snd_timestamp_cache_upd(pi->cga, pi->ifi, pi->now, pi->ts); return (0); }
static int handle_incoming_nonce(struct snd_pkt_info *pi, int *secure) { struct in6_addr tbuf[1], *tgt = NULL; switch (pi->icmp->icmp6_type) { case ND_ROUTER_SOLICIT: case ND_NEIGHBOR_SOLICIT: if (!pi->ndopts.opt[ND_OPT_NONCE]) { DBG(&dbg_snd, "RS / NS: no nonce; dropping"); return (-1); } break; case ND_ROUTER_ADVERT: case ND_NEIGHBOR_ADVERT: if (!pi->ndopts.opt[ND_OPT_NONCE]) { DBG(&dbg, "RA / NA: no nonce; treating as " "unsolicited"); break; } if (pi->icmp->icmp6_type == ND_NEIGHBOR_ADVERT) { struct nd_neighbor_advert *na; na = (struct nd_neighbor_advert *)(pi->icmp); tgt = &na->nd_na_target; } else { /* RA */ ipv6_addr_all_routers(tbuf); tgt = tbuf; } if (snd_proto_check_solicit_nonce(tgt, pi->ifi, (uint8_t *)(pi->ndopts.opt[ND_OPT_NONCE])) < 0) { return (-1); } /* nonce is ok, so skip timestamp check */ *secure = 2; break; default: break; } return (0); }
void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) { struct sock *sk = igmp6_socket->sk; struct sk_buff *skb; struct inet6_dev *idev; struct icmp6hdr *hdr; struct in6_addr *snd_addr; struct in6_addr *addrp; struct in6_addr addr_buf; struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; #ifdef CONFIG_IPV6_MLD6_DEBUG char abuf[128]; in6_ntop(addr, abuf); MDBG3((KERN_DEBUG "igmp6_send(addr=%s, dev=%p(%s), type=%d)\n", abuf, dev, dev->name ? dev->name :"<null>", type)); #endif snd_addr = addr; if (type == ICMPV6_MGM_REDUCTION) { snd_addr = &all_routers; ipv6_addr_all_routers(&all_routers); } len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err); if (skb == NULL) return; skb_reserve(skb, (dev->hard_header_len + 15) & ~15); if (dev->hard_header) { unsigned char ha[MAX_ADDR_LEN]; ndisc_mc_map(snd_addr, ha, dev, 1); if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0) goto out; } if (ipv6_get_lladdr(dev, &addr_buf)) { MDBG1((KERN_WARNING "igmp6: %s no linklocal address\n", dev->name)); goto out; } ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr)); memset(hdr, 0, sizeof(struct icmp6hdr)); hdr->icmp6_type = type; addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); ipv6_addr_copy(addrp, addr); hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len, IPPROTO_ICMPV6, csum_partial((__u8 *) hdr, len, 0)); dev_queue_xmit(skb); idev = in6_dev_get(dev); if (type == ICMPV6_MGM_REDUCTION) ICMP6_INC_STATS(idev,Icmp6OutGroupMembReductions); else ICMP6_INC_STATS(idev,Icmp6OutGroupMembResponses); ICMP6_INC_STATS(idev,Icmp6OutMsgs); if (idev) in6_dev_put(idev); return; out: kfree_skb(skb); }
void igmp6_send(struct in6_addr *addr, struct device *dev, int type) { struct sock *sk = igmp6_socket->sk; struct sk_buff *skb; struct icmp6hdr *hdr; struct inet6_ifaddr *ifp; struct in6_addr *snd_addr; struct in6_addr *addrp; struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 0, 0, 0, IPV6_TLV_PADN, 0 }; snd_addr = addr; if (type == ICMPV6_MGM_REDUCTION) { snd_addr = &all_routers; ipv6_addr_all_routers(&all_routers); } len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err); if (skb == NULL) return; skb_reserve(skb, (dev->hard_header_len + 15) & ~15); if (dev->hard_header) { unsigned char ha[MAX_ADDR_LEN]; ndisc_mc_map(snd_addr, ha, dev, 1); dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len); } ifp = ipv6_get_lladdr(dev); if (ifp == NULL) { #if MCAST_DEBUG >= 1 printk(KERN_DEBUG "igmp6: %s no linklocal address\n", dev->name); #endif return; } ip6_nd_hdr(sk, skb, dev, &ifp->addr, snd_addr, NEXTHDR_HOP, payload_len); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr)); memset(hdr, 0, sizeof(struct icmp6hdr)); hdr->icmp6_type = type; addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); ipv6_addr_copy(addrp, addr); hdr->icmp6_cksum = csum_ipv6_magic(&ifp->addr, snd_addr, len, IPPROTO_ICMPV6, csum_partial((__u8 *) hdr, len, 0)); dev_queue_xmit(skb); if (type == ICMPV6_MGM_REDUCTION) icmpv6_statistics.Icmp6OutGroupMembReductions++; else icmpv6_statistics.Icmp6OutGroupMembResponses++; icmpv6_statistics.Icmp6OutMsgs++; }