dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rcm_daemon / common / ip_anon_rcm.c
blob3ccf02590c4499638325ff5400437a4ab8b4d662
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * RCM module to prevent plumbed IP addresses from being removed.
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <memory.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <thread.h>
38 #include <synch.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <libintl.h>
42 #include <sys/param.h>
43 #include <sys/wait.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/file.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/time.h>
51 #include <net/if.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <netinet/ip6.h>
55 #include <inet/ip.h>
56 #include <inet/ip6.h>
57 #include <libinetutil.h>
59 #include "rcm_module.h"
61 #define SUNW_IP "SUNW_ip/"
62 #define IP_REG_SIZE (9 + INET6_ADDRSTRLEN)
63 #define IP_ANON_USAGE gettext("Plumbed IP Address")
64 #define IP_SUSPEND_ERR gettext("Plumbed IP Addresses cannot be suspended")
65 #define IP_OFFLINE_ERR gettext("Invalid operation: IP cannot be offlined")
66 #define IP_REMOVE_ERR gettext("Invalid operation: IP cannot be removed")
67 #define IP_REG_FAIL gettext("Registration Failed")
69 #define IP_FLAG_NEW 0x00
70 #define IP_FLAG_REG 0x01
71 #define IP_FLAG_CL 0x02
72 #define IP_FLAG_IGNORE 0x04
73 #define IP_FLAG_DELETE 0x08
75 static int ip_anon_register(rcm_handle_t *);
76 static int ip_anon_unregister(rcm_handle_t *);
77 static int ip_anon_getinfo(rcm_handle_t *, char *, id_t, uint_t,
78 char **, char **, nvlist_t *, rcm_info_t **);
79 static int ip_anon_suspend(rcm_handle_t *, char *, id_t,
80 timespec_t *, uint_t, char **, rcm_info_t **);
81 static int ip_anon_resume(rcm_handle_t *, char *, id_t, uint_t,
82 char **, rcm_info_t **);
83 static int ip_anon_offline(rcm_handle_t *, char *, id_t, uint_t,
84 char **, rcm_info_t **);
85 static int ip_anon_online(rcm_handle_t *, char *, id_t, uint_t,
86 char **, rcm_info_t **);
87 static int ip_anon_remove(rcm_handle_t *, char *, id_t, uint_t,
88 char **, rcm_info_t **);
90 typedef struct ip_status {
91 int flags;
92 char device[IP_REG_SIZE];
93 struct ip_status *next;
94 } ip_status_t;
96 static ip_status_t *findreg(char *reg);
97 static ip_status_t *addreg(char *reg);
98 static int deletereg(ip_status_t *entry);
100 static ip_status_t *ip_list = NULL;
101 static mutex_t ip_list_lock;
103 static struct rcm_mod_ops ip_anon_ops =
105 RCM_MOD_OPS_VERSION,
106 ip_anon_register,
107 ip_anon_unregister,
108 ip_anon_getinfo,
109 ip_anon_suspend,
110 ip_anon_resume,
111 ip_anon_offline,
112 ip_anon_online,
113 ip_anon_remove,
114 NULL,
115 NULL,
116 NULL
119 struct rcm_mod_ops *
120 rcm_mod_init()
122 return (&ip_anon_ops);
125 const char *
126 rcm_mod_info()
128 return ("RCM IP address module 1.4");
132 rcm_mod_fini()
134 ip_status_t *tlist;
136 /* free the registration list */
138 (void) mutex_lock(&ip_list_lock);
139 while (ip_list != NULL) {
140 tlist = ip_list->next;
141 free(ip_list);
142 ip_list = tlist;
144 (void) mutex_unlock(&ip_list_lock);
146 (void) mutex_destroy(&ip_list_lock);
147 return (RCM_SUCCESS);
150 static int
151 ip_anon_register(rcm_handle_t *hdl)
153 struct ifaddrlist *al = NULL, *al6 = NULL;
154 char errbuf[ERRBUFSIZE];
155 char treg[IP_REG_SIZE], tstr[IP_REG_SIZE];
156 int num_ifs, num_ifs6, i;
157 ip_status_t *tlist, *tentry;
159 (void) mutex_lock(&ip_list_lock);
161 rcm_log_message(RCM_DEBUG, "ip_anon: registration refresh.\n");
163 /* obtain a list of all IPv4 and IPv6 addresses in the system */
165 rcm_log_message(RCM_DEBUG,
166 "ip_anon: obtaining list of IPv4 addresses.\n");
167 num_ifs = ifaddrlist(&al, AF_INET, LIFC_UNDER_IPMP, errbuf);
168 if (num_ifs == -1) {
169 rcm_log_message(RCM_ERROR,
170 gettext("cannot get IPv4 address list errno=%d (%s)\n"),
171 errno, errbuf);
172 (void) mutex_unlock(&ip_list_lock);
173 return (RCM_FAILURE);
176 rcm_log_message(RCM_DEBUG,
177 "ip_anon: obtaining list of IPv6 addresses.\n");
179 num_ifs6 = ifaddrlist(&al6, AF_INET6, LIFC_UNDER_IPMP, errbuf);
180 if (num_ifs6 == -1) {
181 rcm_log_message(RCM_ERROR,
182 gettext("cannot get IPv6 address list errno=%d (%s)\n"),
183 errno, errbuf);
184 free(al);
185 (void) mutex_unlock(&ip_list_lock);
186 return (RCM_FAILURE);
189 /* check the state of outstanding registrations against the list */
191 rcm_log_message(RCM_DEBUG,
192 "ip_anon: checking outstanding registrations.\n");
194 tlist = ip_list;
195 while (tlist != NULL) {
196 tlist->flags |= IP_FLAG_DELETE;
197 tlist = tlist->next;
200 /* IPv4 */
202 rcm_log_message(RCM_DEBUG, "ip_anon: checking IPv4 addresses.\n");
204 for (i = 0; i < num_ifs; i++) {
205 (void) inet_ntop(AF_INET, &al[i].addr.addr, tstr,
206 INET_ADDRSTRLEN);
207 (void) strcpy(treg, SUNW_IP);
208 (void) strcat(treg, tstr);
210 if ((tlist = findreg(treg)) == NULL)
211 tlist = addreg(treg);
212 else
213 tlist->flags &= (~IP_FLAG_DELETE);
215 if (tlist == NULL) {
216 rcm_log_message(RCM_ERROR,
217 gettext("out of memory\n"));
218 free(al);
219 free(al6);
220 (void) mutex_unlock(&ip_list_lock);
221 return (RCM_FAILURE);
225 /* IPv6 */
227 rcm_log_message(RCM_DEBUG, "ip_anon: checking IPv6 addresses.\n");
229 for (i = 0; i < num_ifs6; i++) {
230 (void) inet_ntop(AF_INET6, &al6[i].addr.addr, tstr,
231 INET6_ADDRSTRLEN);
232 (void) strcpy(treg, SUNW_IP);
233 (void) strcat(treg, tstr);
235 if ((tlist = findreg(treg)) == NULL)
236 tlist = addreg(treg);
237 else
238 tlist->flags &= (~IP_FLAG_DELETE);
240 if (tlist == NULL) {
241 rcm_log_message(RCM_ERROR,
242 gettext("out of memory\n"));
243 free(al);
244 free(al6);
245 (void) mutex_unlock(&ip_list_lock);
246 return (RCM_FAILURE);
250 rcm_log_message(RCM_DEBUG, "ip_anon: updating reg. state.\n");
252 /* examine the list of ip address registrations and their state */
254 tlist = ip_list;
255 while (tlist != NULL) {
256 tentry = tlist;
257 tlist = tlist->next;
259 if (tentry->flags & IP_FLAG_DELETE) {
260 if (tentry->flags & IP_FLAG_REG) {
261 rcm_log_message(RCM_DEBUG,
262 "ip_anon: unregistering interest in %s\n",
263 tentry->device);
264 if (rcm_unregister_interest(hdl,
265 tentry->device, 0) != 0) {
266 rcm_log_message(RCM_ERROR,
267 gettext("failed to unregister"));
270 (void) deletereg(tentry);
271 } else if (!(tentry->flags & IP_FLAG_IGNORE)) {
273 * If the registration is not a clustered devices and
274 * not already registered, then RCM doesn't
275 * currently know about it.
277 if (!(tentry->flags & IP_FLAG_CL) &&
278 !(tentry->flags & IP_FLAG_REG)) {
279 tentry->flags |= IP_FLAG_REG;
280 rcm_log_message(RCM_DEBUG,
281 "ip_anon: registering interest in %s\n",
282 tentry->device);
283 if (rcm_register_interest(hdl,
284 tentry->device, 0, NULL) !=
285 RCM_SUCCESS) {
286 rcm_log_message(RCM_ERROR,
287 IP_REG_FAIL);
288 free(al);
289 free(al6);
290 (void) mutex_unlock(&ip_list_lock);
291 return (RCM_FAILURE);
292 } else {
293 rcm_log_message(RCM_DEBUG,
294 "ip_anon: registered %s\n",
295 tentry->device);
300 * If the entry is registered and clustered, then
301 * the configuration has been changed and it
302 * should be unregistered.
304 if ((tentry->flags & IP_FLAG_REG) &
305 (tentry->flags & IP_FLAG_CL)) {
306 rcm_log_message(RCM_DEBUG,
307 "ip_anon: unregistering in %s\n",
308 tentry->device);
309 if (rcm_unregister_interest(hdl,
310 tentry->device, 0) != 0) {
311 rcm_log_message(RCM_ERROR,
312 gettext("failed to unregister"));
314 tentry->flags &= (~IP_FLAG_REG);
319 tlist = ip_list;
320 while (tlist != NULL) {
321 rcm_log_message(RCM_DEBUG, "ip_anon: %s (%Xh)\n",
322 tlist->device, tlist->flags);
323 tlist = tlist->next;
325 rcm_log_message(RCM_DEBUG, "ip_anon: registration complete.\n");
327 free(al);
328 free(al6);
329 (void) mutex_unlock(&ip_list_lock);
330 return (RCM_SUCCESS);
333 static int
334 ip_anon_unregister(rcm_handle_t *hdl)
336 ip_status_t *tlist;
338 (void) mutex_lock(&ip_list_lock);
340 tlist = ip_list;
341 while (tlist != NULL) {
342 if ((tlist->flags & IP_FLAG_REG)) {
343 if (rcm_unregister_interest(hdl,
344 tlist->device, 0) != 0) {
345 rcm_log_message(RCM_ERROR,
346 gettext("failed to unregister"));
348 tlist->flags &= (~IP_FLAG_REG);
350 tlist = tlist->next;
353 (void) mutex_unlock(&ip_list_lock);
355 return (RCM_SUCCESS);
358 /*ARGSUSED*/
359 static int
360 ip_anon_getinfo(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
361 char **infostr, char **errstr, nvlist_t *props, rcm_info_t **dependent)
364 assert(rsrcname != NULL && infostr != NULL);
366 if ((*infostr = strdup(IP_ANON_USAGE)) == NULL)
367 rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
369 return (RCM_SUCCESS);
372 /*ARGSUSED*/
373 static int
374 ip_anon_suspend(rcm_handle_t *hdl, char *rsrcname, id_t id,
375 timespec_t *interval, uint_t flags, char **errstr,
376 rcm_info_t **dependent)
378 if ((*errstr = strdup(IP_SUSPEND_ERR)) == NULL)
379 rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
381 return (RCM_FAILURE);
384 /*ARGSUSED*/
385 static int
386 ip_anon_resume(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
387 char **errstr, rcm_info_t **dependent)
389 return (RCM_SUCCESS);
392 /*ARGSUSED*/
393 static int
394 ip_anon_offline(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
395 char **errstr, rcm_info_t **dependent)
397 if ((*errstr = strdup(IP_OFFLINE_ERR)) == NULL)
398 rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
400 return (RCM_FAILURE);
403 /*ARGSUSED*/
404 static int
405 ip_anon_online(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
406 char **errstr, rcm_info_t **dependent)
408 return (RCM_SUCCESS);
411 /*ARGSUSED*/
412 static int
413 ip_anon_remove(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
414 char **errstr, rcm_info_t **dependent)
416 if ((*errstr = strdup(IP_REMOVE_ERR)) == NULL)
417 rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
419 return (RCM_FAILURE);
423 * Call with ip_list_lock held.
426 static ip_status_t *
427 findreg(char *reg)
429 ip_status_t *tlist;
430 int done;
432 tlist = ip_list;
433 done = 0;
434 while ((tlist != NULL) && (!done)) {
435 if (strcmp(tlist->device, reg) == 0)
436 done = 1;
437 else
438 tlist = tlist->next;
441 return (tlist);
444 static ip_status_t *
445 addreg(char *reg)
447 ip_status_t *tlist, *tentry;
449 tentry = (ip_status_t *)malloc(sizeof (ip_status_t));
450 if (tentry == NULL)
451 return (tentry);
453 tentry->flags = IP_FLAG_NEW;
454 tentry->next = NULL;
455 (void) strcpy(tentry->device, reg);
457 if (ip_list == NULL)
458 ip_list = tentry;
459 else {
460 tlist = ip_list;
461 while (tlist->next != NULL)
462 tlist = tlist->next;
463 tlist->next = tentry;
466 return (tentry);
469 static int
470 deletereg(ip_status_t *entry)
472 ip_status_t *tlist;
474 if (entry == NULL)
475 return (-1);
477 if (entry == ip_list) {
478 ip_list = ip_list->next;
479 free(entry);
480 } else {
481 tlist = ip_list;
482 while ((tlist->next != NULL) && (tlist->next != entry))
483 tlist = tlist->next;
485 if (tlist->next != entry)
486 return (-1);
487 tlist->next = entry->next;
488 free(entry);
490 return (0);