xref: /onnv-gate/usr/src/uts/common/ipp/ipgpc/classifier.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/kmem.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/socket.h>
32*0Sstevel@tonic-gate #include <sys/strsun.h>
33*0Sstevel@tonic-gate #include <netinet/in.h>
34*0Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h>
35*0Sstevel@tonic-gate #include <inet/ip.h>
36*0Sstevel@tonic-gate #include <inet/ip6.h>
37*0Sstevel@tonic-gate #include <net/if.h>
38*0Sstevel@tonic-gate #include <inet/ipp_common.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /* Implementation file for classifier used in ipgpc module */
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)
44*0Sstevel@tonic-gate  *
45*0Sstevel@tonic-gate  * determines what the result of the selector search and what action needs to
46*0Sstevel@tonic-gate  * be taken next.
47*0Sstevel@tonic-gate  * if a NORMAL_MATCH occurs, business as usual NORMAL_MATCH
48*0Sstevel@tonic-gate  * if the selector was not searched because only DONTCARE keys are loaded,
49*0Sstevel@tonic-gate  * the selector is marked as not being searched
50*0Sstevel@tonic-gate  * otherwise, memory error occurred or no matches were found, classify()
51*0Sstevel@tonic-gate  * should return the error match status immediately
52*0Sstevel@tonic-gate  */
53*0Sstevel@tonic-gate #define	CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)	\
54*0Sstevel@tonic-gate 	(((match_status) == NORMAL_MATCH) ?			\
55*0Sstevel@tonic-gate 	(NORMAL_MATCH) :					\
56*0Sstevel@tonic-gate 	(((match_status) == DONTCARE_ONLY_MATCH) ?		\
57*0Sstevel@tonic-gate 	(*(slctrs_srchd) ^= (selector_mask), NORMAL_MATCH) :	\
58*0Sstevel@tonic-gate 	(match_status)))
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /* used to determine if an action instance already exists */
61*0Sstevel@tonic-gate boolean_t ipgpc_action_exist = B_FALSE;
62*0Sstevel@tonic-gate int ipgpc_debug = 0;		/* IPGPC debugging level */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /* Statics */
65*0Sstevel@tonic-gate static int common_classify(ipgpc_packet_t *, ht_match_t *, uint16_t *);
66*0Sstevel@tonic-gate static void update_stats(int, uint_t);
67*0Sstevel@tonic-gate static int bestmatch(ht_match_t *, uint16_t);
68*0Sstevel@tonic-gate static void get_port_info(ipgpc_packet_t *, void *, int, mblk_t *);
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * common_classify(packet, fid_table, slctrs_srchd)
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * searches each of the common selectors
74*0Sstevel@tonic-gate  * - will return NORMAL_MATCH on sucess.  NO_MATCHES on error
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate static int
77*0Sstevel@tonic-gate common_classify(ipgpc_packet_t *packet, ht_match_t *fid_table,
78*0Sstevel@tonic-gate     uint16_t *slctrs_srchd)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	int match_status;
81*0Sstevel@tonic-gate 	int if_grpnm_hv;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	/* Find on packet direction */
84*0Sstevel@tonic-gate 	match_status =
85*0Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_DIR, packet->direction, fid_table);
86*0Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
87*0Sstevel@tonic-gate 	    ipgpc_table_list[DIR_IDX].info.mask) != NORMAL_MATCH) {
88*0Sstevel@tonic-gate 		return (match_status);
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/* Find on IF_INDEX of packet */
92*0Sstevel@tonic-gate 	match_status =
93*0Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_IF, packet->if_index, fid_table);
94*0Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
95*0Sstevel@tonic-gate 	    ipgpc_table_list[IF_IDX].info.mask) != NORMAL_MATCH) {
96*0Sstevel@tonic-gate 		return (match_status);
97*0Sstevel@tonic-gate 	}
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	/* Find on IF_GRPNM of packet */
100*0Sstevel@tonic-gate 	if (packet->if_groupname_len > 0) {
101*0Sstevel@tonic-gate 		if_grpnm_hv = name_hash(packet->if_groupname, TABLE_SIZE);
102*0Sstevel@tonic-gate 	} else {
103*0Sstevel@tonic-gate 		if_grpnm_hv = IPGPC_WILDCARD;
104*0Sstevel@tonic-gate 	}
105*0Sstevel@tonic-gate 	match_status =
106*0Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_IF_GRPNM, if_grpnm_hv, fid_table);
107*0Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
108*0Sstevel@tonic-gate 	    ipgpc_table_list[IF_GRPNM_IDX].info.mask) != NORMAL_MATCH) {
109*0Sstevel@tonic-gate 		return (match_status);
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	/* Find on DS field */
113*0Sstevel@tonic-gate 	match_status =
114*0Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_BA_DSID, packet->dsfield, fid_table);
115*0Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
116*0Sstevel@tonic-gate 	    ipgpc_ds_table_id.info.mask) != NORMAL_MATCH) {
117*0Sstevel@tonic-gate 		return (match_status);
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	/* Find on UID of packet */
121*0Sstevel@tonic-gate 	match_status =
122*0Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_UID, packet->uid, fid_table);
123*0Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
124*0Sstevel@tonic-gate 	    ipgpc_table_list[UID_IDX].info.mask) != NORMAL_MATCH) {
125*0Sstevel@tonic-gate 		return (match_status);
126*0Sstevel@tonic-gate 	}
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	/* Find on PROJID of packet */
129*0Sstevel@tonic-gate 	match_status =
130*0Sstevel@tonic-gate 	    ipgpc_findfilters(IPGPC_TABLE_PROJID, packet->projid, fid_table);
131*0Sstevel@tonic-gate 	if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
132*0Sstevel@tonic-gate 	    ipgpc_table_list[PROJID_IDX].info.mask) != NORMAL_MATCH) {
133*0Sstevel@tonic-gate 		return (match_status);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	/* Find on IP Protocol field */
137*0Sstevel@tonic-gate 	if (packet->proto > 0) {
138*0Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TABLE_PROTOID,
139*0Sstevel@tonic-gate 		    packet->proto, fid_table);
140*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
141*0Sstevel@tonic-gate 		    ipgpc_table_list[PROTOID_IDX].info.mask)
142*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
143*0Sstevel@tonic-gate 			return (match_status);
144*0Sstevel@tonic-gate 		}
145*0Sstevel@tonic-gate 	} else {
146*0Sstevel@tonic-gate 		/* skip search */
147*0Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_table_list[PROTOID_IDX].info.mask;
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	/* Find on IP Source Port field */
151*0Sstevel@tonic-gate 	if (packet->sport > 0) {
152*0Sstevel@tonic-gate 		match_status =
153*0Sstevel@tonic-gate 		    ipgpc_findfilters(IPGPC_TRIE_SPORTID, packet->sport,
154*0Sstevel@tonic-gate 			fid_table);
155*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
156*0Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SPORTID].info.mask)
157*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
158*0Sstevel@tonic-gate 			return (match_status);
159*0Sstevel@tonic-gate 		}
160*0Sstevel@tonic-gate 	} else {
161*0Sstevel@tonic-gate 		/* skip search */
162*0Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_trie_list[IPGPC_TRIE_SPORTID].info.mask;
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/* Find on IP Destination Port field */
166*0Sstevel@tonic-gate 	if (packet->dport > 0) {
167*0Sstevel@tonic-gate 		match_status =
168*0Sstevel@tonic-gate 		    ipgpc_findfilters(IPGPC_TRIE_DPORTID, packet->dport,
169*0Sstevel@tonic-gate 			fid_table);
170*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, slctrs_srchd,
171*0Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DPORTID].info.mask)
172*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
173*0Sstevel@tonic-gate 			return (match_status);
174*0Sstevel@tonic-gate 		}
175*0Sstevel@tonic-gate 	} else {
176*0Sstevel@tonic-gate 		/* skip search */
177*0Sstevel@tonic-gate 		*slctrs_srchd ^= ipgpc_trie_list[IPGPC_TRIE_DPORTID].info.mask;
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 	return (NORMAL_MATCH);
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate /*
183*0Sstevel@tonic-gate  * update_stats(class_id, nbytes)
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  * if ipgpc_gather_stats == TRUE
186*0Sstevel@tonic-gate  * updates the statistics for class pointed to be the input classid
187*0Sstevel@tonic-gate  * and the global ipgpc kstats
188*0Sstevel@tonic-gate  * updates the last time the class was matched with the current hrtime value,
189*0Sstevel@tonic-gate  * number of packets and number of bytes with nbytes
190*0Sstevel@tonic-gate  */
191*0Sstevel@tonic-gate static void
192*0Sstevel@tonic-gate update_stats(int class_id, uint_t nbytes)
193*0Sstevel@tonic-gate {
194*0Sstevel@tonic-gate 	if (ipgpc_gather_stats) {
195*0Sstevel@tonic-gate 		/* update global stats */
196*0Sstevel@tonic-gate 		BUMP_STATS(ipgpc_npackets);
197*0Sstevel@tonic-gate 		UPDATE_STATS(ipgpc_nbytes, nbytes);
198*0Sstevel@tonic-gate 		if (ipgpc_cid_list[class_id].aclass.gather_stats) {
199*0Sstevel@tonic-gate 			/* update per class stats */
200*0Sstevel@tonic-gate 			SET_STATS(ipgpc_cid_list[class_id].stats.last_match,
201*0Sstevel@tonic-gate 			    gethrtime());
202*0Sstevel@tonic-gate 			BUMP_STATS(ipgpc_cid_list[class_id].stats.npackets);
203*0Sstevel@tonic-gate 			UPDATE_STATS(ipgpc_cid_list[class_id].stats.nbytes,
204*0Sstevel@tonic-gate 			    nbytes);
205*0Sstevel@tonic-gate 		}
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate }
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate /*
210*0Sstevel@tonic-gate  * FREE_FID_TABLE(fid_table, p, q, i)
211*0Sstevel@tonic-gate  *
212*0Sstevel@tonic-gate  * searches fid_table for dynamically allocated memory and frees it
213*0Sstevel@tonic-gate  * p, q, i are temps
214*0Sstevel@tonic-gate  */
215*0Sstevel@tonic-gate #define	FREE_FID_TABLE(fid_table, p, q, i)				\
216*0Sstevel@tonic-gate 	/* free all allocated memory in fid_table */			\
217*0Sstevel@tonic-gate 	for (i = 0; i < HASH_SIZE; ++i) {				\
218*0Sstevel@tonic-gate 		if (fid_table[i].next != NULL) {			\
219*0Sstevel@tonic-gate 			p = fid_table[i].next;				\
220*0Sstevel@tonic-gate 			while (p != NULL) {				\
221*0Sstevel@tonic-gate 				q = p;					\
222*0Sstevel@tonic-gate 				p = p->next;				\
223*0Sstevel@tonic-gate 				kmem_cache_free(ht_match_cache, q);	\
224*0Sstevel@tonic-gate 			}						\
225*0Sstevel@tonic-gate 		}							\
226*0Sstevel@tonic-gate 	}								\
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate  * ipgpc_classify(af, packet)
231*0Sstevel@tonic-gate  *
232*0Sstevel@tonic-gate  * The function that drives the packet classification algorithm.  Given a
233*0Sstevel@tonic-gate  * address family (either AF_INET or AF_INET6) the input packet structure
234*0Sstevel@tonic-gate  * is matched against all the selector structures.  For each search of
235*0Sstevel@tonic-gate  * a selector structure, all matched filters are collected.  Once all
236*0Sstevel@tonic-gate  * selectors are searched, the best match of all matched filters is
237*0Sstevel@tonic-gate  * determined.  Finally, the class associated with the best matching filter
238*0Sstevel@tonic-gate  * is returned.  If no filters were matched, the default class is returned.
239*0Sstevel@tonic-gate  * If a memory error occurred, NULL is returned.
240*0Sstevel@tonic-gate  */
241*0Sstevel@tonic-gate ipgpc_class_t *
242*0Sstevel@tonic-gate ipgpc_classify(int af, ipgpc_packet_t *packet)
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate 	int match_status;
245*0Sstevel@tonic-gate 	uint16_t slctrs_srchd;
246*0Sstevel@tonic-gate 	int class_id;
247*0Sstevel@tonic-gate 	ht_match_t fid_table[HASH_SIZE];
248*0Sstevel@tonic-gate 	ht_match_t *p, *q;
249*0Sstevel@tonic-gate 	int i;
250*0Sstevel@tonic-gate 	int rc;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	if (ipgpc_num_fltrs == 0) {
253*0Sstevel@tonic-gate 		/* zero filters are loaded, return default class */
254*0Sstevel@tonic-gate 		update_stats(ipgpc_def_class_id, packet->len);
255*0Sstevel@tonic-gate 		/*
256*0Sstevel@tonic-gate 		 * no need to free fid_table. Since zero selectors were
257*0Sstevel@tonic-gate 		 * searched and dynamic memory wasn't allocated.
258*0Sstevel@tonic-gate 		 */
259*0Sstevel@tonic-gate 		return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	match_status = 0;
263*0Sstevel@tonic-gate 	slctrs_srchd = ALL_MATCH_MASK;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	bzero(fid_table, sizeof (ht_match_t) * HASH_SIZE);
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	/* first search all address family independent selectors */
268*0Sstevel@tonic-gate 	if ((rc = common_classify(packet, fid_table, &slctrs_srchd)) !=
269*0Sstevel@tonic-gate 		NORMAL_MATCH) {
270*0Sstevel@tonic-gate 		/* free all dynamic allocated memory */
271*0Sstevel@tonic-gate 		FREE_FID_TABLE(fid_table, p, q, i);
272*0Sstevel@tonic-gate 		if (rc == NO_MATCHES) {
273*0Sstevel@tonic-gate 			update_stats(ipgpc_def_class_id, packet->len);
274*0Sstevel@tonic-gate 			return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
275*0Sstevel@tonic-gate 		} else {	/* memory error */
276*0Sstevel@tonic-gate 			return (NULL);
277*0Sstevel@tonic-gate 		}
278*0Sstevel@tonic-gate 	}
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	switch (af) {		/* switch off of address family */
281*0Sstevel@tonic-gate 	case AF_INET:
282*0Sstevel@tonic-gate 		/* Find on IPv4 Source Address field */
283*0Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TRIE_SADDRID,
284*0Sstevel@tonic-gate 		    V4_PART_OF_V6(packet->saddr), fid_table);
285*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
286*0Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SADDRID].info.mask)
287*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
288*0Sstevel@tonic-gate 			/* free all dynamic allocated memory */
289*0Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
290*0Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
291*0Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
292*0Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
293*0Sstevel@tonic-gate 				    aclass);
294*0Sstevel@tonic-gate 			} else { /* memory error */
295*0Sstevel@tonic-gate 				return (NULL);
296*0Sstevel@tonic-gate 			}
297*0Sstevel@tonic-gate 		}
298*0Sstevel@tonic-gate 		/* Find on IPv4 Destination Address field */
299*0Sstevel@tonic-gate 		match_status = ipgpc_findfilters(IPGPC_TRIE_DADDRID,
300*0Sstevel@tonic-gate 		    V4_PART_OF_V6(packet->daddr), fid_table);
301*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
302*0Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DADDRID].info.mask)
303*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
304*0Sstevel@tonic-gate 			/* free all dynamic allocated memory */
305*0Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
306*0Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
307*0Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
308*0Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
309*0Sstevel@tonic-gate 				    aclass);
310*0Sstevel@tonic-gate 			} else { /* memory error */
311*0Sstevel@tonic-gate 				return (NULL);
312*0Sstevel@tonic-gate 			}
313*0Sstevel@tonic-gate 		}
314*0Sstevel@tonic-gate 		break;
315*0Sstevel@tonic-gate 	case AF_INET6:
316*0Sstevel@tonic-gate 		/* Find on IPv6 Source Address field */
317*0Sstevel@tonic-gate 		match_status = ipgpc_findfilters6(IPGPC_TRIE_SADDRID6,
318*0Sstevel@tonic-gate 		    packet->saddr, fid_table);
319*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
320*0Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_SADDRID6].info.mask)
321*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
322*0Sstevel@tonic-gate 			/* free all dynamic allocated memory */
323*0Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
324*0Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
325*0Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
326*0Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
327*0Sstevel@tonic-gate 				    aclass);
328*0Sstevel@tonic-gate 			} else { /* memory error */
329*0Sstevel@tonic-gate 				return (NULL);
330*0Sstevel@tonic-gate 			}
331*0Sstevel@tonic-gate 		}
332*0Sstevel@tonic-gate 		/* Find on IPv6 Destination Address field */
333*0Sstevel@tonic-gate 		match_status = ipgpc_findfilters6(IPGPC_TRIE_DADDRID6,
334*0Sstevel@tonic-gate 		    packet->daddr, fid_table);
335*0Sstevel@tonic-gate 		if (CHECK_MATCH_STATUS(match_status, &slctrs_srchd,
336*0Sstevel@tonic-gate 		    ipgpc_trie_list[IPGPC_TRIE_DADDRID6].info.mask)
337*0Sstevel@tonic-gate 		    != NORMAL_MATCH) {
338*0Sstevel@tonic-gate 			/* free all dynamic allocated memory */
339*0Sstevel@tonic-gate 			FREE_FID_TABLE(fid_table, p, q, i);
340*0Sstevel@tonic-gate 			if (match_status == NO_MATCHES) {
341*0Sstevel@tonic-gate 				update_stats(ipgpc_def_class_id, packet->len);
342*0Sstevel@tonic-gate 				return (&ipgpc_cid_list[ipgpc_def_class_id].
343*0Sstevel@tonic-gate 				    aclass);
344*0Sstevel@tonic-gate 			} else {
345*0Sstevel@tonic-gate 				return (NULL);
346*0Sstevel@tonic-gate 			}
347*0Sstevel@tonic-gate 		}
348*0Sstevel@tonic-gate 		break;
349*0Sstevel@tonic-gate 	default:
350*0Sstevel@tonic-gate 		ipgpc0dbg(("ipgpc_classify(): Unknown Address Family"));
351*0Sstevel@tonic-gate 		/* free all dynamic allocated memory */
352*0Sstevel@tonic-gate 		FREE_FID_TABLE(fid_table, p, q, i);
353*0Sstevel@tonic-gate 		return (NULL);
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	/* zero selectors were searched, return default */
357*0Sstevel@tonic-gate 	if (slctrs_srchd == 0) {
358*0Sstevel@tonic-gate 		/*
359*0Sstevel@tonic-gate 		 * no need to free fid_table.  Since zero selectors were
360*0Sstevel@tonic-gate 		 * searched and dynamic memory wasn't allocated
361*0Sstevel@tonic-gate 		 */
362*0Sstevel@tonic-gate 		update_stats(ipgpc_def_class_id, packet->len);
363*0Sstevel@tonic-gate 		return (&ipgpc_cid_list[ipgpc_def_class_id].aclass);
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/* Perform best match search */
367*0Sstevel@tonic-gate 	class_id = bestmatch(fid_table, slctrs_srchd);
368*0Sstevel@tonic-gate 	/* free all dynamic allocated memory */
369*0Sstevel@tonic-gate 	FREE_FID_TABLE(fid_table, p, q, i);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	update_stats(class_id, packet->len);
372*0Sstevel@tonic-gate 	return (&ipgpc_cid_list[class_id].aclass);
373*0Sstevel@tonic-gate }
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate /*
376*0Sstevel@tonic-gate  * bestmatch(fid_table, bestmask)
377*0Sstevel@tonic-gate  *
378*0Sstevel@tonic-gate  * determines the bestmatching filter in fid_table which matches the criteria
379*0Sstevel@tonic-gate  * described below and returns the class id
380*0Sstevel@tonic-gate  */
381*0Sstevel@tonic-gate static int
382*0Sstevel@tonic-gate bestmatch(ht_match_t *fid_table, uint16_t bestmask)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	int i, key;
385*0Sstevel@tonic-gate 	int bestmatch = -1;
386*0Sstevel@tonic-gate 	int oldbm = -1;
387*0Sstevel@tonic-gate 	uint32_t temp_prec;
388*0Sstevel@tonic-gate 	uint32_t temp_prio;
389*0Sstevel@tonic-gate 	uint64_t best_prio;
390*0Sstevel@tonic-gate 	uint64_t real_prio;
391*0Sstevel@tonic-gate 	ht_match_t *item;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	for (i = 0; i < HASH_SIZE; ++i) {
394*0Sstevel@tonic-gate 		if (fid_table[i].key == 0) {
395*0Sstevel@tonic-gate 			continue;
396*0Sstevel@tonic-gate 		}
397*0Sstevel@tonic-gate 		for (item = &fid_table[i]; item != NULL; item = item->next) {
398*0Sstevel@tonic-gate 			/*
399*0Sstevel@tonic-gate 			 * BESTMATCH is:
400*0Sstevel@tonic-gate 			 * 1. Matches in all selectors searched
401*0Sstevel@tonic-gate 			 * 2. highest priority of filters that meet 1.
402*0Sstevel@tonic-gate 			 * 3. best precedence of filters that meet 2
403*0Sstevel@tonic-gate 			 *    with the same priority
404*0Sstevel@tonic-gate 			 */
405*0Sstevel@tonic-gate 			if ((key = item->key) == 0) {
406*0Sstevel@tonic-gate 				continue;
407*0Sstevel@tonic-gate 			}
408*0Sstevel@tonic-gate 			if (ipgpc_fid_list[key].info <= 0) {
409*0Sstevel@tonic-gate 				continue;
410*0Sstevel@tonic-gate 			}
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 			/*
413*0Sstevel@tonic-gate 			 * check to see if fid has been inserted into a
414*0Sstevel@tonic-gate 			 * selector structure we did not search
415*0Sstevel@tonic-gate 			 * if so, then this filter is not a valid match
416*0Sstevel@tonic-gate 			 * and bestmatch() should continue
417*0Sstevel@tonic-gate 			 * this statement will == 0
418*0Sstevel@tonic-gate 			 * - a selector has been searched and this filter
419*0Sstevel@tonic-gate 			 *   either describes don't care or has inserted a
420*0Sstevel@tonic-gate 			 *   value into this selector structure
421*0Sstevel@tonic-gate 			 * - a selector has not been searched and this filter
422*0Sstevel@tonic-gate 			 *   has described don't care for this selector
423*0Sstevel@tonic-gate 			 */
424*0Sstevel@tonic-gate 			if (((~bestmask) & ipgpc_fid_list[key].insert_map)
425*0Sstevel@tonic-gate 			    != 0) {
426*0Sstevel@tonic-gate 				continue;
427*0Sstevel@tonic-gate 			}
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 			/*
430*0Sstevel@tonic-gate 			 * tests to see if the map of selectors that
431*0Sstevel@tonic-gate 			 * were matched, equals the map of selectors
432*0Sstevel@tonic-gate 			 * structures this filter inserts into
433*0Sstevel@tonic-gate 			 */
434*0Sstevel@tonic-gate 			if (item->match_map != ipgpc_fid_list[key].insert_map) {
435*0Sstevel@tonic-gate 				continue;
436*0Sstevel@tonic-gate 			}
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 			if (bestmatch == -1) { /* first matching filter */
439*0Sstevel@tonic-gate 				/* this filter becomes the bestmatch */
440*0Sstevel@tonic-gate 				temp_prio =
441*0Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.priority;
442*0Sstevel@tonic-gate 				temp_prec =
443*0Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.precedence;
444*0Sstevel@tonic-gate 				best_prio = ((uint64_t)temp_prio << 32) |
445*0Sstevel@tonic-gate 				    (uint64_t)~temp_prec;
446*0Sstevel@tonic-gate 				bestmatch = key;
447*0Sstevel@tonic-gate 				continue;
448*0Sstevel@tonic-gate 			}
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 			/*
451*0Sstevel@tonic-gate 			 * calculate the real priority by combining priority
452*0Sstevel@tonic-gate 			 * and precedence
453*0Sstevel@tonic-gate 			 */
454*0Sstevel@tonic-gate 			real_prio =
455*0Sstevel@tonic-gate 			    ((uint64_t)ipgpc_fid_list[key].filter.priority
456*0Sstevel@tonic-gate 				<< 32) |
457*0Sstevel@tonic-gate 			    (uint64_t)~ipgpc_fid_list[key].filter.precedence;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 			/* check to see if this is the new bestmatch */
460*0Sstevel@tonic-gate 			if (real_prio > best_prio) {
461*0Sstevel@tonic-gate 				oldbm = bestmatch;
462*0Sstevel@tonic-gate 				ipgpc3dbg(("bestmatch: filter %s " \
463*0Sstevel@tonic-gate 				    "REJECTED because of better priority %d" \
464*0Sstevel@tonic-gate 				    " and/or precedence %d",
465*0Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.filter_name,
466*0Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.priority,
467*0Sstevel@tonic-gate 				    ipgpc_fid_list[oldbm].filter.precedence));
468*0Sstevel@tonic-gate 				best_prio = real_prio;
469*0Sstevel@tonic-gate 				bestmatch = key;
470*0Sstevel@tonic-gate 			} else {
471*0Sstevel@tonic-gate 				ipgpc3dbg(("bestmatch: filter %s " \
472*0Sstevel@tonic-gate 				    "REJECTED because of beter priority %d" \
473*0Sstevel@tonic-gate 				    " and/or precedence %d",
474*0Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.filter_name,
475*0Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.priority,
476*0Sstevel@tonic-gate 				    ipgpc_fid_list[key].filter.precedence));
477*0Sstevel@tonic-gate 			}
478*0Sstevel@tonic-gate 		}
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 	if (bestmatch == -1) {	/* no best matches were found */
481*0Sstevel@tonic-gate 		ipgpc3dbg(("bestmatch: No filters ACCEPTED"));
482*0Sstevel@tonic-gate 		return (ipgpc_def_class_id);
483*0Sstevel@tonic-gate 	} else {
484*0Sstevel@tonic-gate 		ipgpc3dbg(("bestmatch: filter %s ACCEPTED with priority %d " \
485*0Sstevel@tonic-gate 		    "and precedence %d",
486*0Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.filter_name,
487*0Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.priority,
488*0Sstevel@tonic-gate 		    ipgpc_fid_list[bestmatch].filter.precedence));
489*0Sstevel@tonic-gate 		return (ipgpc_fid_list[bestmatch].class_id);
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate /*
494*0Sstevel@tonic-gate  * get_port_info(packet, iph, af, mp)
495*0Sstevel@tonic-gate  *
496*0Sstevel@tonic-gate  * Gets the source and destination ports from the ULP header, if present.
497*0Sstevel@tonic-gate  * If this is a fragment, don't try to get the port information even if this
498*0Sstevel@tonic-gate  * is the first fragment. The reason being we won't have this information
499*0Sstevel@tonic-gate  * in subsequent fragments and may end up classifying the first fragment
500*0Sstevel@tonic-gate  * differently than others. This is not desired.
501*0Sstevel@tonic-gate  * For IPv6 packets, step through the extension headers, if present, in
502*0Sstevel@tonic-gate  * order to get to the ULP header.
503*0Sstevel@tonic-gate  */
504*0Sstevel@tonic-gate static void
505*0Sstevel@tonic-gate get_port_info(ipgpc_packet_t *packet, void *iph, int af, mblk_t *mp)
506*0Sstevel@tonic-gate {
507*0Sstevel@tonic-gate 	uint16_t *up;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	if (af == AF_INET) {
510*0Sstevel@tonic-gate 		uint32_t u2, u1;
511*0Sstevel@tonic-gate 		uint_t iplen;
512*0Sstevel@tonic-gate 		ipha_t *ipha = (ipha_t *)iph;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 		u2 = ntohs(ipha->ipha_fragment_offset_and_flags);
515*0Sstevel@tonic-gate 		u1 = u2 & (IPH_MF | IPH_OFFSET);
516*0Sstevel@tonic-gate 		if (u1) {
517*0Sstevel@tonic-gate 			return;
518*0Sstevel@tonic-gate 		}
519*0Sstevel@tonic-gate 		iplen = (ipha->ipha_version_and_hdr_length & 0xF) << 2;
520*0Sstevel@tonic-gate 		up = (uint16_t *)(mp->b_rptr + iplen);
521*0Sstevel@tonic-gate 		packet->sport = (uint16_t)*up++;
522*0Sstevel@tonic-gate 		packet->dport = (uint16_t)*up;
523*0Sstevel@tonic-gate 	} else {	/* AF_INET6 */
524*0Sstevel@tonic-gate 		uint_t  length = IPV6_HDR_LEN;
525*0Sstevel@tonic-gate 		ip6_t *ip6h = (ip6_t *)iph;
526*0Sstevel@tonic-gate 		uint_t  ehdrlen;
527*0Sstevel@tonic-gate 		uint8_t *nexthdrp, *whereptr, *endptr;
528*0Sstevel@tonic-gate 		ip6_dest_t *desthdr;
529*0Sstevel@tonic-gate 		ip6_rthdr_t *rthdr;
530*0Sstevel@tonic-gate 		ip6_hbh_t *hbhhdr;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 		whereptr = ((uint8_t *)&ip6h[1]);
533*0Sstevel@tonic-gate 		endptr = mp->b_wptr;
534*0Sstevel@tonic-gate 		nexthdrp = &ip6h->ip6_nxt;
535*0Sstevel@tonic-gate 		while (whereptr < endptr) {
536*0Sstevel@tonic-gate 			switch (*nexthdrp) {
537*0Sstevel@tonic-gate 			case IPPROTO_HOPOPTS:
538*0Sstevel@tonic-gate 				hbhhdr = (ip6_hbh_t *)whereptr;
539*0Sstevel@tonic-gate 				ehdrlen = 8 * (hbhhdr->ip6h_len + 1);
540*0Sstevel@tonic-gate 				if ((uchar_t *)hbhhdr +  ehdrlen > endptr)
541*0Sstevel@tonic-gate 					return;
542*0Sstevel@tonic-gate 				nexthdrp = &hbhhdr->ip6h_nxt;
543*0Sstevel@tonic-gate 				break;
544*0Sstevel@tonic-gate 			case IPPROTO_DSTOPTS:
545*0Sstevel@tonic-gate 				desthdr = (ip6_dest_t *)whereptr;
546*0Sstevel@tonic-gate 				ehdrlen = 8 * (desthdr->ip6d_len + 1);
547*0Sstevel@tonic-gate 				if ((uchar_t *)desthdr +  ehdrlen > endptr)
548*0Sstevel@tonic-gate 					return;
549*0Sstevel@tonic-gate 				nexthdrp = &desthdr->ip6d_nxt;
550*0Sstevel@tonic-gate 				break;
551*0Sstevel@tonic-gate 			case IPPROTO_ROUTING:
552*0Sstevel@tonic-gate 				rthdr = (ip6_rthdr_t *)whereptr;
553*0Sstevel@tonic-gate 				ehdrlen =  8 * (rthdr->ip6r_len + 1);
554*0Sstevel@tonic-gate 				if ((uchar_t *)rthdr +  ehdrlen > endptr)
555*0Sstevel@tonic-gate 					return;
556*0Sstevel@tonic-gate 				nexthdrp = &rthdr->ip6r_nxt;
557*0Sstevel@tonic-gate 				break;
558*0Sstevel@tonic-gate 			case IPPROTO_FRAGMENT:
559*0Sstevel@tonic-gate 				return;
560*0Sstevel@tonic-gate 			case IPPROTO_TCP:
561*0Sstevel@tonic-gate 			case IPPROTO_UDP:
562*0Sstevel@tonic-gate 			case IPPROTO_SCTP:
563*0Sstevel@tonic-gate 				/*
564*0Sstevel@tonic-gate 				 * Verify we have at least ICMP_MIN_TP_HDR_LEN
565*0Sstevel@tonic-gate 				 * bytes of the ULP's header to get the port
566*0Sstevel@tonic-gate 				 * info.
567*0Sstevel@tonic-gate 				 */
568*0Sstevel@tonic-gate 				if (((uchar_t *)ip6h + length +
569*0Sstevel@tonic-gate 				    ICMP_MIN_TP_HDR_LEN)  > endptr) {
570*0Sstevel@tonic-gate 					return;
571*0Sstevel@tonic-gate 				}
572*0Sstevel@tonic-gate 				/* Get the protocol and the ports */
573*0Sstevel@tonic-gate 				packet->proto = *nexthdrp;
574*0Sstevel@tonic-gate 				up = (uint16_t *)((uchar_t *)ip6h + length);
575*0Sstevel@tonic-gate 				packet->sport = (uint16_t)*up++;
576*0Sstevel@tonic-gate 				packet->dport = (uint16_t)*up;
577*0Sstevel@tonic-gate 				return;
578*0Sstevel@tonic-gate 			case IPPROTO_ICMPV6:
579*0Sstevel@tonic-gate 			case IPPROTO_ENCAP:
580*0Sstevel@tonic-gate 			case IPPROTO_IPV6:
581*0Sstevel@tonic-gate 			case IPPROTO_ESP:
582*0Sstevel@tonic-gate 			case IPPROTO_AH:
583*0Sstevel@tonic-gate 				packet->proto = *nexthdrp;
584*0Sstevel@tonic-gate 				return;
585*0Sstevel@tonic-gate 			case IPPROTO_NONE:
586*0Sstevel@tonic-gate 			default:
587*0Sstevel@tonic-gate 				return;
588*0Sstevel@tonic-gate 			}
589*0Sstevel@tonic-gate 			length += ehdrlen;
590*0Sstevel@tonic-gate 			whereptr += ehdrlen;
591*0Sstevel@tonic-gate 		}
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate /*
596*0Sstevel@tonic-gate  * find_ids(packet, mp)
597*0Sstevel@tonic-gate  *
598*0Sstevel@tonic-gate  * attempt to discern the uid and projid of the originator of a packet by
599*0Sstevel@tonic-gate  * looking at the dblks making up the packet - yeuch!
600*0Sstevel@tonic-gate  *
601*0Sstevel@tonic-gate  * We do it by skipping any fragments with a credp of NULL (originated in
602*0Sstevel@tonic-gate  * kernel), taking the first value that isn't NULL to be the credp for the
603*0Sstevel@tonic-gate  * whole packet. We also suck the projid from the same fragment.
604*0Sstevel@tonic-gate  */
605*0Sstevel@tonic-gate static void
606*0Sstevel@tonic-gate find_ids(ipgpc_packet_t *packet, mblk_t *mp)
607*0Sstevel@tonic-gate {
608*0Sstevel@tonic-gate 	cred_t *cr;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	while (DB_CRED(mp) == NULL && mp->b_cont != NULL)
611*0Sstevel@tonic-gate 		mp = mp->b_cont;
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 	if ((cr = DB_CRED(mp)) != NULL) {
614*0Sstevel@tonic-gate 		packet->uid = crgetuid(cr);
615*0Sstevel@tonic-gate 		packet->projid = crgetprojid(cr);
616*0Sstevel@tonic-gate 	} else {
617*0Sstevel@tonic-gate 		packet->uid = -1;
618*0Sstevel@tonic-gate 		packet->projid = -1;
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate }
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate /*
623*0Sstevel@tonic-gate  * parse_packet(packet, mp)
624*0Sstevel@tonic-gate  *
625*0Sstevel@tonic-gate  * parses the given message block into a ipgpc_packet_t structure
626*0Sstevel@tonic-gate  */
627*0Sstevel@tonic-gate void
628*0Sstevel@tonic-gate parse_packet(ipgpc_packet_t *packet, mblk_t *mp)
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	ipha_t	*ipha;
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	/* parse message block for IP header and ports */
633*0Sstevel@tonic-gate 	ipha = (ipha_t *)mp->b_rptr; /* get ip header */
634*0Sstevel@tonic-gate 	V4_PART_OF_V6(packet->saddr) = (int32_t)ipha->ipha_src;
635*0Sstevel@tonic-gate 	V4_PART_OF_V6(packet->daddr) = (int32_t)ipha->ipha_dst;
636*0Sstevel@tonic-gate 	packet->dsfield = ipha->ipha_type_of_service;
637*0Sstevel@tonic-gate 	packet->proto = ipha->ipha_protocol;
638*0Sstevel@tonic-gate 	packet->sport = 0;
639*0Sstevel@tonic-gate 	packet->dport = 0;
640*0Sstevel@tonic-gate 	find_ids(packet, mp);
641*0Sstevel@tonic-gate 	packet->len = msgdsize(mp);
642*0Sstevel@tonic-gate 	/* parse out TCP/UDP ports, if appropriate */
643*0Sstevel@tonic-gate 	if ((packet->proto == IPPROTO_TCP) || (packet->proto == IPPROTO_UDP) ||
644*0Sstevel@tonic-gate 	    (packet->proto == IPPROTO_SCTP)) {
645*0Sstevel@tonic-gate 		get_port_info(packet, ipha, AF_INET, mp);
646*0Sstevel@tonic-gate 	}
647*0Sstevel@tonic-gate }
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate /*
650*0Sstevel@tonic-gate  * parse_packet6(packet, mp)
651*0Sstevel@tonic-gate  *
652*0Sstevel@tonic-gate  * parses the message block into a ipgpc_packet_t structure for IPv6 traffic
653*0Sstevel@tonic-gate  */
654*0Sstevel@tonic-gate void
655*0Sstevel@tonic-gate parse_packet6(ipgpc_packet_t *packet, mblk_t *mp)
656*0Sstevel@tonic-gate {
657*0Sstevel@tonic-gate 	ip6_t *ip6h = (ip6_t *)mp->b_rptr;
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	/* parse message block for IP header and ports */
660*0Sstevel@tonic-gate 	bcopy(ip6h->ip6_src.s6_addr32, packet->saddr.s6_addr32,
661*0Sstevel@tonic-gate 	    sizeof (ip6h->ip6_src.s6_addr32));
662*0Sstevel@tonic-gate 	bcopy(ip6h->ip6_dst.s6_addr32, packet->daddr.s6_addr32,
663*0Sstevel@tonic-gate 	    sizeof (ip6h->ip6_dst.s6_addr32));
664*0Sstevel@tonic-gate 	/* Will be (re-)assigned in get_port_info */
665*0Sstevel@tonic-gate 	packet->proto = ip6h->ip6_nxt;
666*0Sstevel@tonic-gate 	packet->dsfield = __IPV6_TCLASS_FROM_FLOW(ip6h->ip6_vcf);
667*0Sstevel@tonic-gate 	find_ids(packet, mp);
668*0Sstevel@tonic-gate 	packet->len = msgdsize(mp);
669*0Sstevel@tonic-gate 	packet->sport = 0;
670*0Sstevel@tonic-gate 	packet->dport = 0;
671*0Sstevel@tonic-gate 	/* Need to pullup everything. */
672*0Sstevel@tonic-gate 	if (mp->b_cont != NULL) {
673*0Sstevel@tonic-gate 		if (!pullupmsg(mp, -1)) {
674*0Sstevel@tonic-gate 			ipgpc0dbg(("parse_packet6(): pullup error, can't " \
675*0Sstevel@tonic-gate 			    "find ports"));
676*0Sstevel@tonic-gate 			return;
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 		ip6h = (ip6_t *)mp->b_rptr;
679*0Sstevel@tonic-gate 	}
680*0Sstevel@tonic-gate 	get_port_info(packet, ip6h, AF_INET6, mp);
681*0Sstevel@tonic-gate }
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate #ifdef	IPGPC_DEBUG
684*0Sstevel@tonic-gate /*
685*0Sstevel@tonic-gate  * print_packet(af, packet)
686*0Sstevel@tonic-gate  *
687*0Sstevel@tonic-gate  * prints the contents of the packet structure for specified address family
688*0Sstevel@tonic-gate  */
689*0Sstevel@tonic-gate void
690*0Sstevel@tonic-gate print_packet(int af, ipgpc_packet_t *pkt)
691*0Sstevel@tonic-gate {
692*0Sstevel@tonic-gate 	if (af == AF_INET) {
693*0Sstevel@tonic-gate 		char saddrbuf[INET_ADDRSTRLEN];
694*0Sstevel@tonic-gate 		char daddrbuf[INET_ADDRSTRLEN];
695*0Sstevel@tonic-gate 		ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
696*0Sstevel@tonic-gate 		    ", dport = %u, proto = %u, dsfield = %x, uid = %d," \
697*0Sstevel@tonic-gate 		    " if_index = %d, if_groupname = %s, projid = %d, " \
698*0Sstevel@tonic-gate 		    "direction = %d",
699*0Sstevel@tonic-gate 		    inet_ntop(af, &V4_PART_OF_V6(pkt->saddr), saddrbuf,
700*0Sstevel@tonic-gate 			sizeof (saddrbuf)),
701*0Sstevel@tonic-gate 		    inet_ntop(af, &V4_PART_OF_V6(pkt->daddr), daddrbuf,
702*0Sstevel@tonic-gate 			sizeof (daddrbuf)),
703*0Sstevel@tonic-gate 		    ntohs(pkt->sport), ntohs(pkt->dport), pkt->proto,
704*0Sstevel@tonic-gate 		    pkt->dsfield, pkt->uid, pkt->if_index,
705*0Sstevel@tonic-gate 		    (pkt->if_groupname != NULL) ? pkt->if_groupname : "NULL",
706*0Sstevel@tonic-gate 		    pkt->projid, pkt->direction));
707*0Sstevel@tonic-gate 	} else if (af == AF_INET6) {
708*0Sstevel@tonic-gate 		char saddrbuf[INET6_ADDRSTRLEN];
709*0Sstevel@tonic-gate 		char daddrbuf[INET6_ADDRSTRLEN];
710*0Sstevel@tonic-gate 		ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
711*0Sstevel@tonic-gate 		    ", dport = %u, proto = %u, dsfield = %x, uid = %d," \
712*0Sstevel@tonic-gate 		    " if_index = %d, if_groupname = %s, projid = %d, " \
713*0Sstevel@tonic-gate 		    "direction = %d",
714*0Sstevel@tonic-gate 		    inet_ntop(af, pkt->saddr.s6_addr32, saddrbuf,
715*0Sstevel@tonic-gate 			sizeof (saddrbuf)),
716*0Sstevel@tonic-gate 		    inet_ntop(af, pkt->daddr.s6_addr32, daddrbuf,
717*0Sstevel@tonic-gate 			sizeof (daddrbuf)),
718*0Sstevel@tonic-gate 		    ntohs(pkt->sport), ntohs(pkt->dport), pkt->proto,
719*0Sstevel@tonic-gate 		    pkt->dsfield, pkt->uid, pkt->if_index,
720*0Sstevel@tonic-gate 		    (pkt->if_groupname != NULL) ? pkt->if_groupname : "NULL",
721*0Sstevel@tonic-gate 		    pkt->projid, pkt->direction));
722*0Sstevel@tonic-gate 	}
723*0Sstevel@tonic-gate }
724*0Sstevel@tonic-gate #endif /* IPGPC_DEBUG */
725