patch-2.1.120 linux/net/ipv6/ip6_input.c
Next file: linux/net/ipv6/ip6_output.c
Previous file: linux/net/ipv6/ip6_fw.c
Back to the patch index
Back to the overall index
- Lines: 342
- Date:
Thu Aug 27 19:33:09 1998
- Orig file:
v2.1.119/linux/net/ipv6/ip6_input.c
- Orig date:
Tue Jul 28 14:21:10 1998
diff -u --recursive --new-file v2.1.119/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.10 1998/07/15 05:05:34 davem Exp $
+ * $Id: ip6_input.c,v 1.11 1998/08/26 12:04:59 davem Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
@@ -37,144 +37,21 @@
#include <net/ip6_route.h>
#include <net/addrconf.h>
-static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev,
- __u8 *nhptr, struct ipv6_options *opt);
-
-struct hdrtype_proc {
- u8 type;
- int (*func) (struct sk_buff **, struct device *dev, __u8 *ptr,
- struct ipv6_options *opt);
-} hdrproc_lst[] = {
-
- /*
- TODO
-
- {NEXTHDR_HOP, ipv6_hop_by_hop}
- {NEXTHDR_ROUTING, ipv6_routing_header},
- */
- {NEXTHDR_FRAGMENT, ipv6_reassembly},
-
- {NEXTHDR_DEST, ipv6_dest_opt},
- /*
- {NEXTHDR_AUTH, ipv6_auth_hdr},
- {NEXTHDR_ESP, ipv6_esp_hdr},
- */
- {NEXTHDR_MAX, NULL}
-};
-
-/* New header structures */
-
-
-struct tlvtype_proc {
- u8 type;
- int (*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
- struct ipv6_options *opt);
- /*
- * these functions do NOT update skb->h.raw
- */
-
-} tlvprocdestopt_lst[] = {
- {255, NULL}
-};
-
-int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
-{
- struct in6_addr *daddr;
- int pos;
-
- /*
- * unkown destination option type
- */
-
- pos = (__u8 *) hdr - (__u8 *) skb->nh.raw;
-
- /* I think this is correct please check - IPM */
-
- switch ((hdr->type & 0xC0) >> 6) {
- case 0: /* ignore */
- skb->h.raw += hdr->len+2;
- return 1;
-
- case 1: /* drop packet */
- break;
-
- case 2: /* send ICMP PARM PROB regardless and drop packet */
- icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_UNK_OPTION,
- pos, skb->dev);
- break;
-
- case 3: /* Send ICMP if not a multicast address and drop packet */
- daddr = &skb->nh.ipv6h->daddr;
- if (!(ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST))
- icmpv6_send(skb, ICMPV6_PARAMPROB,
- ICMPV6_UNK_OPTION, pos, skb->dev);
- };
-
- kfree_skb(skb);
- return 0;
-}
-
-static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
- struct device *dev, __u8 *nhptr,
- struct ipv6_options *opt, void *lastopt)
-{
- struct ipv6_tlvtype *hdr;
- struct tlvtype_proc *curr;
-
- while ((hdr=(struct ipv6_tlvtype *)skb->h.raw) != lastopt) {
- switch (hdr->type) {
- case 0: /* TLV encoded Pad1 */
- skb->h.raw++;
- break;
-
- case 1: /* TLV encoded PadN */
- skb->h.raw += hdr->len+2;
- break;
-
- default: /* Other TLV code so scan list */
- for (curr=procs; curr->type != 255; curr++) {
- if (curr->type == (hdr->type)) {
- curr->func(skb, dev, nhptr, opt);
- skb->h.raw += hdr->len+2;
- break;
- }
- }
- if (curr->type==255) {
- if (ip6_dstopt_unknown(skb, hdr) == 0)
- return 0;
- }
- break;
- }
- }
- return 1;
-}
-
-static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev,
- __u8 *nhptr, struct ipv6_options *opt)
-{
- struct sk_buff *skb=*skb_ptr;
- struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
- int res = 0;
- void *lastopt=skb->h.raw+hdr->hdrlen+sizeof(struct ipv6_destopt_hdr);
-
- skb->h.raw += sizeof(struct ipv6_destopt_hdr);
- if (ip6_parse_tlv(tlvprocdestopt_lst, skb, dev, nhptr, opt, lastopt))
- res = hdr->nexthdr;
- skb->h.raw+=hdr->hdrlen;
-
- return res;
-}
-
int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct ipv6hdr *hdr;
- int pkt_len;
+ u32 pkt_len;
- if (skb->pkt_type == PACKET_OTHERHOST) {
- kfree_skb(skb);
- return 0;
- }
+ if (skb->pkt_type == PACKET_OTHERHOST)
+ goto drop;
+
+ ipv6_statistics.Ip6InReceives++;
+
+ /* Store incoming device index. When the packet will
+ be queued, we cannot refer to skb->dev anymore.
+ */
+ ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex;
hdr = skb->nh.ipv6h;
@@ -183,16 +60,31 @@
pkt_len = ntohs(hdr->payload_len);
- if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
- goto err;
+ /* pkt_len may be zero if Jumbo payload option is present */
+ if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
+ if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
+ goto truncated;
+ skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+ }
+
+ if (hdr->nexthdr == NEXTHDR_HOP) {
+ skb->h.raw = (u8*)(hdr+1);
+ if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) {
+ ipv6_statistics.Ip6InHdrErrors++;
+ return 0;
+ }
+ }
- skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+ if (skb->dst == NULL)
+ ip6_route_input(skb);
- ip6_route_input(skb);
-
- return 0;
+ return skb->dst->input(skb);
+
+truncated:
+ ipv6_statistics.Ip6InTruncatedPkts++;
err:
ipv6_statistics.Ip6InHdrErrors++;
+drop:
kfree_skb(skb);
return 0;
}
@@ -217,8 +109,7 @@
* without calling rawv6.c)
*/
static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
- struct ipv6_options *opt,
- int nexthdr, int len)
+ int nexthdr, unsigned long len)
{
struct in6_addr *saddr;
struct in6_addr *daddr;
@@ -253,8 +144,8 @@
continue;
buff = skb_clone(skb, GFP_ATOMIC);
- buff->sk = sk2;
- rawv6_rcv(buff, skb->dev, saddr, daddr, opt, len);
+ if (buff)
+ rawv6_rcv(sk2, buff, len);
}
}
@@ -270,10 +161,8 @@
int ip6_input(struct sk_buff *skb)
{
- struct ipv6_options *opt = (struct ipv6_options *) skb->cb;
struct ipv6hdr *hdr = skb->nh.ipv6h;
struct inet6_protocol *ipprot;
- struct hdrtype_proc *hdrt;
struct sock *raw_sk;
__u8 *nhptr;
int nexthdr;
@@ -281,7 +170,7 @@
u8 hash;
int len;
- skb->h.raw += sizeof(struct ipv6hdr);
+ skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
/*
* Parse extension headers
@@ -290,64 +179,55 @@
nexthdr = hdr->nexthdr;
nhptr = &hdr->nexthdr;
- /*
- * check for extension headers
- */
-
-st_loop:
+ /* Skip hop-by-hop options, they are already parsed. */
+ if (nexthdr == NEXTHDR_HOP) {
+ nhptr = (u8*)(hdr+1);
+ nexthdr = *nhptr;
+ skb->h.raw += (nhptr[1]+1)<<3;
+ }
- for (hdrt=hdrproc_lst; hdrt->type != NEXTHDR_MAX; hdrt++) {
- if (hdrt->type == nexthdr) {
- if ((nexthdr = hdrt->func(&skb, skb->dev, nhptr, opt))) {
- nhptr = skb->h.raw;
- hdr = skb->nh.ipv6h;
- goto st_loop;
- }
+ /* This check is sort of optimization.
+ It would be stupid to detect for optional headers,
+ which are missing with probability of 200%
+ */
+ if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
+ nhptr = ipv6_parse_exthdrs(&skb, nhptr);
+ if (nhptr == NULL)
return 0;
- }
+ nexthdr = *nhptr;
+ hdr = skb->nh.ipv6h;
}
-
len = skb->tail - skb->h.raw;
- raw_sk = ipv6_raw_deliver(skb, opt, nexthdr, len);
+ raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot = (struct inet6_protocol *) ipprot->next) {
struct sk_buff *buff = skb;
-
+
if (ipprot->protocol != nexthdr)
continue;
-
+
if (ipprot->copy || raw_sk)
buff = skb_clone(skb, GFP_ATOMIC);
-
-
- ipprot->handler(buff, skb->dev, &hdr->saddr, &hdr->daddr,
- opt, len, 0, ipprot);
+
+ ipprot->handler(buff, len);
found = 1;
}
-
+
if (raw_sk) {
- skb->sk = raw_sk;
- rawv6_rcv(skb, skb->dev, &hdr->saddr, &hdr->daddr, opt, len);
+ rawv6_rcv(raw_sk, skb, len);
found = 1;
}
-
+
/*
* not found: send ICMP parameter problem back
*/
-
if (!found) {
- unsigned long offset;
-#if IP6_DEBUG >= 2
- printk(KERN_DEBUG "proto not found %d\n", nexthdr);
-#endif
- offset = nhptr - (u8*) hdr;
- icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_UNK_NEXTHDR,
- offset, skb->dev);
- kfree_skb(skb);
+ ipv6_statistics.Ip6InUnknownProtos++;
+ icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr);
}
return 0;
@@ -358,6 +238,8 @@
struct ipv6hdr *hdr;
int deliver = 0;
int discard = 1;
+
+ ipv6_statistics.Ip6InMcastPkts++;
hdr = skb->nh.ipv6h;
if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov