xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd_rules.c (revision 13141:bb6d135b32d1)
110946SSangeeta.Misra@Sun.COM /*
210946SSangeeta.Misra@Sun.COM  * CDDL HEADER START
310946SSangeeta.Misra@Sun.COM  *
410946SSangeeta.Misra@Sun.COM  * The contents of this file are subject to the terms of the
510946SSangeeta.Misra@Sun.COM  * Common Development and Distribution License (the "License").
610946SSangeeta.Misra@Sun.COM  * You may not use this file except in compliance with the License.
710946SSangeeta.Misra@Sun.COM  *
810946SSangeeta.Misra@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910946SSangeeta.Misra@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010946SSangeeta.Misra@Sun.COM  * See the License for the specific language governing permissions
1110946SSangeeta.Misra@Sun.COM  * and limitations under the License.
1210946SSangeeta.Misra@Sun.COM  *
1310946SSangeeta.Misra@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410946SSangeeta.Misra@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510946SSangeeta.Misra@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610946SSangeeta.Misra@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710946SSangeeta.Misra@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810946SSangeeta.Misra@Sun.COM  *
1910946SSangeeta.Misra@Sun.COM  * CDDL HEADER END
2010946SSangeeta.Misra@Sun.COM  */
2110946SSangeeta.Misra@Sun.COM 
2210946SSangeeta.Misra@Sun.COM /*
2312857SSangeeta.Misra@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410946SSangeeta.Misra@Sun.COM  */
2510946SSangeeta.Misra@Sun.COM 
2610946SSangeeta.Misra@Sun.COM #include <stdlib.h>
2710946SSangeeta.Misra@Sun.COM #include <strings.h>
2810946SSangeeta.Misra@Sun.COM #include <stddef.h>
2910946SSangeeta.Misra@Sun.COM #include <unistd.h>
3010946SSangeeta.Misra@Sun.COM #include <sys/types.h>
3110946SSangeeta.Misra@Sun.COM #include <sys/socket.h>
3210946SSangeeta.Misra@Sun.COM #include <netinet/in.h>
3310946SSangeeta.Misra@Sun.COM #include <arpa/inet.h>
3410946SSangeeta.Misra@Sun.COM #include <sys/list.h>
3510946SSangeeta.Misra@Sun.COM #include <net/if.h>
3610946SSangeeta.Misra@Sun.COM #include <assert.h>
3710946SSangeeta.Misra@Sun.COM #include <errno.h>
3810946SSangeeta.Misra@Sun.COM #include <libintl.h>
3910946SSangeeta.Misra@Sun.COM #include <libilb.h>
4010946SSangeeta.Misra@Sun.COM #include <inet/ilb.h>
4110946SSangeeta.Misra@Sun.COM #include "libilb_impl.h"
4210946SSangeeta.Misra@Sun.COM #include "ilbd.h"
4310946SSangeeta.Misra@Sun.COM 
4410946SSangeeta.Misra@Sun.COM /* until we all use AF_* macros ... */
4510946SSangeeta.Misra@Sun.COM #define	AF_2_IPPROTO(_af)	(_af == AF_INET)?IPPROTO_IP:IPPROTO_IPV6
4610946SSangeeta.Misra@Sun.COM #define	IPPROTO_2_AF(_i)	(_i == IPPROTO_IP)?AF_INET:AF_INET6
4710946SSangeeta.Misra@Sun.COM 
4812857SSangeeta.Misra@Sun.COM #define	PROTOCOL_LEN	16				/* protocol type */
4912857SSangeeta.Misra@Sun.COM #define	ADDR_LEN	(2 * INET6_ADDRSTRLEN + 1)	/* prxy src range */
5012857SSangeeta.Misra@Sun.COM #define	PORT_LEN	6			/* hcport:1-65535 or "ANY" */
5112857SSangeeta.Misra@Sun.COM 
5210946SSangeeta.Misra@Sun.COM static ilb_status_t ilbd_disable_one_rule(ilbd_rule_t *, boolean_t);
5310946SSangeeta.Misra@Sun.COM static uint32_t i_flags_d2k(int);
5410946SSangeeta.Misra@Sun.COM 
5510946SSangeeta.Misra@Sun.COM #define	ILB_SGSRV_2_KSRV(s, k)			\
5610946SSangeeta.Misra@Sun.COM 	(k)->addr  = (s)->sgs_addr;		\
5710946SSangeeta.Misra@Sun.COM 	(k)->min_port = (s)->sgs_minport;	\
5810946SSangeeta.Misra@Sun.COM 	(k)->max_port = (s)->sgs_maxport;	\
5910946SSangeeta.Misra@Sun.COM 	(k)->flags = i_flags_d2k((s)->sgs_flags);	\
6010946SSangeeta.Misra@Sun.COM 	(k)->err = 0;				\
6110946SSangeeta.Misra@Sun.COM 	(void) strlcpy((k)->name, (s)->sgs_srvID, sizeof ((k)->name))
6210946SSangeeta.Misra@Sun.COM 
6310946SSangeeta.Misra@Sun.COM list_t		ilbd_rule_hlist;
6410946SSangeeta.Misra@Sun.COM 
6510946SSangeeta.Misra@Sun.COM static ilb_algo_t
algo_impl2lib(ilb_algo_impl_t a)6610946SSangeeta.Misra@Sun.COM algo_impl2lib(ilb_algo_impl_t a)
6710946SSangeeta.Misra@Sun.COM {
6810946SSangeeta.Misra@Sun.COM 	switch (a) {
6910946SSangeeta.Misra@Sun.COM 	case ILB_ALG_IMPL_ROUNDROBIN:
7010946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_ROUNDROBIN);
7110946SSangeeta.Misra@Sun.COM 	case ILB_ALG_IMPL_HASH_IP:
7210946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_HASH_IP);
7310946SSangeeta.Misra@Sun.COM 	case ILB_ALG_IMPL_HASH_IP_SPORT:
7410946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_HASH_IP_SPORT);
7510946SSangeeta.Misra@Sun.COM 	case ILB_ALG_IMPL_HASH_IP_VIP:
7610946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_HASH_IP_VIP);
7710946SSangeeta.Misra@Sun.COM 	}
7810946SSangeeta.Misra@Sun.COM 	return (0);
7910946SSangeeta.Misra@Sun.COM }
8010946SSangeeta.Misra@Sun.COM 
8110946SSangeeta.Misra@Sun.COM static ilb_topo_t
topo_impl2lib(ilb_topo_impl_t t)8210946SSangeeta.Misra@Sun.COM topo_impl2lib(ilb_topo_impl_t t)
8310946SSangeeta.Misra@Sun.COM {
8410946SSangeeta.Misra@Sun.COM 	switch (t) {
8510946SSangeeta.Misra@Sun.COM 	case ILB_TOPO_IMPL_DSR:
8610946SSangeeta.Misra@Sun.COM 		return (ILB_TOPO_DSR);
8710946SSangeeta.Misra@Sun.COM 	case ILB_TOPO_IMPL_NAT:
8810946SSangeeta.Misra@Sun.COM 		return (ILB_TOPO_NAT);
8910946SSangeeta.Misra@Sun.COM 	case ILB_TOPO_IMPL_HALF_NAT:
9010946SSangeeta.Misra@Sun.COM 		return (ILB_TOPO_HALF_NAT);
9110946SSangeeta.Misra@Sun.COM 	}
9210946SSangeeta.Misra@Sun.COM 	return (0);
9310946SSangeeta.Misra@Sun.COM }
9410946SSangeeta.Misra@Sun.COM 
9510946SSangeeta.Misra@Sun.COM ilb_algo_impl_t
algo_lib2impl(ilb_algo_t a)9610946SSangeeta.Misra@Sun.COM algo_lib2impl(ilb_algo_t a)
9710946SSangeeta.Misra@Sun.COM {
9810946SSangeeta.Misra@Sun.COM 	switch (a) {
9910946SSangeeta.Misra@Sun.COM 	case ILB_ALG_ROUNDROBIN:
10010946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_IMPL_ROUNDROBIN);
10110946SSangeeta.Misra@Sun.COM 	case ILB_ALG_HASH_IP:
10210946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_IMPL_HASH_IP);
10310946SSangeeta.Misra@Sun.COM 	case ILB_ALG_HASH_IP_SPORT:
10410946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_IMPL_HASH_IP_SPORT);
10510946SSangeeta.Misra@Sun.COM 	case ILB_ALG_HASH_IP_VIP:
10610946SSangeeta.Misra@Sun.COM 		return (ILB_ALG_IMPL_HASH_IP_VIP);
10710946SSangeeta.Misra@Sun.COM 	}
10810946SSangeeta.Misra@Sun.COM 	return (0);
10910946SSangeeta.Misra@Sun.COM }
11010946SSangeeta.Misra@Sun.COM 
11110946SSangeeta.Misra@Sun.COM ilb_topo_impl_t
topo_lib2impl(ilb_topo_t t)11210946SSangeeta.Misra@Sun.COM topo_lib2impl(ilb_topo_t t)
11310946SSangeeta.Misra@Sun.COM {
11410946SSangeeta.Misra@Sun.COM 	switch (t) {
11510946SSangeeta.Misra@Sun.COM 	case ILB_TOPO_DSR:
11610946SSangeeta.Misra@Sun.COM 		return (ILB_TOPO_IMPL_DSR);
11710946SSangeeta.Misra@Sun.COM 	case ILB_TOPO_NAT:
11810946SSangeeta.Misra@Sun.COM 		return (ILB_TOPO_IMPL_NAT);
11910946SSangeeta.Misra@Sun.COM 	case ILB_TOPO_HALF_NAT:
12010946SSangeeta.Misra@Sun.COM 		return (ILB_TOPO_IMPL_HALF_NAT);
12110946SSangeeta.Misra@Sun.COM 	}
12210946SSangeeta.Misra@Sun.COM 	return (0);
12310946SSangeeta.Misra@Sun.COM }
12410946SSangeeta.Misra@Sun.COM 
12510946SSangeeta.Misra@Sun.COM /*
12610946SSangeeta.Misra@Sun.COM  * Walk the list of rules and check if its safe to add the
12710946SSangeeta.Misra@Sun.COM  * the server to the rule (this is a list of rules hanging
12810946SSangeeta.Misra@Sun.COM  * off of a server group)
12910946SSangeeta.Misra@Sun.COM  */
13010946SSangeeta.Misra@Sun.COM ilb_status_t
i_check_srv2rules(list_t * rlist,ilb_sg_srv_t * srv)13110946SSangeeta.Misra@Sun.COM i_check_srv2rules(list_t *rlist, ilb_sg_srv_t *srv)
13210946SSangeeta.Misra@Sun.COM {
13310946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc = ILB_STATUS_OK;
13410946SSangeeta.Misra@Sun.COM 	ilbd_rule_t	*rl;
13510946SSangeeta.Misra@Sun.COM 	int		server_portrange, rule_portrange;
13610946SSangeeta.Misra@Sun.COM 	int		srv_minport, srv_maxport;
13710946SSangeeta.Misra@Sun.COM 	int		r_minport, r_maxport;
13810946SSangeeta.Misra@Sun.COM 
13910946SSangeeta.Misra@Sun.COM 	if (srv == NULL)
14010946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_OK);
14110946SSangeeta.Misra@Sun.COM 
14210946SSangeeta.Misra@Sun.COM 	srv_minport = ntohs(srv->sgs_minport);
14310946SSangeeta.Misra@Sun.COM 	srv_maxport = ntohs(srv->sgs_maxport);
14410946SSangeeta.Misra@Sun.COM 
14510946SSangeeta.Misra@Sun.COM 	for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) {
14610946SSangeeta.Misra@Sun.COM 		r_minport = ntohs(rl->irl_minport);
14710946SSangeeta.Misra@Sun.COM 		r_maxport = ntohs(rl->irl_maxport);
14810946SSangeeta.Misra@Sun.COM 
14910946SSangeeta.Misra@Sun.COM 		if ((srv_minport != 0) && (srv_minport == srv_maxport)) {
15010946SSangeeta.Misra@Sun.COM 			/* server has single port */
15110946SSangeeta.Misra@Sun.COM 			if (rl->irl_topo == ILB_TOPO_DSR) {
15210946SSangeeta.Misra@Sun.COM 				/*
15310946SSangeeta.Misra@Sun.COM 				 * either we have a DSR rule with a port
15410946SSangeeta.Misra@Sun.COM 				 * range, or both server and rule
15510946SSangeeta.Misra@Sun.COM 				 * have single ports but their values
15610946SSangeeta.Misra@Sun.COM 				 * don't match - this is incompatible
15710946SSangeeta.Misra@Sun.COM 				 */
15810946SSangeeta.Misra@Sun.COM 				if (r_maxport > r_minport) {
15910946SSangeeta.Misra@Sun.COM 					rc = ILB_STATUS_INVAL_SRVR;
16010946SSangeeta.Misra@Sun.COM 					break;
16110946SSangeeta.Misra@Sun.COM 				} else if (srv_minport != r_minport) {
16210946SSangeeta.Misra@Sun.COM 					rc = ILB_STATUS_BADPORT;
16310946SSangeeta.Misra@Sun.COM 					break;
16410946SSangeeta.Misra@Sun.COM 				}
16510946SSangeeta.Misra@Sun.COM 			}
16610946SSangeeta.Misra@Sun.COM 			if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX &&
16710946SSangeeta.Misra@Sun.COM 			    rl->irl_hcport != srv_minport) {
16810946SSangeeta.Misra@Sun.COM 				rc = ILB_STATUS_BADPORT;
16910946SSangeeta.Misra@Sun.COM 				break;
17010946SSangeeta.Misra@Sun.COM 			}
17110946SSangeeta.Misra@Sun.COM 		} else if (srv_maxport > srv_minport) {
17210946SSangeeta.Misra@Sun.COM 			/* server has a port range */
17310946SSangeeta.Misra@Sun.COM 			if ((rl->irl_topo == ILB_TOPO_DSR) &&
17410946SSangeeta.Misra@Sun.COM 			    (r_maxport > r_minport)) {
17510946SSangeeta.Misra@Sun.COM 				if ((r_minport != srv_minport) ||
17610946SSangeeta.Misra@Sun.COM 				    (r_maxport != srv_maxport)) {
17710946SSangeeta.Misra@Sun.COM 					/*
17810946SSangeeta.Misra@Sun.COM 					 * we have a DSR rule with a port range
17910946SSangeeta.Misra@Sun.COM 					 * and its min and max port values
18010946SSangeeta.Misra@Sun.COM 					 * does not meet that of server's
18110946SSangeeta.Misra@Sun.COM 					 * - this is incompatible
18210946SSangeeta.Misra@Sun.COM 					 */
18310946SSangeeta.Misra@Sun.COM 					rc = ILB_STATUS_BADPORT;
18410946SSangeeta.Misra@Sun.COM 					break;
18510946SSangeeta.Misra@Sun.COM 				}
18610946SSangeeta.Misra@Sun.COM 			} else if ((rl->irl_topo == ILB_TOPO_DSR) &&
18710946SSangeeta.Misra@Sun.COM 			    (r_maxport == r_minport)) {
18810946SSangeeta.Misra@Sun.COM 					/*
18910946SSangeeta.Misra@Sun.COM 					 * we have a DSR rule with a single
19010946SSangeeta.Misra@Sun.COM 					 * port and a server with a port range
19110946SSangeeta.Misra@Sun.COM 					 * - this is incompatible
19210946SSangeeta.Misra@Sun.COM 					 */
19310946SSangeeta.Misra@Sun.COM 					rc = ILB_STATUS_INVAL_SRVR;
19410946SSangeeta.Misra@Sun.COM 					break;
19510946SSangeeta.Misra@Sun.COM 			} else if (((rl->irl_topo == ILB_TOPO_NAT) ||
19610946SSangeeta.Misra@Sun.COM 			    (rl->irl_topo == ILB_TOPO_HALF_NAT)) &&
19710946SSangeeta.Misra@Sun.COM 			    (r_maxport > r_minport)) {
19810946SSangeeta.Misra@Sun.COM 				server_portrange = srv_maxport - srv_minport;
19910946SSangeeta.Misra@Sun.COM 				rule_portrange = r_maxport - r_minport;
20010946SSangeeta.Misra@Sun.COM 				if (rule_portrange != server_portrange) {
20110946SSangeeta.Misra@Sun.COM 					/*
20210946SSangeeta.Misra@Sun.COM 					 * we have a NAT/Half-NAT rule with
20310946SSangeeta.Misra@Sun.COM 					 * a port range and server with a port
20410946SSangeeta.Misra@Sun.COM 					 * range and there is a mismatch in the
20510946SSangeeta.Misra@Sun.COM 					 * sizes of the port ranges - this is
20610946SSangeeta.Misra@Sun.COM 					 * incompatible
20710946SSangeeta.Misra@Sun.COM 					 */
20810946SSangeeta.Misra@Sun.COM 					rc = ILB_STATUS_INVAL_SRVR;
20910946SSangeeta.Misra@Sun.COM 					break;
21010946SSangeeta.Misra@Sun.COM 				}
21110946SSangeeta.Misra@Sun.COM 			}
21210946SSangeeta.Misra@Sun.COM 			if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX &&
21310946SSangeeta.Misra@Sun.COM 			    (rl->irl_hcport > srv_maxport ||
21410946SSangeeta.Misra@Sun.COM 			    rl->irl_hcport < srv_minport)) {
21510946SSangeeta.Misra@Sun.COM 				rc = ILB_STATUS_BADPORT;
21610946SSangeeta.Misra@Sun.COM 				break;
21710946SSangeeta.Misra@Sun.COM 			}
21810946SSangeeta.Misra@Sun.COM 		}
21910946SSangeeta.Misra@Sun.COM 	}
22010946SSangeeta.Misra@Sun.COM 
22110946SSangeeta.Misra@Sun.COM 	return (rc);
22210946SSangeeta.Misra@Sun.COM }
22310946SSangeeta.Misra@Sun.COM 
22410946SSangeeta.Misra@Sun.COM void
i_setup_rule_hlist(void)22510946SSangeeta.Misra@Sun.COM i_setup_rule_hlist(void)
22610946SSangeeta.Misra@Sun.COM {
22710946SSangeeta.Misra@Sun.COM 	list_create(&ilbd_rule_hlist, sizeof (ilbd_rule_t),
22810946SSangeeta.Misra@Sun.COM 	    offsetof(ilbd_rule_t, irl_link));
22910946SSangeeta.Misra@Sun.COM }
23010946SSangeeta.Misra@Sun.COM 
23110946SSangeeta.Misra@Sun.COM ilb_status_t
i_ilbd_save_rule(ilbd_rule_t * irl,ilbd_scf_cmd_t scf_cmd)23210946SSangeeta.Misra@Sun.COM i_ilbd_save_rule(ilbd_rule_t *irl, ilbd_scf_cmd_t scf_cmd)
23310946SSangeeta.Misra@Sun.COM {
23410946SSangeeta.Misra@Sun.COM 	boolean_t enable = irl->irl_flags & ILB_FLAGS_RULE_ENABLED;
23510946SSangeeta.Misra@Sun.COM 
23610946SSangeeta.Misra@Sun.COM 	switch (scf_cmd) {
23710946SSangeeta.Misra@Sun.COM 	case ILBD_SCF_CREATE:
23810946SSangeeta.Misra@Sun.COM 		return (ilbd_create_pg(ILBD_SCF_RULE, (void *)irl));
23910946SSangeeta.Misra@Sun.COM 	case ILBD_SCF_DESTROY:
24010946SSangeeta.Misra@Sun.COM 		return (ilbd_destroy_pg(ILBD_SCF_RULE, irl->irl_name));
24110946SSangeeta.Misra@Sun.COM 	case ILBD_SCF_ENABLE_DISABLE:
24210946SSangeeta.Misra@Sun.COM 		return (ilbd_change_prop(ILBD_SCF_RULE, irl->irl_name,
24310946SSangeeta.Misra@Sun.COM 		    "status", &enable));
24410946SSangeeta.Misra@Sun.COM 	default:
24510946SSangeeta.Misra@Sun.COM 		logdebug("i_ilbd_save_rule: invalid scf cmd %d", scf_cmd);
24610946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_INVAL_CMD);
24710946SSangeeta.Misra@Sun.COM 	}
24810946SSangeeta.Misra@Sun.COM }
24910946SSangeeta.Misra@Sun.COM 
25010946SSangeeta.Misra@Sun.COM /*
25110946SSangeeta.Misra@Sun.COM  * allocate a new daemon-specific rule from the "template" passed
25210946SSangeeta.Misra@Sun.COM  * in in *r
25310946SSangeeta.Misra@Sun.COM  */
25410946SSangeeta.Misra@Sun.COM static ilbd_rule_t *
i_alloc_ilbd_rule(ilb_rule_info_t * r)25510946SSangeeta.Misra@Sun.COM i_alloc_ilbd_rule(ilb_rule_info_t *r)
25610946SSangeeta.Misra@Sun.COM {
25710946SSangeeta.Misra@Sun.COM 	ilbd_rule_t	*rl;
25810946SSangeeta.Misra@Sun.COM 
25910946SSangeeta.Misra@Sun.COM 	rl = calloc(sizeof (*rl), 1);
26010946SSangeeta.Misra@Sun.COM 	if (rl != NULL && r != NULL)
26110946SSangeeta.Misra@Sun.COM 		bcopy(r, &rl->irl_info, sizeof (*r));
26210946SSangeeta.Misra@Sun.COM 
26310946SSangeeta.Misra@Sun.COM 	return (rl);
26410946SSangeeta.Misra@Sun.COM }
26510946SSangeeta.Misra@Sun.COM 
26610946SSangeeta.Misra@Sun.COM static ilbd_rule_t *
i_find_rule_byname(const char * name)26710946SSangeeta.Misra@Sun.COM i_find_rule_byname(const char *name)
26810946SSangeeta.Misra@Sun.COM {
26910946SSangeeta.Misra@Sun.COM 	ilbd_rule_t	*rl;
27010946SSangeeta.Misra@Sun.COM 
27110946SSangeeta.Misra@Sun.COM 	/* find position of rule in list */
27210946SSangeeta.Misra@Sun.COM 	rl = list_head(&ilbd_rule_hlist);
27310946SSangeeta.Misra@Sun.COM 	while (rl != NULL &&
27410946SSangeeta.Misra@Sun.COM 	    strncmp(rl->irl_name, name, sizeof (rl->irl_name)) != 0) {
27510946SSangeeta.Misra@Sun.COM 		rl = list_next(&ilbd_rule_hlist, rl);
27610946SSangeeta.Misra@Sun.COM 	}
27710946SSangeeta.Misra@Sun.COM 
27810946SSangeeta.Misra@Sun.COM 	return (rl);
27910946SSangeeta.Misra@Sun.COM }
28010946SSangeeta.Misra@Sun.COM 
28110946SSangeeta.Misra@Sun.COM /*
28210946SSangeeta.Misra@Sun.COM  * get exactly one rule (named in rl->irl_name) data from kernel
28310946SSangeeta.Misra@Sun.COM  */
28410946SSangeeta.Misra@Sun.COM static ilb_status_t
ilb_get_krule(ilb_rule_info_t * rl)28510946SSangeeta.Misra@Sun.COM ilb_get_krule(ilb_rule_info_t *rl)
28610946SSangeeta.Misra@Sun.COM {
28710946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc;
28810946SSangeeta.Misra@Sun.COM 	ilb_rule_cmd_t	kcmd;
28910946SSangeeta.Misra@Sun.COM 
29010946SSangeeta.Misra@Sun.COM 	kcmd.cmd = ILB_LIST_RULE;
29110946SSangeeta.Misra@Sun.COM 	(void) strlcpy(kcmd.name, rl->rl_name, sizeof (kcmd.name));
29210946SSangeeta.Misra@Sun.COM 	kcmd.flags = 0;
29310946SSangeeta.Misra@Sun.COM 
29410946SSangeeta.Misra@Sun.COM 	rc = do_ioctl(&kcmd, 0);
29510946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK)
29610946SSangeeta.Misra@Sun.COM 		return (rc);
29710946SSangeeta.Misra@Sun.COM 
29810946SSangeeta.Misra@Sun.COM 	rl->rl_flags = kcmd.flags;
29910946SSangeeta.Misra@Sun.COM 	rl->rl_ipversion = IPPROTO_2_AF(kcmd.ip_ver);
30010946SSangeeta.Misra@Sun.COM 	rl->rl_vip = kcmd.vip;
30110946SSangeeta.Misra@Sun.COM 	rl->rl_proto = kcmd.proto;
30210946SSangeeta.Misra@Sun.COM 	rl->rl_minport = kcmd.min_port;
30310946SSangeeta.Misra@Sun.COM 	rl->rl_maxport = kcmd.max_port;
30410946SSangeeta.Misra@Sun.COM 	rl->rl_algo = algo_impl2lib(kcmd.algo);
30510946SSangeeta.Misra@Sun.COM 	rl->rl_topo = topo_impl2lib(kcmd.topo);
30610946SSangeeta.Misra@Sun.COM 	rl->rl_stickymask = kcmd.sticky_mask;
30710946SSangeeta.Misra@Sun.COM 	rl->rl_nat_src_start = kcmd.nat_src_start;
30810946SSangeeta.Misra@Sun.COM 	rl->rl_nat_src_end = kcmd.nat_src_end;
30910946SSangeeta.Misra@Sun.COM 	(void) strlcpy(rl->rl_name, kcmd.name, sizeof (rl->rl_name));
31010946SSangeeta.Misra@Sun.COM 	rl->rl_conndrain = kcmd.conn_drain_timeout;
31110946SSangeeta.Misra@Sun.COM 	rl->rl_nat_timeout = kcmd.nat_expiry;
31210946SSangeeta.Misra@Sun.COM 	rl->rl_sticky_timeout = kcmd.sticky_expiry;
31310946SSangeeta.Misra@Sun.COM 
31410946SSangeeta.Misra@Sun.COM 	return (ILB_STATUS_OK);
31510946SSangeeta.Misra@Sun.COM }
31610946SSangeeta.Misra@Sun.COM 
31710946SSangeeta.Misra@Sun.COM ilb_status_t
ilbd_retrieve_rule(ilbd_name_t rl_name,uint32_t * rbuf,size_t * rbufsz)31810946SSangeeta.Misra@Sun.COM ilbd_retrieve_rule(ilbd_name_t rl_name, uint32_t *rbuf, size_t *rbufsz)
31910946SSangeeta.Misra@Sun.COM {
32010946SSangeeta.Misra@Sun.COM 	ilbd_rule_t	*irl = NULL;
32110946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc;
32210946SSangeeta.Misra@Sun.COM 	ilb_rule_info_t	*rinfo;
32310946SSangeeta.Misra@Sun.COM 
32410946SSangeeta.Misra@Sun.COM 	irl = i_find_rule_byname(rl_name);
32510946SSangeeta.Misra@Sun.COM 	if (irl == NULL)
32610946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_ENOENT);
32710946SSangeeta.Misra@Sun.COM 
32810946SSangeeta.Misra@Sun.COM 	ilbd_reply_ok(rbuf, rbufsz);
32910946SSangeeta.Misra@Sun.COM 	rinfo = (ilb_rule_info_t *)&((ilb_comm_t *)rbuf)->ic_data;
33010946SSangeeta.Misra@Sun.COM 	bcopy(&irl->irl_info, rinfo, sizeof (*rinfo));
33110946SSangeeta.Misra@Sun.COM 
33210946SSangeeta.Misra@Sun.COM 	/*
33310946SSangeeta.Misra@Sun.COM 	 * Check if the various timeout values are 0.  If one is, get the
33410946SSangeeta.Misra@Sun.COM 	 * default values from kernel.
33510946SSangeeta.Misra@Sun.COM 	 */
33610946SSangeeta.Misra@Sun.COM 	if (rinfo->rl_conndrain == 0 || rinfo->rl_nat_timeout == 0 ||
33710946SSangeeta.Misra@Sun.COM 	    rinfo->rl_sticky_timeout == 0) {
33810946SSangeeta.Misra@Sun.COM 		ilb_rule_info_t tmp_info;
33910946SSangeeta.Misra@Sun.COM 
34010946SSangeeta.Misra@Sun.COM 		(void) strcpy(tmp_info.rl_name, rinfo->rl_name);
34110946SSangeeta.Misra@Sun.COM 		rc = ilb_get_krule(&tmp_info);
34210946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
34310946SSangeeta.Misra@Sun.COM 			return (rc);
34410946SSangeeta.Misra@Sun.COM 		if (rinfo->rl_conndrain == 0)
34510946SSangeeta.Misra@Sun.COM 			rinfo->rl_conndrain = tmp_info.rl_conndrain;
34610946SSangeeta.Misra@Sun.COM 		if ((rinfo->rl_topo == ILB_TOPO_IMPL_NAT ||
34710946SSangeeta.Misra@Sun.COM 		    rinfo->rl_topo == ILB_TOPO_IMPL_HALF_NAT) &&
34810946SSangeeta.Misra@Sun.COM 		    rinfo->rl_nat_timeout == 0) {
34910946SSangeeta.Misra@Sun.COM 			rinfo->rl_nat_timeout = tmp_info.rl_nat_timeout;
35010946SSangeeta.Misra@Sun.COM 		}
35110946SSangeeta.Misra@Sun.COM 		if ((rinfo->rl_flags & ILB_FLAGS_RULE_STICKY) &&
35210946SSangeeta.Misra@Sun.COM 		    rinfo->rl_sticky_timeout == 0) {
35310946SSangeeta.Misra@Sun.COM 			rinfo->rl_sticky_timeout = tmp_info.rl_sticky_timeout;
35410946SSangeeta.Misra@Sun.COM 		}
35510946SSangeeta.Misra@Sun.COM 	}
35610946SSangeeta.Misra@Sun.COM 	*rbufsz += sizeof (ilb_rule_info_t);
35710946SSangeeta.Misra@Sun.COM 
35810946SSangeeta.Misra@Sun.COM 	return (ILB_STATUS_OK);
35910946SSangeeta.Misra@Sun.COM }
36010946SSangeeta.Misra@Sun.COM 
36110946SSangeeta.Misra@Sun.COM static ilb_status_t
ilbd_destroy_one_rule(ilbd_rule_t * irl)36210946SSangeeta.Misra@Sun.COM ilbd_destroy_one_rule(ilbd_rule_t *irl)
36310946SSangeeta.Misra@Sun.COM {
36410946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc;
36510946SSangeeta.Misra@Sun.COM 	ilb_name_cmd_t	kcmd;
36610946SSangeeta.Misra@Sun.COM 
36710946SSangeeta.Misra@Sun.COM 	/*
36810946SSangeeta.Misra@Sun.COM 	 * as far as talking to the kernel is concerned, "all rules"
36910946SSangeeta.Misra@Sun.COM 	 * is handled in one go somewhere else, so we only
37010946SSangeeta.Misra@Sun.COM 	 * tell the kernel about single rules here.
37110946SSangeeta.Misra@Sun.COM 	 */
37210946SSangeeta.Misra@Sun.COM 	if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) {
37310946SSangeeta.Misra@Sun.COM 		kcmd.cmd = ILB_DESTROY_RULE;
37410946SSangeeta.Misra@Sun.COM 		(void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name));
37510946SSangeeta.Misra@Sun.COM 		kcmd.flags = 0;
37610946SSangeeta.Misra@Sun.COM 
37710946SSangeeta.Misra@Sun.COM 		rc = do_ioctl(&kcmd, 0);
37810946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
37910946SSangeeta.Misra@Sun.COM 			return (rc);
38010946SSangeeta.Misra@Sun.COM 
38110946SSangeeta.Misra@Sun.COM 	}
38210946SSangeeta.Misra@Sun.COM 	list_remove(&irl->irl_sg->isg_rulelist, irl);
38310946SSangeeta.Misra@Sun.COM 	list_remove(&ilbd_rule_hlist, irl);
38410946SSangeeta.Misra@Sun.COM 
38510946SSangeeta.Misra@Sun.COM 	/*
38610946SSangeeta.Misra@Sun.COM 	 * When dissociating a rule, only two errors can happen.  The hc
38710946SSangeeta.Misra@Sun.COM 	 * name is incorrect or the rule is not associated with the hc
38810946SSangeeta.Misra@Sun.COM 	 * object.  Both should not happen....  The check is for debugging
38910946SSangeeta.Misra@Sun.COM 	 * purpose.
39010946SSangeeta.Misra@Sun.COM 	 */
39110946SSangeeta.Misra@Sun.COM 	if (RULE_HAS_HC(irl) && (rc = ilbd_hc_dissociate_rule(irl)) !=
39210946SSangeeta.Misra@Sun.COM 	    ILB_STATUS_OK) {
39310946SSangeeta.Misra@Sun.COM 		logerr("ilbd_destroy_one_rule: cannot "
39410946SSangeeta.Misra@Sun.COM 		    "dissociate %s from hc object %s: %d",
39510946SSangeeta.Misra@Sun.COM 		    irl->irl_name, irl->irl_hcname, rc);
39610946SSangeeta.Misra@Sun.COM 	}
39710946SSangeeta.Misra@Sun.COM 
39810946SSangeeta.Misra@Sun.COM 	rc = i_ilbd_save_rule(irl, ILBD_SCF_DESTROY);
39910946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK)
40010946SSangeeta.Misra@Sun.COM 		logdebug("ilbd_destroy_rule: save rule failed");
40110946SSangeeta.Misra@Sun.COM 
40210946SSangeeta.Misra@Sun.COM 	free(irl);
40310946SSangeeta.Misra@Sun.COM 	return (rc);
40410946SSangeeta.Misra@Sun.COM }
40510946SSangeeta.Misra@Sun.COM 
40610946SSangeeta.Misra@Sun.COM /*
40710946SSangeeta.Misra@Sun.COM  * the following two functions are the other's opposite, and can
40810946SSangeeta.Misra@Sun.COM  * call into each other for roll back purposes in case of error.
40910946SSangeeta.Misra@Sun.COM  * To avoid endless recursion, the 'is_rollback' parameter must be
41010946SSangeeta.Misra@Sun.COM  * set to B_TRUE in the roll back case.
41110946SSangeeta.Misra@Sun.COM  */
41210946SSangeeta.Misra@Sun.COM static ilb_status_t
ilbd_enable_one_rule(ilbd_rule_t * irl,boolean_t is_rollback)41310946SSangeeta.Misra@Sun.COM ilbd_enable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback)
41410946SSangeeta.Misra@Sun.COM {
41510946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc = ILB_STATUS_OK;
41610946SSangeeta.Misra@Sun.COM 	ilb_name_cmd_t	kcmd;
41710946SSangeeta.Misra@Sun.COM 
41810946SSangeeta.Misra@Sun.COM 	/* no use sending a no-op to the kernel */
41910946SSangeeta.Misra@Sun.COM 	if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) != 0)
42010946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_OK);
42110946SSangeeta.Misra@Sun.COM 
42210946SSangeeta.Misra@Sun.COM 	irl->irl_flags |= ILB_FLAGS_RULE_ENABLED;
42310946SSangeeta.Misra@Sun.COM 
42410946SSangeeta.Misra@Sun.COM 	/* "all rules" is handled in one go somewhere else, not here */
42510946SSangeeta.Misra@Sun.COM 	if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) {
42610946SSangeeta.Misra@Sun.COM 		kcmd.cmd = ILB_ENABLE_RULE;
42710946SSangeeta.Misra@Sun.COM 		(void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name));
42810946SSangeeta.Misra@Sun.COM 		kcmd.flags = 0;
42910946SSangeeta.Misra@Sun.COM 
43010946SSangeeta.Misra@Sun.COM 		rc = do_ioctl(&kcmd, 0);
43110946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
43210946SSangeeta.Misra@Sun.COM 			return (rc);
43310946SSangeeta.Misra@Sun.COM 	}
43410946SSangeeta.Misra@Sun.COM 	if (RULE_HAS_HC(irl) && (rc = ilbd_hc_enable_rule(irl)) !=
43510946SSangeeta.Misra@Sun.COM 	    ILB_STATUS_OK) {
43610946SSangeeta.Misra@Sun.COM 		/* Undo the kernel work */
43710946SSangeeta.Misra@Sun.COM 		kcmd.cmd = ILB_DISABLE_RULE;
43810946SSangeeta.Misra@Sun.COM 		/* Cannot do much if ioctl fails... */
43910946SSangeeta.Misra@Sun.COM 		(void) do_ioctl(&kcmd, 0);
44010946SSangeeta.Misra@Sun.COM 		return (rc);
44110946SSangeeta.Misra@Sun.COM 	}
44210946SSangeeta.Misra@Sun.COM 
44310946SSangeeta.Misra@Sun.COM 	if (!is_rollback) {
44410946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
44510946SSangeeta.Misra@Sun.COM 			rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE);
44610946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
44710946SSangeeta.Misra@Sun.COM 			/* ignore rollback return code */
44810946SSangeeta.Misra@Sun.COM 			(void) ilbd_disable_one_rule(irl, B_TRUE);
44910946SSangeeta.Misra@Sun.COM 	}
45010946SSangeeta.Misra@Sun.COM 
45110946SSangeeta.Misra@Sun.COM 	return (rc);
45210946SSangeeta.Misra@Sun.COM }
45310946SSangeeta.Misra@Sun.COM 
45410946SSangeeta.Misra@Sun.COM static ilb_status_t
ilbd_disable_one_rule(ilbd_rule_t * irl,boolean_t is_rollback)45510946SSangeeta.Misra@Sun.COM ilbd_disable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback)
45610946SSangeeta.Misra@Sun.COM {
45710946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc = ILB_STATUS_OK;
45810946SSangeeta.Misra@Sun.COM 	ilb_name_cmd_t	kcmd;
45910946SSangeeta.Misra@Sun.COM 
46010946SSangeeta.Misra@Sun.COM 	/* no use sending a no-op to the kernel */
46110946SSangeeta.Misra@Sun.COM 	if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) == 0)
46210946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_OK);
46310946SSangeeta.Misra@Sun.COM 
46410946SSangeeta.Misra@Sun.COM 	irl->irl_flags &= ~ILB_FLAGS_RULE_ENABLED;
46510946SSangeeta.Misra@Sun.COM 
46610946SSangeeta.Misra@Sun.COM 	/* "all rules" is handled in one go somewhere else, not here */
46710946SSangeeta.Misra@Sun.COM 	if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) {
46810946SSangeeta.Misra@Sun.COM 		kcmd.cmd = ILB_DISABLE_RULE;
46910946SSangeeta.Misra@Sun.COM 		(void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name));
47010946SSangeeta.Misra@Sun.COM 		kcmd.flags = 0;
47110946SSangeeta.Misra@Sun.COM 
47210946SSangeeta.Misra@Sun.COM 		rc = do_ioctl(&kcmd, 0);
47310946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
47410946SSangeeta.Misra@Sun.COM 			return (rc);
47510946SSangeeta.Misra@Sun.COM 	}
47610946SSangeeta.Misra@Sun.COM 
47710946SSangeeta.Misra@Sun.COM 	if (RULE_HAS_HC(irl) && (rc = ilbd_hc_disable_rule(irl)) !=
47810946SSangeeta.Misra@Sun.COM 	    ILB_STATUS_OK) {
47910946SSangeeta.Misra@Sun.COM 		/* Undo the kernel work */
48010946SSangeeta.Misra@Sun.COM 		kcmd.cmd = ILB_ENABLE_RULE;
48110946SSangeeta.Misra@Sun.COM 		/* Cannot do much if ioctl fails... */
48210946SSangeeta.Misra@Sun.COM 		(void) do_ioctl(&kcmd, 0);
48310946SSangeeta.Misra@Sun.COM 		return (rc);
48410946SSangeeta.Misra@Sun.COM 	}
48510946SSangeeta.Misra@Sun.COM 
48610946SSangeeta.Misra@Sun.COM 	if (!is_rollback) {
48710946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
48810946SSangeeta.Misra@Sun.COM 			rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE);
48910946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
49010946SSangeeta.Misra@Sun.COM 			/* ignore rollback return code */
49110946SSangeeta.Misra@Sun.COM 			(void) ilbd_enable_one_rule(irl, B_TRUE);
49210946SSangeeta.Misra@Sun.COM 	}
49310946SSangeeta.Misra@Sun.COM 
49410946SSangeeta.Misra@Sun.COM 	return (rc);
49510946SSangeeta.Misra@Sun.COM }
49610946SSangeeta.Misra@Sun.COM 
49710946SSangeeta.Misra@Sun.COM /*
49810946SSangeeta.Misra@Sun.COM  * Generates an audit record for a supplied rule name
49910946SSangeeta.Misra@Sun.COM  * Used for enable_rule, disable_rule, delete_rule,
50010946SSangeeta.Misra@Sun.COM  * and create_rule subcommands
50110946SSangeeta.Misra@Sun.COM  */
50210946SSangeeta.Misra@Sun.COM static void
ilbd_audit_rule_event(const char * audit_rule_name,ilb_rule_info_t * rlinfo,ilbd_cmd_t cmd,ilb_status_t rc,ucred_t * ucredp)50310946SSangeeta.Misra@Sun.COM ilbd_audit_rule_event(const char *audit_rule_name,
50410946SSangeeta.Misra@Sun.COM     ilb_rule_info_t *rlinfo, ilbd_cmd_t cmd, ilb_status_t rc,
50510946SSangeeta.Misra@Sun.COM     ucred_t *ucredp)
50610946SSangeeta.Misra@Sun.COM {
50710946SSangeeta.Misra@Sun.COM 	adt_session_data_t	*ah;
50810946SSangeeta.Misra@Sun.COM 	adt_event_data_t	*event;
50910946SSangeeta.Misra@Sun.COM 	au_event_t		flag;
51010946SSangeeta.Misra@Sun.COM 	int			scf_val_len = ILBD_MAX_VALUE_LEN;
51112857SSangeeta.Misra@Sun.COM 	char			*aobuf = NULL; /* algo:topo */
51212857SSangeeta.Misra@Sun.COM 	char			*valstr1 = NULL;
51312857SSangeeta.Misra@Sun.COM 	char			*valstr2 = NULL;
51412857SSangeeta.Misra@Sun.COM 	char			pbuf[PROTOCOL_LEN]; /* protocol */
51512857SSangeeta.Misra@Sun.COM 	char			hcpbuf[PORT_LEN]; /* hcport */
51610946SSangeeta.Misra@Sun.COM 	int			audit_error;
51710946SSangeeta.Misra@Sun.COM 
51810946SSangeeta.Misra@Sun.COM 	if ((ucredp == NULL) && (cmd == ILBD_CREATE_RULE))  {
51910946SSangeeta.Misra@Sun.COM 		/*
52010946SSangeeta.Misra@Sun.COM 		 * we came here from the path where ilbd incorporates
52110946SSangeeta.Misra@Sun.COM 		 * the configuration that is listed in SCF :
52210946SSangeeta.Misra@Sun.COM 		 * i_ilbd_read_config->ilbd_walk_rule_pgs->
52310946SSangeeta.Misra@Sun.COM 		 *    ->ilbd_scf_instance_walk_pg->ilbd_create_rule
52410946SSangeeta.Misra@Sun.COM 		 * We skip auditing in that case
52510946SSangeeta.Misra@Sun.COM 		 */
52610946SSangeeta.Misra@Sun.COM 		return;
52710946SSangeeta.Misra@Sun.COM 	}
52810946SSangeeta.Misra@Sun.COM 	if (adt_start_session(&ah, NULL, 0) != 0) {
52910946SSangeeta.Misra@Sun.COM 		logerr("ilbd_audit_rule_event: adt_start_session failed");
53010946SSangeeta.Misra@Sun.COM 		exit(EXIT_FAILURE);
53110946SSangeeta.Misra@Sun.COM 	}
53210946SSangeeta.Misra@Sun.COM 	if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) {
53310946SSangeeta.Misra@Sun.COM 		(void) adt_end_session(ah);
53410946SSangeeta.Misra@Sun.COM 		logerr("ilbd_audit_rule_event: adt_set_from_ucred failed");
53510946SSangeeta.Misra@Sun.COM 		exit(EXIT_FAILURE);
53610946SSangeeta.Misra@Sun.COM 	}
53710946SSangeeta.Misra@Sun.COM 	if (cmd == ILBD_ENABLE_RULE)
53810946SSangeeta.Misra@Sun.COM 		flag = ADT_ilb_enable_rule;
53910946SSangeeta.Misra@Sun.COM 	else if (cmd == ILBD_DISABLE_RULE)
54010946SSangeeta.Misra@Sun.COM 		flag = ADT_ilb_disable_rule;
54110946SSangeeta.Misra@Sun.COM 	else if (cmd == ILBD_DESTROY_RULE)
54210946SSangeeta.Misra@Sun.COM 		flag = ADT_ilb_delete_rule;
54310946SSangeeta.Misra@Sun.COM 	else if (cmd == ILBD_CREATE_RULE)
54410946SSangeeta.Misra@Sun.COM 		flag = ADT_ilb_create_rule;
54510946SSangeeta.Misra@Sun.COM 
54610946SSangeeta.Misra@Sun.COM 	if ((event = adt_alloc_event(ah, flag)) == NULL) {
54710946SSangeeta.Misra@Sun.COM 		logerr("ilbd_audit_rule_event: adt_alloc_event failed");
54810946SSangeeta.Misra@Sun.COM 		exit(EXIT_FAILURE);
54910946SSangeeta.Misra@Sun.COM 	}
55010946SSangeeta.Misra@Sun.COM 
55110946SSangeeta.Misra@Sun.COM 	(void) memset((char *)event, 0, sizeof (adt_event_data_t));
55210946SSangeeta.Misra@Sun.COM 
55310946SSangeeta.Misra@Sun.COM 	switch (cmd) {
55410946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
55510946SSangeeta.Misra@Sun.COM 		event->adt_ilb_delete_rule.auth_used = NET_ILB_CONFIG_AUTH;
55610946SSangeeta.Misra@Sun.COM 		event->adt_ilb_delete_rule.rule_name = (char *)audit_rule_name;
55710946SSangeeta.Misra@Sun.COM 		break;
55810946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
55910946SSangeeta.Misra@Sun.COM 		event->adt_ilb_enable_rule.auth_used = NET_ILB_ENABLE_AUTH;
56010946SSangeeta.Misra@Sun.COM 		event->adt_ilb_enable_rule.rule_name = (char *)audit_rule_name;
56110946SSangeeta.Misra@Sun.COM 		break;
56210946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
56310946SSangeeta.Misra@Sun.COM 		event->adt_ilb_disable_rule.auth_used = NET_ILB_ENABLE_AUTH;
56410946SSangeeta.Misra@Sun.COM 		event->adt_ilb_disable_rule.rule_name = (char *)audit_rule_name;
56510946SSangeeta.Misra@Sun.COM 		break;
56610946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_RULE:
56712857SSangeeta.Misra@Sun.COM 		if (((aobuf = malloc(scf_val_len)) == NULL) ||
56812857SSangeeta.Misra@Sun.COM 		    ((valstr1 = malloc(scf_val_len)) == NULL) ||
56912857SSangeeta.Misra@Sun.COM 		    ((valstr2 = malloc(scf_val_len)) == NULL)) {
57012857SSangeeta.Misra@Sun.COM 			logerr("ilbd_audit_rule_event: could not"
57112857SSangeeta.Misra@Sun.COM 			    " allocate buffer");
57212857SSangeeta.Misra@Sun.COM 			exit(EXIT_FAILURE);
57312857SSangeeta.Misra@Sun.COM 		}
57410946SSangeeta.Misra@Sun.COM 
57510946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.auth_used = NET_ILB_CONFIG_AUTH;
57610946SSangeeta.Misra@Sun.COM 
577*13141SSangeeta.Misra@Sun.COM 		/* Fill in virtual IP address type */
578*13141SSangeeta.Misra@Sun.COM 		if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_vip)) {
579*13141SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.virtual_ipaddress_type =
580*13141SSangeeta.Misra@Sun.COM 			    ADT_IPv4;
581*13141SSangeeta.Misra@Sun.COM 			cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress,
582*13141SSangeeta.Misra@Sun.COM 			    ADT_IPv4, rlinfo->rl_vip);
583*13141SSangeeta.Misra@Sun.COM 		} else {
584*13141SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.virtual_ipaddress_type =
585*13141SSangeeta.Misra@Sun.COM 			    ADT_IPv6;
586*13141SSangeeta.Misra@Sun.COM 			cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress,
587*13141SSangeeta.Misra@Sun.COM 			    ADT_IPv6, rlinfo->rl_vip);
588*13141SSangeeta.Misra@Sun.COM 		}
58910946SSangeeta.Misra@Sun.COM 		/* Fill in port - could be a single value or a range */
59010946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.min_port = ntohs(rlinfo->rl_minport);
59110946SSangeeta.Misra@Sun.COM 		if (ntohs(rlinfo->rl_maxport) > ntohs(rlinfo->rl_minport)) {
59210946SSangeeta.Misra@Sun.COM 			/* port range */
59310946SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.max_port =
59410946SSangeeta.Misra@Sun.COM 			    ntohs(rlinfo->rl_maxport);
59510946SSangeeta.Misra@Sun.COM 		} else {
59610946SSangeeta.Misra@Sun.COM 			/* in audit record, max=min when single port */
59710946SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.max_port =
59810946SSangeeta.Misra@Sun.COM 			    ntohs(rlinfo->rl_minport);
59910946SSangeeta.Misra@Sun.COM 		}
60010946SSangeeta.Misra@Sun.COM 
60110946SSangeeta.Misra@Sun.COM 		/*
60210946SSangeeta.Misra@Sun.COM 		 * Fill in  protocol - if user does not specify it,
60310946SSangeeta.Misra@Sun.COM 		 * its TCP by default
60410946SSangeeta.Misra@Sun.COM 		 */
60510946SSangeeta.Misra@Sun.COM 		if (rlinfo->rl_proto == IPPROTO_UDP)
60612857SSangeeta.Misra@Sun.COM 			(void) snprintf(pbuf, PROTOCOL_LEN, "UDP");
60710946SSangeeta.Misra@Sun.COM 		else
60812857SSangeeta.Misra@Sun.COM 			(void) snprintf(pbuf, PROTOCOL_LEN, "TCP");
60910946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.protocol = pbuf;
61010946SSangeeta.Misra@Sun.COM 
61110946SSangeeta.Misra@Sun.COM 		/* Fill in algorithm and operation type */
61210946SSangeeta.Misra@Sun.COM 		ilbd_algo_to_str(rlinfo->rl_algo, valstr1);
61310946SSangeeta.Misra@Sun.COM 		ilbd_topo_to_str(rlinfo->rl_topo, valstr2);
61412857SSangeeta.Misra@Sun.COM 		(void) snprintf(aobuf, scf_val_len, "%s:%s",
61510946SSangeeta.Misra@Sun.COM 		    valstr1, valstr2);
61610946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.algo_optype = aobuf;
61710946SSangeeta.Misra@Sun.COM 
61810946SSangeeta.Misra@Sun.COM 		/* Fill in proxy-src for the NAT case */
61910946SSangeeta.Misra@Sun.COM 		if (rlinfo->rl_topo == ILB_TOPO_NAT)  {
620*13141SSangeeta.Misra@Sun.COM 			/* copy starting proxy-src address */
621*13141SSangeeta.Misra@Sun.COM 			if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_start)) {
622*13141SSangeeta.Misra@Sun.COM 				/* V4 case */
623*13141SSangeeta.Misra@Sun.COM 				event->adt_ilb_create_rule.proxy_src_min_type =
624*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv4;
625*13141SSangeeta.Misra@Sun.COM 				cvt_addr(
626*13141SSangeeta.Misra@Sun.COM 				    event->adt_ilb_create_rule.proxy_src_min,
627*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv4, rlinfo->rl_nat_src_start);
62810946SSangeeta.Misra@Sun.COM 			} else {
629*13141SSangeeta.Misra@Sun.COM 				/* V6 case */
630*13141SSangeeta.Misra@Sun.COM 				event->adt_ilb_create_rule.proxy_src_min_type =
631*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv6;
632*13141SSangeeta.Misra@Sun.COM 				cvt_addr(
633*13141SSangeeta.Misra@Sun.COM 				    event->adt_ilb_create_rule.proxy_src_min,
634*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv6, rlinfo->rl_nat_src_start);
63510946SSangeeta.Misra@Sun.COM 			}
636*13141SSangeeta.Misra@Sun.COM 
637*13141SSangeeta.Misra@Sun.COM 			/* copy ending proxy-src address */
638*13141SSangeeta.Misra@Sun.COM 			if (&rlinfo->rl_nat_src_end == 0) {
639*13141SSangeeta.Misra@Sun.COM 				/* proxy-src is a single address */
640*13141SSangeeta.Misra@Sun.COM 				event->adt_ilb_create_rule.proxy_src_max_type =
641*13141SSangeeta.Misra@Sun.COM 				    event->
642*13141SSangeeta.Misra@Sun.COM 				    adt_ilb_create_rule.proxy_src_min_type;
643*13141SSangeeta.Misra@Sun.COM 				(void) memcpy(
644*13141SSangeeta.Misra@Sun.COM 				    event->adt_ilb_create_rule.proxy_src_max,
645*13141SSangeeta.Misra@Sun.COM 				    event->adt_ilb_create_rule.proxy_src_min,
646*13141SSangeeta.Misra@Sun.COM 				    (4 * sizeof (uint32_t)));
647*13141SSangeeta.Misra@Sun.COM 			} else if (
648*13141SSangeeta.Misra@Sun.COM 			    IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_end)) {
649*13141SSangeeta.Misra@Sun.COM 				/*
650*13141SSangeeta.Misra@Sun.COM 				 * proxy-src is a address range - copy ending
651*13141SSangeeta.Misra@Sun.COM 				 * proxy-src address
652*13141SSangeeta.Misra@Sun.COM 				 * V4 case
653*13141SSangeeta.Misra@Sun.COM 				 */
654*13141SSangeeta.Misra@Sun.COM 				event->adt_ilb_create_rule.proxy_src_max_type =
655*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv4;
656*13141SSangeeta.Misra@Sun.COM 				cvt_addr(
657*13141SSangeeta.Misra@Sun.COM 				    event->adt_ilb_create_rule.proxy_src_max,
658*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv4, rlinfo->rl_nat_src_end);
659*13141SSangeeta.Misra@Sun.COM 			} else {
660*13141SSangeeta.Misra@Sun.COM 				/* V6 case */
661*13141SSangeeta.Misra@Sun.COM 				event->adt_ilb_create_rule.proxy_src_max_type =
662*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv6;
663*13141SSangeeta.Misra@Sun.COM 				cvt_addr(
664*13141SSangeeta.Misra@Sun.COM 				    event->adt_ilb_create_rule.proxy_src_max,
665*13141SSangeeta.Misra@Sun.COM 				    ADT_IPv6, rlinfo->rl_nat_src_end);
666*13141SSangeeta.Misra@Sun.COM 			}
66710946SSangeeta.Misra@Sun.COM 		}
66810946SSangeeta.Misra@Sun.COM 
66910946SSangeeta.Misra@Sun.COM 		/*
67010946SSangeeta.Misra@Sun.COM 		 * Fill in pmask if user has specified one - 0 means
67110946SSangeeta.Misra@Sun.COM 		 * no persistence
67210946SSangeeta.Misra@Sun.COM 		 */
67310946SSangeeta.Misra@Sun.COM 		valstr1[0] = '\0';
67410946SSangeeta.Misra@Sun.COM 		ilbd_ip_to_str(rlinfo->rl_ipversion, &rlinfo->rl_stickymask,
67510946SSangeeta.Misra@Sun.COM 		    valstr1);
67610946SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.persist_mask = valstr1;
67710946SSangeeta.Misra@Sun.COM 
67810946SSangeeta.Misra@Sun.COM 		/* If there is a hcname */
67910946SSangeeta.Misra@Sun.COM 		if (rlinfo->rl_hcname[0] != '\0')
68010946SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.hcname = rlinfo->rl_hcname;
68110946SSangeeta.Misra@Sun.COM 
68210946SSangeeta.Misra@Sun.COM 		/* Fill in hcport */
68310946SSangeeta.Misra@Sun.COM 		if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_FIX) {
68410946SSangeeta.Misra@Sun.COM 			/* hcport is specified by user */
68512857SSangeeta.Misra@Sun.COM 			(void) snprintf(hcpbuf, PORT_LEN, "%d",
68610946SSangeeta.Misra@Sun.COM 			    rlinfo->rl_hcport);
68710946SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.hcport = hcpbuf;
68810946SSangeeta.Misra@Sun.COM 		} else if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_ANY) {
68910946SSangeeta.Misra@Sun.COM 			/* user has specified "ANY" */
69012857SSangeeta.Misra@Sun.COM 			(void) snprintf(hcpbuf, PORT_LEN, "ANY");
69110946SSangeeta.Misra@Sun.COM 			event->adt_ilb_create_rule.hcport = hcpbuf;
69210946SSangeeta.Misra@Sun.COM 		}
69310946SSangeeta.Misra@Sun.COM 		/*
69410946SSangeeta.Misra@Sun.COM 		 * Fill out the conndrain, nat_timeout and persist_timeout
69510946SSangeeta.Misra@Sun.COM 		 * If the user does not specify them, the default value
69610946SSangeeta.Misra@Sun.COM 		 * is set in the kernel. Userland does not know what
69710946SSangeeta.Misra@Sun.COM 		 * the values are. So if the user
69810946SSangeeta.Misra@Sun.COM 		 * does not specify these values they will show up as
69910946SSangeeta.Misra@Sun.COM 		 * 0 in the audit record.
70010946SSangeeta.Misra@Sun.COM 		 */
70110946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.conndrain_timeout =
70210946SSangeeta.Misra@Sun.COM 		    rlinfo->rl_conndrain;
70310946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.nat_timeout =
70410946SSangeeta.Misra@Sun.COM 		    rlinfo->rl_nat_timeout;
70510946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.persist_timeout =
70610946SSangeeta.Misra@Sun.COM 		    rlinfo->rl_sticky_timeout;
70710946SSangeeta.Misra@Sun.COM 
70810946SSangeeta.Misra@Sun.COM 		/* Fill out servergroup and rule name */
70910946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.server_group = rlinfo->rl_sgname;
71010946SSangeeta.Misra@Sun.COM 		event->adt_ilb_create_rule.rule_name = rlinfo->rl_name;
71110946SSangeeta.Misra@Sun.COM 		break;
71210946SSangeeta.Misra@Sun.COM 	}
71310946SSangeeta.Misra@Sun.COM 	if (rc == ILB_STATUS_OK) {
71410946SSangeeta.Misra@Sun.COM 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
71510946SSangeeta.Misra@Sun.COM 			logerr("ilbd_audit_rule_event:adt_put_event failed");
71610946SSangeeta.Misra@Sun.COM 			exit(EXIT_FAILURE);
71710946SSangeeta.Misra@Sun.COM 		}
71810946SSangeeta.Misra@Sun.COM 	} else {
71910946SSangeeta.Misra@Sun.COM 		audit_error = ilberror2auditerror(rc);
72010946SSangeeta.Misra@Sun.COM 		if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) {
72110946SSangeeta.Misra@Sun.COM 			logerr("ilbd_audit_rule_event: adt_put_event failed");
72210946SSangeeta.Misra@Sun.COM 			exit(EXIT_FAILURE);
72310946SSangeeta.Misra@Sun.COM 		}
72410946SSangeeta.Misra@Sun.COM 	}
72510946SSangeeta.Misra@Sun.COM 	adt_free_event(event);
72612857SSangeeta.Misra@Sun.COM 	free(aobuf);
72712857SSangeeta.Misra@Sun.COM 	free(valstr1);
72812857SSangeeta.Misra@Sun.COM 	free(valstr2);
72910946SSangeeta.Misra@Sun.COM 	(void) adt_end_session(ah);
73010946SSangeeta.Misra@Sun.COM }
731*13141SSangeeta.Misra@Sun.COM /*
732*13141SSangeeta.Misra@Sun.COM  * converts IP address from in6_addr format to uint32_t[4]
733*13141SSangeeta.Misra@Sun.COM  * This conversion is needed for recording IP address in
734*13141SSangeeta.Misra@Sun.COM  * audit records.
735*13141SSangeeta.Misra@Sun.COM  */
736*13141SSangeeta.Misra@Sun.COM void
cvt_addr(uint32_t * audit,int32_t type,struct in6_addr address)737*13141SSangeeta.Misra@Sun.COM cvt_addr(uint32_t *audit, int32_t type, struct in6_addr address)
738*13141SSangeeta.Misra@Sun.COM {
739*13141SSangeeta.Misra@Sun.COM 
740*13141SSangeeta.Misra@Sun.COM 	if (type == ADT_IPv4)  {
741*13141SSangeeta.Misra@Sun.COM 		/* address is IPv4 */
742*13141SSangeeta.Misra@Sun.COM 		audit[0] = address._S6_un._S6_u32[3];
743*13141SSangeeta.Misra@Sun.COM 	} else {
744*13141SSangeeta.Misra@Sun.COM 		/* address is IPv6 */
745*13141SSangeeta.Misra@Sun.COM 		(void) memcpy(audit, address._S6_un._S6_u32,
746*13141SSangeeta.Misra@Sun.COM 		    (4 * sizeof (uint32_t)));
747*13141SSangeeta.Misra@Sun.COM 	}
748*13141SSangeeta.Misra@Sun.COM }
74910946SSangeeta.Misra@Sun.COM 
75010946SSangeeta.Misra@Sun.COM static ilb_status_t
i_ilbd_action_switch(ilbd_rule_t * irl,ilbd_cmd_t cmd,boolean_t is_rollback,ucred_t * ucredp)75110946SSangeeta.Misra@Sun.COM i_ilbd_action_switch(ilbd_rule_t *irl, ilbd_cmd_t cmd,
75210946SSangeeta.Misra@Sun.COM     boolean_t is_rollback, ucred_t *ucredp)
75310946SSangeeta.Misra@Sun.COM {
75410946SSangeeta.Misra@Sun.COM 	ilb_status_t    rc;
75510946SSangeeta.Misra@Sun.COM 
75610946SSangeeta.Misra@Sun.COM 	switch (cmd) {
75710946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
75810946SSangeeta.Misra@Sun.COM 		rc = ilbd_destroy_one_rule(irl);
75910946SSangeeta.Misra@Sun.COM 		if (!is_rollback) {
76010946SSangeeta.Misra@Sun.COM 			ilbd_audit_rule_event(irl->irl_name, NULL,
76110946SSangeeta.Misra@Sun.COM 			    cmd, rc, ucredp);
76210946SSangeeta.Misra@Sun.COM 		}
76310946SSangeeta.Misra@Sun.COM 		return (rc);
76410946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
76510946SSangeeta.Misra@Sun.COM 		rc = ilbd_enable_one_rule(irl, is_rollback);
76610946SSangeeta.Misra@Sun.COM 		if (!is_rollback) {
76710946SSangeeta.Misra@Sun.COM 			ilbd_audit_rule_event(irl->irl_name, NULL, cmd,
76810946SSangeeta.Misra@Sun.COM 			    rc, ucredp);
76910946SSangeeta.Misra@Sun.COM 		}
77010946SSangeeta.Misra@Sun.COM 		return (rc);
77110946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
77210946SSangeeta.Misra@Sun.COM 		rc = ilbd_disable_one_rule(irl, is_rollback);
77310946SSangeeta.Misra@Sun.COM 		if (!is_rollback) {
77410946SSangeeta.Misra@Sun.COM 			ilbd_audit_rule_event(irl->irl_name, NULL, cmd,
77510946SSangeeta.Misra@Sun.COM 			    rc, ucredp);
77610946SSangeeta.Misra@Sun.COM 		}
77710946SSangeeta.Misra@Sun.COM 		return (rc);
77810946SSangeeta.Misra@Sun.COM 	}
77910946SSangeeta.Misra@Sun.COM 	return (ILB_STATUS_INVAL_CMD);
78010946SSangeeta.Misra@Sun.COM }
78110946SSangeeta.Misra@Sun.COM 
78210946SSangeeta.Misra@Sun.COM static ilb_cmd_t
i_ilbd2ilb_cmd(ilbd_cmd_t c)78310946SSangeeta.Misra@Sun.COM i_ilbd2ilb_cmd(ilbd_cmd_t c)
78410946SSangeeta.Misra@Sun.COM {
78510946SSangeeta.Misra@Sun.COM 	ilb_cmd_t	r;
78610946SSangeeta.Misra@Sun.COM 
78710946SSangeeta.Misra@Sun.COM 	switch (c) {
78810946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_RULE:
78910946SSangeeta.Misra@Sun.COM 		r = ILB_CREATE_RULE;
79010946SSangeeta.Misra@Sun.COM 		break;
79110946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
79210946SSangeeta.Misra@Sun.COM 		r = ILB_DESTROY_RULE;
79310946SSangeeta.Misra@Sun.COM 		break;
79410946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
79510946SSangeeta.Misra@Sun.COM 		r = ILB_ENABLE_RULE;
79610946SSangeeta.Misra@Sun.COM 		break;
79710946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
79810946SSangeeta.Misra@Sun.COM 		r = ILB_DISABLE_RULE;
79910946SSangeeta.Misra@Sun.COM 		break;
80010946SSangeeta.Misra@Sun.COM 	}
80110946SSangeeta.Misra@Sun.COM 	return (r);
80210946SSangeeta.Misra@Sun.COM }
80310946SSangeeta.Misra@Sun.COM 
80410946SSangeeta.Misra@Sun.COM static ilbd_cmd_t
get_undo_cmd(ilbd_cmd_t cmd)80510946SSangeeta.Misra@Sun.COM get_undo_cmd(ilbd_cmd_t cmd)
80610946SSangeeta.Misra@Sun.COM {
80710946SSangeeta.Misra@Sun.COM 	ilbd_cmd_t	u_cmd;
80810946SSangeeta.Misra@Sun.COM 
80910946SSangeeta.Misra@Sun.COM 	switch (cmd) {
81010946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
81110946SSangeeta.Misra@Sun.COM 		u_cmd = ILBD_BAD_CMD;
81210946SSangeeta.Misra@Sun.COM 		break;
81310946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
81410946SSangeeta.Misra@Sun.COM 		u_cmd = ILBD_DISABLE_RULE;
81510946SSangeeta.Misra@Sun.COM 		break;
81610946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
81710946SSangeeta.Misra@Sun.COM 		u_cmd = ILBD_ENABLE_RULE;
81810946SSangeeta.Misra@Sun.COM 		break;
81910946SSangeeta.Misra@Sun.COM 	}
82010946SSangeeta.Misra@Sun.COM 
82110946SSangeeta.Misra@Sun.COM 	return (u_cmd);
82210946SSangeeta.Misra@Sun.COM }
82310946SSangeeta.Misra@Sun.COM 
82410946SSangeeta.Misra@Sun.COM static ilb_status_t
i_ilbd_rule_action(const char * rule_name,const struct passwd * ps,ilbd_cmd_t cmd,ucred_t * ucredp)82510946SSangeeta.Misra@Sun.COM i_ilbd_rule_action(const char *rule_name, const struct passwd *ps,
82610946SSangeeta.Misra@Sun.COM     ilbd_cmd_t cmd, ucred_t *ucredp)
82710946SSangeeta.Misra@Sun.COM {
82810946SSangeeta.Misra@Sun.COM 	ilbd_rule_t	*irl, *irl_next;
82910946SSangeeta.Misra@Sun.COM 	boolean_t	is_all_rules = B_FALSE;
83010946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc = ILB_STATUS_OK;
83110946SSangeeta.Misra@Sun.COM 	ilb_name_cmd_t	kcmd;
83210946SSangeeta.Misra@Sun.COM 	ilbd_cmd_t	u_cmd;
83310946SSangeeta.Misra@Sun.COM 	char    rulename[ILB_NAMESZ];
83410946SSangeeta.Misra@Sun.COM 
83510946SSangeeta.Misra@Sun.COM 	if (ps != NULL) {
83610946SSangeeta.Misra@Sun.COM 		if ((cmd == ILBD_ENABLE_RULE) || (cmd == ILBD_DISABLE_RULE))
83710946SSangeeta.Misra@Sun.COM 			rc = ilbd_check_client_enable_auth(ps);
83810946SSangeeta.Misra@Sun.COM 		else
83910946SSangeeta.Misra@Sun.COM 			rc = ilbd_check_client_config_auth(ps);
84010946SSangeeta.Misra@Sun.COM 		/* generate the audit record before bailing out */
84110946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK) {
84210946SSangeeta.Misra@Sun.COM 			if (rule_name != '\0') {
84310946SSangeeta.Misra@Sun.COM 				ilbd_audit_rule_event(rule_name, NULL,
84410946SSangeeta.Misra@Sun.COM 				    cmd, rc, ucredp);
84510946SSangeeta.Misra@Sun.COM 			} else {
84610946SSangeeta.Misra@Sun.COM 				(void) snprintf(rulename, sizeof (rulename),
84710946SSangeeta.Misra@Sun.COM 				    "all");
84810946SSangeeta.Misra@Sun.COM 				ilbd_audit_rule_event(rulename, NULL, cmd, rc,
84910946SSangeeta.Misra@Sun.COM 				    ucredp);
85010946SSangeeta.Misra@Sun.COM 			}
85110946SSangeeta.Misra@Sun.COM 			goto out;
85210946SSangeeta.Misra@Sun.COM 		}
85310946SSangeeta.Misra@Sun.COM 	}
85410946SSangeeta.Misra@Sun.COM 	is_all_rules = rule_name[0] == 0;
85510946SSangeeta.Misra@Sun.COM 
85610946SSangeeta.Misra@Sun.COM 	/* just one rule */
85710946SSangeeta.Misra@Sun.COM 	if (!is_all_rules) {
85810946SSangeeta.Misra@Sun.COM 		irl = i_find_rule_byname(rule_name);
85910946SSangeeta.Misra@Sun.COM 		if (irl == NULL) {
86010946SSangeeta.Misra@Sun.COM 			rc = ILB_STATUS_ENORULE;
86110946SSangeeta.Misra@Sun.COM 			ilbd_audit_rule_event(rule_name, NULL, cmd, rc, ucredp);
86210946SSangeeta.Misra@Sun.COM 			goto out;
86310946SSangeeta.Misra@Sun.COM 		}
86410946SSangeeta.Misra@Sun.COM 		/* auditing will be done by i_ilbd_action_switch() */
86510946SSangeeta.Misra@Sun.COM 		rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp);
86610946SSangeeta.Misra@Sun.COM 		goto out;
86710946SSangeeta.Misra@Sun.COM 	}
86810946SSangeeta.Misra@Sun.COM 
86910946SSangeeta.Misra@Sun.COM 	/* all rules: first tell the kernel, then walk the daemon's list */
87010946SSangeeta.Misra@Sun.COM 	kcmd.cmd = i_ilbd2ilb_cmd(cmd);
87110946SSangeeta.Misra@Sun.COM 	kcmd.flags = ILB_RULE_ALLRULES;
87210946SSangeeta.Misra@Sun.COM 
87310946SSangeeta.Misra@Sun.COM 	rc = do_ioctl(&kcmd, 0);
87410946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK) {
87510946SSangeeta.Misra@Sun.COM 		(void) snprintf(rulename, sizeof (rulename), "all");
87610946SSangeeta.Misra@Sun.COM 		ilbd_audit_rule_event(rulename, NULL, cmd, rc, ucredp);
87710946SSangeeta.Misra@Sun.COM 		goto out;
87810946SSangeeta.Misra@Sun.COM 	}
87910946SSangeeta.Misra@Sun.COM 
88010946SSangeeta.Misra@Sun.COM 	irl = list_head(&ilbd_rule_hlist);
88110946SSangeeta.Misra@Sun.COM 	while (irl != NULL) {
88210946SSangeeta.Misra@Sun.COM 		irl_next = list_next(&ilbd_rule_hlist, irl);
88310946SSangeeta.Misra@Sun.COM 		irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES;
88410946SSangeeta.Misra@Sun.COM 		/* auditing will be done by i_ilbd_action_switch() */
88510946SSangeeta.Misra@Sun.COM 		rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp);
88610946SSangeeta.Misra@Sun.COM 		irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES;
88710946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
88810946SSangeeta.Misra@Sun.COM 			goto rollback_list;
88910946SSangeeta.Misra@Sun.COM 		irl = irl_next;
89010946SSangeeta.Misra@Sun.COM 	}
89110946SSangeeta.Misra@Sun.COM 	return (rc);
89210946SSangeeta.Misra@Sun.COM 
89310946SSangeeta.Misra@Sun.COM rollback_list:
89410946SSangeeta.Misra@Sun.COM 	u_cmd = get_undo_cmd(cmd);
89510946SSangeeta.Misra@Sun.COM 	if (u_cmd == ILBD_BAD_CMD)
89610946SSangeeta.Misra@Sun.COM 		return (rc);
89710946SSangeeta.Misra@Sun.COM 
89810946SSangeeta.Misra@Sun.COM 	if (is_all_rules) {
89910946SSangeeta.Misra@Sun.COM 		kcmd.cmd = i_ilbd2ilb_cmd(u_cmd);
90010946SSangeeta.Misra@Sun.COM 		(void) do_ioctl(&kcmd, 0);
90110946SSangeeta.Misra@Sun.COM 	}
90210946SSangeeta.Misra@Sun.COM 	/* current list element failed, so we start with previous one */
90310946SSangeeta.Misra@Sun.COM 	irl = list_prev(&ilbd_rule_hlist, irl);
90410946SSangeeta.Misra@Sun.COM 	while (irl != NULL) {
90510946SSangeeta.Misra@Sun.COM 		if (is_all_rules)
90610946SSangeeta.Misra@Sun.COM 			irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES;
90710946SSangeeta.Misra@Sun.COM 
90810946SSangeeta.Misra@Sun.COM 		/*
90910946SSangeeta.Misra@Sun.COM 		 * When the processing of a command consists of
91010946SSangeeta.Misra@Sun.COM 		 * multiple sequential steps, and one of them fails,
91110946SSangeeta.Misra@Sun.COM 		 * ilbd performs rollback to undo the steps taken before the
91210946SSangeeta.Misra@Sun.COM 		 * failing step. Since ilbd is initiating these steps
91310946SSangeeta.Misra@Sun.COM 		 * there is not need to audit them.
91410946SSangeeta.Misra@Sun.COM 		 */
91510946SSangeeta.Misra@Sun.COM 		rc = i_ilbd_action_switch(irl, u_cmd, B_TRUE, NULL);
91610946SSangeeta.Misra@Sun.COM 		irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES;
91710946SSangeeta.Misra@Sun.COM 
91810946SSangeeta.Misra@Sun.COM 		irl = list_prev(&ilbd_rule_hlist, irl);
91910946SSangeeta.Misra@Sun.COM 	}
92010946SSangeeta.Misra@Sun.COM out:
92110946SSangeeta.Misra@Sun.COM 	return (rc);
92210946SSangeeta.Misra@Sun.COM }
92310946SSangeeta.Misra@Sun.COM 
92410946SSangeeta.Misra@Sun.COM ilb_status_t
ilbd_destroy_rule(ilbd_name_t rule_name,const struct passwd * ps,ucred_t * ucredp)92510946SSangeeta.Misra@Sun.COM ilbd_destroy_rule(ilbd_name_t rule_name, const struct passwd *ps,
92610946SSangeeta.Misra@Sun.COM     ucred_t *ucredp)
92710946SSangeeta.Misra@Sun.COM {
92810946SSangeeta.Misra@Sun.COM 	return (i_ilbd_rule_action(rule_name, ps, ILBD_DESTROY_RULE, ucredp));
92910946SSangeeta.Misra@Sun.COM }
93010946SSangeeta.Misra@Sun.COM 
93110946SSangeeta.Misra@Sun.COM ilb_status_t
ilbd_enable_rule(ilbd_name_t rule_name,const struct passwd * ps,ucred_t * ucredp)93210946SSangeeta.Misra@Sun.COM ilbd_enable_rule(ilbd_name_t rule_name, const struct passwd *ps,
93310946SSangeeta.Misra@Sun.COM     ucred_t *ucredp)
93410946SSangeeta.Misra@Sun.COM {
93510946SSangeeta.Misra@Sun.COM 	return (i_ilbd_rule_action(rule_name, ps, ILBD_ENABLE_RULE, ucredp));
93610946SSangeeta.Misra@Sun.COM 
93710946SSangeeta.Misra@Sun.COM }
93810946SSangeeta.Misra@Sun.COM 
93910946SSangeeta.Misra@Sun.COM ilb_status_t
ilbd_disable_rule(ilbd_name_t rule_name,const struct passwd * ps,ucred_t * ucredp)94010946SSangeeta.Misra@Sun.COM ilbd_disable_rule(ilbd_name_t rule_name, const struct passwd *ps,
94110946SSangeeta.Misra@Sun.COM     ucred_t *ucredp)
94210946SSangeeta.Misra@Sun.COM {
94310946SSangeeta.Misra@Sun.COM 	return (i_ilbd_rule_action(rule_name, ps, ILBD_DISABLE_RULE, ucredp));
94410946SSangeeta.Misra@Sun.COM }
94510946SSangeeta.Misra@Sun.COM 
94610946SSangeeta.Misra@Sun.COM /*
94710946SSangeeta.Misra@Sun.COM  * allocate storage for a kernel rule command and fill from
94810946SSangeeta.Misra@Sun.COM  * "template" irl, if non-NULL
94910946SSangeeta.Misra@Sun.COM  */
95010946SSangeeta.Misra@Sun.COM static ilb_rule_cmd_t *
i_alloc_kernel_rule_cmd(ilbd_rule_t * irl)95110946SSangeeta.Misra@Sun.COM i_alloc_kernel_rule_cmd(ilbd_rule_t *irl)
95210946SSangeeta.Misra@Sun.COM {
95310946SSangeeta.Misra@Sun.COM 	ilb_rule_cmd_t *kcmd;
95410946SSangeeta.Misra@Sun.COM 
95510946SSangeeta.Misra@Sun.COM 	kcmd = (ilb_rule_cmd_t *)malloc(sizeof (*kcmd));
95610946SSangeeta.Misra@Sun.COM 	if (kcmd == NULL)
95710946SSangeeta.Misra@Sun.COM 		return (kcmd);
95810946SSangeeta.Misra@Sun.COM 
95910946SSangeeta.Misra@Sun.COM 	bzero(kcmd, sizeof (*kcmd));
96010946SSangeeta.Misra@Sun.COM 
96110946SSangeeta.Misra@Sun.COM 	if (irl != NULL) {
96210946SSangeeta.Misra@Sun.COM 		kcmd->flags = irl->irl_flags;
96310946SSangeeta.Misra@Sun.COM 		kcmd->ip_ver = AF_2_IPPROTO(irl->irl_ipversion);
96410946SSangeeta.Misra@Sun.COM 		kcmd->vip = irl->irl_vip;
96510946SSangeeta.Misra@Sun.COM 		kcmd->proto = irl->irl_proto;
96610946SSangeeta.Misra@Sun.COM 		kcmd->min_port = irl->irl_minport;
96710946SSangeeta.Misra@Sun.COM 		kcmd->max_port = irl->irl_maxport;
96810946SSangeeta.Misra@Sun.COM 		kcmd->algo = algo_lib2impl(irl->irl_algo);
96910946SSangeeta.Misra@Sun.COM 		kcmd->topo = topo_lib2impl(irl->irl_topo);
97010946SSangeeta.Misra@Sun.COM 		kcmd->sticky_mask = irl->irl_stickymask;
97110946SSangeeta.Misra@Sun.COM 		kcmd->nat_src_start = irl->irl_nat_src_start;
97210946SSangeeta.Misra@Sun.COM 		kcmd->nat_src_end = irl->irl_nat_src_end;
97310946SSangeeta.Misra@Sun.COM 		kcmd->conn_drain_timeout = irl->irl_conndrain;
97410946SSangeeta.Misra@Sun.COM 		kcmd->nat_expiry = irl->irl_nat_timeout;
97510946SSangeeta.Misra@Sun.COM 		kcmd->sticky_expiry = irl->irl_sticky_timeout;
97610946SSangeeta.Misra@Sun.COM 		(void) strlcpy(kcmd->name, irl->irl_name,
97710946SSangeeta.Misra@Sun.COM 		    sizeof (kcmd->name));
97810946SSangeeta.Misra@Sun.COM 	}
97910946SSangeeta.Misra@Sun.COM 	return (kcmd);
98010946SSangeeta.Misra@Sun.COM }
98110946SSangeeta.Misra@Sun.COM 
98210946SSangeeta.Misra@Sun.COM /*
98310946SSangeeta.Misra@Sun.COM  * ncount is the next to be used index into (*kcmdp)->servers
98410946SSangeeta.Misra@Sun.COM  */
98510946SSangeeta.Misra@Sun.COM static ilb_status_t
adjust_srv_info_cmd(ilb_servers_info_cmd_t ** kcmdp,int index)98610946SSangeeta.Misra@Sun.COM adjust_srv_info_cmd(ilb_servers_info_cmd_t **kcmdp, int index)
98710946SSangeeta.Misra@Sun.COM {
98810946SSangeeta.Misra@Sun.COM 	ilb_servers_info_cmd_t	*kcmd = *kcmdp;
98910946SSangeeta.Misra@Sun.COM 	size_t			sz;
99010946SSangeeta.Misra@Sun.COM 
99110946SSangeeta.Misra@Sun.COM 	if (kcmd != NULL && kcmd->num_servers > index + 1)
99210946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_OK);
99310946SSangeeta.Misra@Sun.COM 
99410946SSangeeta.Misra@Sun.COM 	/*
99510946SSangeeta.Misra@Sun.COM 	 * the first ilb_server_info_t is part of *kcmd, so
99610946SSangeeta.Misra@Sun.COM 	 * by using index (which is one less than the total needed) here,
99710946SSangeeta.Misra@Sun.COM 	 * we allocate exactly the amount we need.
99810946SSangeeta.Misra@Sun.COM 	 */
99910946SSangeeta.Misra@Sun.COM 	sz = sizeof (*kcmd) + (index * sizeof (ilb_server_info_t));
100010946SSangeeta.Misra@Sun.COM 	kcmd = (ilb_servers_info_cmd_t *)realloc(kcmd, sz);
100110946SSangeeta.Misra@Sun.COM 	if (kcmd == NULL)
100210946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_ENOMEM);
100310946SSangeeta.Misra@Sun.COM 
100410946SSangeeta.Misra@Sun.COM 	/*
100510946SSangeeta.Misra@Sun.COM 	 * we don't count the slot we newly allocated yet.
100610946SSangeeta.Misra@Sun.COM 	 */
100710946SSangeeta.Misra@Sun.COM 	kcmd->num_servers = index;
100810946SSangeeta.Misra@Sun.COM 	*kcmdp = kcmd;
100910946SSangeeta.Misra@Sun.COM 
101010946SSangeeta.Misra@Sun.COM 	return (ILB_STATUS_OK);
101110946SSangeeta.Misra@Sun.COM }
101210946SSangeeta.Misra@Sun.COM 
101310946SSangeeta.Misra@Sun.COM /*
101410946SSangeeta.Misra@Sun.COM  * this function adds all servers in srvlist to the kernel(!) rule
101510946SSangeeta.Misra@Sun.COM  * the name of which is passed as argument.
101610946SSangeeta.Misra@Sun.COM  */
101710946SSangeeta.Misra@Sun.COM static ilb_status_t
i_update_ksrv_rules(char * name,ilbd_sg_t * sg,ilbd_rule_t * rl)101810946SSangeeta.Misra@Sun.COM i_update_ksrv_rules(char *name, ilbd_sg_t *sg, ilbd_rule_t *rl)
101910946SSangeeta.Misra@Sun.COM {
102010946SSangeeta.Misra@Sun.COM 	ilb_status_t		rc;
102110946SSangeeta.Misra@Sun.COM 	ilbd_srv_t		*srvp;
102210946SSangeeta.Misra@Sun.COM 	ilb_servers_info_cmd_t	*kcmd = NULL;
102310946SSangeeta.Misra@Sun.COM 	int			i;
102410946SSangeeta.Misra@Sun.COM 
102510946SSangeeta.Misra@Sun.COM 	/*
102610946SSangeeta.Misra@Sun.COM 	 * If the servergroup doesn't have any servers associated with
102710946SSangeeta.Misra@Sun.COM 	 * it yet, there's nothing more to do here.
102810946SSangeeta.Misra@Sun.COM 	 */
102910946SSangeeta.Misra@Sun.COM 	if (sg->isg_srvcount == 0)
103010946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_OK);
103110946SSangeeta.Misra@Sun.COM 
103210946SSangeeta.Misra@Sun.COM 	/*
103310946SSangeeta.Misra@Sun.COM 	 * walk the list of servers attached to this SG
103410946SSangeeta.Misra@Sun.COM 	 */
103510946SSangeeta.Misra@Sun.COM 	srvp = list_head(&sg->isg_srvlist);
103610946SSangeeta.Misra@Sun.COM 	for (i = 0; srvp != NULL; srvp = list_next(&sg->isg_srvlist, srvp)) {
103710946SSangeeta.Misra@Sun.COM 		rc = adjust_srv_info_cmd(&kcmd, i);
103810946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
103910946SSangeeta.Misra@Sun.COM 			return (rc);
104010946SSangeeta.Misra@Sun.COM 
104110946SSangeeta.Misra@Sun.COM 		ILB_SGSRV_2_KSRV(&srvp->isv_srv, &kcmd->servers[i]);
104210946SSangeeta.Misra@Sun.COM 		/*
104310946SSangeeta.Misra@Sun.COM 		 * "no port" means "copy rule's port" (for kernel rule)
104410946SSangeeta.Misra@Sun.COM 		 */
104510946SSangeeta.Misra@Sun.COM 		if (kcmd->servers[i].min_port == 0) {
104610946SSangeeta.Misra@Sun.COM 			kcmd->servers[i].min_port = rl->irl_minport;
104710946SSangeeta.Misra@Sun.COM 			kcmd->servers[i].max_port = rl->irl_maxport;
104810946SSangeeta.Misra@Sun.COM 		}
104910946SSangeeta.Misra@Sun.COM 		i++;
105010946SSangeeta.Misra@Sun.COM 	}
105110946SSangeeta.Misra@Sun.COM 
105210946SSangeeta.Misra@Sun.COM 	kcmd->cmd = ILB_ADD_SERVERS;
105310946SSangeeta.Misra@Sun.COM 	kcmd->num_servers = i;
105410946SSangeeta.Misra@Sun.COM 	(void) strlcpy(kcmd->name, name, sizeof (kcmd->name));
105510946SSangeeta.Misra@Sun.COM 
105610946SSangeeta.Misra@Sun.COM 	rc = do_ioctl(kcmd, 0);
105710946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK)
105810946SSangeeta.Misra@Sun.COM 		return (rc);
105910946SSangeeta.Misra@Sun.COM 
106010946SSangeeta.Misra@Sun.COM 	for (i = 0; i < kcmd->num_servers; i++) {
106110946SSangeeta.Misra@Sun.COM 		int e;
106210946SSangeeta.Misra@Sun.COM 
106310946SSangeeta.Misra@Sun.COM 		if ((e = kcmd->servers[i].err) != 0) {
106410946SSangeeta.Misra@Sun.COM 			logerr("i_update_ksrv_rules "
106510946SSangeeta.Misra@Sun.COM 			    "ioctl indicates failure: %s", strerror(e));
106610946SSangeeta.Misra@Sun.COM 			rc = ilb_map_errno2ilbstat(e);
106710946SSangeeta.Misra@Sun.COM 			/*
106810946SSangeeta.Misra@Sun.COM 			 * if adding even a single server failed, we need to
106910946SSangeeta.Misra@Sun.COM 			 * roll back the whole wad. We ignore any errors and
107010946SSangeeta.Misra@Sun.COM 			 * return the one that was returned by the first ioctl.
107110946SSangeeta.Misra@Sun.COM 			 */
107210946SSangeeta.Misra@Sun.COM 			kcmd->cmd = ILB_DEL_SERVERS;
107310946SSangeeta.Misra@Sun.COM 			(void) do_ioctl(kcmd, 0);
107410946SSangeeta.Misra@Sun.COM 			return (rc);
107510946SSangeeta.Misra@Sun.COM 		}
107610946SSangeeta.Misra@Sun.COM 	}
107710946SSangeeta.Misra@Sun.COM 
107810946SSangeeta.Misra@Sun.COM 	return (ILB_STATUS_OK);
107910946SSangeeta.Misra@Sun.COM }
108010946SSangeeta.Misra@Sun.COM 
108110946SSangeeta.Misra@Sun.COM /* convert a struct in6_addr to valstr */
108210946SSangeeta.Misra@Sun.COM void
ilbd_ip_to_str(uint16_t ipversion,struct in6_addr * addr,char * valstr)108310946SSangeeta.Misra@Sun.COM ilbd_ip_to_str(uint16_t ipversion, struct in6_addr *addr, char *valstr)
108410946SSangeeta.Misra@Sun.COM {
108510946SSangeeta.Misra@Sun.COM 	size_t	vallen;
108610946SSangeeta.Misra@Sun.COM 	ilb_ip_addr_t	ipaddr;
108710946SSangeeta.Misra@Sun.COM 	void	*addrptr;
108810946SSangeeta.Misra@Sun.COM 
108910946SSangeeta.Misra@Sun.COM 	vallen = (ipversion == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
109010946SSangeeta.Misra@Sun.COM 
109110946SSangeeta.Misra@Sun.COM 	IP_COPY_IMPL_2_CLI(addr, &ipaddr);
109210946SSangeeta.Misra@Sun.COM 	addrptr = (ipversion == AF_INET) ?
109310946SSangeeta.Misra@Sun.COM 	    (void *)&ipaddr.ia_v4 : (void *)&ipaddr.ia_v6;
109410946SSangeeta.Misra@Sun.COM 	if (inet_ntop(ipversion, (void *)addrptr, valstr, vallen == NULL))
109510946SSangeeta.Misra@Sun.COM 		logerr("ilbd_ip_to_str: inet_ntop failed");
109610946SSangeeta.Misra@Sun.COM 	return;
109710946SSangeeta.Misra@Sun.COM 
109810946SSangeeta.Misra@Sun.COM }
109910946SSangeeta.Misra@Sun.COM 
110010946SSangeeta.Misra@Sun.COM ilb_status_t
ilbd_create_rule(ilb_rule_info_t * rl,int ev_port,const struct passwd * ps,ucred_t * ucredp)110110946SSangeeta.Misra@Sun.COM ilbd_create_rule(ilb_rule_info_t *rl, int ev_port,
110210946SSangeeta.Misra@Sun.COM     const struct passwd *ps, ucred_t *ucredp)
110310946SSangeeta.Misra@Sun.COM {
110410946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc;
110510946SSangeeta.Misra@Sun.COM 	ilbd_rule_t	*irl = NULL;
110610946SSangeeta.Misra@Sun.COM 	ilbd_sg_t	*sg;
110710946SSangeeta.Misra@Sun.COM 	ilb_rule_cmd_t	*kcmd = NULL;
110810946SSangeeta.Misra@Sun.COM 
110910946SSangeeta.Misra@Sun.COM 	if (ps != NULL) {
111010946SSangeeta.Misra@Sun.COM 		if ((rc = ilbd_check_client_config_auth(ps)) != ILB_STATUS_OK)
111110946SSangeeta.Misra@Sun.COM 			goto out;
111210946SSangeeta.Misra@Sun.COM 	}
111310946SSangeeta.Misra@Sun.COM 
111410946SSangeeta.Misra@Sun.COM 	if (i_find_rule_byname(rl->rl_name) != NULL) {
111510946SSangeeta.Misra@Sun.COM 		logdebug("ilbd_create_rule: rule %s"
111610946SSangeeta.Misra@Sun.COM 		    " already exists", rl->rl_name);
111710946SSangeeta.Misra@Sun.COM 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
111810946SSangeeta.Misra@Sun.COM 		    ILB_STATUS_DUP_RULE, ucredp);
111910946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_DUP_RULE);
112010946SSangeeta.Misra@Sun.COM 	}
112110946SSangeeta.Misra@Sun.COM 
112210946SSangeeta.Misra@Sun.COM 	sg = i_find_sg_byname(rl->rl_sgname);
112310946SSangeeta.Misra@Sun.COM 	if (sg == NULL) {
112410946SSangeeta.Misra@Sun.COM 		logdebug("ilbd_create_rule: rule %s uses non-existent"
112510946SSangeeta.Misra@Sun.COM 		    " servergroup name %s", rl->rl_name, rl->rl_sgname);
112610946SSangeeta.Misra@Sun.COM 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
112710946SSangeeta.Misra@Sun.COM 		    ILB_STATUS_SGUNAVAIL, ucredp);
112810946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_SGUNAVAIL);
112910946SSangeeta.Misra@Sun.COM 	}
113010946SSangeeta.Misra@Sun.COM 
113110946SSangeeta.Misra@Sun.COM 	if ((rc = ilbd_sg_check_rule_port(sg, rl)) != ILB_STATUS_OK) {
113210946SSangeeta.Misra@Sun.COM 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp);
113310946SSangeeta.Misra@Sun.COM 		return (rc);
113410946SSangeeta.Misra@Sun.COM 	}
113510946SSangeeta.Misra@Sun.COM 
113610946SSangeeta.Misra@Sun.COM 	/* allocs and copies contents of arg (if != NULL) into new rule */
113710946SSangeeta.Misra@Sun.COM 	irl = i_alloc_ilbd_rule(rl);
113810946SSangeeta.Misra@Sun.COM 	if (irl == NULL) {
113910946SSangeeta.Misra@Sun.COM 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
114010946SSangeeta.Misra@Sun.COM 		    ILB_STATUS_ENOMEM, ucredp);
114110946SSangeeta.Misra@Sun.COM 		return (ILB_STATUS_ENOMEM);
114210946SSangeeta.Misra@Sun.COM 	}
114310946SSangeeta.Misra@Sun.COM 
114410946SSangeeta.Misra@Sun.COM 	/* make sure rule's IPversion (via vip) and SG's match */
114510946SSangeeta.Misra@Sun.COM 	if (sg->isg_srvcount > 0) {
114610946SSangeeta.Misra@Sun.COM 		ilbd_srv_t	*srv = list_head(&sg->isg_srvlist);
114710946SSangeeta.Misra@Sun.COM 		int32_t		r_af = rl->rl_ipversion;
114810946SSangeeta.Misra@Sun.COM 		int32_t		s_af = GET_AF(&srv->isv_addr);
114910946SSangeeta.Misra@Sun.COM 
115010946SSangeeta.Misra@Sun.COM 		if (r_af != s_af) {
115110946SSangeeta.Misra@Sun.COM 			logdebug("address family mismatch with servergroup");
115210946SSangeeta.Misra@Sun.COM 			rc = ILB_STATUS_MISMATCHSG;
115310946SSangeeta.Misra@Sun.COM 			goto out;
115410946SSangeeta.Misra@Sun.COM 		}
115510946SSangeeta.Misra@Sun.COM 	}
115610946SSangeeta.Misra@Sun.COM 	irl->irl_sg = sg;
115710946SSangeeta.Misra@Sun.COM 
115810946SSangeeta.Misra@Sun.COM 	/* Try associating the rule with the given hc oject. */
115910946SSangeeta.Misra@Sun.COM 	if (RULE_HAS_HC(irl)) {
116010946SSangeeta.Misra@Sun.COM 		if ((rc = ilbd_hc_associate_rule(irl, ev_port)) !=
116110946SSangeeta.Misra@Sun.COM 		    ILB_STATUS_OK)
116210946SSangeeta.Misra@Sun.COM 			goto out;
116310946SSangeeta.Misra@Sun.COM 	}
116410946SSangeeta.Misra@Sun.COM 
116510946SSangeeta.Misra@Sun.COM 	/*
116610946SSangeeta.Misra@Sun.COM 	 * checks are done, now:
116710946SSangeeta.Misra@Sun.COM 	 * 1. create rule in kernel
116810946SSangeeta.Misra@Sun.COM 	 * 2. tell it about the backend server (which we maintain in SG)
116910946SSangeeta.Misra@Sun.COM 	 * 3. attach the rule in memory
117010946SSangeeta.Misra@Sun.COM 	 */
117110946SSangeeta.Misra@Sun.COM 	/* 1. */
117210946SSangeeta.Misra@Sun.COM 	/* allocs and copies contents of arg (if != NULL) into new rule */
117310946SSangeeta.Misra@Sun.COM 	kcmd = i_alloc_kernel_rule_cmd(irl);
117410946SSangeeta.Misra@Sun.COM 	if (kcmd == NULL) {
117510946SSangeeta.Misra@Sun.COM 		rc = ILB_STATUS_ENOMEM;
117610946SSangeeta.Misra@Sun.COM 		goto rollback_hc;
117710946SSangeeta.Misra@Sun.COM 	}
117810946SSangeeta.Misra@Sun.COM 	kcmd->cmd = ILB_CREATE_RULE;
117910946SSangeeta.Misra@Sun.COM 
118010946SSangeeta.Misra@Sun.COM 	rc = do_ioctl(kcmd, 0);
118110946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK)
118210946SSangeeta.Misra@Sun.COM 		goto rollback_kcmd;
118310946SSangeeta.Misra@Sun.COM 
118410946SSangeeta.Misra@Sun.COM 	/* 2. */
118510946SSangeeta.Misra@Sun.COM 	rc = i_update_ksrv_rules(kcmd->name, sg, irl);
118610946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK)
118710946SSangeeta.Misra@Sun.COM 		goto rollback_kcmd;
118810946SSangeeta.Misra@Sun.COM 
118910946SSangeeta.Misra@Sun.COM 	/* 3. */
119010946SSangeeta.Misra@Sun.COM 	(void) i_attach_rule2sg(sg, irl);
119110946SSangeeta.Misra@Sun.COM 	list_insert_tail(&ilbd_rule_hlist, irl);
119210946SSangeeta.Misra@Sun.COM 
119310946SSangeeta.Misra@Sun.COM 	if (ps != NULL) {
119410946SSangeeta.Misra@Sun.COM 		rc = i_ilbd_save_rule(irl, ILBD_SCF_CREATE);
119510946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK)
119610946SSangeeta.Misra@Sun.COM 			goto rollback_rule;
119710946SSangeeta.Misra@Sun.COM 	}
119810946SSangeeta.Misra@Sun.COM 
119910946SSangeeta.Misra@Sun.COM 	free(kcmd);
120010946SSangeeta.Misra@Sun.COM 	ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
120110946SSangeeta.Misra@Sun.COM 	    ILB_STATUS_OK, ucredp);
120210946SSangeeta.Misra@Sun.COM 	return (ILB_STATUS_OK);
120310946SSangeeta.Misra@Sun.COM 
120410946SSangeeta.Misra@Sun.COM rollback_rule:
120510946SSangeeta.Misra@Sun.COM 	/*
120610946SSangeeta.Misra@Sun.COM 	 * ilbd_destroy_one_rule() also frees irl, as well as dissociate
120710946SSangeeta.Misra@Sun.COM 	 * rule and HC, so all we need to do afterwards is free the kcmd
120810946SSangeeta.Misra@Sun.COM 	 * and return.
120910946SSangeeta.Misra@Sun.COM 	 */
121010946SSangeeta.Misra@Sun.COM 	(void) ilbd_destroy_one_rule(irl);
121110946SSangeeta.Misra@Sun.COM 	ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp);
121210946SSangeeta.Misra@Sun.COM 	free(kcmd);
121310946SSangeeta.Misra@Sun.COM 	return (rc);
121410946SSangeeta.Misra@Sun.COM 
121510946SSangeeta.Misra@Sun.COM rollback_kcmd:
121610946SSangeeta.Misra@Sun.COM 	free(kcmd);
121710946SSangeeta.Misra@Sun.COM rollback_hc:
121810946SSangeeta.Misra@Sun.COM 	/* Cannot fail since the rule is just associated with the hc object. */
121910946SSangeeta.Misra@Sun.COM 	if (RULE_HAS_HC(irl))
122010946SSangeeta.Misra@Sun.COM 		(void) ilbd_hc_dissociate_rule(irl);
122110946SSangeeta.Misra@Sun.COM out:
122210946SSangeeta.Misra@Sun.COM 	ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp);
122310946SSangeeta.Misra@Sun.COM 	free(irl);
122410946SSangeeta.Misra@Sun.COM 	return (rc);
122510946SSangeeta.Misra@Sun.COM }
122610946SSangeeta.Misra@Sun.COM 
122710946SSangeeta.Misra@Sun.COM static uint32_t
i_flags_d2k(int f)122810946SSangeeta.Misra@Sun.COM i_flags_d2k(int f)
122910946SSangeeta.Misra@Sun.COM {
123010946SSangeeta.Misra@Sun.COM 	uint32_t	r = 0;
123110946SSangeeta.Misra@Sun.COM 
123210946SSangeeta.Misra@Sun.COM 	if (ILB_IS_SRV_ENABLED(f))
123310946SSangeeta.Misra@Sun.COM 		r |= ILB_SERVER_ENABLED;
123410946SSangeeta.Misra@Sun.COM 	/* more as they are defined */
123510946SSangeeta.Misra@Sun.COM 
123610946SSangeeta.Misra@Sun.COM 	return (r);
123710946SSangeeta.Misra@Sun.COM }
123810946SSangeeta.Misra@Sun.COM 
123910946SSangeeta.Misra@Sun.COM /*
124010946SSangeeta.Misra@Sun.COM  * walk the list of rules and add srv to the *kernel* rule
124110946SSangeeta.Misra@Sun.COM  * (this is a list of rules hanging off of a server group)
124210946SSangeeta.Misra@Sun.COM  */
124310946SSangeeta.Misra@Sun.COM ilb_status_t
i_add_srv2krules(list_t * rlist,ilb_sg_srv_t * srv,int ev_port)124410946SSangeeta.Misra@Sun.COM i_add_srv2krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port)
124510946SSangeeta.Misra@Sun.COM {
124610946SSangeeta.Misra@Sun.COM 	ilb_status_t		rc = ILB_STATUS_OK;
124710946SSangeeta.Misra@Sun.COM 	ilbd_rule_t		*rl, *del_rl;
124810946SSangeeta.Misra@Sun.COM 	ilb_servers_info_cmd_t	kcmd;
124910946SSangeeta.Misra@Sun.COM 	ilb_servers_cmd_t	del_kcmd;
125010946SSangeeta.Misra@Sun.COM 
125110946SSangeeta.Misra@Sun.COM 	kcmd.cmd = ILB_ADD_SERVERS;
125210946SSangeeta.Misra@Sun.COM 	kcmd.num_servers = 1;
125310946SSangeeta.Misra@Sun.COM 	kcmd.servers[0].err = 0;
125410946SSangeeta.Misra@Sun.COM 	kcmd.servers[0].addr = srv->sgs_addr;
125510946SSangeeta.Misra@Sun.COM 	kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags);
125610946SSangeeta.Misra@Sun.COM 	(void) strlcpy(kcmd.servers[0].name, srv->sgs_srvID,
125710946SSangeeta.Misra@Sun.COM 	    sizeof (kcmd.servers[0].name));
125810946SSangeeta.Misra@Sun.COM 
125910946SSangeeta.Misra@Sun.COM 	/*
126010946SSangeeta.Misra@Sun.COM 	 * a note about rollback: since we need to start rollback with the
126110946SSangeeta.Misra@Sun.COM 	 * current list element in some case, and with the previous one
126210946SSangeeta.Misra@Sun.COM 	 * in others, we must "go back" in this latter case before
126310946SSangeeta.Misra@Sun.COM 	 * we jump to the rollback code.
126410946SSangeeta.Misra@Sun.COM 	 */
126510946SSangeeta.Misra@Sun.COM 	for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) {
126610946SSangeeta.Misra@Sun.COM 		(void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name));
126710946SSangeeta.Misra@Sun.COM 		/*
126810946SSangeeta.Misra@Sun.COM 		 * sgs_minport == 0 means "no port specified"; this
126910946SSangeeta.Misra@Sun.COM 		 * indicates that the server matches anything the rule
127010946SSangeeta.Misra@Sun.COM 		 * provides.
127110946SSangeeta.Misra@Sun.COM 		 * NOTE: this can be different for different rules
127210946SSangeeta.Misra@Sun.COM 		 * using the same server group, therefore we don't modify
127310946SSangeeta.Misra@Sun.COM 		 * this information in the servergroup, but *only* in
127410946SSangeeta.Misra@Sun.COM 		 * the kernel's rule.
127510946SSangeeta.Misra@Sun.COM 		 */
127610946SSangeeta.Misra@Sun.COM 		if (srv->sgs_minport == 0) {
127710946SSangeeta.Misra@Sun.COM 			kcmd.servers[0].min_port = rl->irl_minport;
127810946SSangeeta.Misra@Sun.COM 			kcmd.servers[0].max_port = rl->irl_maxport;
127910946SSangeeta.Misra@Sun.COM 		} else {
128010946SSangeeta.Misra@Sun.COM 			kcmd.servers[0].min_port = srv->sgs_minport;
128110946SSangeeta.Misra@Sun.COM 			kcmd.servers[0].max_port = srv->sgs_maxport;
128210946SSangeeta.Misra@Sun.COM 		}
128310946SSangeeta.Misra@Sun.COM 		rc = do_ioctl((void *)&kcmd, 0);
128410946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK) {
128510946SSangeeta.Misra@Sun.COM 			logdebug("i_add_srv2krules: do_ioctl call failed");
128610946SSangeeta.Misra@Sun.COM 			del_rl = list_prev(rlist, rl);
128710946SSangeeta.Misra@Sun.COM 			goto rollback;
128810946SSangeeta.Misra@Sun.COM 		}
128910946SSangeeta.Misra@Sun.COM 
129010946SSangeeta.Misra@Sun.COM 		/*
129110946SSangeeta.Misra@Sun.COM 		 * if ioctl() returns != 0, it doesn't perform the copyout
129210946SSangeeta.Misra@Sun.COM 		 * necessary to indicate *which* server failed (we could be
129310946SSangeeta.Misra@Sun.COM 		 * adding more than one); therefore we must check this
129410946SSangeeta.Misra@Sun.COM 		 * 'err' field even if ioctl() returns 0.
129510946SSangeeta.Misra@Sun.COM 		 */
129610946SSangeeta.Misra@Sun.COM 		if (kcmd.servers[0].err != 0) {
129710946SSangeeta.Misra@Sun.COM 			logerr("i_add_srv2krules: SIOCILB ioctl returned"
129810946SSangeeta.Misra@Sun.COM 			    " error %d", kcmd.servers[0].err);
129910946SSangeeta.Misra@Sun.COM 			rc = ilb_map_errno2ilbstat(kcmd.servers[0].err);
130010946SSangeeta.Misra@Sun.COM 			del_rl = list_prev(rlist, rl);
130110946SSangeeta.Misra@Sun.COM 			goto rollback;
130210946SSangeeta.Misra@Sun.COM 		}
130310946SSangeeta.Misra@Sun.COM 		if (RULE_HAS_HC(rl)) {
130410946SSangeeta.Misra@Sun.COM 			if ((rc = ilbd_hc_add_server(rl, srv, ev_port)) !=
130510946SSangeeta.Misra@Sun.COM 			    ILB_STATUS_OK) {
130610946SSangeeta.Misra@Sun.COM 				logerr("i_add_srv2krules: cannot start timer "
130710946SSangeeta.Misra@Sun.COM 				    " for rules %s server %s", rl->irl_name,
130810946SSangeeta.Misra@Sun.COM 				    srv->sgs_srvID);
130910946SSangeeta.Misra@Sun.COM 
131010946SSangeeta.Misra@Sun.COM 				del_rl = rl;
131110946SSangeeta.Misra@Sun.COM 				goto rollback;
131210946SSangeeta.Misra@Sun.COM 			}
131310946SSangeeta.Misra@Sun.COM 		}
131410946SSangeeta.Misra@Sun.COM 	}
131510946SSangeeta.Misra@Sun.COM 
131610946SSangeeta.Misra@Sun.COM 	return (rc);
131710946SSangeeta.Misra@Sun.COM 
131810946SSangeeta.Misra@Sun.COM rollback:
131910946SSangeeta.Misra@Sun.COM 	/*
132010946SSangeeta.Misra@Sun.COM 	 * this is almost, but not quite, the same as i_rem_srv_frm_krules()
132110946SSangeeta.Misra@Sun.COM 	 * therefore we keep it seperate.
132210946SSangeeta.Misra@Sun.COM 	 */
132310946SSangeeta.Misra@Sun.COM 	del_kcmd.cmd = ILB_DEL_SERVERS;
132410946SSangeeta.Misra@Sun.COM 	del_kcmd.num_servers = 1;
132510946SSangeeta.Misra@Sun.COM 	del_kcmd.servers[0].addr = srv->sgs_addr;
132610946SSangeeta.Misra@Sun.COM 	while (del_rl != NULL) {
132710946SSangeeta.Misra@Sun.COM 		if (RULE_HAS_HC(del_rl))
132810946SSangeeta.Misra@Sun.COM 			(void) ilbd_hc_del_server(del_rl, srv);
132910946SSangeeta.Misra@Sun.COM 		(void) strlcpy(del_kcmd.name, del_rl->irl_name,
133010946SSangeeta.Misra@Sun.COM 		    sizeof (del_kcmd.name));
133110946SSangeeta.Misra@Sun.COM 		(void) do_ioctl((void *)&del_kcmd, 0);
133210946SSangeeta.Misra@Sun.COM 		del_rl = list_prev(rlist, del_rl);
133310946SSangeeta.Misra@Sun.COM 	}
133410946SSangeeta.Misra@Sun.COM 
133510946SSangeeta.Misra@Sun.COM 	return (rc);
133610946SSangeeta.Misra@Sun.COM }
133710946SSangeeta.Misra@Sun.COM 
133810946SSangeeta.Misra@Sun.COM /*
133910946SSangeeta.Misra@Sun.COM  * ev_port is only used for rollback purposes in this function
134010946SSangeeta.Misra@Sun.COM  */
134110946SSangeeta.Misra@Sun.COM ilb_status_t
i_rem_srv_frm_krules(list_t * rlist,ilb_sg_srv_t * srv,int ev_port)134210946SSangeeta.Misra@Sun.COM i_rem_srv_frm_krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port)
134310946SSangeeta.Misra@Sun.COM {
134410946SSangeeta.Misra@Sun.COM 	ilb_status_t		rc = ILB_STATUS_OK;
134510946SSangeeta.Misra@Sun.COM 	ilbd_rule_t		*rl, *add_rl;
134610946SSangeeta.Misra@Sun.COM 	ilb_servers_cmd_t	kcmd;
134710946SSangeeta.Misra@Sun.COM 	ilb_servers_info_cmd_t	add_kcmd;
134810946SSangeeta.Misra@Sun.COM 
134910946SSangeeta.Misra@Sun.COM 	kcmd.cmd = ILB_DEL_SERVERS;
135010946SSangeeta.Misra@Sun.COM 	kcmd.num_servers = 1;
135110946SSangeeta.Misra@Sun.COM 	kcmd.servers[0].err = 0;
135210946SSangeeta.Misra@Sun.COM 	kcmd.servers[0].addr = srv->sgs_addr;
135310946SSangeeta.Misra@Sun.COM 
135410946SSangeeta.Misra@Sun.COM 	for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) {
135510946SSangeeta.Misra@Sun.COM 		(void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name));
135610946SSangeeta.Misra@Sun.COM 		rc = do_ioctl((void *)&kcmd, 0);
135710946SSangeeta.Misra@Sun.COM 		if (rc != ILB_STATUS_OK) {
135810946SSangeeta.Misra@Sun.COM 			logdebug("i_rem_srv_frm_krules: do_ioctl"
135910946SSangeeta.Misra@Sun.COM 			    "call failed");
136010946SSangeeta.Misra@Sun.COM 			add_rl = list_prev(rlist, rl);
136110946SSangeeta.Misra@Sun.COM 			goto rollback;
136210946SSangeeta.Misra@Sun.COM 		}
136310946SSangeeta.Misra@Sun.COM 		/*
136410946SSangeeta.Misra@Sun.COM 		 * if ioctl() returns != 0, it doesn't perform the copyout
136510946SSangeeta.Misra@Sun.COM 		 * necessary to indicate *which* server failed (we could be
136610946SSangeeta.Misra@Sun.COM 		 * removing more than one); therefore we must check this
136710946SSangeeta.Misra@Sun.COM 		 * 'err' field even if ioctl() returns 0.
136810946SSangeeta.Misra@Sun.COM 		 */
136910946SSangeeta.Misra@Sun.COM 		if (kcmd.servers[0].err != 0) {
137010946SSangeeta.Misra@Sun.COM 			logerr("i_rem_srv_frm_krules: SIOCILB ioctl"
137110946SSangeeta.Misra@Sun.COM 			    " returned error %s",
137210946SSangeeta.Misra@Sun.COM 			    strerror(kcmd.servers[0].err));
137310946SSangeeta.Misra@Sun.COM 			rc = ilb_map_errno2ilbstat(kcmd.servers[0].err);
137410946SSangeeta.Misra@Sun.COM 			add_rl = list_prev(rlist, rl);
137510946SSangeeta.Misra@Sun.COM 			goto rollback;
137610946SSangeeta.Misra@Sun.COM 		}
137710946SSangeeta.Misra@Sun.COM 		if (RULE_HAS_HC(rl) &&
137810946SSangeeta.Misra@Sun.COM 		    (rc = ilbd_hc_del_server(rl, srv)) != ILB_STATUS_OK) {
137910946SSangeeta.Misra@Sun.COM 			logerr("i_rem_srv_frm_krules: cannot delete "
138010946SSangeeta.Misra@Sun.COM 			    "timer for rules %s server %s", rl->irl_name,
138110946SSangeeta.Misra@Sun.COM 			    srv->sgs_srvID);
138210946SSangeeta.Misra@Sun.COM 			add_rl = rl;
138310946SSangeeta.Misra@Sun.COM 			goto rollback;
138410946SSangeeta.Misra@Sun.COM 		}
138510946SSangeeta.Misra@Sun.COM 	}
138610946SSangeeta.Misra@Sun.COM 
138710946SSangeeta.Misra@Sun.COM 	return (rc);
138810946SSangeeta.Misra@Sun.COM 
138910946SSangeeta.Misra@Sun.COM rollback:
139010946SSangeeta.Misra@Sun.COM 	/* Don't do roll back if ev_port == -1. */
139110946SSangeeta.Misra@Sun.COM 	if (ev_port == -1)
139210946SSangeeta.Misra@Sun.COM 		return (rc);
139310946SSangeeta.Misra@Sun.COM 
139410946SSangeeta.Misra@Sun.COM 	add_kcmd.cmd = ILB_ADD_SERVERS;
139510946SSangeeta.Misra@Sun.COM 	add_kcmd.num_servers = 1;
139610946SSangeeta.Misra@Sun.COM 	add_kcmd.servers[0].err = 0;
139710946SSangeeta.Misra@Sun.COM 	add_kcmd.servers[0].addr = srv->sgs_addr;
139810946SSangeeta.Misra@Sun.COM 	add_kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags);
139910946SSangeeta.Misra@Sun.COM 	(void) strlcpy(add_kcmd.servers[0].name, srv->sgs_srvID,
140010946SSangeeta.Misra@Sun.COM 	    sizeof (add_kcmd.servers[0].name));
140110946SSangeeta.Misra@Sun.COM 	while (add_rl != NULL) {
140210946SSangeeta.Misra@Sun.COM 		if (srv->sgs_minport == 0) {
140310946SSangeeta.Misra@Sun.COM 			add_kcmd.servers[0].min_port = add_rl->irl_minport;
140410946SSangeeta.Misra@Sun.COM 			add_kcmd.servers[0].max_port = add_rl->irl_maxport;
140510946SSangeeta.Misra@Sun.COM 		} else {
140610946SSangeeta.Misra@Sun.COM 			add_kcmd.servers[0].min_port = srv->sgs_minport;
140710946SSangeeta.Misra@Sun.COM 			add_kcmd.servers[0].max_port = srv->sgs_maxport;
140810946SSangeeta.Misra@Sun.COM 		}
140910946SSangeeta.Misra@Sun.COM 		if (RULE_HAS_HC(add_rl))
141010946SSangeeta.Misra@Sun.COM 			(void) ilbd_hc_add_server(add_rl, srv, ev_port);
141110946SSangeeta.Misra@Sun.COM 		(void) strlcpy(add_kcmd.name, add_rl->irl_name,
141210946SSangeeta.Misra@Sun.COM 		    sizeof (add_kcmd.name));
141310946SSangeeta.Misra@Sun.COM 		(void) do_ioctl((void *)&add_kcmd, 0);
141410946SSangeeta.Misra@Sun.COM 		add_rl = list_prev(rlist, add_rl);
141510946SSangeeta.Misra@Sun.COM 	}
141610946SSangeeta.Misra@Sun.COM 
141710946SSangeeta.Misra@Sun.COM 	return (rc);
141810946SSangeeta.Misra@Sun.COM }
1419