static int ah_output(struct xfrm_state *x, struct sk_buff *skb) { int err; struct iphdr *iph, *top_iph; struct ip_auth_hdr *ah; struct ah_data *ahp; union { struct iphdr iph; char buf[60]; } tmp_iph; top_iph = skb->nh.iph; iph = &tmp_iph.iph; iph->tos = top_iph->tos; iph->ttl = top_iph->ttl; iph->frag_off = top_iph->frag_off; if (top_iph->ihl != 5) { iph->daddr = top_iph->daddr; memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); err = ip_clear_mutable_options(top_iph, &top_iph->daddr); if (err) goto error; } ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4); ah->nexthdr = top_iph->protocol; top_iph->tos = 0; top_iph->tot_len = htons(skb->len); top_iph->frag_off = 0; top_iph->ttl = 0; top_iph->protocol = IPPROTO_AH; top_iph->check = 0; ahp = x->data; ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(++x->replay.oseq); ahp->icv(ahp, skb, ah->auth_data); top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; top_iph->frag_off = iph->frag_off; if (top_iph->ihl != 5) { top_iph->daddr = iph->daddr; memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); } ip_send_check(top_iph); err = 0; error: return err; }
static int ah_output(struct xfrm_state *x, struct sk_buff *skb) { int err; struct iphdr *iph, *top_iph; struct ip_auth_hdr *ah; struct ah_data *ahp; union { struct iphdr iph; char buf[60]; } tmp_iph; skb_push(skb, -skb_network_offset(skb)); top_iph = ip_hdr(skb); iph = &tmp_iph.iph; iph->tos = top_iph->tos; iph->ttl = top_iph->ttl; iph->frag_off = top_iph->frag_off; if (top_iph->ihl != 5) { iph->daddr = top_iph->daddr; memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); err = ip_clear_mutable_options(top_iph, &top_iph->daddr); if (err) goto error; } ah = ip_auth_hdr(skb); ah->nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_AH; top_iph->tos = 0; top_iph->tot_len = htons(skb->len); top_iph->frag_off = 0; top_iph->ttl = 0; top_iph->check = 0; ahp = x->data; ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); spin_unlock_bh(&x->lock); if (err) goto error; top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; top_iph->frag_off = iph->frag_off; if (top_iph->ihl != 5) { top_iph->daddr = iph->daddr; memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); } err = 0; error: return err; }
static int ah_input(struct xfrm_state *x, struct sk_buff *skb) { int ah_hlen; int ihl; int nexthdr; int err = -EINVAL; struct iphdr *iph; struct ip_auth_hdr *ah; struct ah_data *ahp; char work_buf[60]; if (!pskb_may_pull(skb, sizeof(*ah))) goto out; ah = (struct ip_auth_hdr *)skb->data; ahp = x->data; nexthdr = ah->nexthdr; ah_hlen = (ah->hdrlen + 2) << 2; if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) && ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len)) goto out; if (!pskb_may_pull(skb, ah_hlen)) goto out; /* We are going to _remove_ AH header to keep sockets happy, * so... Later this can change. */ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto out; skb->ip_summed = CHECKSUM_NONE; ah = (struct ip_auth_hdr *)skb->data; iph = ip_hdr(skb); ihl = skb->data - skb_network_header(skb); memcpy(work_buf, iph, ihl); iph->ttl = 0; iph->tos = 0; iph->frag_off = 0; iph->check = 0; if (ihl > sizeof(*iph)) { __be32 dummy; if (ip_clear_mutable_options(iph, &dummy)) goto out; } spin_lock(&x->lock); { u8 auth_data[MAX_AH_AUTH_LEN]; memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); skb_push(skb, ihl); err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto unlock; if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) err = -EBADMSG; } unlock: spin_unlock(&x->lock); if (err) goto out; skb->network_header += ah_hlen; memcpy(skb_network_header(skb), work_buf, ihl); skb->transport_header = skb->network_header; __skb_pull(skb, ah_hlen + ihl); return nexthdr; out: return err; }
int ipsec_ah_output(struct ipsec_state *x, struct sk_buff *skb) { int err = -1; struct iphdr *iph, *top_iph; struct ip_auth_hdr *ah; struct ipsec_alg_tfms * alg_tfms = g_alg_tfms[smp_processor_id()][x->props.auth_algo][0]; struct crypto_hash * hash = alg_tfms->hash; struct sa_ah_data *ahp; union { struct iphdr iph; char buf[60]; } tmp_iph; iph = &tmp_iph.iph; top_iph = skb->nh.iph; iph->tos = top_iph->tos; iph->ttl = top_iph->ttl; iph->frag_off = top_iph->frag_off; if (top_iph->ihl != 5) { iph->daddr = top_iph->daddr; memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); err = ip_clear_mutable_options(top_iph, &top_iph->daddr); if (err) { return -1; } } ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4); ah->nexthdr = top_iph->protocol; top_iph->tos = 0; top_iph->tot_len = htons(skb->len); top_iph->frag_off = 0; top_iph->ttl = 0; top_iph->protocol = IPPROTO_AH; top_iph->check = 0; ahp = &x->u.ah_data; ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; if ((NULL != g_drv_sae_func_s.ipsec_get_seqnum) && (x->drv_content != NULL)) { ah->seq_no = g_drv_sae_func_s.ipsec_get_seqnum(x->drv_content); } else { ah->seq_no = htonl(++x->oseq); } if(unlikely(!(skb->service_flags&SKB_SERVICE_FLAG_IPSEC_UNPAR))&&(NULL != g_drv_sae_func_s.encrypt_hmac)&&(x->drv_content != NULL)) { drv_sae_fw_s drv_sea_fw_p; int tmp = -1; drv_sae_platcontent_s *platcontent_s_p = (drv_sae_platcontent_s *)kmalloc(sizeof(drv_sae_platcontent_s)+60,GFP_ATOMIC); if (NULL == platcontent_s_p) { return -1; } memcpy(platcontent_s_p->buf,iph,60); platcontent_s_p->protono = IPPROTO_AH; platcontent_s_p->sa = (unsigned char *)x; drv_sea_fw_p.hash_data_len = skb->len; drv_sea_fw_p.hash_data_offset = 0; drv_sea_fw_p.cipher_data_len = 0; drv_sea_fw_p.cipher_data_offset = 0; drv_sea_fw_p.iv_len = 0; drv_sea_fw_p.iv_offset= 0; drv_sea_fw_p.hash_out_len = ahp->icv_full_len; drv_sea_fw_p.hash_out_buf = NULL;//do not need anymore drv_sea_fw_p.plat_content = (u8*)platcontent_s_p; drv_sea_fw_p.drv_content = x->drv_content; memset(ah->auth_data, 0, ahp->icv_trunc_len); tmp = g_drv_sae_func_s.encrypt_hmac(skb, &drv_sea_fw_p); if(0 == tmp) return IPSEC_HARD_OPEATE_OK; kfree(platcontent_s_p); } if (crypto_hash_setkey(hash, x->auth_key.alg_key, (x->auth_key.alg_key_len+7)/8)) { IPSEC_INNEC_POLICY_COUNTER(set_auth_key_err); goto error; } err = ipsec_ah_mac_digest(ahp, alg_tfms, skb, ah->auth_data); if (err) { goto error; } memcpy(ah->auth_data, alg_tfms->work_icv, ahp->icv_trunc_len); top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; top_iph->frag_off = iph->frag_off; if (top_iph->ihl != 5) { top_iph->daddr = iph->daddr; memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); } ip_send_check(top_iph); error: return 0; }
int ipsec_ah_input(struct ipsec_state *x, struct sk_buff *skb, unsigned int spi) { int ah_hlen; int ihl; int err; struct iphdr *iph; struct ip_auth_hdr *ah; struct sa_ah_data *ahp; struct ipsec_alg_tfms * alg_tfms = g_alg_tfms[smp_processor_id()][x->props.auth_algo][0]; struct crypto_hash * hash = alg_tfms->hash; u8 auth_buf[32]; int temp; if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) { return -1; } ah = (struct ip_auth_hdr*)skb->data; ahp = &x->u.ah_data; ah_hlen = (ah->hdrlen + 2) << 2; if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) return -1; if (!pskb_may_pull(skb, ah_hlen)) return -1; /* We are going to _remove_ AH header to keep sockets happy, * so... Later this can change. */ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) return -1; skb->ip_summed = CHECKSUM_NONE; ah = (struct ip_auth_hdr*)skb->data; iph = skb->nh.iph; ihl = skb->data - skb->nh.raw; iph->ttl = 0; iph->tos = 0; iph->frag_off = 0; iph->check = 0; if (ihl > sizeof(*iph)) { __be32 dummy; if (ip_clear_mutable_options(iph, &dummy)) { return -1; } } temp = skb->data - skb->nh.raw; __skb_push(skb,temp ); if ((NULL != g_drv_sae_func_s.decrypt_hmac)&&(x->drv_content != NULL)) { drv_sae_platcontent_s *platcontent_s_p; drv_sae_fw_s drv_sea_fw_p; int tmp = -1; platcontent_s_p = (drv_sae_platcontent_s *)kmalloc(sizeof(drv_sae_platcontent_s)+60+ahp->icv_trunc_len,GFP_ATOMIC); if (NULL == platcontent_s_p) { return -1; } platcontent_s_p->protono = (-1)*(IPPROTO_AH); platcontent_s_p->sa = (unsigned char *)x; memcpy(platcontent_s_p->buf, iph, ihl);//ip header memcpy((platcontent_s_p->buf + 60), ah->auth_data, ahp->icv_trunc_len);//auth data drv_sea_fw_p.hash_data_len = skb->len; drv_sea_fw_p.hash_data_offset = 0; drv_sea_fw_p.cipher_data_len = 0; drv_sea_fw_p.cipher_data_offset = 0; drv_sea_fw_p.iv_len = 0; drv_sea_fw_p.iv_offset = 0; drv_sea_fw_p.hash_out_len = ahp->icv_full_len; drv_sea_fw_p.hash_out_buf = NULL;//do not need anymore drv_sea_fw_p.plat_content = (u8*)platcontent_s_p; drv_sea_fw_p.drv_content = x->drv_content; memset(ah->auth_data, 0, ahp->icv_trunc_len); tmp = g_drv_sae_func_s.decrypt_hmac(skb, &drv_sea_fw_p); __skb_pull(skb,temp ); skb_push(skb, ihl); if( 0 == tmp ) return IPSEC_HARD_OPEATE_OK; memcpy(auth_buf, (platcontent_s_p->buf + 60), ahp->icv_trunc_len); kfree(platcontent_s_p); } if (crypto_hash_setkey(hash, x->auth_key.alg_key, (x->auth_key.alg_key_len+7)/8)) { IPSEC_INNEC_POLICY_COUNTER(set_auth_key_err); err = -1; goto out; } err = ipsec_ah_mac_digest(ahp, alg_tfms, skb, ah->auth_data); if (err) { goto out; } err = -EINVAL; if (memcmp(alg_tfms->work_icv, auth_buf, ahp->icv_trunc_len)) { goto out; } iph->protocol = ah->nexthdr; skb->h.raw = memcpy(skb->nh.raw += ah_hlen, iph, ihl); __skb_pull(skb, ah_hlen + ihl); return 0; out: return err; }
static int ah_input(struct xfrm_state *x, struct sk_buff *skb) { int ah_hlen; int ihl; int err = -EINVAL; struct iphdr *iph; struct ip_auth_hdr *ah; struct ah_data *ahp; char work_buf[60]; if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) goto out; ah = (struct ip_auth_hdr*)skb->data; ahp = x->data; ah_hlen = (ah->hdrlen + 2) << 2; if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) goto out; if (!pskb_may_pull(skb, ah_hlen)) goto out; /* We are going to _remove_ AH header to keep sockets happy, * so... Later this can change. */ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto out; skb->ip_summed = CHECKSUM_NONE; ah = (struct ip_auth_hdr*)skb->data; iph = skb->nh.iph; ihl = skb->data - skb->nh.raw; memcpy(work_buf, iph, ihl); iph->ttl = 0; iph->tos = 0; iph->frag_off = 0; iph->check = 0; if (ihl > sizeof(*iph)) { __be32 dummy; if (ip_clear_mutable_options(iph, &dummy)) goto out; } { u8 auth_data[MAX_AH_AUTH_LEN]; memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); skb_push(skb, ihl); err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto out; err = -EINVAL; if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { x->stats.integrity_failed++; goto out; } } ((struct iphdr*)work_buf)->protocol = ah->nexthdr; skb->h.raw = memcpy(skb->nh.raw += ah_hlen, work_buf, ihl); __skb_pull(skb, ah_hlen + ihl); return 0; out: return err; }
static int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) { int ah_hlen; struct iphdr *iph; struct ip_auth_hdr *ah; struct ah_data *ahp; char work_buf[60]; if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) goto out; ah = (struct ip_auth_hdr*)skb->data; if (x->props.replay_window && xfrm_replay_check(x, ah->seq_no)) goto out; ahp = x->data; ah_hlen = (ah->hdrlen + 2) << 2; if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) goto out; if (!pskb_may_pull(skb, ah_hlen)) goto out; /* We are going to _remove_ AH header to keep sockets happy, * so... Later this can change. */ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto out; skb->ip_summed = CHECKSUM_NONE; ah = (struct ip_auth_hdr*)skb->data; iph = skb->nh.iph; memcpy(work_buf, iph, iph->ihl*4); iph->ttl = 0; iph->tos = 0; iph->frag_off = 0; iph->check = 0; if (iph->ihl != 5) { u32 dummy; if (ip_clear_mutable_options(iph, &dummy)) goto out; } { u8 auth_data[MAX_AH_AUTH_LEN]; memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); skb_push(skb, skb->data - skb->nh.raw); ahp->icv(ahp, skb, ah->auth_data); if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { x->stats.integrity_failed++; goto out; } } if (x->props.replay_window) xfrm_replay_advance(x, ah->seq_no); ((struct iphdr*)work_buf)->protocol = ah->nexthdr; skb->nh.raw = skb_pull(skb, ah_hlen); memcpy(skb->nh.raw, work_buf, iph->ihl*4); skb->nh.iph->tot_len = htons(skb->len); skb_pull(skb, skb->nh.iph->ihl*4); skb->h.raw = skb->data; return 0; out: return -EINVAL; }