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