Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libipadm/common/ipadm_ndpd.c
+++ new/usr/src/lib/libipadm/common/ipadm_ndpd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 /*
26 26 * This file contains the functions that are required for communicating
27 27 * with in.ndpd while creating autoconfigured addresses.
28 28 */
29 29
30 30 #include <stdio.h>
31 31 #include <stdlib.h>
32 32 #include <string.h>
33 33 #include <strings.h>
34 34 #include <errno.h>
35 35 #include <fcntl.h>
36 36 #include <unistd.h>
37 37 #include <sys/sockio.h>
38 38 #include <sys/types.h>
39 39 #include <sys/stat.h>
40 40 #include <sys/socket.h>
41 41 #include <netinet/in.h>
42 42 #include <inet/ip.h>
43 43 #include <arpa/inet.h>
44 44 #include <assert.h>
45 45 #include <poll.h>
46 46 #include <ipadm_ndpd.h>
47 47 #include "libipadm_impl.h"
48 48
49 49 #define NDPDTIMEOUT 5000
50 50 #define PREFIXLEN_LINKLOCAL 10
51 51
52 52 static ipadm_status_t i_ipadm_create_linklocal(ipadm_handle_t,
53 53 ipadm_addrobj_t);
54 54 static void i_ipadm_make_linklocal(struct sockaddr_in6 *,
55 55 const struct in6_addr *);
56 56 static ipadm_status_t i_ipadm_send_ndpd_cmd(const char *,
57 57 const struct ipadm_addrobj_s *, int);
58 58
59 59 /*
60 60 * Sends message to in.ndpd asking not to do autoconf for the given interface,
61 61 * until IPADM_CREATE_ADDRS or IPADM_ENABLE_AUTOCONF is sent.
62 62 */
63 63 ipadm_status_t
64 64 i_ipadm_disable_autoconf(const char *ifname)
65 65 {
66 66 return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_DISABLE_AUTOCONF));
67 67 }
68 68
69 69 /*
70 70 * Sends message to in.ndpd to enable autoconf for the given interface,
71 71 * until another IPADM_DISABLE_AUTOCONF is sent.
72 72 */
73 73 ipadm_status_t
74 74 i_ipadm_enable_autoconf(const char *ifname)
75 75 {
76 76 return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_ENABLE_AUTOCONF));
77 77 }
78 78
79 79 ipadm_status_t
80 80 i_ipadm_create_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t addr,
81 81 uint32_t i_flags)
82 82 {
83 83 ipadm_status_t status;
84 84
85 85 /*
86 86 * Create the link local based on the given token. If the same intfid
87 87 * was already used with a different address object, this step will
88 88 * fail.
89 89 */
90 90 status = i_ipadm_create_linklocal(iph, addr);
91 91 if (status != IPADM_SUCCESS)
92 92 return (status);
93 93
94 94 /*
95 95 * Request in.ndpd to start the autoconfiguration.
96 96 * If autoconfiguration was already started by another means (e.g.
97 97 * "ifconfig" ), in.ndpd will return EEXIST.
98 98 */
99 99 if (addr->ipadm_stateless || addr->ipadm_stateful) {
|
↓ open down ↓ |
99 lines elided |
↑ open up ↑ |
100 100 status = i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
101 101 IPADM_CREATE_ADDRS);
102 102 if (status != IPADM_SUCCESS &&
103 103 status != IPADM_NDPD_NOT_RUNNING) {
104 104 (void) i_ipadm_delete_addr(iph, addr);
105 105 return (status);
106 106 }
107 107 }
108 108
109 109 /* Persist the intfid. */
110 - status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags);
110 + status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags, NULL);
111 111 if (status != IPADM_SUCCESS) {
112 112 (void) i_ipadm_delete_addr(iph, addr);
113 113 (void) i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
114 114 IPADM_DELETE_ADDRS);
115 115 }
116 116
117 117 return (status);
118 118 }
119 119
120 120 ipadm_status_t
121 121 i_ipadm_delete_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
122 122 {
123 123 ipadm_status_t status;
124 124
125 125 /*
126 126 * Send a msg to in.ndpd to remove the autoconfigured addresses,
127 127 * and delete the link local that was created.
128 128 */
129 129 status = i_ipadm_send_ndpd_cmd(ipaddr->ipadm_ifname, ipaddr,
130 130 IPADM_DELETE_ADDRS);
131 131 if (status == IPADM_NDPD_NOT_RUNNING)
132 132 status = IPADM_SUCCESS;
133 133 if (status == IPADM_SUCCESS)
134 134 status = i_ipadm_delete_addr(iph, ipaddr);
135 135
136 136 return (status);
137 137 }
138 138
139 139 static ipadm_status_t
140 140 i_ipadm_create_linklocal(ipadm_handle_t iph, ipadm_addrobj_t addr)
141 141 {
142 142 boolean_t addif = B_FALSE;
143 143 struct sockaddr_in6 *sin6;
144 144 struct lifreq lifr;
145 145 int err;
146 146 ipadm_status_t status;
147 147 in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
148 148 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
149 149
150 150 /*
151 151 * Create a logical interface if needed.
152 152 */
153 153 retry:
154 154 status = i_ipadm_do_addif(iph, addr);
155 155 if (status != IPADM_SUCCESS)
156 156 return (status);
157 157 if (!(iph->iph_flags & IPH_INIT)) {
158 158 status = i_ipadm_setlifnum_addrobj(iph, addr);
159 159 if (status == IPADM_ADDROBJ_EXISTS)
160 160 goto retry;
161 161 if (status != IPADM_SUCCESS)
162 162 return (status);
163 163 }
164 164
165 165 bzero(&lifr, sizeof (lifr));
166 166 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, LIFNAMSIZ);
167 167 i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
168 168 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
169 169
170 170 /* Create the link-local address */
171 171 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
172 172 (void) plen2mask(PREFIXLEN_LINKLOCAL, AF_INET6,
173 173 (struct sockaddr *)&lifr.lifr_addr);
174 174 if ((err = ioctl(iph->iph_sock6, SIOCSLIFNETMASK, (caddr_t)&lifr)) < 0)
175 175 goto fail;
176 176 if (addr->ipadm_intfidlen == 0) {
177 177 /*
178 178 * If we have to use the default interface id,
179 179 * we just need to set the prefix to the link-local prefix.
180 180 * SIOCSLIFPREFIX sets the address with the given prefix
181 181 * and the default interface id.
182 182 */
183 183 sin6->sin6_addr = ll_template;
184 184 err = ioctl(iph->iph_sock6, SIOCSLIFPREFIX, (caddr_t)&lifr);
185 185 if (err < 0)
186 186 goto fail;
187 187 } else {
188 188 /* Make a linklocal address in sin6 and set it */
189 189 i_ipadm_make_linklocal(sin6, &addr->ipadm_intfid.sin6_addr);
190 190 err = ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr);
191 191 if (err < 0)
192 192 goto fail;
193 193 }
194 194 if ((err = ioctl(iph->iph_sock6, SIOCGLIFFLAGS, (char *)&lifr)) < 0)
195 195 goto fail;
196 196 lifr.lifr_flags |= IFF_UP;
197 197 if ((err = ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (char *)&lifr)) < 0)
198 198 goto fail;
199 199 return (IPADM_SUCCESS);
200 200
201 201 fail:
202 202 if (errno == EEXIST)
203 203 status = IPADM_ADDRCONF_EXISTS;
204 204 else
205 205 status = ipadm_errno2status(errno);
206 206 /* Remove the linklocal that was created. */
207 207 if (addif) {
208 208 (void) ioctl(iph->iph_sock6, SIOCLIFREMOVEIF, (caddr_t)&lifr);
209 209 } else {
210 210 struct sockaddr_in6 *sin6;
211 211
212 212 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
213 213 lifr.lifr_flags &= ~IFF_UP;
214 214 (void) ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (caddr_t)&lifr);
215 215 sin6->sin6_family = AF_INET6;
216 216 sin6->sin6_addr = in6addr_any;
217 217 (void) ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr);
218 218 }
219 219 return (status);
220 220 }
221 221
222 222 /*
223 223 * Make a linklocal address based on the given intfid and copy it into
224 224 * the output parameter `sin6'.
225 225 */
226 226 static void
227 227 i_ipadm_make_linklocal(struct sockaddr_in6 *sin6, const struct in6_addr *intfid)
228 228 {
229 229 int i;
230 230 in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
231 231 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
232 232
233 233 sin6->sin6_family = AF_INET6;
234 234 sin6->sin6_addr = *intfid;
235 235 for (i = 0; i < 4; i++) {
236 236 sin6->sin6_addr.s6_addr[i] =
237 237 sin6->sin6_addr.s6_addr[i] | ll_template.s6_addr[i];
238 238 }
239 239 }
240 240
241 241 /*
242 242 * Function that forms an ndpd msg and sends it to the in.ndpd daemon's loopback
243 243 * listener socket.
244 244 */
245 245 static ipadm_status_t
246 246 i_ipadm_send_ndpd_cmd(const char *ifname, const struct ipadm_addrobj_s *addr,
247 247 int cmd)
248 248 {
249 249 int fd;
250 250 struct sockaddr_un servaddr;
251 251 int flags;
252 252 ipadm_ndpd_msg_t msg;
253 253 int retval;
254 254
255 255 if (addr == NULL &&
256 256 (cmd == IPADM_CREATE_ADDRS || cmd == IPADM_DELETE_ADDRS)) {
257 257 return (IPADM_INVALID_ARG);
258 258 }
259 259
260 260 fd = socket(AF_UNIX, SOCK_STREAM, 0);
261 261 if (fd == -1)
262 262 return (IPADM_FAILURE);
263 263
264 264 /* Put the socket in non-blocking mode */
265 265 flags = fcntl(fd, F_GETFL, 0);
266 266 if (flags != -1)
267 267 (void) fcntl(fd, F_SETFL, flags | O_NONBLOCK);
268 268
269 269 /* Connect to in.ndpd */
270 270 bzero(&servaddr, sizeof (servaddr));
271 271 servaddr.sun_family = AF_UNIX;
272 272 (void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH,
273 273 sizeof (servaddr.sun_path));
274 274 if (connect(fd, (struct sockaddr *)&servaddr, sizeof (servaddr)) == -1)
275 275 goto fail;
276 276
277 277 bzero(&msg, sizeof (msg));
278 278 msg.inm_cmd = cmd;
279 279 (void) strlcpy(msg.inm_ifname, ifname, sizeof (msg.inm_ifname));
280 280 if (addr != NULL) {
281 281 msg.inm_intfid = addr->ipadm_intfid;
282 282 msg.inm_intfidlen = addr->ipadm_intfidlen;
283 283 msg.inm_stateless = addr->ipadm_stateless;
284 284 msg.inm_stateful = addr->ipadm_stateful;
285 285 if (cmd == IPADM_CREATE_ADDRS) {
286 286 (void) strlcpy(msg.inm_aobjname, addr->ipadm_aobjname,
287 287 sizeof (msg.inm_aobjname));
288 288 }
289 289 }
290 290 if (ipadm_ndpd_write(fd, &msg, sizeof (msg)) < 0)
291 291 goto fail;
292 292 if (ipadm_ndpd_read(fd, &retval, sizeof (retval)) < 0)
293 293 goto fail;
294 294 (void) close(fd);
295 295 if (cmd == IPADM_CREATE_ADDRS && retval == EEXIST)
296 296 return (IPADM_ADDRCONF_EXISTS);
297 297 return (ipadm_errno2status(retval));
298 298 fail:
299 299 (void) close(fd);
300 300 return (IPADM_NDPD_NOT_RUNNING);
301 301 }
302 302
303 303 /*
304 304 * Attempt to read `buflen' worth of bytes from `fd' into the buffer pointed
305 305 * to by `buf'.
306 306 */
307 307 int
308 308 ipadm_ndpd_read(int fd, void *buffer, size_t buflen)
309 309 {
310 310 int retval;
311 311 ssize_t nbytes = 0; /* total bytes processed */
312 312 ssize_t prbytes; /* per-round bytes processed */
313 313 struct pollfd pfd;
314 314
315 315 while (nbytes < buflen) {
316 316
317 317 pfd.fd = fd;
318 318 pfd.events = POLLIN;
319 319
320 320 /*
321 321 * Wait for data to come in or for the timeout to fire.
322 322 */
323 323 retval = poll(&pfd, 1, NDPDTIMEOUT);
324 324 if (retval <= 0) {
325 325 if (retval == 0)
326 326 errno = ETIME;
327 327 break;
328 328 }
329 329
330 330 /*
331 331 * Descriptor is ready; have at it.
332 332 */
333 333 prbytes = read(fd, (caddr_t)buffer + nbytes, buflen - nbytes);
334 334 if (prbytes <= 0) {
335 335 if (prbytes == -1 && errno == EINTR)
336 336 continue;
337 337 break;
338 338 }
339 339 nbytes += prbytes;
340 340 }
341 341
342 342 return (nbytes == buflen ? 0 : -1);
343 343 }
344 344
345 345 /*
346 346 * Write `buflen' bytes from `buffer' to open file `fd'. Returns 0
347 347 * if all requested bytes were written, or an error code if not.
348 348 */
349 349 int
350 350 ipadm_ndpd_write(int fd, const void *buffer, size_t buflen)
351 351 {
352 352 size_t nwritten;
353 353 ssize_t nbytes;
354 354 const char *buf = buffer;
355 355
356 356 for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
357 357 nbytes = write(fd, &buf[nwritten], buflen - nwritten);
358 358 if (nbytes == -1)
359 359 return (-1);
360 360 if (nbytes == 0) {
361 361 errno = EIO;
362 362 return (-1);
363 363 }
364 364 }
365 365
366 366 assert(nwritten == buflen);
367 367 return (0);
368 368 }
|
↓ open down ↓ |
248 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX