15
#include <util/binalign.h>
17
#include <net/l0/net_tx.h>
18
#include <net/l3/icmpv6.h>
19
#include <net/l3/ipv6.h>
20
#include <net/l2/ethernet.h>
21
#include <net/lib/icmpv6.h>
22
#include <net/lib/ipv6.h>
23
#include <net/inetdevice.h>
24
#include <net/netdevice.h>
25
#include <net/skbuff.h>
27
static int ndp_xmit(struct sk_buff *skb, struct net_device *dev) {
28
struct net_header_info hdr_info;
33
hdr_info.type = ETH_P_IPV6;
34
hdr_info.src_hw = dev->dev_addr;
35
hdr_info.dst_hw = dev->broadcast;
37
return net_tx(skb, &hdr_info);
40
int ndp_send(uint8_t type, uint8_t code, const void *body,
41
size_t body_sz, struct net_device *dev) {
43
struct in_device *in_dev;
44
struct in6_addr dst_ip6;
48
skb = skb_alloc(dev->hdr_len + IP6_HEADER_SIZE
49
+ ICMP6_MIN_HEADER_SIZE + body_sz);
55
skb->nh.raw = skb->mac.raw + dev->hdr_len;
56
skb->h.raw = skb->nh.raw + IP6_HEADER_SIZE;
58
in_dev = inetdev_get_by_dev(dev);
59
assert(in_dev != NULL);
61
inet_pton(AF_INET6, "ff02::1:ff02:10", &dst_ip6);
62
ip6_build(skb->nh.ip6h, ICMP6_MIN_HEADER_SIZE + body_sz,
63
IPPROTO_ICMPV6, 255, &in_dev->ifa6_address, &dst_ip6);
65
icmp6_build(skb->h.icmp6h, type, code, body, body_sz);
66
icmp6_set_check_field(skb->h.icmp6h, skb->nh.ip6h);
68
return ndp_xmit(skb, dev);
71
int ndp_discover(struct net_device *dev, const void *tpa) {
73
#pragma clang diagnostic push
74
#pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
77
struct ndpbody_neighbor_solicit body;
78
struct ndpoptions_ll_addr ops;
79
char __ops_ll_addr_storage[MAX_ADDR_LEN];
80
} __attribute__((packed)) nbr_solicit;
82
#pragma clang diagnostic pop
85
nbr_solicit.body.zero = 0;
86
memcpy(&nbr_solicit.body.target, tpa, sizeof(nbr_solicit.body.target));
87
nbr_solicit.ops.hdr.type = NDP_SOURCE_LL_ADDR;
88
nbr_solicit.ops.hdr.len =
89
binalign_bound(sizeof nbr_solicit.ops + dev->addr_len, 8) / 8;
90
memcpy(nbr_solicit.ops.ll_addr, &dev->dev_addr[0], dev->addr_len);
92
return ndp_send(NDP_NEIGHBOR_SOLICIT, 0, &nbr_solicit,
93
sizeof(nbr_solicit.body) + sizeof(nbr_solicit.ops) + dev->addr_len, dev);