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 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 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 * 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 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 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 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 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 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 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