ip6_input.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * IPv6 input
  3.  * Linux INET6 implementation 
  4.  *
  5.  * Authors:
  6.  * Pedro Roque <roque@di.fc.ul.pt>
  7.  * Ian P. Morris <I.P.Morris@soton.ac.uk>
  8.  *
  9.  * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $
  10.  *
  11.  * Based in linux/net/ipv4/ip_input.c
  12.  *
  13.  * This program is free software; you can redistribute it and/or
  14.  *      modify it under the terms of the GNU General Public License
  15.  *      as published by the Free Software Foundation; either version
  16.  *      2 of the License, or (at your option) any later version.
  17.  */
  18. #include <linux/errno.h>
  19. #include <linux/types.h>
  20. #include <linux/socket.h>
  21. #include <linux/sockios.h>
  22. #include <linux/sched.h>
  23. #include <linux/net.h>
  24. #include <linux/netdevice.h>
  25. #include <linux/in6.h>
  26. #include <linux/icmpv6.h>
  27. #include <linux/netfilter.h>
  28. #include <linux/netfilter_ipv6.h>
  29. #include <net/sock.h>
  30. #include <net/snmp.h>
  31. #include <net/ipv6.h>
  32. #include <net/protocol.h>
  33. #include <net/transp_v6.h>
  34. #include <net/rawv6.h>
  35. #include <net/ndisc.h>
  36. #include <net/ip6_route.h>
  37. #include <net/addrconf.h>
  38. static inline int ip6_rcv_finish( struct sk_buff *skb) 
  39. {
  40. if (skb->dst == NULL)
  41. ip6_route_input(skb);
  42. return skb->dst->input(skb);
  43. }
  44. int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
  45. {
  46. struct ipv6hdr *hdr;
  47. u32  pkt_len;
  48. if (skb->pkt_type == PACKET_OTHERHOST)
  49. goto drop;
  50. IP6_INC_STATS_BH(Ip6InReceives);
  51. if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
  52. goto out;
  53. /* Store incoming device index. When the packet will
  54.    be queued, we cannot refer to skb->dev anymore.
  55.  */
  56. ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex;
  57. if (skb->len < sizeof(struct ipv6hdr))
  58. goto err;
  59. if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  60. goto drop;
  61. hdr = skb->nh.ipv6h;
  62. if (hdr->version != 6)
  63. goto err;
  64. pkt_len = ntohs(hdr->payload_len);
  65. /* pkt_len may be zero if Jumbo payload option is present */
  66. if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
  67. if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
  68. goto truncated;
  69. if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
  70. if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)))
  71. goto drop;
  72. hdr = skb->nh.ipv6h;
  73. if (skb->ip_summed == CHECKSUM_HW)
  74. skb->ip_summed = CHECKSUM_NONE;
  75. }
  76. }
  77. if (hdr->nexthdr == NEXTHDR_HOP) {
  78. skb->h.raw = (u8*)(hdr+1);
  79. if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
  80. IP6_INC_STATS_BH(Ip6InHdrErrors);
  81. return 0;
  82. }
  83. hdr = skb->nh.ipv6h;
  84. }
  85. return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
  86. truncated:
  87. IP6_INC_STATS_BH(Ip6InTruncatedPkts);
  88. err:
  89. IP6_INC_STATS_BH(Ip6InHdrErrors);
  90. drop:
  91. kfree_skb(skb);
  92. out:
  93. return 0;
  94. }
  95. /*
  96.  * Deliver the packet to the host
  97.  */
  98. static inline int ip6_input_finish(struct sk_buff *skb)
  99. {
  100. struct ipv6hdr *hdr = skb->nh.ipv6h;
  101. struct inet6_protocol *ipprot;
  102. struct sock *raw_sk;
  103. int nhoff;
  104. int nexthdr;
  105. int found = 0;
  106. u8 hash;
  107. skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
  108. /*
  109.  * Parse extension headers
  110.  */
  111. nexthdr = hdr->nexthdr;
  112. nhoff = offsetof(struct ipv6hdr, nexthdr);
  113. /* Skip  hop-by-hop options, they are already parsed. */
  114. if (nexthdr == NEXTHDR_HOP) {
  115. nhoff = sizeof(struct ipv6hdr);
  116. nexthdr = skb->h.raw[0];
  117. skb->h.raw += (skb->h.raw[1]+1)<<3;
  118. }
  119. /* This check is sort of optimization.
  120.    It would be stupid to detect for optional headers,
  121.    which are missing with probability of 200%
  122.  */
  123. if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
  124. nhoff = ipv6_parse_exthdrs(&skb, nhoff);
  125. if (nhoff < 0)
  126. return 0;
  127. nexthdr = skb->nh.raw[nhoff];
  128. hdr = skb->nh.ipv6h;
  129. }
  130. if (!pskb_pull(skb, skb->h.raw - skb->data))
  131. goto discard;
  132. if (skb->ip_summed == CHECKSUM_HW)
  133. skb->csum = csum_sub(skb->csum,
  134.      csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
  135. raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
  136. if (raw_sk)
  137. raw_sk = ipv6_raw_deliver(skb, nexthdr);
  138. hash = nexthdr & (MAX_INET_PROTOS - 1);
  139. for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
  140.      ipprot != NULL; 
  141.      ipprot = (struct inet6_protocol *) ipprot->next) {
  142. struct sk_buff *buff = skb;
  143. if (ipprot->protocol != nexthdr)
  144. continue;
  145. if (ipprot->copy || raw_sk)
  146. buff = skb_clone(skb, GFP_ATOMIC);
  147. if (buff)
  148. ipprot->handler(buff);
  149. found = 1;
  150. }
  151. if (raw_sk) {
  152. rawv6_rcv(raw_sk, skb);
  153. sock_put(raw_sk);
  154. found = 1;
  155. }
  156. /*
  157.  * not found: send ICMP parameter problem back
  158.  */
  159. if (!found) {
  160. IP6_INC_STATS_BH(Ip6InUnknownProtos);
  161. icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
  162. }
  163. return 0;
  164. discard:
  165. kfree_skb(skb);
  166. return 0;
  167. }
  168. int ip6_input(struct sk_buff *skb)
  169. {
  170. return NF_HOOK(PF_INET6,NF_IP6_LOCAL_IN, skb, skb->dev, NULL, ip6_input_finish);
  171. }
  172. int ip6_mc_input(struct sk_buff *skb)
  173. {
  174. struct ipv6hdr *hdr;
  175. int deliver = 0;
  176. int discard = 1;
  177. IP6_INC_STATS_BH(Ip6InMcastPkts);
  178. hdr = skb->nh.ipv6h;
  179. if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
  180. deliver = 1;
  181. /*
  182.  * IPv6 multicast router mode isnt currently supported.
  183.  */
  184. #if 0
  185. if (ipv6_config.multicast_route) {
  186. int addr_type;
  187. addr_type = ipv6_addr_type(&hdr->daddr);
  188. if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
  189. struct sk_buff *skb2;
  190. struct dst_entry *dst;
  191. dst = skb->dst;
  192. if (deliver) {
  193. skb2 = skb_clone(skb, GFP_ATOMIC);
  194. } else {
  195. discard = 0;
  196. skb2 = skb;
  197. }
  198. dst->output(skb2);
  199. }
  200. }
  201. #endif
  202. if (deliver) {
  203. discard = 0;
  204. ip6_input(skb);
  205. }
  206. if (discard)
  207. kfree_skb(skb);
  208. return 0;
  209. }