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