pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
esp_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,	       struct mbuf **mp){    struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform;    struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform;    struct ip *ip, ipo;    int i, ilen, ohlen, nh, rlen, plen, padding, rest;    struct esp_new espo;    struct mbuf *mi, *mo;    u_char *pad, *idat, *odat, *ivp;    u_char iv[ESP_MAX_IVS], blk[ESP_MAX_BLKS], auth[AH_ALEN_MAX], opts[40];    union {	 MD5_CTX md5ctx;	 SHA1_CTX sha1ctx;	 RMD160_CTX rmd160ctx;    } ctx;    int iphlen, blks, alen;        blks = espx->blocksize;    if (esph)      alen = AH_HMAC_HASHLEN;    else      alen = 0;    espstat.esps_output++;    m = m_pullup(m, sizeof (struct ip));   /* Get IP header in one mbuf */    if (m == NULL)    {        DPRINTF(("esp_new_output(): m_pullup() failed, SA %s/%08x\n",		 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));	espstat.esps_hdrops++;	return ENOBUFS;    }    if (tdb->tdb_rpl == 0)    {	DPRINTF(("esp_new_output(): SA %s/%0x8 should have expired\n",		 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));	m_freem(m);	espstat.esps_wrap++;	return ENOBUFS;    }    espo.esp_spi = tdb->tdb_spi;    espo.esp_rpl = htonl(tdb->tdb_rpl++);    ip = mtod(m, struct ip *);    iphlen = (ip->ip_hl << 2);        /* Update the counters */    tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);    espstat.esps_obytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);    /* Hard expiration */    if ((tdb->tdb_flags & TDBF_BYTES) &&	(tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes))    {/* XXX   encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb, NULL);*/	tdb_delete(tdb, 0);	m_freem(m);	return EINVAL;    }    /* Notify on expiration */    if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&	(tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes))    {/* XXX        encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb, NULL);*/	tdb->tdb_flags &= ~TDBF_SOFT_BYTES;     /* Turn off checking */    }    /*     * If options are present, pullup the IP header, the options.     */    if (iphlen != sizeof(struct ip))    {	m = m_pullup(m, iphlen + 8);	if (m == NULL)	{	    DPRINTF(("esp_new_input(): m_pullup() failed for SA %s/%08x\n",		     ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));	    espstat.esps_hdrops++;	    return ENOBUFS;	}	ip = mtod(m, struct ip *);	/* Keep the options */	m_copydata(m, sizeof(struct ip), iphlen - sizeof(struct ip), 		   (caddr_t) opts);    }    ilen = ntohs(ip->ip_len);    /* Size of the packet */    ohlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen;    ipo = *ip;    nh = ipo.ip_p;    /* Raw payload length */    rlen = ilen - iphlen;     padding = ((blks - ((rlen + 2) % blks)) % blks) + 2;    if (iphlen + ohlen + rlen + padding + alen > IP_MAXPACKET)    {	DPRINTF(("esp_new_output(): packet in SA %s/%0x8 got too big\n",		 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));	m_freem(m);	espstat.esps_toobig++;        return EMSGSIZE;    }    pad = (u_char *) m_pad(m, padding + alen, 0);    if (pad == NULL)    {        DPRINTF(("esp_new_output(): m_pad() failed for SA %s/%08x\n",		 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));      	return ENOBUFS;    }    /* Self describing padding */    for (i = 0; i < padding - 2; i++)      pad[i] = i + 1;    pad[padding - 2] = padding - 2;    pad[padding - 1] = nh;    mi = m;    plen = rlen + padding;    ilen = m->m_len - iphlen;    idat = mtod(m, u_char *) + iphlen;    bcopy(tdb->tdb_iv, iv, tdb->tdb_ivlen);    bcopy(tdb->tdb_iv, espo.esp_iv, tdb->tdb_ivlen);    /* Authenticate the esp header */    if (esph)    {	bcopy(tdb->tdb_ictx, &ctx, esph->ctxsize);	esph->Update(&ctx, (unsigned char *) &espo, 		  2 * sizeof(u_int32_t) + tdb->tdb_ivlen);    }    /* Encrypt the payload */    ivp = iv;    rest = ilen % blks;    while (plen > 0)		/* while not done */    {	if (ilen < blks) 	{	    if (rest)	    {	        if (ivp == blk)		{			bcopy(blk, iv, blks);			ivp = iv;		}		bcopy(idat, blk, rest);		odat = idat;	    }	    do {		mi = (mo = mi)->m_next;		if (mi == NULL)		{		    DPRINTF(("esp_new_output(): bad mbuf chain, SA %s/%08x\n",			     ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));		    espstat.esps_hdrops++;		    m_freem(m);		    return EINVAL;		}	    } while (mi->m_len == 0);	    if (mi->m_len < blks - rest)	    {		if ((mi = m_pullup(mi, blks - rest)) == NULL)		{		    DPRINTF(("esp_new_output(): m_pullup() failed, SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));		    m_freem(m);		    espstat.esps_hdrops++;		    return ENOBUFS;		}		/* 		 * m_pullup was not called at the beginning of the chain		 * but might return a new mbuf, link it into the chain.		 */		mo->m_next = mi;	    }		    	    ilen = mi->m_len;	    idat = mtod(mi, u_char *);	    if (rest)	    {		bcopy(idat, blk + rest, blks - rest);		    		for (i = 0; i < blks; i++)		    blk[i] ^= ivp[i];		espx->encrypt(tdb, blk);		if (esph)		    esph->Update(&ctx, blk, blks);		ivp = blk;		bcopy(blk, odat, rest);		bcopy(blk + rest, idat, blks - rest);				idat += blks - rest;		ilen -= blks - rest;		plen -= blks;	    }	    rest = ilen % blks;	}	while (ilen >= blks && plen > 0)	{	    for (i = 0; i < blks; i++)		idat[i] ^= ivp[i];	    espx->encrypt(tdb, idat);	    if (esph)		esph->Update(&ctx, idat, blks);	    ivp = idat;	    idat += blks;	    ilen -= blks;	    plen -= blks;	}    }    /* Put in authentication data */    if (esph)    {	esph->Final(auth, &ctx);	bcopy(tdb->tdb_octx, &ctx, esph->ctxsize);	esph->Update(&ctx, auth, esph->hashsize);	esph->Final(auth, &ctx);	/* Copy the final authenticator */	bcopy(auth, pad + padding, alen);    }    /*     * Done with encryption. Let's wedge in the ESP header     * and send it out.     */    M_PREPEND(m, ohlen, M_DONTWAIT);    if (m == NULL)    {        DPRINTF(("esp_new_output(): M_PREPEND failed, SA %s/%08x\n",		 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));        return ENOBUFS;    }    m = m_pullup(m, iphlen + ohlen);    if (m == NULL)    {        DPRINTF(("esp_new_output(): m_pullup() failed, SA %s/%08x\n",		 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));	espstat.esps_hdrops++;        return ENOBUFS;    }    /* Fix the length and the next protocol, copy back and off we go */    ipo.ip_len = htons(iphlen + ohlen + rlen + padding + alen);    ipo.ip_p = IPPROTO_ESP;    /* Save the last encrypted block, to be used as the next IV */    bcopy(ivp, tdb->tdb_iv, tdb->tdb_ivlen);    m_copyback(m, 0, sizeof(struct ip), (caddr_t) &ipo);    /* Copy options, if existing */    if (iphlen != sizeof(struct ip))      m_copyback(m, sizeof(struct ip), iphlen - sizeof(struct ip),		 (caddr_t) opts);    /* Copy in the esp header */    m_copyback(m, iphlen, ohlen, (caddr_t) &espo);	    *mp = m;    return 0;}	