Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ip6_input.c

Go to the documentation of this file.
00001 /*
00002  *      IPv6 input
00003  *      Linux INET6 implementation 
00004  *
00005  *      Authors:
00006  *      Pedro Roque             <roque@di.fc.ul.pt>
00007  *      Ian P. Morris           <I.P.Morris@soton.ac.uk>
00008  *
00009  *      $Id: ip6_input.c,v 1.11.2.3 2001/06/07 06:47:54 davem Exp $
00010  *
00011  *      Based in linux/net/ipv4/ip_input.c
00012  *
00013  *      This program is free software; you can redistribute it and/or
00014  *      modify it under the terms of the GNU General Public License
00015  *      as published by the Free Software Foundation; either version
00016  *      2 of the License, or (at your option) any later version.
00017  */
00018 
00019 #include <linux/errno.h>
00020 #include <linux/types.h>
00021 #include <linux/socket.h>
00022 #include <linux/sockios.h>
00023 #include <linux/sched.h>
00024 #include <linux/net.h>
00025 #include <linux/netdevice.h>
00026 #include <linux/in6.h>
00027 #include <linux/icmpv6.h>
00028 
00029 #include <net/sock.h>
00030 #include <net/snmp.h>
00031 
00032 #include <net/ipv6.h>
00033 #include <net/protocol.h>
00034 #include <net/transp_v6.h>
00035 #include <net/rawv6.h>
00036 #include <net/ndisc.h>
00037 #include <net/ip6_route.h>
00038 #include <net/addrconf.h>
00039 
00040 
00041 int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
00042 {
00043         struct ipv6hdr *hdr;
00044         u32             pkt_len;
00045 
00046         if (skb->pkt_type == PACKET_OTHERHOST)
00047                 goto drop;
00048 
00049         ipv6_statistics.Ip6InReceives++;
00050 
00051         /* Store incoming device index. When the packet will
00052            be queued, we cannot refer to skb->dev anymore.
00053          */
00054         ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex;
00055 
00056         hdr = skb->nh.ipv6h;
00057 
00058         if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6)
00059                 goto err;
00060 
00061         pkt_len = ntohs(hdr->payload_len);
00062 
00063         /* pkt_len may be zero if Jumbo payload option is present */
00064         if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
00065                 if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
00066                         goto truncated;
00067                 skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
00068         }
00069 
00070         if (hdr->nexthdr == NEXTHDR_HOP) {
00071                 skb->h.raw = (u8*)(hdr+1);
00072                 if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) {
00073                         ipv6_statistics.Ip6InHdrErrors++;
00074                         return 0;
00075                 }
00076         }
00077 
00078         if (skb->dst == NULL)
00079                 ip6_route_input(skb);
00080 
00081         return skb->dst->input(skb);
00082 
00083 truncated:
00084         ipv6_statistics.Ip6InTruncatedPkts++;
00085 err:
00086         ipv6_statistics.Ip6InHdrErrors++;
00087 drop:
00088         kfree_skb(skb);
00089         return 0;
00090 }
00091 
00092 /*
00093  *      0 - deliver
00094  *      1 - block
00095  */
00096 static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
00097 {
00098         struct icmp6hdr *icmph;
00099         struct raw6_opt *opt;
00100         int bit_nr;
00101 
00102         opt = &sk->tp_pinfo.tp_raw;
00103         icmph = (struct icmp6hdr *) skb->h.raw;
00104         bit_nr = icmph->icmp6_type;
00105         if (bit_nr >= (8 * 32))
00106                 return 0;
00107         return ((opt->filter.data[bit_nr >> 5] & (1 << bit_nr)) != 0);
00108 }
00109 
00110 /*
00111  *      demultiplex raw sockets.
00112  *      (should consider queueing the skb in the sock receive_queue
00113  *      without calling rawv6.c)
00114  */
00115 static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
00116                                       int nexthdr, unsigned long len)
00117 {
00118         struct in6_addr *saddr;
00119         struct in6_addr *daddr;
00120         struct sock *sk, *sk2;
00121         __u8 hash;
00122 
00123         saddr = &skb->nh.ipv6h->saddr;
00124         daddr = saddr + 1;
00125 
00126         hash = nexthdr & (MAX_INET_PROTOS - 1);
00127 
00128         sk = raw_v6_htable[hash];
00129 
00130         /*
00131          *      The first socket found will be delivered after
00132          *      delivery to transport protocols.
00133          */
00134 
00135         if (sk == NULL)
00136                 return NULL;
00137 
00138         sk = raw_v6_lookup(sk, nexthdr, daddr, saddr);
00139 
00140         if (sk) {
00141                 sk2 = sk;
00142 
00143                 while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
00144                         struct sk_buff *buff;
00145 
00146                         if (nexthdr == IPPROTO_ICMPV6 &&
00147                             icmpv6_filter(sk2, skb))
00148                                 continue;
00149 
00150                         buff = skb_clone(skb, GFP_ATOMIC);
00151                         if (buff)
00152                                 rawv6_rcv(sk2, buff, len);
00153                 }
00154         }
00155 
00156         if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
00157                 sk = NULL;
00158 
00159         return sk;
00160 }
00161 
00162 /*
00163  *      Deliver the packet to the host
00164  */
00165 
00166 int ip6_input(struct sk_buff *skb)
00167 {
00168         struct ipv6hdr *hdr = skb->nh.ipv6h;
00169         struct inet6_protocol *ipprot;
00170         struct sock *raw_sk;
00171         __u8 *nhptr;
00172         int nexthdr;
00173         int found = 0;
00174         u8 hash;
00175         int len;
00176         
00177         skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
00178 
00179         /*
00180          *      Parse extension headers
00181          */
00182 
00183         nexthdr = hdr->nexthdr;
00184         nhptr = &hdr->nexthdr;
00185 
00186         /* Skip  hop-by-hop options, they are already parsed. */
00187         if (nexthdr == NEXTHDR_HOP) {
00188                 nhptr = (u8*)(hdr+1);
00189                 nexthdr = *nhptr;
00190                 skb->h.raw += (nhptr[1]+1)<<3;
00191         }
00192 
00193         /* This check is sort of optimization.
00194            It would be stupid to detect for optional headers,
00195            which are missing with probability of 200%
00196          */
00197         if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
00198                 nhptr = ipv6_parse_exthdrs(&skb, nhptr);
00199                 if (nhptr == NULL)
00200                         return 0;
00201                 nexthdr = *nhptr;
00202                 hdr = skb->nh.ipv6h;
00203         }
00204         len = skb->tail - skb->h.raw;
00205 
00206         raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
00207 
00208         hash = nexthdr & (MAX_INET_PROTOS - 1);
00209         for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
00210              ipprot != NULL; 
00211              ipprot = (struct inet6_protocol *) ipprot->next) {
00212                 struct sk_buff *buff = skb;
00213 
00214                 if (ipprot->protocol != nexthdr)
00215                         continue;
00216 
00217                 if (ipprot->copy || raw_sk)
00218                         buff = skb_clone(skb, GFP_ATOMIC);
00219                 /* buff == NULL ?????? */
00220                 ipprot->handler(buff, len);
00221                 found = 1;
00222         }
00223 
00224         if (raw_sk) {
00225                 rawv6_rcv(raw_sk, skb, len);
00226                 found = 1;
00227         }
00228 
00229         /*
00230          *      not found: send ICMP parameter problem back
00231          */
00232         if (!found) {
00233                 ipv6_statistics.Ip6InUnknownProtos++;
00234                 icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr);
00235         }
00236 
00237         return 0;
00238 }
00239 
00240 int ip6_mc_input(struct sk_buff *skb)
00241 {
00242         struct ipv6hdr *hdr;    
00243         int deliver = 0;
00244         int discard = 1;
00245 
00246         ipv6_statistics.Ip6InMcastPkts++;
00247 
00248         hdr = skb->nh.ipv6h;
00249         if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
00250                 deliver = 1;
00251 
00252         /*
00253          *      IPv6 multicast router mode isnt currently supported.
00254          */
00255 #if 0
00256         if (ipv6_config.multicast_route) {
00257                 int addr_type;
00258 
00259                 addr_type = ipv6_addr_type(&hdr->daddr);
00260 
00261                 if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
00262                         struct sk_buff *skb2;
00263                         struct dst_entry *dst;
00264 
00265                         dst = skb->dst;
00266                         
00267                         if (deliver) {
00268                                 skb2 = skb_clone(skb, GFP_ATOMIC);
00269                         } else {
00270                                 discard = 0;
00271                                 skb2 = skb;
00272                         }
00273 
00274                         dst->output(skb2);
00275                 }
00276         }
00277 #endif
00278 
00279         if (deliver) {
00280                 discard = 0;
00281                 ip6_input(skb);
00282         }
00283 
00284         if (discard)
00285                 kfree_skb(skb);
00286 
00287         return 0;
00288 }