17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5769b977dSvi  * Common Development and Distribution License (the "License").
6769b977dSvi  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21769b977dSvi 
227c478bd9Sstevel@tonic-gate /*
23e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
287c478bd9Sstevel@tonic-gate #include <sys/systm.h>
297c478bd9Sstevel@tonic-gate #include <sys/socket.h>
30*de8c4a14SErik Nordmark #include <sys/strsubr.h>
317c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
327c478bd9Sstevel@tonic-gate #include <netinet/in.h>
337c478bd9Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h>
347c478bd9Sstevel@tonic-gate #include <inet/ip.h>
357c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
367c478bd9Sstevel@tonic-gate #include <net/if.h>
377c478bd9Sstevel@tonic-gate #include <inet/ipp_common.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /* Implementation file for classifier used in ipgpc module */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * determines what the result of the selector search and what action needs to
457c478bd9Sstevel@tonic-gate  * be taken next.
467c478bd9Sstevel@tonic-gate  * if a NORMAL_MATCH occurs, business as usual NORMAL_MATCH
477c478bd9Sstevel@tonic-gate  * if the selector was not searched because only DONTCARE keys are loaded,
487c478bd9Sstevel@tonic-gate  * the selector is marked as not being searched
497c478bd9Sstevel@tonic-gate  * otherwise, memory error occurred or no matches were found, classify()
507c478bd9Sstevel@tonic-gate  * should return the error match status immediately
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate #define	CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)	\
537c478bd9Sstevel@tonic-gate 	(((match_status) == NORMAL_MATCH) ?			\
547c478bd9Sstevel@tonic-gate 	(NORMAL_MATCH) :					\
557c478bd9Sstevel@tonic-gate 	(((match_status) == DONTCARE_ONLY_MATCH) ?		\
567c478bd9Sstevel@tonic-gate 	(*(slctrs_srchd) ^= (selector_mask), NORMAL_MATCH) :	\
577c478bd9Sstevel@tonic-gate 	(match_status)))
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* used to determine if an action instance already exists */
607c478bd9Sstevel@tonic-gate boolean_t ipgpc_action_exist = B_FALSE;
617c478bd9Sstevel@tonic-gate int ipgpc_debug = 0;		/* IPGPC debugging level */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /* Statics */
647c478bd9Sstevel@tonic-gate static int common_classify(ipgpc_packet_t *, ht_match_t *, uint16_t *);
657c478bd9Sstevel@tonic-gate static void update_stats(int, uint_t);
667c478bd9Sstevel@tonic-gate static int bestmatch(ht_match_t *, uint16_t);
677c478bd9Sstevel@tonic-gate static void get_port_info(ipgpc_packet_t *, void *, int, mblk_t *);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * common_classify(packet, fid_table, slctrs_srchd)
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  * searches each of the common selectors
73da6c28aaSamw  * - will return NORMAL_MATCH on success.  NO_MATCHES on error
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate static int
common_classify(ipgpc_packet_t * packet,ht_match_t * fid_table,uint16_t * slctrs_srchd)767c478bd9Sstevel@tonic-gate common_classify(ipgpc_packet_t *packet, ht_match_t *fid_table,
777c478bd9Sstevel@tonic-gate     uint16_t *slctrs_srchd)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	int match_status;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	/* Find on packet direction */
827c478bd9Sstevel@tonic-gate 	match_status =
837c478bd9Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_DIR, packet->direction, fid_table);
847c478bd9Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
857c478bd9Sstevel@tonic-gate 	    ipgpc_table_list[DIR_IDX].info.mask) != NORMAL_MATCH) {
867c478bd9Sstevel@tonic-gate 		return (match_status);
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	/* Find on IF_INDEX of packet */
907c478bd9Sstevel@tonic-gate 	match_status =
917c478bd9Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_IF, packet->if_index, fid_table);
927c478bd9Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
937c478bd9Sstevel@tonic-gate 	    ipgpc_table_list[IF_IDX].info.mask) != NORMAL_MATCH) {
947c478bd9Sstevel@tonic-gate 		return (match_status);
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	/* Find on DS field */
987c478bd9Sstevel@tonic-gate 	match_status =
997c478bd9Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_BA_DSID, packet->dsfield, fid_table);
1007c478bd9Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1017c478bd9Sstevel@tonic-gate 	    ipgpc_ds_table_id.info.mask) != NORMAL_MATCH) {
1027c478bd9Sstevel@tonic-gate 		return (match_status);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/* Find on UID of packet */
1067c478bd9Sstevel@tonic-gate 	match_status =
1077c478bd9Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_UID, packet->uid, fid_table);
1087c478bd9Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1097c478bd9Sstevel@tonic-gate 	    ipgpc_table_list[UID_IDX].info.mask) != NORMAL_MATCH) {
1107c478bd9Sstevel@tonic-gate 		return (match_status);
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/* Find on PROJID of packet */
1147c478bd9Sstevel@tonic-gate 	match_status =
1157c478bd9Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_PROJID, packet->projid, fid_table);
1167c478bd9Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1177c478bd9Sstevel@tonic-gate 	    ipgpc_table_list[PROJID_IDX].info.mask) != NORMAL_MATCH) {
1187c478bd9Sstevel@tonic-gate 		return (match_status);
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	/* Find on IP Protocol field */
1227c478bd9Sstevel@tonic-gate 	if (packet->proto > 0) {
1237c478bd9Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TABLE_PROTOID,
1247c478bd9Sstevel@tonic-gate 		    packet->proto, fid_table);
1257c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1267c478bd9Sstevel@tonic-gate 		    ipgpc_table_list[PROTOID_IDX].info.mask)
1277c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
1287c478bd9Sstevel@tonic-gate 			return (match_status);
1297c478bd9Sstevel@tonic-gate 		}
1307c478bd9Sstevel@tonic-gate 	} else {
1317c478bd9Sstevel@tonic-gate 		/* skip search */
1327c478bd9Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_table_list[PROTOID_IDX].info.mask;
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	/* Find on IP Source Port field */
1367c478bd9Sstevel@tonic-gate 	if (packet->sport > 0) {
137e11c3f44Smeem 		match_status = ipgpc_findfilters(IPGPC_TRIE_SPORTID,
138e11c3f44Smeem 		    packet->sport, fid_table);
1397c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1407c478bd9Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SPORTID].info.mask)
1417c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
1427c478bd9Sstevel@tonic-gate 			return (match_status);
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 	} else {
1457c478bd9Sstevel@tonic-gate 		/* skip search */
1467c478bd9Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_trie_list[IPGPC_TRIE_SPORTID].info.mask;
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* Find on IP Destination Port field */
1507c478bd9Sstevel@tonic-gate 	if (packet->dport > 0) {
151e11c3f44Smeem 		match_status = ipgpc_findfilters(IPGPC_TRIE_DPORTID,
152e11c3f44Smeem 		    packet->dport, fid_table);
1537c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
1547c478bd9Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DPORTID].info.mask)
1557c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
1567c478bd9Sstevel@tonic-gate 			return (match_status);
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 	} else {
1597c478bd9Sstevel@tonic-gate 		/* skip search */
1607c478bd9Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_trie_list[IPGPC_TRIE_DPORTID].info.mask;
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 	return (NORMAL_MATCH);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * update_stats(class_id, nbytes)
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  * if ipgpc_gather_stats == TRUE
1697c478bd9Sstevel@tonic-gate  * updates the statistics for class pointed to be the input classid
1707c478bd9Sstevel@tonic-gate  * and the global ipgpc kstats
1717c478bd9Sstevel@tonic-gate  * updates the last time the class was matched with the current hrtime value,
1727c478bd9Sstevel@tonic-gate  * number of packets and number of bytes with nbytes
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate static void
update_stats(int class_id,uint_t nbytes)1757c478bd9Sstevel@tonic-gate update_stats(int class_id, uint_t nbytes)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	if (ipgpc_gather_stats) {
1787c478bd9Sstevel@tonic-gate 		/* update global stats */
1797c478bd9Sstevel@tonic-gate 		BUMP_STATS(ipgpc_npackets);
1807c478bd9Sstevel@tonic-gate 		UPDATE_STATS(ipgpc_nbytes, nbytes);
1817c478bd9Sstevel@tonic-gate 		if (ipgpc_cid_list[class_id].aclass.gather_stats) {
1827c478bd9Sstevel@tonic-gate 			/* update per class stats */
1837c478bd9Sstevel@tonic-gate 			SET_STATS(ipgpc_cid_list[class_id].stats.last_match,
1847c478bd9Sstevel@tonic-gate 			    gethrtime());
1857c478bd9Sstevel@tonic-gate 			BUMP_STATS(ipgpc_cid_list[class_id].stats.npackets);
1867c478bd9Sstevel@tonic-gate 			UPDATE_STATS(ipgpc_cid_list[class_id].stats.nbytes,
1877c478bd9Sstevel@tonic-gate 			    nbytes);
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate  * FREE_FID_TABLE(fid_table, p, q, i)
1947c478bd9Sstevel@tonic-gate  *
1957c478bd9Sstevel@tonic-gate  * searches fid_table for dynamically allocated memory and frees it
1967c478bd9Sstevel@tonic-gate  * p, q, i are temps
1977c478bd9Sstevel@tonic-gate  */
1987c478bd9Sstevel@tonic-gate #define	FREE_FID_TABLE(fid_table, p, q, i)				\
1997c478bd9Sstevel@tonic-gate 	/* free all allocated memory in fid_table */			\
2007c478bd9Sstevel@tonic-gate 	for (i = 0; i < HASH_SIZE; ++i) {				\
2017c478bd9Sstevel@tonic-gate 		if (fid_table[i].next != NULL) {			\
2027c478bd9Sstevel@tonic-gate 			p = fid_table[i].next;				\
2037c478bd9Sstevel@tonic-gate 			while (p != NULL) {				\
2047c478bd9Sstevel@tonic-gate 				q = p;					\
2057c478bd9Sstevel@tonic-gate 				p = p->next;				\
2067c478bd9Sstevel@tonic-gate 				kmem_cache_free(ht_match_cache, q);	\
2077c478bd9Sstevel@tonic-gate 			}						\
2087c478bd9Sstevel@tonic-gate 		}							\
209769b977dSvi 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * ipgpc_classify(af, packet)
2147c478bd9Sstevel@tonic-gate  *
2157c478bd9Sstevel@tonic-gate  * The function that drives the packet classification algorithm.  Given a
2167c478bd9Sstevel@tonic-gate  * address family (either AF_INET or AF_INET6) the input packet structure
2177c478bd9Sstevel@tonic-gate  * is matched against all the selector structures.  For each search of
2187c478bd9Sstevel@tonic-gate  * a selector structure, all matched filters are collected.  Once all
2197c478bd9Sstevel@tonic-gate  * selectors are searched, the best match of all matched filters is
2207c478bd9Sstevel@tonic-gate  * determined.  Finally, the class associated with the best matching filter
2217c478bd9Sstevel@tonic-gate  * is returned.  If no filters were matched, the default class is returned.
2227c478bd9Sstevel@tonic-gate  * If a memory error occurred, NULL is returned.
2237c478bd9Sstevel@tonic-gate  */
2247c478bd9Sstevel@tonic-gate ipgpc_class_t *
ipgpc_classify(int af,ipgpc_packet_t * packet)2257c478bd9Sstevel@tonic-gate ipgpc_classify(int af, ipgpc_packet_t *packet)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	int match_status;
2287c478bd9Sstevel@tonic-gate 	uint16_t slctrs_srchd;
2297c478bd9Sstevel@tonic-gate 	int class_id;
2307c478bd9Sstevel@tonic-gate 	ht_match_t fid_table[HASH_SIZE];
2317c478bd9Sstevel@tonic-gate 	ht_match_t *p, *q;
2327c478bd9Sstevel@tonic-gate 	int i;
2337c478bd9Sstevel@tonic-gate 	int rc;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if (ipgpc_num_fltrs == 0) {
2367c478bd9Sstevel@tonic-gate 		/* zero filters are loaded, return default class */
2377c478bd9Sstevel@tonic-gate 		update_stats(ipgpc_def_class_id, packet->len);
2387c478bd9Sstevel@tonic-gate 		/*
2397c478bd9Sstevel@tonic-gate 		 * no need to free fid_table. Since zero selectors were
2407c478bd9Sstevel@tonic-gate 		 * searched and dynamic memory wasn't allocated.
2417c478bd9Sstevel@tonic-gate 		 */
2427c478bd9Sstevel@tonic-gate 		return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	match_status = 0;
2467c478bd9Sstevel@tonic-gate 	slctrs_srchd = ALL_MATCH_MASK;
2477c478bd9Sstevel@tonic-gate 	bzero(fid_table, sizeof (ht_match_t) * HASH_SIZE);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/* first search all address family independent selectors */
250e11c3f44Smeem 	rc = common_classify(packet, fid_table, &slctrs_srchd);
251e11c3f44Smeem 	if (rc != NORMAL_MATCH) {
2527c478bd9Sstevel@tonic-gate 		/* free all dynamic allocated memory */
2537c478bd9Sstevel@tonic-gate 		FREE_FID_TABLE(fid_table, p, q, i);
2547c478bd9Sstevel@tonic-gate 		if (rc == NO_MATCHES) {
2557c478bd9Sstevel@tonic-gate 			update_stats(ipgpc_def_class_id, packet->len);
2567c478bd9Sstevel@tonic-gate 			return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
2577c478bd9Sstevel@tonic-gate 		} else {	/* memory error */
2587c478bd9Sstevel@tonic-gate 			return (NULL);
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	switch (af) {		/* switch off of address family */
2637c478bd9Sstevel@tonic-gate 	case AF_INET:
2647c478bd9Sstevel@tonic-gate 		/* Find on IPv4 Source Address field */
2657c478bd9Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TRIE_SADDRID,
2667c478bd9Sstevel@tonic-gate 		    V4_PART_OF_V6(packet->saddr), fid_table);
2677c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
2687c478bd9Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SADDRID].info.mask)
2697c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
2707c478bd9Sstevel@tonic-gate 			/* free all dynamic allocated memory */
2717c478bd9Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
2727c478bd9Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
2737c478bd9Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
2747c478bd9Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
2757c478bd9Sstevel@tonic-gate 				    aclass);
2767c478bd9Sstevel@tonic-gate 			} else { /* memory error */
2777c478bd9Sstevel@tonic-gate 				return (NULL);
2787c478bd9Sstevel@tonic-gate 			}
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 		/* Find on IPv4 Destination Address field */
2817c478bd9Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TRIE_DADDRID,
2827c478bd9Sstevel@tonic-gate 		    V4_PART_OF_V6(packet->daddr), fid_table);
2837c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
2847c478bd9Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DADDRID].info.mask)
2857c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
2867c478bd9Sstevel@tonic-gate 			/* free all dynamic allocated memory */
2877c478bd9Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
2887c478bd9Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
2897c478bd9Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
2907c478bd9Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
2917c478bd9Sstevel@tonic-gate 				    aclass);
2927c478bd9Sstevel@tonic-gate 			} else { /* memory error */
2937c478bd9Sstevel@tonic-gate 				return (NULL);
2947c478bd9Sstevel@tonic-gate 			}
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 		break;
2977c478bd9Sstevel@tonic-gate 	case AF_INET6:
2987c478bd9Sstevel@tonic-gate 		/* Find on IPv6 Source Address field */
2997c478bd9Sstevel@tonic-gate 		match_status = ipgpc_findfilters6(IPGPC_TRIE_SADDRID6,
3007c478bd9Sstevel@tonic-gate 		    packet->saddr, fid_table);
3017c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
3027c478bd9Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SADDRID6].info.mask)
3037c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
3047c478bd9Sstevel@tonic-gate 			/* free all dynamic allocated memory */
3057c478bd9Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
3067c478bd9Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
3077c478bd9Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
3087c478bd9Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
3097c478bd9Sstevel@tonic-gate 				    aclass);
3107c478bd9Sstevel@tonic-gate 			} else { /* memory error */
3117c478bd9Sstevel@tonic-gate 				return (NULL);
3127c478bd9Sstevel@tonic-gate 			}
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 		/* Find on IPv6 Destination Address field */
3157c478bd9Sstevel@tonic-gate 		match_status = ipgpc_findfilters6(IPGPC_TRIE_DADDRID6,
3167c478bd9Sstevel@tonic-gate 		    packet->daddr, fid_table);
3177c478bd9Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
3187c478bd9Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DADDRID6].info.mask)
3197c478bd9Sstevel@tonic-gate 		    != NORMAL_MATCH) {
3207c478bd9Sstevel@tonic-gate 			/* free all dynamic allocated memory */
3217c478bd9Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
3227c478bd9Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
3237c478bd9Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
3247c478bd9Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
3257c478bd9Sstevel@tonic-gate 				    aclass);
3267c478bd9Sstevel@tonic-gate 			} else {
3277c478bd9Sstevel@tonic-gate 				return (NULL);
3287c478bd9Sstevel@tonic-gate 			}
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 		break;
3317c478bd9Sstevel@tonic-gate 	default:
3327c478bd9Sstevel@tonic-gate 		ipgpc0dbg(("ipgpc_classify(): Unknown Address Family"));
3337c478bd9Sstevel@tonic-gate 		/* free all dynamic allocated memory */
3347c478bd9Sstevel@tonic-gate 		FREE_FID_TABLE(fid_table, p, q, i);
3357c478bd9Sstevel@tonic-gate 		return (NULL);
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	/* zero selectors were searched, return default */
3397c478bd9Sstevel@tonic-gate 	if (slctrs_srchd == 0) {
3407c478bd9Sstevel@tonic-gate 		/*
3417c478bd9Sstevel@tonic-gate 		 * no need to free fid_table.  Since zero selectors were
3427c478bd9Sstevel@tonic-gate 		 * searched and dynamic memory wasn't allocated
3437c478bd9Sstevel@tonic-gate 		 */
3447c478bd9Sstevel@tonic-gate 		update_stats(ipgpc_def_class_id, packet->len);
3457c478bd9Sstevel@tonic-gate 		return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	/* Perform best match search */
3497c478bd9Sstevel@tonic-gate 	class_id = bestmatch(fid_table, slctrs_srchd);
3507c478bd9Sstevel@tonic-gate 	/* free all dynamic allocated memory */
3517c478bd9Sstevel@tonic-gate 	FREE_FID_TABLE(fid_table, p, q, i);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	update_stats(class_id, packet->len);
3547c478bd9Sstevel@tonic-gate 	return (&ipgpc_cid_list[class_id].aclass);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * bestmatch(fid_table, bestmask)
3597c478bd9Sstevel@tonic-gate  *
3607c478bd9Sstevel@tonic-gate  * determines the bestmatching filter in fid_table which matches the criteria
3617c478bd9Sstevel@tonic-gate  * described below and returns the class id
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate static int
bestmatch(ht_match_t * fid_table,uint16_t bestmask)3647c478bd9Sstevel@tonic-gate bestmatch(ht_match_t *fid_table, uint16_t bestmask)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 	int i, key;
3677c478bd9Sstevel@tonic-gate 	int bestmatch = -1;
3687c478bd9Sstevel@tonic-gate 	int oldbm = -1;
3697c478bd9Sstevel@tonic-gate 	uint32_t temp_prec;
3707c478bd9Sstevel@tonic-gate 	uint32_t temp_prio;
3717c478bd9Sstevel@tonic-gate 	uint64_t best_prio;
3727c478bd9Sstevel@tonic-gate 	uint64_t real_prio;
3737c478bd9Sstevel@tonic-gate 	ht_match_t *item;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	for (i = 0; i < HASH_SIZE; ++i) {
3767c478bd9Sstevel@tonic-gate 		if (fid_table[i].key == 0) {
3777c478bd9Sstevel@tonic-gate 			continue;
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 		for (item = &fid_table[i]; item != NULL; item = item->next) {
3807c478bd9Sstevel@tonic-gate 			/*
3817c478bd9Sstevel@tonic-gate 			 * BESTMATCH is:
3827c478bd9Sstevel@tonic-gate 			 * 1. Matches in all selectors searched
3837c478bd9Sstevel@tonic-gate 			 * 2. highest priority of filters that meet 1.
3847c478bd9Sstevel@tonic-gate 			 * 3. best precedence of filters that meet 2
3857c478bd9Sstevel@tonic-gate 			 *    with the same priority
3867c478bd9Sstevel@tonic-gate 			 */
3877c478bd9Sstevel@tonic-gate 			if ((key = item->key) == 0) {
3887c478bd9Sstevel@tonic-gate 				continue;
3897c478bd9Sstevel@tonic-gate 			}
3907c478bd9Sstevel@tonic-gate 			if (ipgpc_fid_list[key].info <= 0) {
3917c478bd9Sstevel@tonic-gate 				continue;
3927c478bd9Sstevel@tonic-gate 			}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 			/*
3957c478bd9Sstevel@tonic-gate 			 * check to see if fid has been inserted into a
3967c478bd9Sstevel@tonic-gate 			 * selector structure we did not search
3977c478bd9Sstevel@tonic-gate 			 * if so, then this filter is not a valid match
3987c478bd9Sstevel@tonic-gate 			 * and bestmatch() should continue
3997c478bd9Sstevel@tonic-gate 			 * this statement will == 0
4007c478bd9Sstevel@tonic-gate 			 * - a selector has been searched and this filter
4017c478bd9Sstevel@tonic-gate 			 *   either describes don't care or has inserted a
4027c478bd9Sstevel@tonic-gate 			 *   value into this selector structure
4037c478bd9Sstevel@tonic-gate 			 * - a selector has not been searched and this filter
4047c478bd9Sstevel@tonic-gate 			 *   has described don't care for this selector
4057c478bd9Sstevel@tonic-gate 			 */
4067c478bd9Sstevel@tonic-gate 			if (((~bestmask) & ipgpc_fid_list[key].insert_map)
4077c478bd9Sstevel@tonic-gate 			    != 0) {
4087c478bd9Sstevel@tonic-gate 				continue;
4097c478bd9Sstevel@tonic-gate 			}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 			/*
4127c478bd9Sstevel@tonic-gate 			 * tests to see if the map of selectors that
4137c478bd9Sstevel@tonic-gate 			 * were matched, equals the map of selectors
4147c478bd9Sstevel@tonic-gate 			 * structures this filter inserts into
4157c478bd9Sstevel@tonic-gate 			 */
4167c478bd9Sstevel@tonic-gate 			if (item->match_map != ipgpc_fid_list[key].insert_map) {
4177c478bd9Sstevel@tonic-gate 				continue;
4187c478bd9Sstevel@tonic-gate 			}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 			if (bestmatch == -1) { /* first matching filter */
4217c478bd9Sstevel@tonic-gate 				/* this filter becomes the bestmatch */
4227c478bd9Sstevel@tonic-gate 				temp_prio =
4237c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.priority;
4247c478bd9Sstevel@tonic-gate 				temp_prec =
4257c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.precedence;
4267c478bd9Sstevel@tonic-gate 				best_prio = ((uint64_t)temp_prio << 32) |
4277c478bd9Sstevel@tonic-gate 				    (uint64_t)~temp_prec;
4287c478bd9Sstevel@tonic-gate 				bestmatch = key;
4297c478bd9Sstevel@tonic-gate 				continue;
4307c478bd9Sstevel@tonic-gate 			}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 			/*
4337c478bd9Sstevel@tonic-gate 			 * calculate the real priority by combining priority
4347c478bd9Sstevel@tonic-gate 			 * and precedence
4357c478bd9Sstevel@tonic-gate 			 */
4367c478bd9Sstevel@tonic-gate 			real_prio =
4377c478bd9Sstevel@tonic-gate 			    ((uint64_t)ipgpc_fid_list[key].filter.priority
438e11c3f44Smeem 			    << 32) |
4397c478bd9Sstevel@tonic-gate 			    (uint64_t)~ipgpc_fid_list[key].filter.precedence;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 			/* check to see if this is the new bestmatch */
4427c478bd9Sstevel@tonic-gate 			if (real_prio > best_prio) {
4437c478bd9Sstevel@tonic-gate 				oldbm = bestmatch;
4447c478bd9Sstevel@tonic-gate 				ipgpc3dbg(("bestmatch: filter %s " \
4457c478bd9Sstevel@tonic-gate 				    "REJECTED because of better priority %d" \
4467c478bd9Sstevel@tonic-gate 				    " and/or precedence %d",
4477c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.filter_name,
4487c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.priority,
4497c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.precedence));
4507c478bd9Sstevel@tonic-gate 				best_prio = real_prio;
4517c478bd9Sstevel@tonic-gate 				bestmatch = key;
4527c478bd9Sstevel@tonic-gate 			} else {
4537c478bd9Sstevel@tonic-gate 				ipgpc3dbg(("bestmatch: filter %s " \
4547c478bd9Sstevel@tonic-gate 				    "REJECTED because of beter priority %d" \
4557c478bd9Sstevel@tonic-gate 				    " and/or precedence %d",
4567c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.filter_name,
4577c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.priority,
4587c478bd9Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.precedence));
4597c478bd9Sstevel@tonic-gate 			}
4607c478bd9Sstevel@tonic-gate 		}
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	if (bestmatch == -1) {	/* no best matches were found */
4637c478bd9Sstevel@tonic-gate 		ipgpc3dbg(("bestmatch: No filters ACCEPTED"));
4647c478bd9Sstevel@tonic-gate 		return (ipgpc_def_class_id);
4657c478bd9Sstevel@tonic-gate 	} else {
4667c478bd9Sstevel@tonic-gate 		ipgpc3dbg(("bestmatch: filter %s ACCEPTED with priority %d " \
4677c478bd9Sstevel@tonic-gate 		    "and precedence %d",
4687c478bd9Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.filter_name,
4697c478bd9Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.priority,
4707c478bd9Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.precedence));
4717c478bd9Sstevel@tonic-gate 		return (ipgpc_fid_list[bestmatch].class_id);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate /*
4767c478bd9Sstevel@tonic-gate  * get_port_info(packet, iph, af, mp)
4777c478bd9Sstevel@tonic-gate  *
4787c478bd9Sstevel@tonic-gate  * Gets the source and destination ports from the ULP header, if present.
4797c478bd9Sstevel@tonic-gate  * If this is a fragment, don't try to get the port information even if this
4807c478bd9Sstevel@tonic-gate  * is the first fragment. The reason being we won't have this information
4817c478bd9Sstevel@tonic-gate  * in subsequent fragments and may end up classifying the first fragment
4827c478bd9Sstevel@tonic-gate  * differently than others. This is not desired.
4837c478bd9Sstevel@tonic-gate  * For IPv6 packets, step through the extension headers, if present, in
4847c478bd9Sstevel@tonic-gate  * order to get to the ULP header.
4857c478bd9Sstevel@tonic-gate  */
4867c478bd9Sstevel@tonic-gate static void
get_port_info(ipgpc_packet_t * packet,void * iph,int af,mblk_t * mp)4877c478bd9Sstevel@tonic-gate get_port_info(ipgpc_packet_t *packet, void *iph, int af, mblk_t *mp)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate 	uint16_t *up;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
4927c478bd9Sstevel@tonic-gate 		uint32_t u2, u1;
4937c478bd9Sstevel@tonic-gate 		uint_t iplen;
4947c478bd9Sstevel@tonic-gate 		ipha_t *ipha = (ipha_t *)iph;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		u2 = ntohs(ipha->ipha_fragment_offset_and_flags);
4977c478bd9Sstevel@tonic-gate 		u1 = u2 & (IPH_MF | IPH_OFFSET);
4987c478bd9Sstevel@tonic-gate 		if (u1) {
4997c478bd9Sstevel@tonic-gate 			return;
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 		iplen = (ipha->ipha_version_and_hdr_length & 0xF) << 2;
5027c478bd9Sstevel@tonic-gate 		up = (uint16_t *)(mp->b_rptr + iplen);
5037c478bd9Sstevel@tonic-gate 		packet->sport = (uint16_t)*up++;
5047c478bd9Sstevel@tonic-gate 		packet->dport = (uint16_t)*up;
5057c478bd9Sstevel@tonic-gate 	} else {	/* AF_INET6 */
5067c478bd9Sstevel@tonic-gate 		uint_t  length = IPV6_HDR_LEN;
5077c478bd9Sstevel@tonic-gate 		ip6_t *ip6h = (ip6_t *)iph;
5087c478bd9Sstevel@tonic-gate 		uint_t  ehdrlen;
5097c478bd9Sstevel@tonic-gate 		uint8_t *nexthdrp, *whereptr, *endptr;
5107c478bd9Sstevel@tonic-gate 		ip6_dest_t *desthdr;
5117c478bd9Sstevel@tonic-gate 		ip6_rthdr_t *rthdr;
5127c478bd9Sstevel@tonic-gate 		ip6_hbh_t *hbhhdr;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		whereptr = ((uint8_t *)&ip6h[1]);
5157c478bd9Sstevel@tonic-gate 		endptr = mp->b_wptr;
5167c478bd9Sstevel@tonic-gate 		nexthdrp = &ip6h->ip6_nxt;
5177c478bd9Sstevel@tonic-gate 		while (whereptr < endptr) {
5187c478bd9Sstevel@tonic-gate 			switch (*nexthdrp) {
5197c478bd9Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
5207c478bd9Sstevel@tonic-gate 				hbhhdr = (ip6_hbh_t *)whereptr;
5217c478bd9Sstevel@tonic-gate 				ehdrlen = 8 * (hbhhdr->ip6h_len + 1);
5227c478bd9Sstevel@tonic-gate 				if ((uchar_t *)hbhhdr +  ehdrlen > endptr)
5237c478bd9Sstevel@tonic-gate 					return;
5247c478bd9Sstevel@tonic-gate 				nexthdrp = &hbhhdr->ip6h_nxt;
5257c478bd9Sstevel@tonic-gate 				break;
5267c478bd9Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
5277c478bd9Sstevel@tonic-gate 				desthdr = (ip6_dest_t *)whereptr;
5287c478bd9Sstevel@tonic-gate 				ehdrlen = 8 * (desthdr->ip6d_len + 1);
5297c478bd9Sstevel@tonic-gate 				if ((uchar_t *)desthdr +  ehdrlen > endptr)
5307c478bd9Sstevel@tonic-gate 					return;
5317c478bd9Sstevel@tonic-gate 				nexthdrp = &desthdr->ip6d_nxt;
5327c478bd9Sstevel@tonic-gate 				break;
5337c478bd9Sstevel@tonic-gate 			case IPPROTO_ROUTING:
5347c478bd9Sstevel@tonic-gate 				rthdr = (ip6_rthdr_t *)whereptr;
5357c478bd9Sstevel@tonic-gate 				ehdrlen =  8 * (rthdr->ip6r_len + 1);
5367c478bd9Sstevel@tonic-gate 				if ((uchar_t *)rthdr +  ehdrlen > endptr)
5377c478bd9Sstevel@tonic-gate 					return;
5387c478bd9Sstevel@tonic-gate 				nexthdrp = &rthdr->ip6r_nxt;
5397c478bd9Sstevel@tonic-gate 				break;
5407c478bd9Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
5417c478bd9Sstevel@tonic-gate 				return;
5427c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
5437c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
5447c478bd9Sstevel@tonic-gate 			case IPPROTO_SCTP:
5457c478bd9Sstevel@tonic-gate 				/*
5467c478bd9Sstevel@tonic-gate 				 * Verify we have at least ICMP_MIN_TP_HDR_LEN
5477c478bd9Sstevel@tonic-gate 				 * bytes of the ULP's header to get the port
5487c478bd9Sstevel@tonic-gate 				 * info.
5497c478bd9Sstevel@tonic-gate 				 */
5507c478bd9Sstevel@tonic-gate 				if (((uchar_t *)ip6h + length +
5517c478bd9Sstevel@tonic-gate 				    ICMP_MIN_TP_HDR_LEN)  > endptr) {
5527c478bd9Sstevel@tonic-gate 					return;
5537c478bd9Sstevel@tonic-gate 				}
5547c478bd9Sstevel@tonic-gate 				/* Get the protocol and the ports */
5557c478bd9Sstevel@tonic-gate 				packet->proto = *nexthdrp;
5567c478bd9Sstevel@tonic-gate 				up = (uint16_t *)((uchar_t *)ip6h + length);
5577c478bd9Sstevel@tonic-gate 				packet->sport = (uint16_t)*up++;
5587c478bd9Sstevel@tonic-gate 				packet->dport = (uint16_t)*up;
5597c478bd9Sstevel@tonic-gate 				return;
5607c478bd9Sstevel@tonic-gate 			case IPPROTO_ICMPV6:
5617c478bd9Sstevel@tonic-gate 			case IPPROTO_ENCAP:
5627c478bd9Sstevel@tonic-gate 			case IPPROTO_IPV6:
5637c478bd9Sstevel@tonic-gate 			case IPPROTO_ESP:
5647c478bd9Sstevel@tonic-gate 			case IPPROTO_AH:
5657c478bd9Sstevel@tonic-gate 				packet->proto = *nexthdrp;
5667c478bd9Sstevel@tonic-gate 				return;
5677c478bd9Sstevel@tonic-gate 			case IPPROTO_NONE:
5687c478bd9Sstevel@tonic-gate 			default:
5697c478bd9Sstevel@tonic-gate 				return;
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 			length += ehdrlen;
5727c478bd9Sstevel@tonic-gate 			whereptr += ehdrlen;
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * find_ids(packet, mp)
5797c478bd9Sstevel@tonic-gate  *
5807c478bd9Sstevel@tonic-gate  * attempt to discern the uid and projid of the originator of a packet by
5817c478bd9Sstevel@tonic-gate  * looking at the dblks making up the packet - yeuch!
5827c478bd9Sstevel@tonic-gate  *
5837c478bd9Sstevel@tonic-gate  * We do it by skipping any fragments with a credp of NULL (originated in
5847c478bd9Sstevel@tonic-gate  * kernel), taking the first value that isn't NULL to be the credp for the
5857c478bd9Sstevel@tonic-gate  * whole packet. We also suck the projid from the same fragment.
5867c478bd9Sstevel@tonic-gate  */
5877c478bd9Sstevel@tonic-gate static void
find_ids(ipgpc_packet_t * packet,mblk_t * mp)5887c478bd9Sstevel@tonic-gate find_ids(ipgpc_packet_t *packet, mblk_t *mp)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	cred_t *cr;
5917c478bd9Sstevel@tonic-gate 
592*de8c4a14SErik Nordmark 	cr = msg_getcred(mp, NULL);
593*de8c4a14SErik Nordmark 	if (cr != NULL) {
5947c478bd9Sstevel@tonic-gate 		packet->uid = crgetuid(cr);
5957c478bd9Sstevel@tonic-gate 		packet->projid = crgetprojid(cr);
5967c478bd9Sstevel@tonic-gate 	} else {
597f48205beScasper 		packet->uid = (uid_t)-1;
5987c478bd9Sstevel@tonic-gate 		packet->projid = -1;
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate /*
6037c478bd9Sstevel@tonic-gate  * parse_packet(packet, mp)
6047c478bd9Sstevel@tonic-gate  *
6057c478bd9Sstevel@tonic-gate  * parses the given message block into a ipgpc_packet_t structure
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate void
parse_packet(ipgpc_packet_t * packet,mblk_t * mp)6087c478bd9Sstevel@tonic-gate parse_packet(ipgpc_packet_t *packet, mblk_t *mp)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	ipha_t	*ipha;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/* parse message block for IP header and ports */
6137c478bd9Sstevel@tonic-gate 	ipha = (ipha_t *)mp->b_rptr; /* get ip header */
6147c478bd9Sstevel@tonic-gate 	V4_PART_OF_V6(packet->saddr) = (int32_t)ipha->ipha_src;
6157c478bd9Sstevel@tonic-gate 	V4_PART_OF_V6(packet->daddr) = (int32_t)ipha->ipha_dst;
6167c478bd9Sstevel@tonic-gate 	packet->dsfield = ipha->ipha_type_of_service;
6177c478bd9Sstevel@tonic-gate 	packet->proto = ipha->ipha_protocol;
6187c478bd9Sstevel@tonic-gate 	packet->sport = 0;
6197c478bd9Sstevel@tonic-gate 	packet->dport = 0;
6207c478bd9Sstevel@tonic-gate 	find_ids(packet, mp);
6217c478bd9Sstevel@tonic-gate 	packet->len = msgdsize(mp);
6227c478bd9Sstevel@tonic-gate 	/* parse out TCP/UDP ports, if appropriate */
6237c478bd9Sstevel@tonic-gate 	if ((packet->proto == IPPROTO_TCP) || (packet->proto == IPPROTO_UDP) ||
6247c478bd9Sstevel@tonic-gate 	    (packet->proto == IPPROTO_SCTP)) {
6257c478bd9Sstevel@tonic-gate 		get_port_info(packet, ipha, AF_INET, mp);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate /*
6307c478bd9Sstevel@tonic-gate  * parse_packet6(packet, mp)
6317c478bd9Sstevel@tonic-gate  *
6327c478bd9Sstevel@tonic-gate  * parses the message block into a ipgpc_packet_t structure for IPv6 traffic
6337c478bd9Sstevel@tonic-gate  */
6347c478bd9Sstevel@tonic-gate void
parse_packet6(ipgpc_packet_t * packet,mblk_t * mp)6357c478bd9Sstevel@tonic-gate parse_packet6(ipgpc_packet_t *packet, mblk_t *mp)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate 	ip6_t *ip6h = (ip6_t *)mp->b_rptr;
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	/* parse message block for IP header and ports */
6407c478bd9Sstevel@tonic-gate 	bcopy(ip6h->ip6_src.s6_addr32, packet->saddr.s6_addr32,
6417c478bd9Sstevel@tonic-gate 	    sizeof (ip6h->ip6_src.s6_addr32));
6427c478bd9Sstevel@tonic-gate 	bcopy(ip6h->ip6_dst.s6_addr32, packet->daddr.s6_addr32,
6437c478bd9Sstevel@tonic-gate 	    sizeof (ip6h->ip6_dst.s6_addr32));
6447c478bd9Sstevel@tonic-gate 	/* Will be (re-)assigned in get_port_info */
6457c478bd9Sstevel@tonic-gate 	packet->proto = ip6h->ip6_nxt;
6467c478bd9Sstevel@tonic-gate 	packet->dsfield = __IPV6_TCLASS_FROM_FLOW(ip6h->ip6_vcf);
6477c478bd9Sstevel@tonic-gate 	find_ids(packet, mp);
6487c478bd9Sstevel@tonic-gate 	packet->len = msgdsize(mp);
6497c478bd9Sstevel@tonic-gate 	packet->sport = 0;
6507c478bd9Sstevel@tonic-gate 	packet->dport = 0;
6517c478bd9Sstevel@tonic-gate 	/* Need to pullup everything. */
6527c478bd9Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
6537c478bd9Sstevel@tonic-gate 		if (!pullupmsg(mp, -1)) {
6547c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("parse_packet6(): pullup error, can't " \
6557c478bd9Sstevel@tonic-gate 			    "find ports"));
6567c478bd9Sstevel@tonic-gate 			return;
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)mp->b_rptr;
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 	get_port_info(packet, ip6h, AF_INET6, mp);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate #ifdef	IPGPC_DEBUG
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate  * print_packet(af, packet)
6667c478bd9Sstevel@tonic-gate  *
6677c478bd9Sstevel@tonic-gate  * prints the contents of the packet structure for specified address family
6687c478bd9Sstevel@tonic-gate  */
6697c478bd9Sstevel@tonic-gate void
print_packet(int af,ipgpc_packet_t * pkt)6707c478bd9Sstevel@tonic-gate print_packet(int af, ipgpc_packet_t *pkt)
6717c478bd9Sstevel@tonic-gate {
672e11c3f44Smeem 	char saddrbuf[INET6_ADDRSTRLEN];
673e11c3f44Smeem 	char daddrbuf[INET6_ADDRSTRLEN];
674e11c3f44Smeem 
6757c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
676e11c3f44Smeem 		(void) inet_ntop(af, &V4_PART_OF_V6(pkt->saddr), saddrbuf,
677e11c3f44Smeem 		    sizeof (saddrbuf));
678e11c3f44Smeem 		(void) inet_ntop(af, &V4_PART_OF_V6(pkt->daddr), daddrbuf,
679e11c3f44Smeem 		    sizeof (daddrbuf));
680e11c3f44Smeem 
6817c478bd9Sstevel@tonic-gate 		ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
6827c478bd9Sstevel@tonic-gate 		    ", dport = %u, proto = %u, dsfield = %x, uid = %d," \
683e11c3f44Smeem 		    " if_index = %d, projid = %d, direction = %d", saddrbuf,
684e11c3f44Smeem 		    daddrbuf, ntohs(pkt->sport), ntohs(pkt->dport), pkt->proto,
6857c478bd9Sstevel@tonic-gate 		    pkt->dsfield, pkt->uid, pkt->if_index,
6867c478bd9Sstevel@tonic-gate 		    pkt->projid, pkt->direction));
6877c478bd9Sstevel@tonic-gate 	} else if (af == AF_INET6) {
688e11c3f44Smeem 		(void) inet_ntop(af, pkt->saddr.s6_addr32, saddrbuf,
689e11c3f44Smeem 		    sizeof (saddrbuf));
690e11c3f44Smeem 		(void) inet_ntop(af, pkt->daddr.s6_addr32, daddrbuf,
691e11c3f44Smeem 		    sizeof (daddrbuf));
692e11c3f44Smeem 
6937c478bd9Sstevel@tonic-gate 		ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
6947c478bd9Sstevel@tonic-gate 		    ", dport = %u, proto = %u, dsfield = %x, uid = %d," \
695e11c3f44Smeem 		    " if_index = %d, projid = %d, direction = %d", saddrbuf,
696e11c3f44Smeem 		    daddrbuf, ntohs(pkt->sport), ntohs(pkt->dport), pkt->proto,
6977c478bd9Sstevel@tonic-gate 		    pkt->dsfield, pkt->uid, pkt->if_index,
6987c478bd9Sstevel@tonic-gate 		    pkt->projid, pkt->direction));
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate #endif /* IPGPC_DEBUG */
702