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