xref: /onnv-gate/usr/src/uts/common/ipp/ipgpc/classifier.c (revision 4321:a8930ec16e52)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51932Svi117747  * Common Development and Distribution License (the "License").
61932Svi117747  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211932Svi117747 
220Sstevel@tonic-gate /*
23*4321Scasper  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/kmem.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/socket.h>
320Sstevel@tonic-gate #include <sys/strsun.h>
330Sstevel@tonic-gate #include <netinet/in.h>
340Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h>
350Sstevel@tonic-gate #include <inet/ip.h>
360Sstevel@tonic-gate #include <inet/ip6.h>
370Sstevel@tonic-gate #include <net/if.h>
380Sstevel@tonic-gate #include <inet/ipp_common.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /* Implementation file for classifier used in ipgpc module */
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * determines what the result of the selector search and what action needs to
460Sstevel@tonic-gate  * be taken next.
470Sstevel@tonic-gate  * if a NORMAL_MATCH occurs, business as usual NORMAL_MATCH
480Sstevel@tonic-gate  * if the selector was not searched because only DONTCARE keys are loaded,
490Sstevel@tonic-gate  * the selector is marked as not being searched
500Sstevel@tonic-gate  * otherwise, memory error occurred or no matches were found, classify()
510Sstevel@tonic-gate  * should return the error match status immediately
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate #define	CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)	\
540Sstevel@tonic-gate 	(((match_status) == NORMAL_MATCH) ?			\
550Sstevel@tonic-gate 	(NORMAL_MATCH) :					\
560Sstevel@tonic-gate 	(((match_status) == DONTCARE_ONLY_MATCH) ?		\
570Sstevel@tonic-gate 	(*(slctrs_srchd) ^= (selector_mask), NORMAL_MATCH) :	\
580Sstevel@tonic-gate 	(match_status)))
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /* used to determine if an action instance already exists */
610Sstevel@tonic-gate boolean_t ipgpc_action_exist = B_FALSE;
620Sstevel@tonic-gate int ipgpc_debug = 0;		/* IPGPC debugging level */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /* Statics */
650Sstevel@tonic-gate static int common_classify(ipgpc_packet_t *, ht_match_t *, uint16_t *);
660Sstevel@tonic-gate static void update_stats(int, uint_t);
670Sstevel@tonic-gate static int bestmatch(ht_match_t *, uint16_t);
680Sstevel@tonic-gate static void get_port_info(ipgpc_packet_t *, void *, int, mblk_t *);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * common_classify(packet, fid_table, slctrs_srchd)
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  * searches each of the common selectors
740Sstevel@tonic-gate  * - will return NORMAL_MATCH on sucess.  NO_MATCHES on error
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate static int
770Sstevel@tonic-gate common_classify(ipgpc_packet_t *packet, ht_match_t *fid_table,
780Sstevel@tonic-gate     uint16_t *slctrs_srchd)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	int match_status;
810Sstevel@tonic-gate 	int if_grpnm_hv;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	/* Find on packet direction */
840Sstevel@tonic-gate 	match_status =
850Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_DIR, packet->direction, fid_table);
860Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
870Sstevel@tonic-gate 	    ipgpc_table_list[DIR_IDX].info.mask) != NORMAL_MATCH) {
880Sstevel@tonic-gate 		return (match_status);
890Sstevel@tonic-gate 	}
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	/* Find on IF_INDEX of packet */
920Sstevel@tonic-gate 	match_status =
930Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_IF, packet->if_index, fid_table);
940Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
950Sstevel@tonic-gate 	    ipgpc_table_list[IF_IDX].info.mask) != NORMAL_MATCH) {
960Sstevel@tonic-gate 		return (match_status);
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	/* Find on IF_GRPNM of packet */
1000Sstevel@tonic-gate 	if (packet->if_groupname_len > 0) {
1010Sstevel@tonic-gate 		if_grpnm_hv = name_hash(packet->if_groupname, TABLE_SIZE);
1020Sstevel@tonic-gate 	} else {
1030Sstevel@tonic-gate 		if_grpnm_hv = IPGPC_WILDCARD;
1040Sstevel@tonic-gate 	}
1050Sstevel@tonic-gate 	match_status =
1060Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_IF_GRPNM, if_grpnm_hv, fid_table);
1070Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1080Sstevel@tonic-gate 	    ipgpc_table_list[IF_GRPNM_IDX].info.mask) != NORMAL_MATCH) {
1090Sstevel@tonic-gate 		return (match_status);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/* Find on DS field */
1130Sstevel@tonic-gate 	match_status =
1140Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_BA_DSID, packet->dsfield, fid_table);
1150Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1160Sstevel@tonic-gate 	    ipgpc_ds_table_id.info.mask) != NORMAL_MATCH) {
1170Sstevel@tonic-gate 		return (match_status);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* Find on UID of packet */
1210Sstevel@tonic-gate 	match_status =
1220Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_UID, packet->uid, fid_table);
1230Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1240Sstevel@tonic-gate 	    ipgpc_table_list[UID_IDX].info.mask) != NORMAL_MATCH) {
1250Sstevel@tonic-gate 		return (match_status);
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	/* Find on PROJID of packet */
1290Sstevel@tonic-gate 	match_status =
1300Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_PROJID, packet->projid, fid_table);
1310Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1320Sstevel@tonic-gate 	    ipgpc_table_list[PROJID_IDX].info.mask) != NORMAL_MATCH) {
1330Sstevel@tonic-gate 		return (match_status);
1340Sstevel@tonic-gate 	}
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	/* Find on IP Protocol field */
1370Sstevel@tonic-gate 	if (packet->proto > 0) {
1380Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TABLE_PROTOID,
1390Sstevel@tonic-gate 		    packet->proto, fid_table);
1400Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1410Sstevel@tonic-gate 		    ipgpc_table_list[PROTOID_IDX].info.mask)
1420Sstevel@tonic-gate 		    != NORMAL_MATCH) {
1430Sstevel@tonic-gate 			return (match_status);
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 	} else {
1460Sstevel@tonic-gate 		/* skip search */
1470Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_table_list[PROTOID_IDX].info.mask;
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	/* Find on IP Source Port field */
1510Sstevel@tonic-gate 	if (packet->sport > 0) {
1520Sstevel@tonic-gate 		match_status =
1530Sstevel@tonic-gate 		    ipgpc_findfilters(IPGPC_TRIE_SPORTID, packet->sport,
1540Sstevel@tonic-gate 			fid_table);
1550Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1560Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SPORTID].info.mask)
1570Sstevel@tonic-gate 		    != NORMAL_MATCH) {
1580Sstevel@tonic-gate 			return (match_status);
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 	} else {
1610Sstevel@tonic-gate 		/* skip search */
1620Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_trie_list[IPGPC_TRIE_SPORTID].info.mask;
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	/* Find on IP Destination Port field */
1660Sstevel@tonic-gate 	if (packet->dport > 0) {
1670Sstevel@tonic-gate 		match_status =
1680Sstevel@tonic-gate 		    ipgpc_findfilters(IPGPC_TRIE_DPORTID, packet->dport,
1690Sstevel@tonic-gate 			fid_table);
1700Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1710Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DPORTID].info.mask)
1720Sstevel@tonic-gate 		    != NORMAL_MATCH) {
1730Sstevel@tonic-gate 			return (match_status);
1740Sstevel@tonic-gate 		}
1750Sstevel@tonic-gate 	} else {
1760Sstevel@tonic-gate 		/* skip search */
1770Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_trie_list[IPGPC_TRIE_DPORTID].info.mask;
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate 	return (NORMAL_MATCH);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate  * update_stats(class_id, nbytes)
1840Sstevel@tonic-gate  *
1850Sstevel@tonic-gate  * if ipgpc_gather_stats == TRUE
1860Sstevel@tonic-gate  * updates the statistics for class pointed to be the input classid
1870Sstevel@tonic-gate  * and the global ipgpc kstats
1880Sstevel@tonic-gate  * updates the last time the class was matched with the current hrtime value,
1890Sstevel@tonic-gate  * number of packets and number of bytes with nbytes
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate static void
1920Sstevel@tonic-gate update_stats(int class_id, uint_t nbytes)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	if (ipgpc_gather_stats) {
1950Sstevel@tonic-gate 		/* update global stats */
1960Sstevel@tonic-gate 		BUMP_STATS(ipgpc_npackets);
1970Sstevel@tonic-gate 		UPDATE_STATS(ipgpc_nbytes, nbytes);
1980Sstevel@tonic-gate 		if (ipgpc_cid_list[class_id].aclass.gather_stats) {
1990Sstevel@tonic-gate 			/* update per class stats */
2000Sstevel@tonic-gate 			SET_STATS(ipgpc_cid_list[class_id].stats.last_match,
2010Sstevel@tonic-gate 			    gethrtime());
2020Sstevel@tonic-gate 			BUMP_STATS(ipgpc_cid_list[class_id].stats.npackets);
2030Sstevel@tonic-gate 			UPDATE_STATS(ipgpc_cid_list[class_id].stats.nbytes,
2040Sstevel@tonic-gate 			    nbytes);
2050Sstevel@tonic-gate 		}
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate  * FREE_FID_TABLE(fid_table, p, q, i)
2110Sstevel@tonic-gate  *
2120Sstevel@tonic-gate  * searches fid_table for dynamically allocated memory and frees it
2130Sstevel@tonic-gate  * p, q, i are temps
2140Sstevel@tonic-gate  */
2150Sstevel@tonic-gate #define	FREE_FID_TABLE(fid_table, p, q, i)				\
2160Sstevel@tonic-gate 	/* free all allocated memory in fid_table */			\
2170Sstevel@tonic-gate 	for (i = 0; i < HASH_SIZE; ++i) {				\
2180Sstevel@tonic-gate 		if (fid_table[i].next != NULL) {			\
2190Sstevel@tonic-gate 			p = fid_table[i].next;				\
2200Sstevel@tonic-gate 			while (p != NULL) {				\
2210Sstevel@tonic-gate 				q = p;					\
2220Sstevel@tonic-gate 				p = p->next;				\
2230Sstevel@tonic-gate 				kmem_cache_free(ht_match_cache, q);	\
2240Sstevel@tonic-gate 			}						\
2250Sstevel@tonic-gate 		}							\
2261932Svi117747 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate  * ipgpc_classify(af, packet)
2310Sstevel@tonic-gate  *
2320Sstevel@tonic-gate  * The function that drives the packet classification algorithm.  Given a
2330Sstevel@tonic-gate  * address family (either AF_INET or AF_INET6) the input packet structure
2340Sstevel@tonic-gate  * is matched against all the selector structures.  For each search of
2350Sstevel@tonic-gate  * a selector structure, all matched filters are collected.  Once all
2360Sstevel@tonic-gate  * selectors are searched, the best match of all matched filters is
2370Sstevel@tonic-gate  * determined.  Finally, the class associated with the best matching filter
2380Sstevel@tonic-gate  * is returned.  If no filters were matched, the default class is returned.
2390Sstevel@tonic-gate  * If a memory error occurred, NULL is returned.
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate ipgpc_class_t *
2420Sstevel@tonic-gate ipgpc_classify(int af, ipgpc_packet_t *packet)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	int match_status;
2450Sstevel@tonic-gate 	uint16_t slctrs_srchd;
2460Sstevel@tonic-gate 	int class_id;
2470Sstevel@tonic-gate 	ht_match_t fid_table[HASH_SIZE];
2480Sstevel@tonic-gate 	ht_match_t *p, *q;
2490Sstevel@tonic-gate 	int i;
2500Sstevel@tonic-gate 	int rc;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (ipgpc_num_fltrs == 0) {
2530Sstevel@tonic-gate 		/* zero filters are loaded, return default class */
2540Sstevel@tonic-gate 		update_stats(ipgpc_def_class_id, packet->len);
2550Sstevel@tonic-gate 		/*
2560Sstevel@tonic-gate 		 * no need to free fid_table. Since zero selectors were
2570Sstevel@tonic-gate 		 * searched and dynamic memory wasn't allocated.
2580Sstevel@tonic-gate 		 */
2590Sstevel@tonic-gate 		return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	match_status = 0;
2630Sstevel@tonic-gate 	slctrs_srchd = ALL_MATCH_MASK;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	bzero(fid_table, sizeof (ht_match_t) * HASH_SIZE);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/* first search all address family independent selectors */
2680Sstevel@tonic-gate 	if ((rc = common_classify(packet, fid_table, &slctrs_srchd)) !=
2690Sstevel@tonic-gate 		NORMAL_MATCH) {
2700Sstevel@tonic-gate 		/* free all dynamic allocated memory */
2710Sstevel@tonic-gate 		FREE_FID_TABLE(fid_table, p, q, i);
2720Sstevel@tonic-gate 		if (rc == NO_MATCHES) {
2730Sstevel@tonic-gate 			update_stats(ipgpc_def_class_id, packet->len);
2740Sstevel@tonic-gate 			return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
2750Sstevel@tonic-gate 		} else {	/* memory error */
2760Sstevel@tonic-gate 			return (NULL);
2770Sstevel@tonic-gate 		}
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	switch (af) {		/* switch off of address family */
2810Sstevel@tonic-gate 	case AF_INET:
2820Sstevel@tonic-gate 		/* Find on IPv4 Source Address field */
2830Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TRIE_SADDRID,
2840Sstevel@tonic-gate 		    V4_PART_OF_V6(packet->saddr), fid_table);
2850Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
2860Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SADDRID].info.mask)
2870Sstevel@tonic-gate 		    != NORMAL_MATCH) {
2880Sstevel@tonic-gate 			/* free all dynamic allocated memory */
2890Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
2900Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
2910Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
2920Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
2930Sstevel@tonic-gate 				    aclass);
2940Sstevel@tonic-gate 			} else { /* memory error */
2950Sstevel@tonic-gate 				return (NULL);
2960Sstevel@tonic-gate 			}
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 		/* Find on IPv4 Destination Address field */
2990Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TRIE_DADDRID,
3000Sstevel@tonic-gate 		    V4_PART_OF_V6(packet->daddr), fid_table);
3010Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
3020Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DADDRID].info.mask)
3030Sstevel@tonic-gate 		    != NORMAL_MATCH) {
3040Sstevel@tonic-gate 			/* free all dynamic allocated memory */
3050Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
3060Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
3070Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
3080Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
3090Sstevel@tonic-gate 				    aclass);
3100Sstevel@tonic-gate 			} else { /* memory error */
3110Sstevel@tonic-gate 				return (NULL);
3120Sstevel@tonic-gate 			}
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 		break;
3150Sstevel@tonic-gate 	case AF_INET6:
3160Sstevel@tonic-gate 		/* Find on IPv6 Source Address field */
3170Sstevel@tonic-gate 		match_status = ipgpc_findfilters6(IPGPC_TRIE_SADDRID6,
3180Sstevel@tonic-gate 		    packet->saddr, fid_table);
3190Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
3200Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SADDRID6].info.mask)
3210Sstevel@tonic-gate 		    != NORMAL_MATCH) {
3220Sstevel@tonic-gate 			/* free all dynamic allocated memory */
3230Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
3240Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
3250Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
3260Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
3270Sstevel@tonic-gate 				    aclass);
3280Sstevel@tonic-gate 			} else { /* memory error */
3290Sstevel@tonic-gate 				return (NULL);
3300Sstevel@tonic-gate 			}
3310Sstevel@tonic-gate 		}
3320Sstevel@tonic-gate 		/* Find on IPv6 Destination Address field */
3330Sstevel@tonic-gate 		match_status = ipgpc_findfilters6(IPGPC_TRIE_DADDRID6,
3340Sstevel@tonic-gate 		    packet->daddr, fid_table);
3350Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
3360Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DADDRID6].info.mask)
3370Sstevel@tonic-gate 		    != NORMAL_MATCH) {
3380Sstevel@tonic-gate 			/* free all dynamic allocated memory */
3390Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
3400Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
3410Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
3420Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
3430Sstevel@tonic-gate 				    aclass);
3440Sstevel@tonic-gate 			} else {
3450Sstevel@tonic-gate 				return (NULL);
3460Sstevel@tonic-gate 			}
3470Sstevel@tonic-gate 		}
3480Sstevel@tonic-gate 		break;
3490Sstevel@tonic-gate 	default:
3500Sstevel@tonic-gate 		ipgpc0dbg(("ipgpc_classify(): Unknown Address Family"));
3510Sstevel@tonic-gate 		/* free all dynamic allocated memory */
3520Sstevel@tonic-gate 		FREE_FID_TABLE(fid_table, p, q, i);
3530Sstevel@tonic-gate 		return (NULL);
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/* zero selectors were searched, return default */
3570Sstevel@tonic-gate 	if (slctrs_srchd == 0) {
3580Sstevel@tonic-gate 		/*
3590Sstevel@tonic-gate 		 * no need to free fid_table.  Since zero selectors were
3600Sstevel@tonic-gate 		 * searched and dynamic memory wasn't allocated
3610Sstevel@tonic-gate 		 */
3620Sstevel@tonic-gate 		update_stats(ipgpc_def_class_id, packet->len);
3630Sstevel@tonic-gate 		return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/* Perform best match search */
3670Sstevel@tonic-gate 	class_id = bestmatch(fid_table, slctrs_srchd);
3680Sstevel@tonic-gate 	/* free all dynamic allocated memory */
3690Sstevel@tonic-gate 	FREE_FID_TABLE(fid_table, p, q, i);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	update_stats(class_id, packet->len);
3720Sstevel@tonic-gate 	return (&ipgpc_cid_list[class_id].aclass);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate /*
3760Sstevel@tonic-gate  * bestmatch(fid_table, bestmask)
3770Sstevel@tonic-gate  *
3780Sstevel@tonic-gate  * determines the bestmatching filter in fid_table which matches the criteria
3790Sstevel@tonic-gate  * described below and returns the class id
3800Sstevel@tonic-gate  */
3810Sstevel@tonic-gate static int
3820Sstevel@tonic-gate bestmatch(ht_match_t *fid_table, uint16_t bestmask)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate 	int i, key;
3850Sstevel@tonic-gate 	int bestmatch = -1;
3860Sstevel@tonic-gate 	int oldbm = -1;
3870Sstevel@tonic-gate 	uint32_t temp_prec;
3880Sstevel@tonic-gate 	uint32_t temp_prio;
3890Sstevel@tonic-gate 	uint64_t best_prio;
3900Sstevel@tonic-gate 	uint64_t real_prio;
3910Sstevel@tonic-gate 	ht_match_t *item;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	for (i = 0; i < HASH_SIZE; ++i) {
3940Sstevel@tonic-gate 		if (fid_table[i].key == 0) {
3950Sstevel@tonic-gate 			continue;
3960Sstevel@tonic-gate 		}
3970Sstevel@tonic-gate 		for (item = &fid_table[i]; item != NULL; item = item->next) {
3980Sstevel@tonic-gate 			/*
3990Sstevel@tonic-gate 			 * BESTMATCH is:
4000Sstevel@tonic-gate 			 * 1. Matches in all selectors searched
4010Sstevel@tonic-gate 			 * 2. highest priority of filters that meet 1.
4020Sstevel@tonic-gate 			 * 3. best precedence of filters that meet 2
4030Sstevel@tonic-gate 			 *    with the same priority
4040Sstevel@tonic-gate 			 */
4050Sstevel@tonic-gate 			if ((key = item->key) == 0) {
4060Sstevel@tonic-gate 				continue;
4070Sstevel@tonic-gate 			}
4080Sstevel@tonic-gate 			if (ipgpc_fid_list[key].info <= 0) {
4090Sstevel@tonic-gate 				continue;
4100Sstevel@tonic-gate 			}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 			/*
4130Sstevel@tonic-gate 			 * check to see if fid has been inserted into a
4140Sstevel@tonic-gate 			 * selector structure we did not search
4150Sstevel@tonic-gate 			 * if so, then this filter is not a valid match
4160Sstevel@tonic-gate 			 * and bestmatch() should continue
4170Sstevel@tonic-gate 			 * this statement will == 0
4180Sstevel@tonic-gate 			 * - a selector has been searched and this filter
4190Sstevel@tonic-gate 			 *   either describes don't care or has inserted a
4200Sstevel@tonic-gate 			 *   value into this selector structure
4210Sstevel@tonic-gate 			 * - a selector has not been searched and this filter
4220Sstevel@tonic-gate 			 *   has described don't care for this selector
4230Sstevel@tonic-gate 			 */
4240Sstevel@tonic-gate 			if (((~bestmask) & ipgpc_fid_list[key].insert_map)
4250Sstevel@tonic-gate 			    != 0) {
4260Sstevel@tonic-gate 				continue;
4270Sstevel@tonic-gate 			}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 			/*
4300Sstevel@tonic-gate 			 * tests to see if the map of selectors that
4310Sstevel@tonic-gate 			 * were matched, equals the map of selectors
4320Sstevel@tonic-gate 			 * structures this filter inserts into
4330Sstevel@tonic-gate 			 */
4340Sstevel@tonic-gate 			if (item->match_map != ipgpc_fid_list[key].insert_map) {
4350Sstevel@tonic-gate 				continue;
4360Sstevel@tonic-gate 			}
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 			if (bestmatch == -1) { /* first matching filter */
4390Sstevel@tonic-gate 				/* this filter becomes the bestmatch */
4400Sstevel@tonic-gate 				temp_prio =
4410Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.priority;
4420Sstevel@tonic-gate 				temp_prec =
4430Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.precedence;
4440Sstevel@tonic-gate 				best_prio = ((uint64_t)temp_prio << 32) |
4450Sstevel@tonic-gate 				    (uint64_t)~temp_prec;
4460Sstevel@tonic-gate 				bestmatch = key;
4470Sstevel@tonic-gate 				continue;
4480Sstevel@tonic-gate 			}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 			/*
4510Sstevel@tonic-gate 			 * calculate the real priority by combining priority
4520Sstevel@tonic-gate 			 * and precedence
4530Sstevel@tonic-gate 			 */
4540Sstevel@tonic-gate 			real_prio =
4550Sstevel@tonic-gate 			    ((uint64_t)ipgpc_fid_list[key].filter.priority
4560Sstevel@tonic-gate 				<< 32) |
4570Sstevel@tonic-gate 			    (uint64_t)~ipgpc_fid_list[key].filter.precedence;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 			/* check to see if this is the new bestmatch */
4600Sstevel@tonic-gate 			if (real_prio > best_prio) {
4610Sstevel@tonic-gate 				oldbm = bestmatch;
4620Sstevel@tonic-gate 				ipgpc3dbg(("bestmatch: filter %s " \
4630Sstevel@tonic-gate 				    "REJECTED because of better priority %d" \
4640Sstevel@tonic-gate 				    " and/or precedence %d",
4650Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.filter_name,
4660Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.priority,
4670Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.precedence));
4680Sstevel@tonic-gate 				best_prio = real_prio;
4690Sstevel@tonic-gate 				bestmatch = key;
4700Sstevel@tonic-gate 			} else {
4710Sstevel@tonic-gate 				ipgpc3dbg(("bestmatch: filter %s " \
4720Sstevel@tonic-gate 				    "REJECTED because of beter priority %d" \
4730Sstevel@tonic-gate 				    " and/or precedence %d",
4740Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.filter_name,
4750Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.priority,
4760Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.precedence));
4770Sstevel@tonic-gate 			}
4780Sstevel@tonic-gate 		}
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 	if (bestmatch == -1) {	/* no best matches were found */
4810Sstevel@tonic-gate 		ipgpc3dbg(("bestmatch: No filters ACCEPTED"));
4820Sstevel@tonic-gate 		return (ipgpc_def_class_id);
4830Sstevel@tonic-gate 	} else {
4840Sstevel@tonic-gate 		ipgpc3dbg(("bestmatch: filter %s ACCEPTED with priority %d " \
4850Sstevel@tonic-gate 		    "and precedence %d",
4860Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.filter_name,
4870Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.priority,
4880Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.precedence));
4890Sstevel@tonic-gate 		return (ipgpc_fid_list[bestmatch].class_id);
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate /*
4940Sstevel@tonic-gate  * get_port_info(packet, iph, af, mp)
4950Sstevel@tonic-gate  *
4960Sstevel@tonic-gate  * Gets the source and destination ports from the ULP header, if present.
4970Sstevel@tonic-gate  * If this is a fragment, don't try to get the port information even if this
4980Sstevel@tonic-gate  * is the first fragment. The reason being we won't have this information
4990Sstevel@tonic-gate  * in subsequent fragments and may end up classifying the first fragment
5000Sstevel@tonic-gate  * differently than others. This is not desired.
5010Sstevel@tonic-gate  * For IPv6 packets, step through the extension headers, if present, in
5020Sstevel@tonic-gate  * order to get to the ULP header.
5030Sstevel@tonic-gate  */
5040Sstevel@tonic-gate static void
5050Sstevel@tonic-gate get_port_info(ipgpc_packet_t *packet, void *iph, int af, mblk_t *mp)
5060Sstevel@tonic-gate {
5070Sstevel@tonic-gate 	uint16_t *up;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (af == AF_INET) {
5100Sstevel@tonic-gate 		uint32_t u2, u1;
5110Sstevel@tonic-gate 		uint_t iplen;
5120Sstevel@tonic-gate 		ipha_t *ipha = (ipha_t *)iph;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 		u2 = ntohs(ipha->ipha_fragment_offset_and_flags);
5150Sstevel@tonic-gate 		u1 = u2 & (IPH_MF | IPH_OFFSET);
5160Sstevel@tonic-gate 		if (u1) {
5170Sstevel@tonic-gate 			return;
5180Sstevel@tonic-gate 		}
5190Sstevel@tonic-gate 		iplen = (ipha->ipha_version_and_hdr_length & 0xF) << 2;
5200Sstevel@tonic-gate 		up = (uint16_t *)(mp->b_rptr + iplen);
5210Sstevel@tonic-gate 		packet->sport = (uint16_t)*up++;
5220Sstevel@tonic-gate 		packet->dport = (uint16_t)*up;
5230Sstevel@tonic-gate 	} else {	/* AF_INET6 */
5240Sstevel@tonic-gate 		uint_t  length = IPV6_HDR_LEN;
5250Sstevel@tonic-gate 		ip6_t *ip6h = (ip6_t *)iph;
5260Sstevel@tonic-gate 		uint_t  ehdrlen;
5270Sstevel@tonic-gate 		uint8_t *nexthdrp, *whereptr, *endptr;
5280Sstevel@tonic-gate 		ip6_dest_t *desthdr;
5290Sstevel@tonic-gate 		ip6_rthdr_t *rthdr;
5300Sstevel@tonic-gate 		ip6_hbh_t *hbhhdr;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 		whereptr = ((uint8_t *)&ip6h[1]);
5330Sstevel@tonic-gate 		endptr = mp->b_wptr;
5340Sstevel@tonic-gate 		nexthdrp = &ip6h->ip6_nxt;
5350Sstevel@tonic-gate 		while (whereptr < endptr) {
5360Sstevel@tonic-gate 			switch (*nexthdrp) {
5370Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
5380Sstevel@tonic-gate 				hbhhdr = (ip6_hbh_t *)whereptr;
5390Sstevel@tonic-gate 				ehdrlen = 8 * (hbhhdr->ip6h_len + 1);
5400Sstevel@tonic-gate 				if ((uchar_t *)hbhhdr +  ehdrlen > endptr)
5410Sstevel@tonic-gate 					return;
5420Sstevel@tonic-gate 				nexthdrp = &hbhhdr->ip6h_nxt;
5430Sstevel@tonic-gate 				break;
5440Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
5450Sstevel@tonic-gate 				desthdr = (ip6_dest_t *)whereptr;
5460Sstevel@tonic-gate 				ehdrlen = 8 * (desthdr->ip6d_len + 1);
5470Sstevel@tonic-gate 				if ((uchar_t *)desthdr +  ehdrlen > endptr)
5480Sstevel@tonic-gate 					return;
5490Sstevel@tonic-gate 				nexthdrp = &desthdr->ip6d_nxt;
5500Sstevel@tonic-gate 				break;
5510Sstevel@tonic-gate 			case IPPROTO_ROUTING:
5520Sstevel@tonic-gate 				rthdr = (ip6_rthdr_t *)whereptr;
5530Sstevel@tonic-gate 				ehdrlen =  8 * (rthdr->ip6r_len + 1);
5540Sstevel@tonic-gate 				if ((uchar_t *)rthdr +  ehdrlen > endptr)
5550Sstevel@tonic-gate 					return;
5560Sstevel@tonic-gate 				nexthdrp = &rthdr->ip6r_nxt;
5570Sstevel@tonic-gate 				break;
5580Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
5590Sstevel@tonic-gate 				return;
5600Sstevel@tonic-gate 			case IPPROTO_TCP:
5610Sstevel@tonic-gate 			case IPPROTO_UDP:
5620Sstevel@tonic-gate 			case IPPROTO_SCTP:
5630Sstevel@tonic-gate 				/*
5640Sstevel@tonic-gate 				 * Verify we have at least ICMP_MIN_TP_HDR_LEN
5650Sstevel@tonic-gate 				 * bytes of the ULP's header to get the port
5660Sstevel@tonic-gate 				 * info.
5670Sstevel@tonic-gate 				 */
5680Sstevel@tonic-gate 				if (((uchar_t *)ip6h + length +
5690Sstevel@tonic-gate 				    ICMP_MIN_TP_HDR_LEN)  > endptr) {
5700Sstevel@tonic-gate 					return;
5710Sstevel@tonic-gate 				}
5720Sstevel@tonic-gate 				/* Get the protocol and the ports */
5730Sstevel@tonic-gate 				packet->proto = *nexthdrp;
5740Sstevel@tonic-gate 				up = (uint16_t *)((uchar_t *)ip6h + length);
5750Sstevel@tonic-gate 				packet->sport = (uint16_t)*up++;
5760Sstevel@tonic-gate 				packet->dport = (uint16_t)*up;
5770Sstevel@tonic-gate 				return;
5780Sstevel@tonic-gate 			case IPPROTO_ICMPV6:
5790Sstevel@tonic-gate 			case IPPROTO_ENCAP:
5800Sstevel@tonic-gate 			case IPPROTO_IPV6:
5810Sstevel@tonic-gate 			case IPPROTO_ESP:
5820Sstevel@tonic-gate 			case IPPROTO_AH:
5830Sstevel@tonic-gate 				packet->proto = *nexthdrp;
5840Sstevel@tonic-gate 				return;
5850Sstevel@tonic-gate 			case IPPROTO_NONE:
5860Sstevel@tonic-gate 			default:
5870Sstevel@tonic-gate 				return;
5880Sstevel@tonic-gate 			}
5890Sstevel@tonic-gate 			length += ehdrlen;
5900Sstevel@tonic-gate 			whereptr += ehdrlen;
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate  * find_ids(packet, mp)
5970Sstevel@tonic-gate  *
5980Sstevel@tonic-gate  * attempt to discern the uid and projid of the originator of a packet by
5990Sstevel@tonic-gate  * looking at the dblks making up the packet - yeuch!
6000Sstevel@tonic-gate  *
6010Sstevel@tonic-gate  * We do it by skipping any fragments with a credp of NULL (originated in
6020Sstevel@tonic-gate  * kernel), taking the first value that isn't NULL to be the credp for the
6030Sstevel@tonic-gate  * whole packet. We also suck the projid from the same fragment.
6040Sstevel@tonic-gate  */
6050Sstevel@tonic-gate static void
6060Sstevel@tonic-gate find_ids(ipgpc_packet_t *packet, mblk_t *mp)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 	cred_t *cr;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	while (DB_CRED(mp) == NULL && mp->b_cont != NULL)
6110Sstevel@tonic-gate 		mp = mp->b_cont;
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if ((cr = DB_CRED(mp)) != NULL) {
6140Sstevel@tonic-gate 		packet->uid = crgetuid(cr);
6150Sstevel@tonic-gate 		packet->projid = crgetprojid(cr);
6160Sstevel@tonic-gate 	} else {
617*4321Scasper 		packet->uid = (uid_t)-1;
6180Sstevel@tonic-gate 		packet->projid = -1;
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate /*
6230Sstevel@tonic-gate  * parse_packet(packet, mp)
6240Sstevel@tonic-gate  *
6250Sstevel@tonic-gate  * parses the given message block into a ipgpc_packet_t structure
6260Sstevel@tonic-gate  */
6270Sstevel@tonic-gate void
6280Sstevel@tonic-gate parse_packet(ipgpc_packet_t *packet, mblk_t *mp)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	ipha_t	*ipha;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	/* parse message block for IP header and ports */
6330Sstevel@tonic-gate 	ipha = (ipha_t *)mp->b_rptr; /* get ip header */
6340Sstevel@tonic-gate 	V4_PART_OF_V6(packet->saddr) = (int32_t)ipha->ipha_src;
6350Sstevel@tonic-gate 	V4_PART_OF_V6(packet->daddr) = (int32_t)ipha->ipha_dst;
6360Sstevel@tonic-gate 	packet->dsfield = ipha->ipha_type_of_service;
6370Sstevel@tonic-gate 	packet->proto = ipha->ipha_protocol;
6380Sstevel@tonic-gate 	packet->sport = 0;
6390Sstevel@tonic-gate 	packet->dport = 0;
6400Sstevel@tonic-gate 	find_ids(packet, mp);
6410Sstevel@tonic-gate 	packet->len = msgdsize(mp);
6420Sstevel@tonic-gate 	/* parse out TCP/UDP ports, if appropriate */
6430Sstevel@tonic-gate 	if ((packet->proto == IPPROTO_TCP) || (packet->proto == IPPROTO_UDP) ||
6440Sstevel@tonic-gate 	    (packet->proto == IPPROTO_SCTP)) {
6450Sstevel@tonic-gate 		get_port_info(packet, ipha, AF_INET, mp);
6460Sstevel@tonic-gate 	}
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate /*
6500Sstevel@tonic-gate  * parse_packet6(packet, mp)
6510Sstevel@tonic-gate  *
6520Sstevel@tonic-gate  * parses the message block into a ipgpc_packet_t structure for IPv6 traffic
6530Sstevel@tonic-gate  */
6540Sstevel@tonic-gate void
6550Sstevel@tonic-gate parse_packet6(ipgpc_packet_t *packet, mblk_t *mp)
6560Sstevel@tonic-gate {
6570Sstevel@tonic-gate 	ip6_t *ip6h = (ip6_t *)mp->b_rptr;
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/* parse message block for IP header and ports */
6600Sstevel@tonic-gate 	bcopy(ip6h->ip6_src.s6_addr32, packet->saddr.s6_addr32,
6610Sstevel@tonic-gate 	    sizeof (ip6h->ip6_src.s6_addr32));
6620Sstevel@tonic-gate 	bcopy(ip6h->ip6_dst.s6_addr32, packet->daddr.s6_addr32,
6630Sstevel@tonic-gate 	    sizeof (ip6h->ip6_dst.s6_addr32));
6640Sstevel@tonic-gate 	/* Will be (re-)assigned in get_port_info */
6650Sstevel@tonic-gate 	packet->proto = ip6h->ip6_nxt;
6660Sstevel@tonic-gate 	packet->dsfield = __IPV6_TCLASS_FROM_FLOW(ip6h->ip6_vcf);
6670Sstevel@tonic-gate 	find_ids(packet, mp);
6680Sstevel@tonic-gate 	packet->len = msgdsize(mp);
6690Sstevel@tonic-gate 	packet->sport = 0;
6700Sstevel@tonic-gate 	packet->dport = 0;
6710Sstevel@tonic-gate 	/* Need to pullup everything. */
6720Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
6730Sstevel@tonic-gate 		if (!pullupmsg(mp, -1)) {
6740Sstevel@tonic-gate 			ipgpc0dbg(("parse_packet6(): pullup error, can't " \
6750Sstevel@tonic-gate 			    "find ports"));
6760Sstevel@tonic-gate 			return;
6770Sstevel@tonic-gate 		}
6780Sstevel@tonic-gate 		ip6h = (ip6_t *)mp->b_rptr;
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 	get_port_info(packet, ip6h, AF_INET6, mp);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate #ifdef	IPGPC_DEBUG
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate  * print_packet(af, packet)
6860Sstevel@tonic-gate  *
6870Sstevel@tonic-gate  * prints the contents of the packet structure for specified address family
6880Sstevel@tonic-gate  */
6890Sstevel@tonic-gate void
6900Sstevel@tonic-gate print_packet(int af, ipgpc_packet_t *pkt)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	if (af == AF_INET) {
6930Sstevel@tonic-gate 		char saddrbuf[INET_ADDRSTRLEN];
6940Sstevel@tonic-gate 		char daddrbuf[INET_ADDRSTRLEN];
6950Sstevel@tonic-gate 		ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
6960Sstevel@tonic-gate 		    ", dport = %u, proto = %u, dsfield = %x, uid = %d," \
6970Sstevel@tonic-gate 		    " if_index = %d, if_groupname = %s, projid = %d, " \
6980Sstevel@tonic-gate 		    "direction = %d",
6990Sstevel@tonic-gate 		    inet_ntop(af, &V4_PART_OF_V6(pkt->saddr), saddrbuf,
7000Sstevel@tonic-gate 			sizeof (saddrbuf)),
7010Sstevel@tonic-gate 		    inet_ntop(af, &V4_PART_OF_V6(pkt->daddr), daddrbuf,
7020Sstevel@tonic-gate 			sizeof (daddrbuf)),
7030Sstevel@tonic-gate 		    ntohs(pkt->sport), ntohs(pkt->dport), pkt->proto,
7040Sstevel@tonic-gate 		    pkt->dsfield, pkt->uid, pkt->if_index,
7050Sstevel@tonic-gate 		    (pkt->if_groupname != NULL) ? pkt->if_groupname : "NULL",
7060Sstevel@tonic-gate 		    pkt->projid, pkt->direction));
7070Sstevel@tonic-gate 	} else if (af == AF_INET6) {
7080Sstevel@tonic-gate 		char saddrbuf[INET6_ADDRSTRLEN];
7090Sstevel@tonic-gate 		char daddrbuf[INET6_ADDRSTRLEN];
7100Sstevel@tonic-gate 		ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
7110Sstevel@tonic-gate 		    ", dport = %u, proto = %u, dsfield = %x, uid = %d," \
7120Sstevel@tonic-gate 		    " if_index = %d, if_groupname = %s, projid = %d, " \
7130Sstevel@tonic-gate 		    "direction = %d",
7140Sstevel@tonic-gate 		    inet_ntop(af, pkt->saddr.s6_addr32, saddrbuf,
7150Sstevel@tonic-gate 			sizeof (saddrbuf)),
7160Sstevel@tonic-gate 		    inet_ntop(af, pkt->daddr.s6_addr32, daddrbuf,
7170Sstevel@tonic-gate 			sizeof (daddrbuf)),
7180Sstevel@tonic-gate 		    ntohs(pkt->sport), ntohs(pkt->dport), pkt->proto,
7190Sstevel@tonic-gate 		    pkt->dsfield, pkt->uid, pkt->if_index,
7200Sstevel@tonic-gate 		    (pkt->if_groupname != NULL) ? pkt->if_groupname : "NULL",
7210Sstevel@tonic-gate 		    pkt->projid, pkt->direction));
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate #endif /* IPGPC_DEBUG */
725