⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ndisc.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	err = xfrm_lookup(&dst, &fl, NULL, 0);	if (err < 0) {		dst_release(dst);		return;	}	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);	send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);	if (send_llinfo)		len += NDISC_OPT_SPACE(dev->addr_len);	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),				  1, &err);	if (skb == NULL) {		ND_PRINTK0(KERN_ERR			   "ICMPv6 NA: %s() failed to allocate an skb.\n", 			   __FUNCTION__);		dst_release(dst);		return;	}	skb_reserve(skb, LL_RESERVED_SPACE(dev));	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);	msg = (struct nd_msg *)skb_put(skb, len);	skb->h.raw = (unsigned char*)msg;	msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;	msg->icmph.icmp6_code = 0;	msg->icmph.icmp6_cksum = 0;	msg->icmph.icmp6_unused = 0;	/* Set the target address. */	ipv6_addr_copy(&msg->target, solicit);	if (send_llinfo)		ndisc_fill_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);	/* checksum */	msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,						 daddr, len, 						 IPPROTO_ICMPV6,						 csum_partial((__u8 *) msg, 							      len, 0));	/* send it! */	skb->dst = dst;	idev = in6_dev_get(dst->dev);	IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);	if (!err) {		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS);		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);	}	if (likely(idev != NULL))		in6_dev_put(idev);}void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,		   struct in6_addr *daddr){	struct flowi fl;	struct dst_entry* dst;	struct inet6_dev *idev;	struct sock *sk = ndisc_socket->sk;        struct sk_buff *skb;        struct icmp6hdr *hdr;	__u8 * opt;        int len;	int err;	ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr);	dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output);	if (!dst)		return;	err = xfrm_lookup(&dst, &fl, NULL, 0);	if (err < 0) {		dst_release(dst);		return;	}	len = sizeof(struct icmp6hdr);	if (dev->addr_len)		len += NDISC_OPT_SPACE(dev->addr_len);        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),				  1, &err);	if (skb == NULL) {		ND_PRINTK0(KERN_ERR			   "ICMPv6 RS: %s() failed to allocate an skb.\n", 			   __FUNCTION__);		dst_release(dst);		return;	}	skb_reserve(skb, LL_RESERVED_SPACE(dev));	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);        hdr = (struct icmp6hdr *)skb_put(skb, len);        skb->h.raw = (unsigned char*)hdr;        hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;        hdr->icmp6_code = 0;        hdr->icmp6_cksum = 0;        hdr->icmp6_unused = 0;	opt = (u8*) (hdr + 1);	if (dev->addr_len)		ndisc_fill_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);	/* checksum */	hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,					   IPPROTO_ICMPV6,					   csum_partial((__u8 *) hdr, len, 0));	/* send it! */	skb->dst = dst;	idev = in6_dev_get(dst->dev);	IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);		err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);	if (!err) {		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS);		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);	}	if (likely(idev != NULL))		in6_dev_put(idev);}		   static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb){	/*	 *	"The sender MUST return an ICMP	 *	 destination unreachable"	 */	dst_link_failure(skb);	kfree_skb(skb);}/* Called with locked neigh: either read or both */static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb){	struct in6_addr *saddr = NULL;	struct in6_addr mcaddr;	struct net_device *dev = neigh->dev;	struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;	int probes = atomic_read(&neigh->probes);	if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 1))		saddr = &skb->nh.ipv6h->saddr;	if ((probes -= neigh->parms->ucast_probes) < 0) {		if (!(neigh->nud_state & NUD_VALID)) {			ND_PRINTK1(KERN_DEBUG				   "%s(): trying to ucast probe in NUD_INVALID: "				   "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",				   __FUNCTION__,				   NIP6(*target));		}		ndisc_send_ns(dev, neigh, target, target, saddr);	} else if ((probes -= neigh->parms->app_probes) < 0) {#ifdef CONFIG_ARPD		neigh_app_ns(neigh);#endif	} else {		addrconf_addr_solict_mult(target, &mcaddr);		ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);	}}static void ndisc_recv_ns(struct sk_buff *skb){	struct nd_msg *msg = (struct nd_msg *)skb->h.raw;	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;	u8 *lladdr = NULL;	int lladdrlen = 0;	u32 ndoptlen = skb->tail - msg->opt;	struct ndisc_options ndopts;	struct net_device *dev = skb->dev;	struct inet6_ifaddr *ifp;	struct inet6_dev *idev = NULL;	struct neighbour *neigh;	int dad = ipv6_addr_any(saddr);	int inc;	if (ipv6_addr_is_multicast(&msg->target)) {		ND_PRINTK2(KERN_WARNING 			   "ICMPv6 NS: multicast target address");		return;	}	/*	 * RFC2461 7.1.1:	 * DAD has to be destined for solicited node multicast address.	 */	if (dad &&	    !(daddr->s6_addr32[0] == htonl(0xff020000) &&	      daddr->s6_addr32[1] == htonl(0x00000000) &&	      daddr->s6_addr32[2] == htonl(0x00000001) &&	      daddr->s6_addr [12] == 0xff )) {		ND_PRINTK2(KERN_WARNING			   "ICMPv6 NS: bad DAD packet (wrong destination)\n");		return;	}	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {		ND_PRINTK2(KERN_WARNING 			   "ICMPv6 NS: invalid ND options\n");		return;	}	if (ndopts.nd_opts_src_lladdr) {		lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1);		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;		if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {			ND_PRINTK2(KERN_WARNING				   "ICMPv6 NS: invalid link-layer address length\n");			return;		}		/* RFC2461 7.1.1:	 	 *	If the IP source address is the unspecified address, 		 *	there MUST NOT be source link-layer address option 		 *	in the message.		 */		if (dad) {			ND_PRINTK2(KERN_WARNING 				   "ICMPv6 NS: bad DAD packet (link-layer address option)\n");			return;		}	}	inc = ipv6_addr_is_multicast(daddr);	if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {		if (ifp->flags & IFA_F_TENTATIVE) {			/* Address is tentative. If the source			   is unspecified address, it is someone			   does DAD, otherwise we ignore solicitations			   until DAD timer expires.			 */			if (!dad)				goto out;			if (dev->type == ARPHRD_IEEE802_TR) {				unsigned char *sadr = skb->mac.raw;				if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&				    sadr[9] == dev->dev_addr[1] &&				    sadr[10] == dev->dev_addr[2] &&				    sadr[11] == dev->dev_addr[3] &&				    sadr[12] == dev->dev_addr[4] &&				    sadr[13] == dev->dev_addr[5]) {					/* looped-back to us */					goto out;				}			}			addrconf_dad_failure(ifp); 			return;		}		idev = ifp->idev;	} else {		idev = in6_dev_get(dev);		if (!idev) {			/* XXX: count this drop? */			return;		}		if (ipv6_chk_acast_addr(dev, &msg->target) ||		    (idev->cnf.forwarding && 		     pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {			if (skb->stamp.tv_sec != LOCALLY_ENQUEUED &&			    skb->pkt_type != PACKET_HOST &&			    inc != 0 &&			    idev->nd_parms->proxy_delay != 0) {				/*				 * for anycast or proxy,				 * sender should delay its response 				 * by a random time between 0 and 				 * MAX_ANYCAST_DELAY_TIME seconds.				 * (RFC2461) -- yoshfuji				 */				struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);				if (n)					pneigh_enqueue(&nd_tbl, idev->nd_parms, n);				goto out;			}		} else			goto out;	}	if (dad) {		struct in6_addr maddr;		ipv6_addr_all_nodes(&maddr);		ndisc_send_na(dev, NULL, &maddr, &msg->target,			      idev->cnf.forwarding, 0, (ifp != NULL), 1);		goto out;	}	if (inc)		NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);	else		NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);	/* 	 *	update / create cache entry	 *	for the source address	 */	neigh = __neigh_lookup(&nd_tbl, saddr, dev,			       !inc || lladdr || !dev->addr_len);	if (neigh)		neigh_update(neigh, lladdr, NUD_STALE, 			     NEIGH_UPDATE_F_WEAK_OVERRIDE|			     NEIGH_UPDATE_F_OVERRIDE);	if (neigh || !dev->hard_header) {		ndisc_send_na(dev, neigh, saddr, &msg->target,			      idev->cnf.forwarding, 			      1, (ifp != NULL && inc), inc);		if (neigh)			neigh_release(neigh);	}out:	if (ifp)		in6_ifa_put(ifp);	else		in6_dev_put(idev);	return;}static void ndisc_recv_na(struct sk_buff *skb){	struct nd_msg *msg = (struct nd_msg *)skb->h.raw;	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;	u8 *lladdr = NULL;	int lladdrlen = 0;	u32 ndoptlen = skb->tail - msg->opt;	struct ndisc_options ndopts;	struct net_device *dev = skb->dev;	struct inet6_ifaddr *ifp;	struct neighbour *neigh;	if (skb->len < sizeof(struct nd_msg)) {		ND_PRINTK2(KERN_WARNING			   "ICMPv6 NA: packet too short\n");		return;	}	if (ipv6_addr_is_multicast(&msg->target)) {		ND_PRINTK2(KERN_WARNING			   "ICMPv6 NA: target address is multicast.\n");		return;	}	if (ipv6_addr_is_multicast(daddr) &&	    msg->icmph.icmp6_solicited) {		ND_PRINTK2(KERN_WARNING			   "ICMPv6 NA: solicited NA is multicasted.\n");		return;	}			if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {		ND_PRINTK2(KERN_WARNING			   "ICMPv6 NS: invalid ND option\n");		return;	}	if (ndopts.nd_opts_tgt_lladdr) {		lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;		if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {			ND_PRINTK2(KERN_WARNING				   "ICMPv6 NA: invalid link-layer address length\n");			return;		}	}	if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1))) {		if (ifp->flags & IFA_F_TENTATIVE) {			addrconf_dad_failure(ifp);			return;		}		/* What should we make now? The advertisement		   is invalid, but ndisc specs say nothing		   about it. It could be misconfiguration, or		   an smart proxy agent tries to help us :-)		 */		ND_PRINTK1(KERN_WARNING			   "ICMPv6 NA: someone advertises our address on %s!\n",			   ifp->idev->dev->name);		in6_ifa_put(ifp);		return;	}	neigh = neigh_lookup(&nd_tbl, &msg->target, dev);	if (neigh) {		u8 old_flags = neigh->flags;		neigh_update(neigh, lladdr,			     msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,			     NEIGH_UPDATE_F_WEAK_OVERRIDE|			     (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|			     NEIGH_UPDATE_F_OVERRIDE_ISROUTER|			     (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));		if ((old_flags & ~neigh->flags) & NTF_ROUTER) {			/*			 * Change: router to host			 */			struct rt6_info *rt;			rt = rt6_get_dflt_router(saddr, dev);			if (rt)				ip6_del_rt(rt, NULL, NULL);		}		neigh_release(neigh);	}}static void ndisc_router_discovery(struct sk_buff *skb){        struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;	struct neighbour *neigh;	struct inet6_dev *in6_dev;	struct rt6_info *rt;	int lifetime;	struct ndisc_options ndopts;	int optlen;	__u8 * opt = (__u8 *)(ra_msg + 1);	optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg);	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {		ND_PRINTK2(KERN_WARNING			   "ICMPv6 RA: source address is not link-local.\n");		return;	}	if (optlen < 0) {		ND_PRINTK2(KERN_WARNING 			   "ICMPv6 RA: packet too short\n");		return;	}	/*	 *	set the RA_RECV flag in the interface	 */	in6_dev = in6_dev_get(skb->dev);	if (in6_dev == NULL) {		ND_PRINTK0(KERN_ERR			   "ICMPv6 RA: can't find inet6 device for %s.\n",			   skb->dev->name);		return;	}	if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {		in6_dev_put(in6_dev);		return;	}	if (!ndisc_parse_options(opt, optlen, &ndopts)) {		in6_dev_put(in6_dev);		ND_PRINTK2(KERN_WARNING			   "ICMP6 RA: invalid ND options\n");		return;	}	if (in6_dev->if_flags & IF_RS_SENT) {		/*		 *	flag that an RA was received after an RS was sent		 *	out on this interface.		 */		in6_dev->if_flags |= IF_RA_RCVD;	}	/*	 * Remember the managed/otherconf flags from most recently	 * received RA message (RFC 2462) -- yoshfuji	 */	in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |				IF_RA_OTHERCONF)) |				(ra_msg->icmph.icmp6_addrconf_managed ?					IF_RA_MANAGED : 0) |				(ra_msg->icmph.icmp6_addrconf_other ?					IF_RA_OTHERCONF : 0);	lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);	rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);	if (rt && lifetime == 0) {		ip6_del_rt(rt, NULL, NULL);		rt = NULL;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -