NDP(7P) | Protocols | NDP(7P) |
ndp
, NDP
—
#include <sys/socket.h>
#include <sys/sockio.h>
#include <netinet/in.h>
#include <net/if.h>
s = socket(PF_INET6, SOCK_DGRAM, 0); struct lifreq lifr; ioctl(s, SIOCLIFGETND, &lifr); ioctl(s, SIOCLIFSETND, &lifr); ioctl(s, SIOCLIFDELND, &lifr);
typedef struct lif_nd_req { struct sockaddr_storage lnr_addr; uint8_t lnr_state_create; uint8_t lnr_state_same_lla; uint8_t lnr_state_diff_lla; int lnr_hdw_len; int lnr_flags; int lnr_pad0; char lnr_hdw_addr[ND_MAX_HDW_LEN]; } lif_nd_req_t;
The lnr_addr field should be filled in with an IPv6 address (see sockaddr_in6(3SOCKET)), and the lnr_hdw_addr is the link-layer address of length lnr_hdw_len.
State flags for lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla can be set to one of the following values:
When creating a new entry, the only valid values for lnr_state_create are ND_REACHABLE and ND_STALE. Any other value will return EINVAL. The lnr_state_same_lla and lnr_state_diff_lla fields are reserved for future use and can be safely set to ND_UNCHANGED and ND_STALE respectively.
Flags that can be placed in lnr_flags are:
When using SIOCLIFGETND, these flags represent the current state of the corresponding Neighbor Cache Entry. When using SIOCLIFSETND, these flags represent what changes should be applied to the underlying entry.
The only fields that need to be set for the SIOCLIFGETND or SIOCLIFDELND ioctls are lifr_name and lnr_addr. All other fields should be zeroed out. After successfully getting an entry, the other fields will be filled in. When using SIOCLIFSETND, all fields should be set to an appropriate value, as described above, with the exception of lnr_pad0, which is unused and only exists for padding purposes.
After performing the ioctl, the following errors may be returned through the global errno variable:
$ gcc -Wall -lsocket -o get get.c $ cat get.c /* * Example of getting a mapping for a node name. */ #include <strings.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/sockio.h> #include <unistd.h> #include <netdb.h> #include <net/if.h> int get(char *host) { struct lifreq lifr; struct addrinfo hints, *serverinfo, *p; int err, s; bzero(&hints, sizeof (struct addrinfo)); hints.ai_family = PF_INET6; hints.ai_protocol = IPPROTO_IPV6; if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) { (void) fprintf(stderr, "Unable to lookup %s: %s\n", host, gai_strerror(err)); return (1); } s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { perror("Failed to open IPv6 socket"); return (1); } for (p = serverinfo; p != NULL; p = p->ai_next) { /* Zero out structure */ bzero(&lifr, sizeof (struct lifreq)); (void) strlcpy(lifr.lifr_name, "net0", sizeof (lifr.lifr_name)); (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr, sizeof (struct sockaddr_storage)); /* Get mapping */ if (ioctl(s, SIOCLIFGETND, &lifr) < 0) { perror("Unable to get NDP mapping"); continue; } /* * lifr.lifr_nd.lnr_hdw_addr now contains the MAC address, * and can be used as desired. */ } /* * Clean up linked list. */ freeaddrinfo(serverinfo); return (0); } int main(int argc, char *argv[]) { if (argc < 2) exit(1); return (get(argv[1])); }
Deleting a mapping would work similarly, except that instead of using SIOCLIFGETND, you would instead use the SIOCLIFDELND ioctl.
$ gcc -Wall -lsocket -o set set.c $ cat set.c /* * Example of setting a mapping to an all-zero Ethernet address. */ #include <strings.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/sockio.h> #include <unistd.h> #include <netdb.h> #include <net/if.h> int set(char *host) { struct lifreq lifr; struct addrinfo hints, *serverinfo, *p; int err, s; bzero(&hints, sizeof (struct addrinfo)); hints.ai_family = PF_INET6; hints.ai_protocol = IPPROTO_IPV6; if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) { (void) fprintf(stderr, "Unable to lookup %s: %s\n", host, gai_strerror(err)); return (1); } s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { perror("Failed to open IPv6 socket"); return (1); } for (p = serverinfo; p != NULL; p = p->ai_next) { /* Zero out structure */ bzero(&lifr, sizeof (struct lifreq)); (void) strlcpy(lifr.lifr_name, "net0", sizeof (lifr.lifr_name)); (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr, sizeof (struct sockaddr_storage)); lifr.lifr_nd.lnr_state_create = ND_REACHABLE; lifr.lifr_nd.lnr_flags = NDF_STATIC; /* Get mapping */ if (ioctl(s, SIOCLIFSETND, &lifr) < 0) { perror("Unable to set NDP mapping"); continue; } } /* * Clean up linked list. */ freeaddrinfo(serverinfo); return (0); } int main(int argc, char *argv[]) { if (argc < 2) exit(1); return (set(argv[1])); }
Narten, T., Nordmark, E., Simpson, W., and Soliman, H., RFC 4861, Neighbor Discovery for IP version 6, September 2007.
September 2, 2015 | OmniOS |