Commit 951dbc8a authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[IPV6]: Move nextheader offset to the IP6CB

Move nextheader offset to the IP6CB to make it possible to pass a
packet to ip6_input_finish multiple times and have it skip already
parsed headers. As a nice side effect this gets rid of the manual
hopopts skipping in ip6_input_finish.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 16a6677f
...@@ -191,6 +191,7 @@ struct inet6_skb_parm { ...@@ -191,6 +191,7 @@ struct inet6_skb_parm {
__u16 srcrt; __u16 srcrt;
__u16 dst1; __u16 dst1;
__u16 lastopt; __u16 lastopt;
__u32 nhoff;
}; };
#define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb))
......
...@@ -43,7 +43,7 @@ struct net_protocol { ...@@ -43,7 +43,7 @@ struct net_protocol {
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct inet6_protocol struct inet6_protocol
{ {
int (*handler)(struct sk_buff **skb, unsigned int *nhoffp); int (*handler)(struct sk_buff **skb);
void (*err_handler)(struct sk_buff *skb, void (*err_handler)(struct sk_buff *skb,
struct inet6_skb_parm *opt, struct inet6_skb_parm *opt,
......
...@@ -831,7 +831,7 @@ struct xfrm_tunnel { ...@@ -831,7 +831,7 @@ struct xfrm_tunnel {
}; };
struct xfrm6_tunnel { struct xfrm6_tunnel {
int (*handler)(struct sk_buff **pskb, unsigned int *nhoffp); int (*handler)(struct sk_buff **pskb);
void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info); int type, int code, int offset, __u32 info);
}; };
...@@ -868,8 +868,8 @@ extern int xfrm4_rcv(struct sk_buff *skb); ...@@ -868,8 +868,8 @@ extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_output(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
extern int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi); extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); extern int xfrm6_rcv(struct sk_buff **pskb);
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
......
...@@ -1029,7 +1029,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1029,7 +1029,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0; return 0;
} }
static int dccp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) static int dccp_v6_rcv(struct sk_buff **pskb)
{ {
const struct dccp_hdr *dh; const struct dccp_hdr *dh;
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
......
...@@ -152,7 +152,7 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = { ...@@ -152,7 +152,7 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
{-1, NULL} {-1, NULL}
}; };
static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) static int ipv6_destopt_rcv(struct sk_buff **skbp)
{ {
struct sk_buff *skb = *skbp; struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb); struct inet6_skb_parm *opt = IP6CB(skb);
...@@ -169,7 +169,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) ...@@ -169,7 +169,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
skb->h.raw += ((skb->h.raw[1]+1)<<3); skb->h.raw += ((skb->h.raw[1]+1)<<3);
*nhoffp = opt->dst1; opt->nhoff = opt->dst1;
return 1; return 1;
} }
...@@ -192,7 +192,7 @@ void __init ipv6_destopt_init(void) ...@@ -192,7 +192,7 @@ void __init ipv6_destopt_init(void)
NONE header. No data in packet. NONE header. No data in packet.
********************************/ ********************************/
static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp) static int ipv6_nodata_rcv(struct sk_buff **skbp)
{ {
struct sk_buff *skb = *skbp; struct sk_buff *skb = *skbp;
...@@ -215,7 +215,7 @@ void __init ipv6_nodata_init(void) ...@@ -215,7 +215,7 @@ void __init ipv6_nodata_init(void)
Routing header. Routing header.
********************************/ ********************************/
static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) static int ipv6_rthdr_rcv(struct sk_buff **skbp)
{ {
struct sk_buff *skb = *skbp; struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb); struct inet6_skb_parm *opt = IP6CB(skb);
...@@ -249,7 +249,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) ...@@ -249,7 +249,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
skb->h.raw += (hdr->hdrlen + 1) << 3; skb->h.raw += (hdr->hdrlen + 1) << 3;
opt->dst0 = opt->dst1; opt->dst0 = opt->dst1;
opt->dst1 = 0; opt->dst1 = 0;
*nhoffp = (&hdr->nexthdr) - skb->nh.raw; opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
return 1; return 1;
} }
...@@ -487,9 +487,14 @@ static struct tlvtype_proc tlvprochopopt_lst[] = { ...@@ -487,9 +487,14 @@ static struct tlvtype_proc tlvprochopopt_lst[] = {
int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
{ {
IP6CB(skb)->hop = sizeof(struct ipv6hdr); struct inet6_skb_parm *opt = IP6CB(skb);
if (ip6_parse_tlv(tlvprochopopt_lst, skb))
opt->hop = sizeof(struct ipv6hdr);
if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
skb->h.raw += (skb->h.raw[1]+1)<<3;
opt->nhoff = sizeof(struct ipv6hdr);
return sizeof(struct ipv6hdr); return sizeof(struct ipv6hdr);
}
return -1; return -1;
} }
......
...@@ -79,7 +79,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly; ...@@ -79,7 +79,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly;
static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL; static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
#define icmpv6_socket __get_cpu_var(__icmpv6_socket) #define icmpv6_socket __get_cpu_var(__icmpv6_socket)
static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); static int icmpv6_rcv(struct sk_buff **pskb);
static struct inet6_protocol icmpv6_protocol = { static struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv, .handler = icmpv6_rcv,
...@@ -581,7 +581,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) ...@@ -581,7 +581,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
* Handle icmp messages * Handle icmp messages
*/ */
static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) static int icmpv6_rcv(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
......
...@@ -97,6 +97,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ...@@ -97,6 +97,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (hdr->version != 6) if (hdr->version != 6)
goto err; goto err;
skb->h.raw = (u8 *)(hdr + 1);
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
pkt_len = ntohs(hdr->payload_len); pkt_len = ntohs(hdr->payload_len);
/* pkt_len may be zero if Jumbo payload option is present */ /* pkt_len may be zero if Jumbo payload option is present */
...@@ -111,8 +114,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ...@@ -111,8 +114,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
} }
if (hdr->nexthdr == NEXTHDR_HOP) { if (hdr->nexthdr == NEXTHDR_HOP) {
skb->h.raw = (u8*)(hdr+1); if (ipv6_parse_hopopts(skb, IP6CB(skb)->nhoff) < 0) {
if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
return 0; return 0;
} }
...@@ -143,26 +145,15 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -143,26 +145,15 @@ static inline int ip6_input_finish(struct sk_buff *skb)
int nexthdr; int nexthdr;
u8 hash; u8 hash;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
/* /*
* Parse extension headers * Parse extension headers
*/ */
nexthdr = skb->nh.ipv6h->nexthdr;
nhoff = offsetof(struct ipv6hdr, nexthdr);
/* Skip hop-by-hop options, they are already parsed. */
if (nexthdr == NEXTHDR_HOP) {
nhoff = sizeof(struct ipv6hdr);
nexthdr = skb->h.raw[0];
skb->h.raw += (skb->h.raw[1]+1)<<3;
}
rcu_read_lock(); rcu_read_lock();
resubmit: resubmit:
if (!pskb_pull(skb, skb->h.raw - skb->data)) if (!pskb_pull(skb, skb->h.raw - skb->data))
goto discard; goto discard;
nhoff = IP6CB(skb)->nhoff;
nexthdr = skb->nh.raw[nhoff]; nexthdr = skb->nh.raw[nhoff];
raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]); raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
...@@ -194,7 +185,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -194,7 +185,7 @@ static inline int ip6_input_finish(struct sk_buff *skb)
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard; goto discard;
ret = ipprot->handler(&skb, &nhoff); ret = ipprot->handler(&skb);
if (ret > 0) if (ret > 0)
goto resubmit; goto resubmit;
else if (ret == 0) else if (ret == 0)
......
...@@ -510,7 +510,7 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, ...@@ -510,7 +510,7 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
**/ **/
static int static int
ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) ip6ip6_rcv(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct ipv6hdr *ipv6h; struct ipv6hdr *ipv6h;
......
...@@ -581,7 +581,6 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ...@@ -581,7 +581,6 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
* the last and the first frames arrived and all the bits are here. * the last and the first frames arrived and all the bits are here.
*/ */
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
unsigned int *nhoffp,
struct net_device *dev) struct net_device *dev)
{ {
struct sk_buff *fp, *head = fq->fragments; struct sk_buff *fp, *head = fq->fragments;
...@@ -654,6 +653,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -654,6 +653,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
head->dev = dev; head->dev = dev;
skb_set_timestamp(head, &fq->stamp); skb_set_timestamp(head, &fq->stamp);
head->nh.ipv6h->payload_len = htons(payload_len); head->nh.ipv6h->payload_len = htons(payload_len);
IP6CB(head)->nhoff = nhoff;
*skb_in = head; *skb_in = head;
...@@ -663,7 +663,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -663,7 +663,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
fq->fragments = NULL; fq->fragments = NULL;
*nhoffp = nhoff;
return 1; return 1;
out_oversize: out_oversize:
...@@ -678,7 +677,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -678,7 +677,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
return -1; return -1;
} }
static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) static int ipv6_frag_rcv(struct sk_buff **skbp)
{ {
struct sk_buff *skb = *skbp; struct sk_buff *skb = *skbp;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
...@@ -710,7 +709,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) ...@@ -710,7 +709,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
skb->h.raw += sizeof(struct frag_hdr); skb->h.raw += sizeof(struct frag_hdr);
IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
*nhoffp = (u8*)fhdr - skb->nh.raw; IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw;
return 1; return 1;
} }
...@@ -722,11 +721,11 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) ...@@ -722,11 +721,11 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
spin_lock(&fq->lock); spin_lock(&fq->lock);
ip6_frag_queue(fq, skb, fhdr, *nhoffp); ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
if (fq->last_in == (FIRST_IN|LAST_IN) && if (fq->last_in == (FIRST_IN|LAST_IN) &&
fq->meat == fq->len) fq->meat == fq->len)
ret = ip6_frag_reasm(fq, skbp, nhoffp, dev); ret = ip6_frag_reasm(fq, skbp, dev);
spin_unlock(&fq->lock); spin_unlock(&fq->lock);
fq_put(fq, NULL); fq_put(fq, NULL);
......
...@@ -1153,7 +1153,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1153,7 +1153,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0; return 0;
} }
static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) static int tcp_v6_rcv(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct tcphdr *th; struct tcphdr *th;
......
...@@ -435,7 +435,7 @@ static void udpv6_mcast_deliver(struct udphdr *uh, ...@@ -435,7 +435,7 @@ static void udpv6_mcast_deliver(struct udphdr *uh,
read_unlock(&udp_hash_lock); read_unlock(&udp_hash_lock);
} }
static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) static int udpv6_rcv(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct sock *sk; struct sock *sk;
......
...@@ -26,7 +26,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) ...@@ -26,7 +26,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
IP6_ECN_set_ce(inner_iph); IP6_ECN_set_ce(inner_iph);
} }
int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi) int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
int err; int err;
...@@ -38,7 +38,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi) ...@@ -38,7 +38,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
int nexthdr; int nexthdr;
unsigned int nhoff; unsigned int nhoff;
nhoff = *nhoffp; nhoff = IP6CB(skb)->nhoff;
nexthdr = skb->nh.raw[nhoff]; nexthdr = skb->nh.raw[nhoff];
seq = 0; seq = 0;
...@@ -144,7 +144,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi) ...@@ -144,7 +144,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi)
EXPORT_SYMBOL(xfrm6_rcv_spi); EXPORT_SYMBOL(xfrm6_rcv_spi);
int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) int xfrm6_rcv(struct sk_buff **pskb)
{ {
return xfrm6_rcv_spi(pskb, nhoffp, 0); return xfrm6_rcv_spi(pskb, 0);
} }
...@@ -397,7 +397,7 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) ...@@ -397,7 +397,7 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
EXPORT_SYMBOL(xfrm6_tunnel_deregister); EXPORT_SYMBOL(xfrm6_tunnel_deregister);
static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp) static int xfrm6_tunnel_rcv(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct xfrm6_tunnel *handler = xfrm6_tunnel_handler; struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
...@@ -405,11 +405,11 @@ static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp) ...@@ -405,11 +405,11 @@ static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
u32 spi; u32 spi;
/* device-like_ip6ip6_handler() */ /* device-like_ip6ip6_handler() */
if (handler && handler->handler(pskb, nhoffp) == 0) if (handler && handler->handler(pskb) == 0)
return 0; return 0;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
return xfrm6_rcv_spi(pskb, nhoffp, spi); return xfrm6_rcv_spi(pskb, spi);
} }
static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
......
...@@ -905,7 +905,7 @@ static struct inet_protosw sctpv6_stream_protosw = { ...@@ -905,7 +905,7 @@ static struct inet_protosw sctpv6_stream_protosw = {
.flags = SCTP_PROTOSW_FLAG, .flags = SCTP_PROTOSW_FLAG,
}; };
static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) static int sctp6_rcv(struct sk_buff **pskb)
{ {
return sctp_rcv(*pskb) ? -1 : 0; return sctp_rcv(*pskb) ? -1 : 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment