1.\" 2.\" This file and its contents are supplied under the terms of the 3.\" Common Development and Distribution License ("CDDL"), version 1.0. 4.\" You may only use this file in accordance with the terms of version 5.\" 1.0 of the CDDL. 6.\" 7.\" A full copy of the text of the CDDL should have accompanied this 8.\" source. A copy of the CDDL is also available via the Internet at 9.\" http://www.illumos.org/license/CDDL. 10.\" 11.\" 12.\" Copyright (c) 2015, Joyent, Inc. All rights reserved. 13.\" 14.Dd Sep 02, 2015 15.Dt NDP 7P 16.Os 17.Sh NAME 18.Nm ndp , 19.Nm NDP 20.Nd Neighbor Discovery Protocol 21.Sh SYNOPSIS 22.In sys/socket.h 23.In sys/sockio.h 24.In netinet/in.h 25.In net/if.h 26.Bd -literal 27s = socket(PF_INET6, SOCK_DGRAM, 0); 28 29struct lifreq lifr; 30ioctl(s, SIOCLIFGETND, &lifr); 31ioctl(s, SIOCLIFSETND, &lifr); 32ioctl(s, SIOCLIFDELND, &lifr); 33.Ed 34.Sh DESCRIPTION 35The Neighbor Discovery Protocol (NDP) is a protocol used to distribute and request 36information about neighboring IPv6 systems on the local network, much like 37.Xr ARP 7P 38for IPv4. NDP is also responsible for spreading information about the network 39gateway and how hosts should configure themselves 40.Pq see Xr in.ndpd 1M for more on how this happens . 41.Sh APPLICATION PROGRAMMING INTERFACE 42The operating system provides several ioctls to help manipulate the mappings 43obtained through NDP. They are 44.Sy SIOCLIFGETND , 45.Sy SIOCLIFSETND , 46and 47.Sy SIOCLIFDELND , 48for getting, setting, and deleting respectively. Each of these ioctls takes a 49.Vt struct lifreq 50.Pq see Xr if 7P for details , 51where the 52.Fa lifr_lifru 53field is of type 54.Vt struct lif_nd_req : 55.Bd -literal -offset 2m 56typedef struct lif_nd_req { 57 struct sockaddr_storage lnr_addr; 58 uint8_t lnr_state_create; 59 uint8_t lnr_state_same_lla; 60 uint8_t lnr_state_diff_lla; 61 int lnr_hdw_len; 62 int lnr_flags; 63 int lnr_pad0; 64 char lnr_hdw_addr[ND_MAX_HDW_LEN]; 65} lif_nd_req_t; 66.Ed 67.Pp 68The 69.Fa lnr_addr 70field should be filled in with an IPv6 address 71.Pq see Xr sockaddr_in6 3SOCKET , 72and the 73.Fa lnr_hdw_addr 74is the link-layer address of length 75.Fa lnr_hdw_len . 76.Pp 77State flags for 78.Fa lnr_state_create , 79.Fa lnr_state_same_lla , 80and 81.Fa lnr_state_diff_lla 82can be set to one of the following values: 83.Bl -tag -offset indent -width 16m 84.It Sy ND_UNCHANGED 85For ioctls that don't modify state 86.It Sy ND_INCOMPLETE 87Address resolution is currently in progress 88.It Sy ND_REACHABLE 89The link-layer address has recently been reachable 90.It Sy ND_STALE 91The link-layer address may be unreachable, and the system shouldn't do anything 92.It Sy ND_DELAY 93This entry hasn't yet started sending Neighbor Solicitations 94.It Sy ND_PROBE 95The operating system is currently sending out Neighbor Solicitations for the address 96.It Sy ND_UNREACHABLE 97The link-layer address is unreachable, and this entry is going to be deleted. 98.El 99.sp 100When creating a new entry, the only valid values for 101.Fa lnr_state_create 102are 103.Sy ND_REACHABLE 104and 105.Sy ND_STALE . 106Any other value will return 107.Sy EINVAL . 108The 109.Fa lnr_state_same_lla 110and 111.Fa lnr_state_diff_lla 112fields are reserved for future use and can be safely set to 113.Sy ND_UNCHANGED 114and 115.Sy ND_STALE 116respectively. 117.Pp 118Flags that can be placed in 119.Fa lnr_flags 120are: 121.Bl -tag -offset indent -width 16m 122.It Sy NDF_ISROUTER_ON 123Mark this entry as being a router. This will cause Neighbor Advertisements for 124this address to be sent with the R-bit (Router). 125.It Sy NDF_ISROUTER_OFF 126If this entry was flagged as being a router, remove the flag. 127.It Sy NDF_ANYCAST_ON 128Mark this entry as being for an anycast address. This prevents sending Neighbor 129Advertisements with the O-bit (Override). 130.It Sy NDF_ANYCAST_OFF 131If this entry was flagged as an anycast address, remove the flag. 132.It Sy NDF_STATIC 133Prevent this entry from being deleted by the system. 134.El 135.sp 136When using 137.Sy SIOCLIFGETND , 138these flags represent the current state of the corresponding Neighbor Cache 139Entry. When using 140.Sy SIOCLIFSETND , 141these flags represent what changes should be applied to the underlying entry. 142.Pp 143The only fields that need to be set for the 144.Sy SIOCLIFGETND 145or 146.Sy SIOCLIFDELND 147ioctls are 148.Fa lifr_name 149and 150.Fa lnr_addr . 151All other fields should be zeroed out. After successfully getting an entry, the 152other fields will be filled in. When using 153.Sy SIOCLIFSETND , 154all fields should be set to an appropriate value, as described above, with the 155exception of 156.Fa lnr_pad0 , 157which is unused and only exists for padding purposes. 158.Pp 159After performing the ioctl, the following errors may be returned through the 160global 161.Sy errno 162variable: 163.Bl -tag -offset indent -width 16m 164.It Sy EAFNOSUPPORT 165A non-IPv6 socket was used to perform the ioctl. 166.It Sy EINVAL 167The request contents were bad. This could be because conflicting flags were 168used, the specified interface wasn't logical unit zero, or another reason. 169.It Sy ENOMEM 170The system ran out of memory for internal data structures. 171.It Sy ENXIO 172The specified interface does not exist. 173.It Sy EPERM 174The caller does not have permission to modify the Neighbor Cache Entries 175associated with this interface. They may be lacking the 176.Sy PRIV_SYS_NET_CONFIG 177privilege 178.Po see Xr privileges 5 Pc , 179or the interface is managed by IPMP (IP Network Multipathing). 180.It Sy ESRCH 181There is no entry matching the specified address. 182.El 183.Sh EXAMPLES 184The following examples demonstrate how to get and set NDP mappings using the 185provided ioctls. They can be compiled by using a C compiler and linking against 186the sockets library. 187.Ss Example 1: Getting a mapping 188.Bd -literal -offset indent 189$ gcc -Wall -lsocket -o get get.c 190$ cat get.c 191/* 192 * Example of getting a mapping for a node name. 193 */ 194#include <strings.h> 195#include <stdio.h> 196#include <stdlib.h> 197#include <sys/socket.h> 198#include <sys/sockio.h> 199#include <unistd.h> 200#include <netdb.h> 201#include <net/if.h> 202 203int get(char *host) { 204 struct lifreq lifr; 205 struct addrinfo hints, *serverinfo, *p; 206 int err, s; 207 208 bzero(&hints, sizeof (struct addrinfo)); 209 hints.ai_family = PF_INET6; 210 hints.ai_protocol = IPPROTO_IPV6; 211 212 if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) { 213 (void) fprintf(stderr, "Unable to lookup %s: %s\\n", host, 214 gai_strerror(err)); 215 return (1); 216 } 217 218 s = socket(AF_INET6, SOCK_DGRAM, 0); 219 if (s < 0) { 220 perror("Failed to open IPv6 socket"); 221 return (1); 222 } 223 224 for (p = serverinfo; p != NULL; p = p->ai_next) { 225 /* Zero out structure */ 226 bzero(&lifr, sizeof (struct lifreq)); 227 (void) strlcpy(lifr.lifr_name, "net0", 228 sizeof (lifr.lifr_name)); 229 (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr, 230 sizeof (struct sockaddr_storage)); 231 232 /* Get mapping */ 233 if (ioctl(s, SIOCLIFGETND, &lifr) < 0) { 234 perror("Unable to get NDP mapping"); 235 continue; 236 } 237 238 /* 239 * lifr.lifr_nd.lnr_hdw_addr now contains the MAC address, 240 * and can be used as desired. 241 */ 242 } 243 244 /* 245 * Clean up linked list. 246 */ 247 freeaddrinfo(serverinfo); 248 return (0); 249} 250 251int main(int argc, char *argv[]) { 252 if (argc < 2) 253 exit(1); 254 return (get(argv[1])); 255} 256.Ed 257.sp 258Deleting a mapping would work similarly, except that instead of using 259.Sy SIOCLIFGETND , 260you would instead use the 261.Sy SIOCLIFDELND 262ioctl. 263.Ss Example 2: Adding a mapping 264.Bd -literal -offset indent 265$ gcc -Wall -lsocket -o set set.c 266$ cat set.c 267/* 268 * Example of setting a mapping to an all-zero Ethernet address. 269 */ 270#include <strings.h> 271#include <stdio.h> 272#include <stdlib.h> 273#include <sys/socket.h> 274#include <sys/sockio.h> 275#include <unistd.h> 276#include <netdb.h> 277#include <net/if.h> 278 279int set(char *host) { 280 struct lifreq lifr; 281 struct addrinfo hints, *serverinfo, *p; 282 int err, s; 283 284 bzero(&hints, sizeof (struct addrinfo)); 285 hints.ai_family = PF_INET6; 286 hints.ai_protocol = IPPROTO_IPV6; 287 288 if ((err = getaddrinfo(host, NULL, &hints, &serverinfo)) != 0) { 289 (void) fprintf(stderr, "Unable to lookup %s: %s\\n", host, 290 gai_strerror(err)); 291 return (1); 292 } 293 294 s = socket(AF_INET6, SOCK_DGRAM, 0); 295 if (s < 0) { 296 perror("Failed to open IPv6 socket"); 297 return (1); 298 } 299 300 for (p = serverinfo; p != NULL; p = p->ai_next) { 301 /* Zero out structure */ 302 bzero(&lifr, sizeof (struct lifreq)); 303 (void) strlcpy(lifr.lifr_name, "net0", 304 sizeof (lifr.lifr_name)); 305 (void) memcpy(&lifr.lifr_nd.lnr_addr, p->ai_addr, 306 sizeof (struct sockaddr_storage)); 307 308 lifr.lifr_nd.lnr_state_create = ND_REACHABLE; 309 lifr.lifr_nd.lnr_flags = NDF_STATIC; 310 311 /* Get mapping */ 312 if (ioctl(s, SIOCLIFSETND, &lifr) < 0) { 313 perror("Unable to set NDP mapping"); 314 continue; 315 } 316 } 317 318 /* 319 * Clean up linked list. 320 */ 321 freeaddrinfo(serverinfo); 322 return (0); 323} 324 325int main(int argc, char *argv[]) { 326 if (argc < 2) 327 exit(1); 328 return (set(argv[1])); 329} 330.Ed 331.Sh SEE ALSO 332.Xr in.ndpd 1M , 333.Xr ndp 1M , 334.Xr ifconfig 1M , 335.Xr sockaddr_in6 3SOCKET , 336.Xr privileges 5 337.Rs 338.%A Narten, T. 339.%A Nordmark, E. 340.%A Simpson, W. 341.%A Soliman, H. 342.%R Neighbor Discovery for IP version 6 343.%T RFC 4861 344.%D September 2007 345.Re 346