1*38361Ssam /* slcompress.c 7.1 89/06/28 */ 2*38361Ssam 3*38361Ssam /* 4*38361Ssam * THIS CODE IS NOT FOR DISTRIBUTION! 5*38361Ssam * KEEP YOUR GRUBBY HANDS OFF UNLESS AUTHORIZED BY VAN JACOBSON TO COPY! 6*38361Ssam * ASK SAM, MIKE, OR BILL ABOUT IT. 7*38361Ssam */ 8*38361Ssam 9*38361Ssam /* 10*38361Ssam * Routines to compress and uncompess tcp packets (for transmission 11*38361Ssam * over low speed serial lines. 12*38361Ssam * 13*38361Ssam * Copyright (c) 1988, 1989 by Van Jacobson, Lawrence Berkeley Laboratory 14*38361Ssam * All rights reserved. 15*38361Ssam */ 16*38361Ssam 17*38361Ssam #ifndef lint 18*38361Ssam static char rcsid[] = "$Header: slcompress.c,v 1.7 89/03/19 18:10:19 van Locked $"; 19*38361Ssam #endif 20*38361Ssam 21*38361Ssam #include <sys/types.h> 22*38361Ssam #include <sys/param.h> 23*38361Ssam #include <sys/mbuf.h> 24*38361Ssam #include <netinet/in.h> 25*38361Ssam #include <netinet/in_systm.h> 26*38361Ssam #include <netinet/ip.h> 27*38361Ssam #include <netinet/tcp.h> 28*38361Ssam 29*38361Ssam #include "slcompress.h" 30*38361Ssam 31*38361Ssam int sls_packets; 32*38361Ssam int sls_searches; 33*38361Ssam int sls_misses; 34*38361Ssam int sls_compressed; 35*38361Ssam int sls_ipin; 36*38361Ssam int sls_uncompressedin; 37*38361Ssam int sls_compressedin; 38*38361Ssam 39*38361Ssam #define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) 40*38361Ssam #define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) 41*38361Ssam 42*38361Ssam #ifndef KERNEL 43*38361Ssam extern struct mbuf *m_get(); 44*38361Ssam #undef MGET 45*38361Ssam #define MGET(m, w, t) ((m) = m_get((w), (t))) 46*38361Ssam #endif 47*38361Ssam 48*38361Ssam #if BSD>=198810 49*38361Ssam #define m_off m_data 50*38361Ssam #endif 51*38361Ssam 52*38361Ssam void 53*38361Ssam sl_compress_init(comp) 54*38361Ssam struct slcompress *comp; 55*38361Ssam { 56*38361Ssam register u_int i; 57*38361Ssam register struct cstate *tstate = comp->tstate; 58*38361Ssam 59*38361Ssam bzero((char *)comp, sizeof(*comp)); 60*38361Ssam for (i = MAX_STATES - 1; i > 0; --i) { 61*38361Ssam tstate[i].cs_id = i; 62*38361Ssam tstate[i].cs_next = &tstate[i - 1]; 63*38361Ssam } 64*38361Ssam tstate[0].cs_next = &tstate[MAX_STATES - 1]; 65*38361Ssam tstate[0].cs_id = 0; 66*38361Ssam comp->last_cs = &tstate[0]; 67*38361Ssam comp->last_recv = 255; 68*38361Ssam comp->last_xmit = 255; 69*38361Ssam } 70*38361Ssam 71*38361Ssam 72*38361Ssam /* ENCODE encodes a number that is known to be non-zero. ENCODEZ 73*38361Ssam * checks for zero (since zero has to be encoded in the long, 3 byte 74*38361Ssam * form). 75*38361Ssam */ 76*38361Ssam #define ENCODE(n) { \ 77*38361Ssam if ((u_short)(n) >= 256) { \ 78*38361Ssam *cp++ = 0; \ 79*38361Ssam cp[1] = (n); \ 80*38361Ssam cp[0] = (n) >> 8; \ 81*38361Ssam cp += 2; \ 82*38361Ssam } else { \ 83*38361Ssam *cp++ = (n); \ 84*38361Ssam } \ 85*38361Ssam } 86*38361Ssam #define ENCODEZ(n) { \ 87*38361Ssam if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ 88*38361Ssam *cp++ = 0; \ 89*38361Ssam cp[1] = (n); \ 90*38361Ssam cp[0] = (n) >> 8; \ 91*38361Ssam cp += 2; \ 92*38361Ssam } else { \ 93*38361Ssam *cp++ = (n); \ 94*38361Ssam } \ 95*38361Ssam } 96*38361Ssam 97*38361Ssam #define DECODEL(f) { \ 98*38361Ssam if (*cp == 0) {\ 99*38361Ssam (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ 100*38361Ssam cp += 3; \ 101*38361Ssam } else { \ 102*38361Ssam (f) = htonl(ntohl(f) + (u_long)*cp++); \ 103*38361Ssam } \ 104*38361Ssam } 105*38361Ssam 106*38361Ssam #define DECODES(f) { \ 107*38361Ssam if (*cp == 0) {\ 108*38361Ssam (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ 109*38361Ssam cp += 3; \ 110*38361Ssam } else { \ 111*38361Ssam (f) = htons(ntohs(f) + (u_long)*cp++); \ 112*38361Ssam } \ 113*38361Ssam } 114*38361Ssam 115*38361Ssam 116*38361Ssam u_char 117*38361Ssam sl_compress_tcp(m, ip, comp) 118*38361Ssam struct mbuf *m; 119*38361Ssam register struct ip *ip; 120*38361Ssam struct slcompress *comp; 121*38361Ssam { 122*38361Ssam register struct cstate *cs = comp->last_cs->cs_next; 123*38361Ssam register u_int hlen = ip->ip_hl; 124*38361Ssam register struct tcphdr *oth; 125*38361Ssam register struct tcphdr *th; 126*38361Ssam register u_int deltaS, deltaA; 127*38361Ssam register u_int changes = 0; 128*38361Ssam u_char new_seq[16]; 129*38361Ssam register u_char *cp = new_seq; 130*38361Ssam 131*38361Ssam /* 132*38361Ssam * Bail if this is an ip fragment or if we don't have 133*38361Ssam * a complete ip & tcp header in the first mbuf. Otherwise, 134*38361Ssam * check flags to see if this is a packet we might compress 135*38361Ssam * and, if so, try to locate the connection state. 136*38361Ssam * since slip links tend to be end nodes, check the tcp ports 137*38361Ssam * first since the inet addresses won't usually change. 138*38361Ssam * special case the most recently used connection since 139*38361Ssam * it's most likely to be used again & we don't have to 140*38361Ssam * do any reordering if it's used. 141*38361Ssam */ 142*38361Ssam if ((ip->ip_off & 0x3fff) || m->m_len < 40) 143*38361Ssam return (TYPE_IP); 144*38361Ssam 145*38361Ssam th = (struct tcphdr *)&((int *)ip)[hlen]; 146*38361Ssam if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) 147*38361Ssam return (TYPE_IP); 148*38361Ssam 149*38361Ssam ++sls_packets; 150*38361Ssam if (*(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl] || 151*38361Ssam ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 152*38361Ssam ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr) { 153*38361Ssam /* 154*38361Ssam * Wasn't the first -- search for it. 155*38361Ssam * 156*38361Ssam * States are kept in a circularly linked list with 157*38361Ssam * first_cs pointing to the head of the list. The 158*38361Ssam * list is kept in lru order by moving a state to the 159*38361Ssam * head of the list whenever it is referenced. Since 160*38361Ssam * the list is short and, empirically, the connection 161*38361Ssam * we want is almost always near the front, we locate 162*38361Ssam * states via linear search. If we don't find a state 163*38361Ssam * for the datagram, the oldest state is used. 164*38361Ssam */ 165*38361Ssam register struct cstate *lcs; 166*38361Ssam 167*38361Ssam do { 168*38361Ssam lcs = cs; cs = cs->cs_next; 169*38361Ssam ++sls_searches; 170*38361Ssam if (*(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl] 171*38361Ssam && ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr 172*38361Ssam && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr) 173*38361Ssam goto found; 174*38361Ssam } while (cs != comp->last_cs); 175*38361Ssam ++sls_misses; 176*38361Ssam 177*38361Ssam /* 178*38361Ssam * Didn't find it -- re-use oldest cstate. 179*38361Ssam * Send an uncompressed packet that tells 180*38361Ssam * the other side what connection number 181*38361Ssam * we're using for this conversation. Note 182*38361Ssam * that since the state list is circular, the 183*38361Ssam * oldest state points to the newest and we only 184*38361Ssam * need to set last_cs to update the lru linkage. 185*38361Ssam */ 186*38361Ssam comp->last_cs = lcs; 187*38361Ssam hlen += th->th_off; 188*38361Ssam hlen <<= 2; 189*38361Ssam goto uncompressed; 190*38361Ssam 191*38361Ssam found: 192*38361Ssam /* 193*38361Ssam * Found it -- move to the front on the connection list. 194*38361Ssam */ 195*38361Ssam if (comp->last_cs == cs) 196*38361Ssam comp->last_cs = lcs; 197*38361Ssam else { 198*38361Ssam lcs->cs_next = cs->cs_next; 199*38361Ssam cs->cs_next = comp->last_cs->cs_next; 200*38361Ssam comp->last_cs->cs_next = cs; 201*38361Ssam } 202*38361Ssam } 203*38361Ssam 204*38361Ssam /* 205*38361Ssam * Make sure that only what we expect to change changed. 206*38361Ssam */ 207*38361Ssam oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; 208*38361Ssam deltaS = hlen; 209*38361Ssam hlen += th->th_off; 210*38361Ssam hlen <<= 2; 211*38361Ssam 212*38361Ssam if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || 213*38361Ssam ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || 214*38361Ssam th->th_off != oth->th_off || 215*38361Ssam (deltaS > 5 && 216*38361Ssam BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 217*38361Ssam (th->th_off > 5 && 218*38361Ssam BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) 219*38361Ssam goto uncompressed; 220*38361Ssam 221*38361Ssam /* 222*38361Ssam * Figure out which of the changing fields changed. The 223*38361Ssam * receiver expects changes in the order: urgent, window, 224*38361Ssam * ack, seq (the order minimizes the number of temporaries 225*38361Ssam * needed in this section of code). 226*38361Ssam */ 227*38361Ssam if (th->th_flags & TH_URG) { 228*38361Ssam deltaS = ntohs(th->th_urp); 229*38361Ssam ENCODEZ(deltaS); 230*38361Ssam changes |= NEW_U; 231*38361Ssam } else if (th->th_urp != oth->th_urp) 232*38361Ssam /* argh! URG not set but urp changed -- a sensible 233*38361Ssam * implementation should never do this but RFC793 234*38361Ssam * doesn't prohibit the change so we have to deal 235*38361Ssam * with it. */ 236*38361Ssam goto uncompressed; 237*38361Ssam 238*38361Ssam if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) { 239*38361Ssam ENCODE(deltaS); 240*38361Ssam changes |= NEW_W; 241*38361Ssam } 242*38361Ssam 243*38361Ssam if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) { 244*38361Ssam if (deltaA > 0xffff) 245*38361Ssam goto uncompressed; 246*38361Ssam ENCODE(deltaA); 247*38361Ssam changes |= NEW_A; 248*38361Ssam } 249*38361Ssam 250*38361Ssam if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) { 251*38361Ssam if (deltaS > 0xffff) 252*38361Ssam goto uncompressed; 253*38361Ssam ENCODE(deltaS); 254*38361Ssam changes |= NEW_S; 255*38361Ssam } 256*38361Ssam 257*38361Ssam switch(changes) { 258*38361Ssam 259*38361Ssam case 0: 260*38361Ssam if (ip->ip_len != cs->cs_ip.ip_len && ntohs(ip->ip_len) != hlen) 261*38361Ssam break; 262*38361Ssam /* 263*38361Ssam * Nothing changed and this packet looks like a duplicate 264*38361Ssam * of the last or contains no data -- this is probably a 265*38361Ssam * retransmitted ack or window probe. Send it 266*38361Ssam * uncompressed in case the other side missed the 267*38361Ssam * compressed version. 268*38361Ssam * 269*38361Ssam * (fall through) 270*38361Ssam */ 271*38361Ssam 272*38361Ssam case SPECIAL_I: 273*38361Ssam case SPECIAL_D: 274*38361Ssam /* 275*38361Ssam * actual changes match one of our special case encodings -- 276*38361Ssam * send packet uncompressed. 277*38361Ssam */ 278*38361Ssam goto uncompressed; 279*38361Ssam 280*38361Ssam case NEW_S|NEW_A: 281*38361Ssam if (deltaS == deltaA && 282*38361Ssam deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 283*38361Ssam /* special case for echoed terminal traffic */ 284*38361Ssam changes = SPECIAL_I; 285*38361Ssam cp = new_seq; 286*38361Ssam } 287*38361Ssam break; 288*38361Ssam 289*38361Ssam case NEW_S: 290*38361Ssam if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { 291*38361Ssam /* special case for data xfer */ 292*38361Ssam changes = SPECIAL_D; 293*38361Ssam cp = new_seq; 294*38361Ssam } 295*38361Ssam break; 296*38361Ssam } 297*38361Ssam 298*38361Ssam deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 299*38361Ssam if (deltaS != 1) { 300*38361Ssam ENCODEZ(deltaS); 301*38361Ssam changes |= NEW_I; 302*38361Ssam } 303*38361Ssam if (th->th_flags & TH_PUSH) 304*38361Ssam changes |= TCP_PUSH_BIT; 305*38361Ssam /* 306*38361Ssam * Grab the cksum before we overwrite it below. Then update our 307*38361Ssam * state with this packet's header. 308*38361Ssam */ 309*38361Ssam deltaA = ntohs(th->th_sum); 310*38361Ssam BCOPY(ip, &cs->cs_ip, hlen); 311*38361Ssam 312*38361Ssam /* 313*38361Ssam * We want to use the original packet as our compressed packet. 314*38361Ssam * (cp - new_seq) is the number of bytes we need for compressed 315*38361Ssam * sequence numbers. In addition we need one byte for the change 316*38361Ssam * mask, one for the connection id and two for the tcp checksum. 317*38361Ssam * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how 318*38361Ssam * many bytes of the original packet to toss so subtract the two to 319*38361Ssam * get the new packet size. 320*38361Ssam */ 321*38361Ssam deltaS = cp - new_seq; 322*38361Ssam cp = (u_char *)ip; 323*38361Ssam if (comp->last_xmit != cs->cs_id) { 324*38361Ssam comp->last_xmit = cs->cs_id; 325*38361Ssam hlen -= deltaS + 4; 326*38361Ssam cp += hlen; m->m_len -= hlen; m->m_off += hlen; 327*38361Ssam *cp++ = changes | NEW_C; 328*38361Ssam *cp++ = cs->cs_id; 329*38361Ssam } else { 330*38361Ssam hlen -= deltaS + 3; 331*38361Ssam cp += hlen; m->m_len -= hlen; m->m_off += hlen; 332*38361Ssam *cp++ = changes; 333*38361Ssam } 334*38361Ssam *cp++ = deltaA >> 8; 335*38361Ssam *cp++ = deltaA; 336*38361Ssam BCOPY(new_seq, cp, deltaS); 337*38361Ssam ++sls_compressed; 338*38361Ssam /* note: low order version bits used */ 339*38361Ssam ip = mtod(m, struct ip *); 340*38361Ssam ip->ip_v |= (TYPE_COMPRESSED_TCP>>4); 341*38361Ssam return (TYPE_COMPRESSED_TCP); 342*38361Ssam 343*38361Ssam /* 344*38361Ssam * Update connection state cs & send uncompressed packet ('uncompressed' 345*38361Ssam * means a regular ip/tcp packet but with the 'conversation id' we hope 346*38361Ssam * to use on future compressed packets in the protocol field). 347*38361Ssam */ 348*38361Ssam uncompressed: 349*38361Ssam BCOPY(ip, &cs->cs_ip, hlen); 350*38361Ssam ip->ip_p = cs->cs_id; 351*38361Ssam comp->last_xmit = cs->cs_id; 352*38361Ssam ip->ip_v = (TYPE_UNCOMPRESSED_TCP>>4); 353*38361Ssam return (TYPE_UNCOMPRESSED_TCP); 354*38361Ssam } 355*38361Ssam 356*38361Ssam int uncdeb ; 357*38361Ssam 358*38361Ssam struct mbuf * 359*38361Ssam sl_uncompress_tcp(m, type, comp) 360*38361Ssam register struct mbuf *m; 361*38361Ssam u_char type; 362*38361Ssam struct slcompress *comp; 363*38361Ssam { 364*38361Ssam register u_char *cp; 365*38361Ssam register u_int hlen, changes; 366*38361Ssam register struct tcphdr *th; 367*38361Ssam register struct cstate *cs; 368*38361Ssam register struct ip *ip; 369*38361Ssam register struct mbuf *m0; 370*38361Ssam 371*38361Ssam switch (type) { 372*38361Ssam 373*38361Ssam case TYPE_UNCOMPRESSED_TCP: 374*38361Ssam ip = mtod(m, struct ip *); 375*38361Ssam if (ip->ip_p >= MAX_STATES) 376*38361Ssam goto bad; 377*38361Ssam ip->ip_v = 4; 378*38361Ssam 379*38361Ssam cs = &comp->rstate[comp->last_recv = ip->ip_p]; 380*38361Ssam comp->flags &=~ SLF_TOSS; 381*38361Ssam ip->ip_p = IPPROTO_TCP; 382*38361Ssam hlen = ip->ip_hl; 383*38361Ssam hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off; 384*38361Ssam hlen <<= 2; 385*38361Ssam BCOPY(ip, &cs->cs_ip, hlen); 386*38361Ssam cs->cs_ip.ip_sum = 0; 387*38361Ssam cs->cs_hlen = hlen; 388*38361Ssam ++sls_uncompressedin; 389*38361Ssam return (m); 390*38361Ssam 391*38361Ssam default: 392*38361Ssam if(type&TYPE_COMPRESSED_TCP) goto compre; 393*38361Ssam ++sls_ipin; 394*38361Ssam return (m); 395*38361Ssam 396*38361Ssam case TYPE_ERROR: 397*38361Ssam comp->flags |= SLF_TOSS; 398*38361Ssam return (m); 399*38361Ssam 400*38361Ssam case TYPE_COMPRESSED_TCP: 401*38361Ssam compre: 402*38361Ssam break; 403*38361Ssam } 404*38361Ssam /* We've got a compressed packet. */ 405*38361Ssam ++sls_compressedin; 406*38361Ssam cp = mtod(m, u_char *); 407*38361Ssam changes = *cp++; 408*38361Ssam if (changes & NEW_C) { 409*38361Ssam /* Make sure the state index is in range, then grab the state. 410*38361Ssam * If we have a good state index, clear the 'discard' flag. */ 411*38361Ssam if (*cp >= MAX_STATES) 412*38361Ssam goto bad; 413*38361Ssam 414*38361Ssam comp->flags &=~ SLF_TOSS; 415*38361Ssam comp->last_recv = *cp++; 416*38361Ssam } else { 417*38361Ssam /* this packet has an implicit state index. If we've 418*38361Ssam * had a line error since the last time we got an 419*38361Ssam * explicit state index, we have to toss the packet. */ 420*38361Ssam if (comp->flags & SLF_TOSS) 421*38361Ssam goto bad; 422*38361Ssam } 423*38361Ssam cs = &comp->rstate[comp->last_recv]; 424*38361Ssam hlen = cs->cs_ip.ip_hl << 2; 425*38361Ssam th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; 426*38361Ssam th->th_sum = htons((*cp << 8) | cp[1]); 427*38361Ssam cp += 2; 428*38361Ssam if (changes & TCP_PUSH_BIT) 429*38361Ssam th->th_flags |= TH_PUSH; 430*38361Ssam else 431*38361Ssam th->th_flags &=~ TH_PUSH; 432*38361Ssam 433*38361Ssam switch (changes & SPECIALS_MASK) { 434*38361Ssam case SPECIAL_I: 435*38361Ssam { 436*38361Ssam register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 437*38361Ssam th->th_ack = htonl(ntohl(th->th_ack) + i); 438*38361Ssam th->th_seq = htonl(ntohl(th->th_seq) + i); 439*38361Ssam } 440*38361Ssam break; 441*38361Ssam 442*38361Ssam case SPECIAL_D: 443*38361Ssam th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) 444*38361Ssam - cs->cs_hlen); 445*38361Ssam break; 446*38361Ssam 447*38361Ssam default: 448*38361Ssam if (changes & NEW_U) { 449*38361Ssam th->th_flags |= TH_URG; 450*38361Ssam DECODES(th->th_urp) 451*38361Ssam } else 452*38361Ssam th->th_flags &=~ TH_URG; 453*38361Ssam if (changes & NEW_W) 454*38361Ssam DECODES(th->th_win) 455*38361Ssam if (changes & NEW_A) 456*38361Ssam DECODEL(th->th_ack) 457*38361Ssam if (changes & NEW_S) 458*38361Ssam DECODEL(th->th_seq) 459*38361Ssam break; 460*38361Ssam } 461*38361Ssam if (changes & NEW_I) { 462*38361Ssam DECODES(cs->cs_ip.ip_id) 463*38361Ssam } else 464*38361Ssam cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); 465*38361Ssam 466*38361Ssam /* 467*38361Ssam * At this point, cp points to the first byte of data in the 468*38361Ssam * packet (if any). Toss the compressed header from the 469*38361Ssam * original packet, allocatate a new mbuf for the uncompressed 470*38361Ssam * header (to make sure it's aligned correctly), then chain it 471*38361Ssam * in front of the original. Set up the ip length & ip checksum then 472*38361Ssam * return the rebuilt packet. 473*38361Ssam */ 474*38361Ssam changes = cp - mtod(m, u_char *); 475*38361Ssam m->m_off += changes; m->m_len -= changes; 476*38361Ssam changes = cs->cs_hlen; 477*38361Ssam for (m0 = m; m0; m0 = m0->m_next) 478*38361Ssam changes += m0->m_len; 479*38361Ssam cs->cs_ip.ip_len = htons(changes); 480*38361Ssam 481*38361Ssam /*MGET(m0, M_DONTWAIT, MT_DATA);*/ 482*38361Ssam MGETHDR(m0, M_DONTWAIT, MT_DATA); /* XXX! */ 483*38361Ssam if (! m0) 484*38361Ssam goto bad; 485*38361Ssam 486*38361Ssam m0->m_next = m; 487*38361Ssam m0->m_pkthdr.rcvif = m->m_pkthdr.rcvif ; /* XXX! */ 488*38361Ssam m0->m_pkthdr.len = m->m_pkthdr.len; /* XXX! */ 489*38361Ssam m = m0; 490*38361Ssam m->m_len = cs->cs_hlen; 491*38361Ssam ip = mtod(m, struct ip *); 492*38361Ssam BCOPY(&cs->cs_ip, ip, cs->cs_hlen); 493*38361Ssam 494*38361Ssam ip->ip_sum = in_cksum(m, hlen); 495*38361Ssam return (m); 496*38361Ssam 497*38361Ssam bad: 498*38361Ssam m_freem(m); 499*38361Ssam return ((struct mbuf *)0); 500*38361Ssam } 501