static uint16_t arp_send_eventhandler(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *priv, uint16_t flags) { FAR struct arp_send_s *state = (FAR struct arp_send_s *)priv; ninfo("flags: %04x sent: %d\n", flags, state->snd_sent); if (state) { /* Check if the network is still up */ if ((flags & NETDEV_DOWN) != 0) { nerr("ERROR: Interface is down\n"); arp_send_terminate(state, -ENETUNREACH); return flags; } /* Check if the outgoing packet is available. It may have been claimed * by a send event handler serving a different thread -OR- if the * output buffer currently contains unprocessed incoming data. In * these cases we will just have to wait for the next polling cycle. */ if (dev->d_sndlen > 0 || (flags & PKT_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ /* REVISIT: No timeout. Just wait for the next polling cycle */ return flags; } /* It looks like we are good to send the data */ /* Copy the packet data into the device packet buffer and send it */ arp_format(dev, state->snd_ipaddr); /* Make sure no ARP request overwrites this ARP request. This * flag will be cleared in arp_out(). */ IFF_SET_NOARP(dev->d_flags); /* Don't allow any further call backs. */ arp_send_terminate(state, OK); } return flags; }
void icmpv6_solicit(FAR struct net_driver_s *dev, FAR const net_ipv6addr_t ipaddr) { FAR struct icmpv6_iphdr_s *icmp; FAR struct icmpv6_neighbor_solicit_s *sol; FAR struct eth_hdr_s *eth; /* Set up the IPv6 header (most is probably already in place) */ icmp = ICMPv6BUF; icmp->vtc = 0x60; /* Version/traffic class (MS) */ icmp->tcf = 0; /* Traffic class (LS)/Flow label (MS) */ icmp->flow = 0; /* Flow label (LS) */ /* Length excludes the IPv6 header */ icmp->len[0] = (sizeof(struct icmpv6_neighbor_solicit_s) >> 8); icmp->len[1] = (sizeof(struct icmpv6_neighbor_solicit_s) & 0xff); icmp->proto = IP_PROTO_ICMP6; /* Next header */ icmp->ttl = 255; /* Hop limit */ /* Set the multicast destination IP address */ memcpy(icmp->destipaddr, g_icmpv_mcastaddr, 6*sizeof(uint16_t)); icmp->destipaddr[6] = ipaddr[6] | HTONS(0xff00); icmp->destipaddr[7] = ipaddr[7]; /* Add out IPv6 address as the source address */ net_ipv6addr_copy(icmp->srcipaddr, dev->d_ipv6addr); /* Set up the ICMPv6 Neighbor Solicitation message */ sol = ICMPv6SOLICIT; sol->type = ICMPv6_NEIGHBOR_SOLICIT; /* Message type */ sol->code = 0; /* Message qualifier */ sol->flags[0] = 0; /* flags */ sol->flags[1] = 0; sol->flags[2] = 0; sol->flags[3] = 0; /* Copy the target address into the Neighbor Solicitation message */ net_ipv6addr_copy(sol->tgtaddr, ipaddr); /* Set up the options */ sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */ sol->optlen = 1; /* Option length = 1 octet */ /* Copy our link layer address into the message * REVISIT: What if the link layer is not Ethernet? */ memcpy(sol->srclladdr, &dev->d_mac, IFHWADDRLEN); /* Calculate the checksum over both the ICMP header and payload */ icmp->chksum = 0; icmp->chksum = ~icmpv6_chksum(dev); /* Set the size to the size of the IPv6 header and the payload size */ dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_neighbor_solicit_s); #ifdef CONFIG_NET_ETHERNET #ifdef CONFIG_NET_MULTILINK if (dev->d_lltype == NET_LL_ETHERNET) #endif { /* Set the destination IPv6 multicast Ethernet address: * * For IPv6 multicast addresses, the Ethernet MAC is derived by * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00, * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map * to the Ethernet MAC address 33:33:00:01:00:03. * * NOTES: This appears correct for the ICMPv6 Router Solicitation * Message, but the ICMPv6 Neighbor Solicitation message seems to * use 33:33:ff:01:00:03. */ eth = ETHBUF; eth->dest[0] = 0x33; eth->dest[1] = 0x33; eth->dest[2] = 0xff; eth->dest[3] = ipaddr[6] >> 8; eth->dest[4] = ipaddr[7] & 0xff; eth->dest[5] = ipaddr[7] >> 8; /* Move our source Ethernet addresses into the Ethernet header */ memcpy(eth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); /* Set the IPv6 Ethernet type */ eth->type = HTONS(ETHTYPE_IP6); #if 0 /* No additional neighbor lookup is required on this packet. * REVISIT: It is inappropriate to set this bit if we get here * via neighbor_out(); It is no necessary to set this bit if we * get here via icmpv6_input(). Is it ever necessary? */ IFF_SET_NOARP(dev->d_flags); #endif }
static uint16_t icmpv6_neighbor_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *priv, uint16_t flags) { FAR struct icmpv6_neighbor_s *state = (FAR struct icmpv6_neighbor_s *)priv; nllvdbg("flags: %04x sent: %d\n", flags, state->snd_sent); if (state) { #ifdef CONFIG_NETDEV_MULTINIC /* Is this the device that we need to route this request? */ if (strncmp((FAR const char *)dev->d_ifname, (FAR const char *)state->snd_ifname, IFNAMSIZ) != 0) { /* No... pass on this one and wait for the device that we want */ return flags; } #endif /* Check if the outgoing packet is available. It may have been claimed * by a send interrupt serving a different thread -OR- if the output * buffer currently contains unprocessed incoming data. In these cases * we will just have to wait for the next polling cycle. */ if (dev->d_sndlen > 0 || (flags & ICMPv6_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ /* REVISIT: No timeout. Just wait for the next polling cycle */ return flags; } /* It looks like we are good to send the data */ /* Copy the packet data into the device packet buffer and send it */ icmpv6_solicit(dev, state->snd_ipaddr); /* Make sure no additional Neighbor Solicitation overwrites this one. * This flag will be cleared in icmpv6_out(). */ IFF_SET_NOARP(dev->d_flags); /* Don't allow any further call backs. */ state->snd_sent = true; state->snd_cb->flags = 0; state->snd_cb->priv = NULL; state->snd_cb->event = NULL; /* Wake up the waiting thread */ sem_post(&state->snd_sem); } return flags; }
static uint16_t icmpv6_router_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *priv, uint16_t flags) { FAR struct icmpv6_router_s *state = (FAR struct icmpv6_router_s *)priv; ninfo("flags: %04x sent: %d\n", flags, state->snd_sent); if (state) { /* Check if the network is still up */ if ((flags & NETDEV_DOWN) != 0) { nerr("ERROR: Interface is down\n"); icmpv6_router_terminate(state, -ENETUNREACH); return flags; } /* Check if the outgoing packet is available. It may have been claimed * by a send interrupt serving a different thread -OR- if the output * buffer currently contains unprocessed incoming data. In these cases * we will just have to wait for the next polling cycle. */ else if (dev->d_sndlen > 0 || (flags & ICMPv6_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ /* REVISIT: No timeout. Just wait for the next polling cycle */ return flags; } /* It looks like we are good to send the data */ /* Copy the packet data into the device packet buffer and send it */ if (state->snd_advertise) { /* Send the ICMPv6 Neighbor Advertisement message */ icmpv6_advertise(dev, g_ipv6_allnodes); } else { /* Send the ICMPv6 Router Solicitation message */ icmpv6_rsolicit(dev); } /* Make sure no additional Router Solicitation overwrites this one. * This flag will be cleared in icmpv6_out(). */ IFF_SET_NOARP(dev->d_flags); /* Don't allow any further call backs. */ icmpv6_router_terminate(state, OK); } return flags; }