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 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2012 David Hoeppner.  All rights reserved.
  29  */
  30 
  31 /*
  32  * Functions related to the output path.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/stream.h>
  37 #include <sys/strsun.h>
  38 #include <sys/strsubr.h>
  39 #include <sys/stropts.h>
  40 #include <sys/strlog.h>
  41 #define _SUN_TPI_VERSION 2
  42 #include <sys/tihdr.h>
  43 #include <sys/suntpi.h>
  44 #include <sys/xti_inet.h>
  45 #include <sys/squeue_impl.h>
  46 #include <sys/squeue.h>
  47 #include <sys/tsol/tnet.h>
  48 
  49 #include <inet/common.h>
  50 #include <inet/ip.h>
  51 #include <inet/ipsec_impl.h>
  52 
  53 #include <sys/cmn_err.h>
  54 
  55 #include "dccp_impl.h"
  56 #include "dccp_stack.h"
  57 
  58 static void     dccp_xmit_early_reset(char *, mblk_t *, uint32_t, uint32_t,
  59                     int, ip_recv_attr_t *, ip_stack_t *, conn_t *);
  60 static boolean_t        dccp_send_rst_chk(dccp_stack_t *);
  61 
  62 /*
  63  * STREAMS
  64  */
  65 void
  66 dccp_wput(queue_t *q, mblk_t *mp)
  67 {
  68         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput\n");
  69 }
  70 
  71 /*
  72  *
  73  */
  74 void
  75 dccp_wput_sock(queue_t *wq, mblk_t *mp)
  76 {
  77         conn_t  *connp = Q_TO_CONN(wq);
  78         dccp_t  *dccp = connp->conn_dccp;
  79         struct T_capability_req *car = (struct T_capability_req *)mp->b_rptr;
  80 
  81         ASSERT(wq->q_qinfo == &dccp_sock_winit);
  82         wq->q_qinfo = &dccp_winit;
  83 
  84         ASSERT(IPCL_IS_TCP(connp));
  85         ASSERT(DCCP_IS_SOCKET(dccp));
  86 
  87         if (DB_TYPE(mp) == M_PCPROTO &&
  88             MBLKL(mp) == sizeof (struct T_capability_req) &&
  89             car->PRIM_type == T_CAPABILITY_REQ) {
  90                 dccp_capability_req(dccp, mp);
  91                 return;
  92         }
  93 
  94         dccp_wput(wq, mp);
  95 }
  96 
  97 /* ARGSUSED */
  98 void
  99 dccp_wput_fallback(queue_t *eq, mblk_t *mp)
 100 {
 101         cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_fallback");
 102 
 103 #ifdef DEBUG
 104         cmn_err(CE_CONT, "tcp_wput_fallback: Message during fallback \n");
 105 #endif /* DEBUG */
 106 
 107         freemsg(mp);
 108 }
 109 
 110 void
 111 dccp_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 112 {
 113         cmn_err(CE_NOTE, "dccp_output.c: dccp_output");
 114 }
 115 
 116 void
 117 dccp_output_urgent(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 118 {
 119         cmn_err(CE_NOTE, "dccp_output.c: dccp_output_urgent");
 120 }
 121 
 122 // XXX */
 123 
 124 #pragma inline(dccp_send_data)
 125 
 126 void
 127 dccp_send_data(dccp_t *dccp, mblk_t *mp)
 128 {
 129         conn_t  *connp = dccp->dccp_connp;
 130 
 131         /* XXX dtrace */
 132 
 133         ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp);
 134         (void) conn_ip_output(mp, connp->conn_ixa);
 135 }
 136 
 137 /*
 138  * Send a reset as response to an incoming packet or
 139  * reset a connection.
 140  */
 141 void
 142 dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
 143     conn_t *connp)
 144 {
 145         netstack_t      *ns = ipst->ips_netstack;
 146         dccp_stack_t    *dccps = ns->netstack_dccp;
 147         ipsec_stack_t   *ipss = dccps->dccps_netstack->netstack_ipsec;
 148         dccpha_t        *dccpha;
 149         ipha_t          *ipha;
 150         ip6_t           *ip6h;
 151         uchar_t         *rptr;
 152         uint32_t        seq_len;
 153         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 154         boolean_t       policy_present;
 155 
 156         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
 157 
 158         DCCP_STAT(dccps, dccp_no_listener);
 159 
 160         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 161                 policy_present = ipss->ipsec_inbound_v4_policy_present;
 162                 ipha = (ipha_t *)mp->b_rptr;
 163                 ip6h = NULL;
 164         } else {
 165                 policy_present = ipss->ipsec_inbound_v6_policy_present;
 166                 ipha = NULL;
 167                 ip6h = (ip6_t *)mp->b_rptr;
 168         }
 169 
 170         if (policy_present) {
 171                 mp = ipsec_check_global_policy(mp, (conn_t *)NULL, ipha, ip6h,
 172                     ira, ns);
 173                 if (mp == NULL) {
 174                         return;
 175                 }
 176         }
 177 
 178         rptr = mp->b_rptr;
 179 
 180         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
 181 
 182         seq_len = msgdsize(mp) - (ip_hdr_len);
 183 
 184         dccp_xmit_early_reset("no dccp, reset", mp, 0,
 185             0, 0, ira, ipst, connp);
 186 }
 187 
 188 /*
 189  * RFC 4340, Section 8.1.3
 190  */
 191 static void
 192 dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
 193     ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
 194 {
 195         dccpha_t        *dccpha;
 196         dccpha_t        *nmp_dccpha;
 197         dccpha_ack_t    *nmp_dccpha_ack;
 198         dccpha_reset_t  *dccpha_reset;
 199         dccpha_reset_t  *nmp_dccpha_reset;
 200         dccpha_ext_t    *dccpha_ext;
 201         dccpha_ext_t    *nmp_dccpha_ext;
 202         netstack_t      *ns = ipst->ips_netstack;
 203         dccp_stack_t    *dccps = ns->netstack_dccp;
 204         ip6_t           *ip6h;
 205         ipha_t          *ipha;
 206         ipha_t          *nmp_ipha;
 207         ip_xmit_attr_t  ixas;
 208         ip_xmit_attr_t  *ixa;
 209         in6_addr_t      v6addr;
 210         ipaddr_t        v4addr;
 211         mblk_t          *nmp;
 212         uint64_t        pkt_ack;
 213         uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 214         ushort_t        port;
 215         ushort_t        len;
 216 
 217         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
 218 
 219         if (!dccp_send_rst_chk(dccps)) {
 220                 cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
 221                 DCCP_STAT(dccps, dccp_rst_unsent);
 222                 freemsg(mp);
 223                 return;
 224         }
 225 
 226                 bzero(&ixas, sizeof (ixas));
 227                 ixa = &ixas;
 228 
 229                 ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
 230                 ixa->ixa_protocol = IPPROTO_DCCP;
 231                 ixa->ixa_zoneid = ira->ira_zoneid;
 232                 ixa->ixa_ifindex = 0;
 233                 ixa->ixa_ipst = ipst;
 234                 ixa->ixa_cred = kcred;
 235                 ixa->ixa_cpid = NOPID;
 236 
 237         if (str && dccps->dccps_dbg) {
 238                 (void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
 239                     "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
 240                     "flags 0x%x",
 241                     str, seq, ack, ctl);
 242         }
 243 
 244         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 245                 ipha = (ipha_t *)mp->b_rptr;
 246 
 247         } else {
 248                 /* XXX */
 249         }
 250 
 251         /*
 252          * Allocate a new DCCP reset message
 253          */
 254         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
 255         nmp = allocb(len, BPRI_MED);
 256         if (nmp == NULL) {
 257                 cmn_err(CE_NOTE, "alloc failed");
 258                 return;
 259         }
 260         bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
 261 
 262         nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
 263         nmp_dccpha->dha_offset = 7;
 264 
 265         if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 266                 nmp_ipha = (ipha_t *)nmp->b_rptr;
 267 
 268                 nmp_ipha->ipha_length = htons(len);
 269                 nmp_ipha->ipha_src = ipha->ipha_dst;
 270                 nmp_ipha->ipha_dst = ipha->ipha_src;
 271 
 272                 ixa->ixa_flags |= IXAF_IS_IPV4;
 273                 ixa->ixa_ip_hdr_length = ip_hdr_len;
 274         } else {
 275                 cmn_err(CE_NOTE, "not v4");
 276         }
 277 
 278         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 279 
 280         nmp->b_wptr = &nmp->b_rptr[len];
 281 
 282         ixa->ixa_pktlen = len; // ?
 283 
 284         nmp_dccpha->dha_fport = dccpha->dha_lport;
 285         nmp_dccpha->dha_lport = dccpha->dha_fport;
 286         nmp_dccpha->dha_type = DCCP_PKT_RESET;
 287         nmp_dccpha->dha_x = 1;
 288         nmp_dccpha->dha_res_seq = 0;
 289         nmp_dccpha->dha_seq = 0;
 290 
 291         nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
 292 
 293         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 294         nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 295         nmp_dccpha_ext->dha_ext_seq = 0;
 296 
 297         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
 298         nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
 299         nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
 300         nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
 301 
 302         len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
 303         nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
 304         nmp_dccpha_reset->dha_reset_code = 7;
 305         nmp_dccpha_reset->dha_reset_data[0] = 0;
 306         nmp_dccpha_reset->dha_reset_data[1] = 0;
 307         nmp_dccpha_reset->dha_reset_data[2] = 0;
 308 
 309         (void) ip_output_simple(nmp, ixa);
 310 
 311         ixa_cleanup(ixa);
 312 }
 313 
 314 /*
 315  *
 316  */
 317 static boolean_t
 318 dccp_send_rst_chk(dccp_stack_t *dccps)
 319 {
 320         int64_t now;
 321 
 322         if (dccps->dccps_rst_sent_rate_enabled != 0) {
 323                 now = ddi_get_lbolt64();
 324                 if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
 325                     1 * SECONDS) {
 326                         dccps->dccps_last_rst_intrvl = now;
 327                         dccps->dccps_rst_cnt = 1;
 328                 } else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
 329                         return (B_FALSE);
 330                 }
 331         }
 332 
 333         return (B_TRUE);
 334 }
 335 
 336 void
 337 dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
 338 {
 339         cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
 340 }
 341 
 342 mblk_t *
 343 dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
 344     mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
 345     boolean_t rexmit)
 346 {
 347         conn_t          *connp = dccp->dccp_connp;
 348         dccp_stack_t    *dccps = dccp->dccp_dccps;
 349         dccpha_t        *dccpha;
 350         dccpha_ext_t    *dccpha_ext;
 351         dccpha_ack_t    *dccpha_ack;
 352         dccpha_srv_t    *dccpha_srv;
 353         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 354         mblk_t          *mp1;
 355         uchar_t         *rptr;
 356         ushort_t        len;
 357         int             data_length;
 358 
 359         cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
 360 
 361         // dccpha_t already in iphc_len?
 362         len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
 363 
 364         //mp1 = dccp_generate_packet(connp, mp);
 365         mp1 = allocb(len, BPRI_MED);
 366         if (mp1 == NULL) {
 367                 cmn_err(CE_NOTE, "allocb failed");
 368                 return (NULL);
 369         }
 370 
 371         data_length = 0;
 372 
 373         rptr = mp1->b_rptr;
 374         mp1->b_wptr = &mp1->b_rptr[len];
 375         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 376         dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
 377         dccpha->dha_type = DCCP_PKT_RESPONSE;
 378         dccpha->dha_offset = 8;
 379         dccpha->dha_x = 1;
 380         dccpha->dha_ccval = 0;
 381         dccpha->dha_cscov = 0;
 382         dccpha->dha_reserved = 0;
 383         dccpha->dha_res_seq = 0;
 384         dccpha->dha_seq = 0;
 385 
 386         dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
 387         dccpha_ext->dha_ext_seq = 0;
 388 
 389         dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 390         dccpha_ack->dha_ack_reserved = 0;
 391         dccpha_ack->dha_ack_high = 0;
 392         dccpha_ack->dha_ack_low = 0;
 393 
 394         dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 395         dccpha_srv->dha_srv_code = 0;
 396 
 397         return (mp1);
 398 }
 399 
 400 mblk_t *
 401 dccp_generate_packet(conn_t *connp, mblk_t *mp)
 402 {
 403         dccpha_t        *dccpha;
 404         dccpha_ext_t    *dccpha_ext;
 405         dccpha_ack_t    *dccpha_ack;
 406         dccpha_srv_t    *dccpha_srv;
 407         mblk_t          *mp1;
 408         uint16_t        ack_high;
 409         uint32_t        ack_low;
 410 //      uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
 411         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 412         uint_t          ip_hdr_len;
 413         uint_t          len;
 414         uint_t          total_hdr_len;
 415         uchar_t         *rptr;
 416         dccp_t          *dccp = connp->conn_dccp;
 417         void            *options;
 418         size_t          opt_len;
 419         int             error;
 420 
 421         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
 422 
 423         ip_hdr_len = ixa->ixa_ip_hdr_length;
 424 
 425         if (mp == NULL) {
 426                 cmn_err(CE_NOTE, "NULL pointer mp");
 427                 return (NULL);
 428         }
 429 
 430         dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
 431         dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 432 
 433         ack_high = dccpha->dha_seq;
 434         ack_low = dccpha_ext->dha_ext_seq;
 435 
 436         error = dccp_generate_options(dccp, &options, &opt_len);
 437         if (error != 0) {
 438                 cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_options failed");
 439         }
 440         cmn_err(CE_NOTE, "generated options len: %d", (int) opt_len);
 441 
 442 
 443         /*
 444          * conn_ht_iphc_len = ip_hdr_length (20) + ulp_hdr_length
 445          * (20) simple ip header (without vtag or options)
 446          */
 447         total_hdr_len = len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len;
 448         mp1 = allocb(len, BPRI_MED);
 449         if (mp1 == NULL) {
 450                 cmn_err(CE_NOTE, "allocb failed");
 451                 return (NULL);
 452         }
 453 
 454         rptr = mp1->b_rptr;
 455         mp1->b_wptr = &mp1->b_rptr[len];
 456 
 457         bcopy(options, &mp1->b_rptr[len-opt_len], opt_len);
 458         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 459         dccpha = (dccpha_t *)&rptr[ip_hdr_len];
 460 
 461         dccpha->dha_type = DCCP_PKT_RESPONSE;
 462         dccpha->dha_offset = 7 + (opt_len / 4);
 463         dccpha->dha_x = 1;
 464         dccpha->dha_ccval = 0;
 465         dccpha->dha_cscov = 0;
 466         dccpha->dha_reserved = 0;
 467         dccpha->dha_res_seq = 0;
 468         dccpha->dha_seq = 0;
 469         dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len);
 470 
 471 
 472         dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
 473         dccpha_ext->dha_ext_seq = 1234567;
 474 
 475         dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
 476         dccpha_ack->dha_ack_high = ack_high;
 477         dccpha_ack->dha_ack_low = ack_low;
 478 
 479         dccpha_srv = (dccpha_srv_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
 480         dccpha_srv->dha_srv_code = 0;
 481 
 482         ixa->ixa_pktlen = total_hdr_len;
 483 
 484         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 485                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 486         } else {
 487                 ip6_t *ip6 = (ip6_t *)rptr;
 488 
 489                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 490         }
 491 
 492         cmn_err(CE_NOTE, "IPHC LEN: %d", connp->conn_ht_iphc_len);
 493         cmn_err(CE_NOTE, "TOTAL LEN: %d", total_hdr_len);
 494 
 495         kmem_free(options, opt_len);
 496 
 497         return (mp1);
 498 }
 499 
 500 /*
 501  * Generate a request packet. Must use 48-bit sequence
 502  * numbers.
 503  */
 504 mblk_t *
 505 dccp_generate_request(conn_t *connp)
 506 {
 507         dccp_t          *dccp = connp->conn_dccp;
 508         dccpha_t        *dccpha;
 509         dccpha_ext_t    *dccpha_ext;
 510         dccpha_srv_t    *dccpha_srv;
 511         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 512         mblk_t          *mp;
 513         uchar_t         *rptr;
 514         uint_t          total_hdr_len;
 515         uint_t          len = ixa->ixa_ip_hdr_length;
 516 
 517         cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_request");
 518 
 519         total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_srv_t);
 520         mp = allocb(total_hdr_len, BPRI_MED);
 521         if (mp == NULL) {
 522                 return (NULL);
 523         }
 524 
 525         rptr = mp->b_rptr;
 526         /* Copy in the template header */
 527         bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
 528 
 529         dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
 530         dccpha->dha_type = DCCP_PKT_REQUEST;
 531         dccpha->dha_x = 1;
 532 
 533         /* Extended sequence number */
 534         len += sizeof (dccpha_t);
 535         dccpha_ext = (dccpha_ext_t *)&rptr[len];
 536 
 537         /* Service number */
 538         len += sizeof (dccpha_ext_t);
 539         dccpha_srv = (dccpha_srv_t *)&rptr[len];
 540         dccpha_srv->dha_srv_code = 0;
 541 
 542         ixa->ixa_pktlen = total_hdr_len;
 543         if (ixa->ixa_flags & IXAF_IS_IPV4) {
 544                 ((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
 545         } else {
 546                 ip6_t *ip6 = (ip6_t *)rptr;
 547 
 548                 ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
 549         }
 550 
 551         return (mp);
 552 }