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