コード例 #1
0
int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
{
	int err;
	struct ip_comp_hdr *ipch;
	struct ipcomp_data *ipcd = x->data;

	if (skb->len < ipcd->threshold) {
		
		goto out_ok;
	}

	if (skb_linearize_cow(skb))
		goto out_ok;

	err = ipcomp_compress(x, skb);

	if (err) {
		goto out_ok;
	}

	
	ipch = ip_comp_hdr(skb);
	ipch->nexthdr = *skb_mac_header(skb);
	ipch->flags = 0;
	ipch->cpi = htons((u16 )ntohl(x->id.spi));
	*skb_mac_header(skb) = IPPROTO_COMP;
out_ok:
	skb_push(skb, -skb_network_offset(skb));
	return 0;
}
コード例 #2
0
static int ipcomp_output(struct sk_buff *skb)
{
	int err;
	struct dst_entry *dst = skb->dst;
	struct xfrm_state *x = dst->xfrm;
	struct iphdr *iph, *top_iph;
	struct ip_comp_hdr *ipch;
	struct ipcomp_data *ipcd = x->data;
	union {
		struct iphdr	iph;
		char 		buf[60];
	} tmp_iph;
	int hdr_len = 0;

	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
		err = -EINVAL;
		goto error_nolock;
	}

	spin_lock_bh(&x->lock);
	err = xfrm_check_output(x, skb, AF_INET);
	if (err)
		goto error;

	/* Don't bother compressing */
	if (!x->props.mode) {
		iph = skb->nh.iph;
		hdr_len = iph->ihl * 4;
	}
	if ((skb->len - hdr_len) < ipcd->threshold) {
		if (x->props.mode) {
			ipcomp_tunnel_encap(x, skb);
			iph = skb->nh.iph;
			iph->protocol = IPPROTO_IPIP;
			ip_send_check(iph);
		}
		goto out_ok;
	}

	if (x->props.mode) 
		ipcomp_tunnel_encap(x, skb);

	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
	    skb_linearize(skb, GFP_ATOMIC) != 0) {
	    	err = -ENOMEM;
	    	goto error;
	}
	
	err = ipcomp_compress(x, skb);
	if (err) {
		if (err == -EMSGSIZE) {
			if (x->props.mode) {
				iph = skb->nh.iph;
				iph->protocol = IPPROTO_IPIP;
				ip_send_check(iph);
			}
			goto out_ok;
		}
		goto error;
	}

	/* Install ipcomp header, convert into ipcomp datagram. */
	iph = skb->nh.iph;
	memcpy(&tmp_iph, iph, iph->ihl * 4);
	top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ip_comp_hdr));
	memcpy(top_iph, &tmp_iph, iph->ihl * 4);
	iph = top_iph;
	if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN))
		IP_ECN_clear(iph);
	iph->tot_len = htons(skb->len);
	iph->protocol = IPPROTO_COMP;
	iph->check = 0;
	ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4);
	ipch->nexthdr = x->props.mode ? IPPROTO_IPIP : tmp_iph.iph.protocol;
	ipch->flags = 0;
	ipch->cpi = htons((u16 )ntohl(x->id.spi));
	ip_send_check(iph);
	skb->nh.raw = skb->data;

out_ok:
	x->curlft.bytes += skb->len;
	x->curlft.packets++;
	spin_unlock_bh(&x->lock);
	
	if ((skb->dst = dst_pop(dst)) == NULL) {
		err = -EHOSTUNREACH;
		goto error_nolock;
	}
	err = NET_XMIT_BYPASS;

out_exit:
	return err;
error:
	spin_unlock_bh(&x->lock);
error_nolock:
	kfree_skb(skb);
	goto out_exit;
}