patch-2.1.30 linux/net/ipv6/ipv6_input.c
Next file: linux/net/ipv6/ipv6_output.c
Previous file: linux/net/ipv6/ip6_output.c
Back to the patch index
Back to the overall index
- Lines: 446
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.1.29/linux/net/ipv6/ipv6_input.c
- Orig date:
Tue Mar 4 10:25:27 1997
diff -u --recursive --new-file v2.1.29/linux/net/ipv6/ipv6_input.c linux/net/ipv6/ipv6_input.c
@@ -1,445 +0,0 @@
-/*
- * IPv6 input
- * Linux INET6 implementation
- *
- * Authors:
- * Pedro Roque <roque@di.fc.ul.pt>
- * Ian P. Morris <I.P.Morris@soton.ac.uk>
- *
- * Based in linux/net/ipv4/ip_input.c
- *
- * $Id: ipv6_input.c,v 1.4 1997/02/28 09:56:33 davem Exp $
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/sched.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/in6.h>
-#include <linux/icmpv6.h>
-
-#include <net/sock.h>
-#include <net/snmp.h>
-
-#include <net/ipv6.h>
-#include <net/protocol.h>
-#include <net/transp_v6.h>
-#include <net/rawv6.h>
-#include <net/ndisc.h>
-#include <net/ipv6_route.h>
-#include <net/addrconf.h>
-
-/*
- * Header processing function list
- * We process headers in order (as per RFC)
- * If the processing function returns 0 the packet is considered
- * delivered else it returns the value of the nexthdr.
- * The ptr field of the function points to the previous nexthdr field.
- * This is allows the processing function to change it if it's sematics
- * is: return a new packet without this header (like fragmentation).
- * When a next_header value is not within the list
- * the inet protocol list is searched (i.e. to deliver to
- * TCP for instance)
- */
-
-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 ipv6_tlvtype {
- u8 type;
- u8 len;
-};
-
-struct ipv6_destopt_hdr {
- u8 nexthdr;
- u8 hdrlen;
-};
-
-
-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}
-};
-
-
-static int 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;
- int pos;
-
- while ((hdr=(struct ipv6_tlvtype *)skb->h.raw) != lastopt)
- switch (hdr->type & 0x3F)
- {
- 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 & 0x3F))
- {
- curr->func(skb, dev, nhptr, opt);
- skb->h.raw += hdr->len+2;
- break;
- }
-
- if (curr->type==255)
- {
- /* unkown type */
- pos= (__u8 *) skb->h.raw - (__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;
- break;
-
- case 1: /* drop packet */
- kfree_skb(skb, FREE_READ);
- return 0;
-
- case 2: /* send ICMP PARM PROB regardless and
- drop packet */
- icmpv6_send(skb, ICMPV6_PARAMETER_PROB,
- 2, pos, dev);
- kfree_skb(skb, FREE_READ);
- return 0;
-
- case 3: /* Send ICMP if not a multicast address
- and drop packet */
- if (!(ipv6_addr_type(&(skb->nh.ipv6h->daddr)) & IPV6_ADDR_MULTICAST) )
- icmpv6_send(skb, ICMPV6_PARAMETER_PROB, 2, pos, dev);
- kfree_skb(skb, FREE_READ);
- 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;
-
- if (parse_tlv(tlvprocdestopt_lst, skb, dev, nhptr, opt,skb->h.raw+hdr->hdrlen))
- return hdr->nexthdr;
- else
- return 0;
-}
-
-
-
-/*
- * 0 - deliver
- * 1 - block
- */
-static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
-{
- struct icmpv6hdr *icmph;
- struct raw6_opt *opt;
-
- opt = &sk->tp_pinfo.tp_raw;
- icmph = (struct icmpv6hdr *) (skb->nh.ipv6h + 1);
- return test_bit(icmph->type, &opt->filter);
-}
-
-/*
- * demultiplex raw sockets.
- * (should consider queueing the skb in the sock receive_queue
- * without calling rawv6.c)
- */
-static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
- struct device *dev,
- struct ipv6_options *opt,
- __u16 nexthdr,
- __u16 len,
- struct in6_addr *saddr,
- struct in6_addr *daddr)
-{
- struct sock *sk, *sk2;
- __u8 hash;
-
- hash = nexthdr & (MAX_INET_PROTOS - 1);
-
- sk = raw_v6_htable[hash];
-
- /*
- * The first socket found will be delivered after
- * delivery to transport protocols.
- */
-
- if (sk == NULL)
- return NULL;
-
- sk = raw_v6_lookup(sk, nexthdr, daddr, saddr);
-
- if (sk)
- {
- sk2 = sk;
-
- while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr)))
- {
- struct sk_buff *buff;
-
- if (nexthdr == IPPROTO_ICMPV6 &&
- icmpv6_filter(sk2, skb))
- {
- continue;
- }
- buff = skb_clone(skb, GFP_ATOMIC);
- buff->sk = sk2;
- rawv6_rcv(buff, dev, saddr, daddr, opt, len);
- }
- }
-
- if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
- {
- sk = NULL;
- }
-
- return sk;
-}
-
-int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- struct inet6_ifaddr *ifp;
- struct ipv6_options *opt = (struct ipv6_options *) skb->cb;
- struct ipv6hdr *hdr;
- u8 hash;
- u8 addr_type;
- struct inet6_protocol *ipprot;
- struct sock *raw_sk;
- int found = 0;
- int nexthdr = 0;
- __u8 *nhptr;
- int pkt_len;
-
- if (skb->pkt_type == PACKET_OTHERHOST) {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- hdr = skb->nh.ipv6h;
- skb->h.raw = (__u8*)hdr;
-
- if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6)
- {
- ipv6_statistics.Ip6InHdrErrors++;
- printk(KERN_DEBUG "ipv6_rcv: broken header\n");
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- pkt_len = ntohs(hdr->payload_len);
-
- if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
- {
- printk(KERN_DEBUG "ipv6_rcv: invalid payload length\n");
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
-
- /* check daddr */
-
- /* Accounting & Firewall check */
-
- addr_type = ipv6_addr_type(&hdr->daddr);
-
- if (addr_type & IPV6_ADDR_MULTICAST)
- {
- /*
- * if mcast address is not for one of our groups
- * either pass it to mcast router or discard it
- */
-
- if (ipv6_chk_mcast_addr(dev, &hdr->daddr) == 0)
- {
- /* something like:
- if (acting_as_router)
- ipv6_mcast_route(skb, ...)
- else
- */
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- }
-
- if (addr_type & IPV6_ADDR_MULTICAST ||
- (ifp = ipv6_chk_addr(&hdr->daddr)))
- {
-
- /* loop in a cicle parsing nexthdrs */
-
- skb->h.raw += sizeof(struct ipv6hdr);
-
- /* extension header processing must update skb->h.raw */
-
- nexthdr = hdr->nexthdr;
- nhptr = &hdr->nexthdr;
-
-
- while(1)
- {
- struct hdrtype_proc *hdrt;
-
- /* check for extension header */
-
- for (hdrt=hdrproc_lst; hdrt->type != NEXTHDR_MAX; hdrt++)
- {
- if (hdrt->type == nexthdr)
- {
- if ((nexthdr = hdrt->func(&skb, dev, nhptr, opt)))
- {
- nhptr = skb->h.raw;
- hdr = skb->nh.ipv6h;
- continue;
- }
- return 0;
- }
- }
- break;
-
- }
-
- /*
- * deliver to raw sockets
- * should we deliver raw after or before parsing
- * extension headers ?
- * delivering after means we do reassembly of datagrams
- * in ip.
- */
-
- pkt_len = skb->tail - skb->h.raw;
-
- raw_sk = ipv6_raw_deliver(skb, dev, opt, nexthdr, pkt_len,
- &hdr->saddr, &hdr->daddr);
-
- /* check inet6_protocol list */
-
- 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, dev,
- &hdr->saddr, &hdr->daddr,
- opt, pkt_len,
- 0, ipprot);
- found = 1;
- }
-
- if (raw_sk)
- {
- skb->sk = raw_sk;
- rawv6_rcv(skb, dev, &hdr->saddr, &hdr->daddr, opt,
- htons(hdr->payload_len));
- found = 1;
- }
-
- /* not found: send ICMP parameter problem back */
-
- if (!found)
- {
- printk(KERN_DEBUG "proto not found %d\n", nexthdr);
- kfree_skb(skb, FREE_READ);
- }
-
- }
- else
- {
- if (skb->pkt_type != PACKET_HOST) {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- if (ipv6_forwarding)
- {
- if (addr_type & IPV6_ADDR_LINKLOCAL)
- {
- printk(KERN_DEBUG
- "link local pkt to forward\n");
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- ipv6_forward(skb, dev, 0);
- }
- else
- {
- printk(KERN_WARNING "IPV6: packet to forward -"
- "host not configured as router\n");
- kfree_skb(skb, FREE_READ);
- }
- }
-
- return 0;
-}
-
-/*
- * Local variables:
- * c-file-style: "Linux"
- * End:
- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov