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