1 /*
2  *	IPv6 BSD socket options interface
3  *	Linux INET6 implementation
4  *
5  *	Authors:
6  *	Pedro Roque		<pedro_m@yahoo.com>
7  *
8  *	Based on linux/net/ipv4/ip_sockglue.c
9  *
10  *	$Id: ipv6_sockglue.c,v 1.40 2001/09/18 22:29:10 davem Exp $
11  *
12  *	This program is free software; you can redistribute it and/or
13  *      modify it under the terms of the GNU General Public License
14  *      as published by the Free Software Foundation; either version
15  *      2 of the License, or (at your option) any later version.
16  *
17  *	FIXME: Make the setsockopt code POSIX compliant: That is
18  *
19  *	o	Return -EINVAL for setsockopt of short lengths
20  *	o	Truncate getsockopt returns
21  *	o	Return an optlen of the truncated length if need be
22  *
23  *	Changes:
24  *	David L Stevens <dlstevens@us.ibm.com>:
25  *		- added multicast source filtering API for MLDv2
26  */
27 
28 #include <linux/module.h>
29 #include <linux/config.h>
30 #include <linux/errno.h>
31 #include <linux/types.h>
32 #include <linux/socket.h>
33 #include <linux/sockios.h>
34 #include <linux/sched.h>
35 #include <linux/net.h>
36 #include <linux/in6.h>
37 #include <linux/netdevice.h>
38 #include <linux/if_arp.h>
39 #include <linux/init.h>
40 #include <linux/sysctl.h>
41 #include <linux/netfilter.h>
42 
43 #include <net/sock.h>
44 #include <net/snmp.h>
45 #include <net/ipv6.h>
46 #include <net/ndisc.h>
47 #include <net/protocol.h>
48 #include <net/transp_v6.h>
49 #include <net/ip6_route.h>
50 #include <net/addrconf.h>
51 #include <net/inet_common.h>
52 #include <net/tcp.h>
53 #include <net/udp.h>
54 
55 #include <asm/uaccess.h>
56 
57 struct ipv6_mib ipv6_statistics[NR_CPUS*2];
58 
59 struct packet_type ipv6_packet_type =
60 {
61 	__constant_htons(ETH_P_IPV6),
62 	NULL,					/* All devices */
63 	ipv6_rcv,
64 	(void*)1,
65 	NULL
66 };
67 
68 /*
69  *	addrconf module should be notifyed of a device going up
70  */
71 static struct notifier_block ipv6_dev_notf = {
72 	addrconf_notify,
73 	NULL,
74 	0
75 };
76 
77 struct ip6_ra_chain *ip6_ra_chain;
78 rwlock_t ip6_ra_lock = RW_LOCK_UNLOCKED;
79 
ip6_ra_control(struct sock * sk,int sel,void (* destructor)(struct sock *))80 int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
81 {
82 	struct ip6_ra_chain *ra, *new_ra, **rap;
83 
84 	/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
85 	if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
86 		return -EINVAL;
87 
88 	new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
89 
90 	write_lock_bh(&ip6_ra_lock);
91 	for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
92 		if (ra->sk == sk) {
93 			if (sel>=0) {
94 				write_unlock_bh(&ip6_ra_lock);
95 				if (new_ra)
96 					kfree(new_ra);
97 				return -EADDRINUSE;
98 			}
99 
100 			*rap = ra->next;
101 			write_unlock_bh(&ip6_ra_lock);
102 
103 			if (ra->destructor)
104 				ra->destructor(sk);
105 			sock_put(sk);
106 			kfree(ra);
107 			return 0;
108 		}
109 	}
110 	if (new_ra == NULL) {
111 		write_unlock_bh(&ip6_ra_lock);
112 		return -ENOBUFS;
113 	}
114 	new_ra->sk = sk;
115 	new_ra->sel = sel;
116 	new_ra->destructor = destructor;
117 	new_ra->next = ra;
118 	*rap = new_ra;
119 	sock_hold(sk);
120 	write_unlock_bh(&ip6_ra_lock);
121 	return 0;
122 }
123 
124 extern int ip6_mc_source(int add, int omode, struct sock *sk,
125 	struct group_source_req *pgsr);
126 extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
127 extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
128 	struct group_filter *optval, int *optlen);
129 
130 
ipv6_setsockopt(struct sock * sk,int level,int optname,char * optval,int optlen)131 int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
132 		    int optlen)
133 {
134 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
135 	int val, valbool;
136 	int retv = -ENOPROTOOPT;
137 
138 	if(level==SOL_IP && sk->type != SOCK_RAW)
139 		return udp_prot.setsockopt(sk, level, optname, optval, optlen);
140 
141 	if(level!=SOL_IPV6)
142 		goto out;
143 
144 	if (optval == NULL)
145 		val=0;
146 	else if (get_user(val, (int *) optval))
147 		return -EFAULT;
148 
149 	valbool = (val!=0);
150 
151 	lock_sock(sk);
152 
153 	switch (optname) {
154 
155 	case IPV6_ADDRFORM:
156 		if (val == PF_INET) {
157 			struct ipv6_txoptions *opt;
158 			struct sk_buff *pktopt;
159 
160 			if (sk->protocol != IPPROTO_UDP &&
161 			    sk->protocol != IPPROTO_TCP)
162 				break;
163 
164 			if (sk->state != TCP_ESTABLISHED) {
165 				retv = -ENOTCONN;
166 				break;
167 			}
168 
169 			if (ipv6_only_sock(sk) ||
170 			    !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
171 				retv = -EADDRNOTAVAIL;
172 				break;
173 			}
174 
175 			fl6_free_socklist(sk);
176 			ipv6_sock_mc_close(sk);
177 
178 			if (sk->protocol == IPPROTO_TCP) {
179 				struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
180 
181 				local_bh_disable();
182 				sock_prot_dec_use(sk->prot);
183 				sock_prot_inc_use(&tcp_prot);
184 				local_bh_enable();
185 				sk->prot = &tcp_prot;
186 				tp->af_specific = &ipv4_specific;
187 				sk->socket->ops = &inet_stream_ops;
188 				sk->family = PF_INET;
189 				tcp_sync_mss(sk, tp->pmtu_cookie);
190 			} else {
191 				local_bh_disable();
192 				sock_prot_dec_use(sk->prot);
193 				sock_prot_inc_use(&udp_prot);
194 				local_bh_enable();
195 				sk->prot = &udp_prot;
196 				sk->socket->ops = &inet_dgram_ops;
197 				sk->family = PF_INET;
198 			}
199 			opt = xchg(&np->opt, NULL);
200 			if (opt)
201 				sock_kfree_s(sk, opt, opt->tot_len);
202 			pktopt = xchg(&np->pktoptions, NULL);
203 			if (pktopt)
204 				kfree_skb(pktopt);
205 
206 			sk->destruct = inet_sock_destruct;
207 #ifdef INET_REFCNT_DEBUG
208 			atomic_dec(&inet6_sock_nr);
209 #endif
210 			MOD_DEC_USE_COUNT;
211 			retv = 0;
212 			break;
213 		}
214 		goto e_inval;
215 
216 	case IPV6_V6ONLY:
217 		if (sk->num)
218 			goto e_inval;
219 		np->ipv6only = valbool;
220 		retv = 0;
221 		break;
222 
223 	case IPV6_PKTINFO:
224 		np->rxopt.bits.rxinfo = valbool;
225 		retv = 0;
226 		break;
227 
228 	case IPV6_HOPLIMIT:
229 		np->rxopt.bits.rxhlim = valbool;
230 		retv = 0;
231 		break;
232 
233 	case IPV6_RTHDR:
234 		if (val < 0 || val > 2)
235 			goto e_inval;
236 		np->rxopt.bits.srcrt = val;
237 		retv = 0;
238 		break;
239 
240 	case IPV6_HOPOPTS:
241 		np->rxopt.bits.hopopts = valbool;
242 		retv = 0;
243 		break;
244 
245 	case IPV6_AUTHHDR:
246 		np->rxopt.bits.authhdr = valbool;
247 		retv = 0;
248 		break;
249 
250 	case IPV6_DSTOPTS:
251 		np->rxopt.bits.dstopts = valbool;
252 		retv = 0;
253 		break;
254 
255 	case IPV6_FLOWINFO:
256 		np->rxopt.bits.rxflow = valbool;
257 		retv = 0;
258 		break;
259 
260 	case IPV6_PKTOPTIONS:
261 	{
262 		struct ipv6_txoptions *opt = NULL;
263 		struct msghdr msg;
264 		struct flowi fl;
265 		int junk;
266 
267 		fl.fl6_flowlabel = 0;
268 		fl.oif = sk->bound_dev_if;
269 
270 		if (optlen == 0)
271 			goto update;
272 
273 		/* 1K is probably excessive
274 		 * 1K is surely not enough, 2K per standard header is 16K.
275 		 */
276 		retv = -EINVAL;
277 		if (optlen > 64*1024)
278 			break;
279 
280 		opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
281 		retv = -ENOBUFS;
282 		if (opt == NULL)
283 			break;
284 
285 		memset(opt, 0, sizeof(*opt));
286 		opt->tot_len = sizeof(*opt) + optlen;
287 		retv = -EFAULT;
288 		if (copy_from_user(opt+1, optval, optlen))
289 			goto done;
290 
291 		msg.msg_controllen = optlen;
292 		msg.msg_control = (void*)(opt+1);
293 
294 		retv = datagram_send_ctl(&msg, &fl, opt, &junk);
295 		if (retv)
296 			goto done;
297 update:
298 		retv = 0;
299 		if (sk->type == SOCK_STREAM) {
300 			if (opt) {
301 				struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
302 				if (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
303 				    && sk->daddr != LOOPBACK4_IPV6) {
304 					tp->ext_header_len = opt->opt_flen + opt->opt_nflen;
305 					tcp_sync_mss(sk, tp->pmtu_cookie);
306 				}
307 			}
308 			opt = xchg(&np->opt, opt);
309 			sk_dst_reset(sk);
310 		} else {
311 			write_lock(&sk->dst_lock);
312 			opt = xchg(&np->opt, opt);
313 			write_unlock(&sk->dst_lock);
314 			sk_dst_reset(sk);
315 		}
316 
317 done:
318 		if (opt)
319 			sock_kfree_s(sk, opt, opt->tot_len);
320 		break;
321 	}
322 	case IPV6_UNICAST_HOPS:
323 		if (val > 255 || val < -1)
324 			goto e_inval;
325 		np->hop_limit = val;
326 		retv = 0;
327 		break;
328 
329 	case IPV6_MULTICAST_HOPS:
330 		if (sk->type == SOCK_STREAM)
331 			goto e_inval;
332 		if (val > 255 || val < -1)
333 			goto e_inval;
334 		np->mcast_hops = val;
335 		retv = 0;
336 		break;
337 
338 	case IPV6_MULTICAST_LOOP:
339 		np->mc_loop = valbool;
340 		retv = 0;
341 		break;
342 
343 	case IPV6_MULTICAST_IF:
344 		if (sk->type == SOCK_STREAM)
345 			goto e_inval;
346 		if (sk->bound_dev_if && sk->bound_dev_if != val)
347 			goto e_inval;
348 
349 		if (__dev_get_by_index(val) == NULL) {
350 			retv = -ENODEV;
351 			break;
352 		}
353 		np->mcast_oif = val;
354 		retv = 0;
355 		break;
356 	case IPV6_ADD_MEMBERSHIP:
357 	case IPV6_DROP_MEMBERSHIP:
358 	{
359 		struct ipv6_mreq mreq;
360 
361 		retv = -EFAULT;
362 		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
363 			break;
364 
365 		if (optname == IPV6_ADD_MEMBERSHIP)
366 			retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
367 		else
368 			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
369 		break;
370 	}
371 	case IPV6_JOIN_ANYCAST:
372 	case IPV6_LEAVE_ANYCAST:
373 	{
374 		struct ipv6_mreq mreq;
375 
376 		if (optlen != sizeof(struct ipv6_mreq))
377 			goto e_inval;
378 
379 		retv = -EFAULT;
380 		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
381 			break;
382 
383 		if (optname == IPV6_JOIN_ANYCAST)
384 			retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
385 		else
386 			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
387 		break;
388 	}
389 	case MCAST_JOIN_GROUP:
390 	case MCAST_LEAVE_GROUP:
391 	{
392 		struct group_req greq;
393 		struct sockaddr_in6 *psin6;
394 
395 		retv = -EFAULT;
396 		if (copy_from_user(&greq, optval, sizeof(struct group_req)))
397 			break;
398 		if (greq.gr_group.ss_family != AF_INET6) {
399 			retv = -EADDRNOTAVAIL;
400 			break;
401 		}
402 		psin6 = (struct sockaddr_in6 *)&greq.gr_group;
403 		if (optname == MCAST_JOIN_GROUP)
404 			retv = ipv6_sock_mc_join(sk, greq.gr_interface,
405 				&psin6->sin6_addr);
406 		else
407 			retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
408 				&psin6->sin6_addr);
409 		break;
410 	}
411 	case MCAST_JOIN_SOURCE_GROUP:
412 	case MCAST_LEAVE_SOURCE_GROUP:
413 	case MCAST_BLOCK_SOURCE:
414 	case MCAST_UNBLOCK_SOURCE:
415 	{
416 		struct group_source_req greqs;
417 		int omode, add;
418 
419 		if (optlen != sizeof(struct group_source_req))
420 			goto e_inval;
421 		if (copy_from_user(&greqs, optval, sizeof(greqs))) {
422 			retv = -EFAULT;
423 			break;
424 		}
425 		if (greqs.gsr_group.ss_family != AF_INET6 ||
426 		    greqs.gsr_source.ss_family != AF_INET6) {
427 			retv = -EADDRNOTAVAIL;
428 			break;
429 		}
430 		if (optname == MCAST_BLOCK_SOURCE) {
431 			omode = MCAST_EXCLUDE;
432 			add = 1;
433 		} else if (optname == MCAST_UNBLOCK_SOURCE) {
434 			omode = MCAST_EXCLUDE;
435 			add = 0;
436 		} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
437 			struct sockaddr_in6 *psin6;
438 
439 			psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
440 			retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
441 				&psin6->sin6_addr);
442 			if (retv)
443 				break;
444 			omode = MCAST_INCLUDE;
445 			add = 1;
446 		} else /*IP_DROP_SOURCE_MEMBERSHIP */ {
447 			omode = MCAST_INCLUDE;
448 			add = 0;
449 		}
450 		retv = ip6_mc_source(add, omode, sk, &greqs);
451 		break;
452 	}
453 	case MCAST_MSFILTER:
454 	{
455 		extern int sysctl_optmem_max;
456 		extern int sysctl_mld_max_msf;
457 		struct group_filter *gsf;
458 
459 		if (optlen < GROUP_FILTER_SIZE(0))
460 			goto e_inval;
461 		if (optlen > sysctl_optmem_max) {
462 			retv = -ENOBUFS;
463 			break;
464 		}
465 		gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
466 		if (gsf == 0) {
467 			retv = -ENOBUFS;
468 			break;
469 		}
470 		retv = -EFAULT;
471 		if (copy_from_user(gsf, optval, optlen)) {
472 			kfree(gsf);
473 			break;
474 		}
475 		/* numsrc >= (4G-140)/128 overflow in 32 bits */
476 		if (gsf->gf_numsrc >= 0x1ffffffU ||
477 		    gsf->gf_numsrc > sysctl_mld_max_msf) {
478 			kfree(gsf);
479 			retv = -ENOBUFS;
480 			break;
481 		}
482 		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
483 			kfree(gsf);
484 			retv = -EINVAL;
485 			break;
486 		}
487 		retv = ip6_mc_msfilter(sk, gsf);
488 		kfree(gsf);
489 
490 		break;
491 	}
492 	case IPV6_ROUTER_ALERT:
493 		retv = ip6_ra_control(sk, val, NULL);
494 		break;
495 	case IPV6_MTU_DISCOVER:
496 		if (val<0 || val>2)
497 			goto e_inval;
498 		np->pmtudisc = val;
499 		retv = 0;
500 		break;
501 	case IPV6_MTU:
502 		if (val && val < IPV6_MIN_MTU)
503 			goto e_inval;
504 		np->frag_size = val;
505 		retv = 0;
506 		break;
507 	case IPV6_RECVERR:
508 		np->recverr = valbool;
509 		if (!val)
510 			skb_queue_purge(&sk->error_queue);
511 		retv = 0;
512 		break;
513 	case IPV6_FLOWINFO_SEND:
514 		np->sndflow = valbool;
515 		retv = 0;
516 		break;
517 	case IPV6_FLOWLABEL_MGR:
518 		retv = ipv6_flowlabel_opt(sk, optval, optlen);
519 		break;
520 
521 #ifdef CONFIG_NETFILTER
522 	default:
523 		retv = nf_setsockopt(sk, PF_INET6, optname, optval,
524 					    optlen);
525 		break;
526 #endif
527 
528 	}
529 	release_sock(sk);
530 
531 out:
532 	return retv;
533 
534 e_inval:
535 	release_sock(sk);
536 	return -EINVAL;
537 }
538 
ipv6_getsockopt(struct sock * sk,int level,int optname,char * optval,int * optlen)539 int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
540 		    int *optlen)
541 {
542 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
543 	int len;
544 	int val;
545 
546 	if(level==SOL_IP && sk->type != SOCK_RAW)
547 		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
548 	if(level!=SOL_IPV6)
549 		return -ENOPROTOOPT;
550 	if (get_user(len, optlen))
551 		return -EFAULT;
552 	switch (optname) {
553 	case IPV6_PKTOPTIONS:
554 	{
555 		struct msghdr msg;
556 		struct sk_buff *skb;
557 
558 		if (sk->type != SOCK_STREAM)
559 			return -ENOPROTOOPT;
560 
561 		msg.msg_control = optval;
562 		msg.msg_controllen = len;
563 		msg.msg_flags = 0;
564 
565 		lock_sock(sk);
566 		skb = np->pktoptions;
567 		if (skb)
568 			atomic_inc(&skb->users);
569 		release_sock(sk);
570 
571 		if (skb) {
572 			int err = datagram_recv_ctl(sk, &msg, skb);
573 			kfree_skb(skb);
574 			if (err)
575 				return err;
576 		} else {
577 			if (np->rxopt.bits.rxinfo) {
578 				struct in6_pktinfo src_info;
579 				src_info.ipi6_ifindex = np->mcast_oif;
580 				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
581 				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
582 			}
583 			if (np->rxopt.bits.rxhlim) {
584 				int hlim = np->mcast_hops;
585 				put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
586 			}
587 		}
588 		len -= msg.msg_controllen;
589 		return put_user(len, optlen);
590 	}
591 	case IPV6_MTU:
592 	{
593 		struct dst_entry *dst;
594 		val = 0;
595 		lock_sock(sk);
596 		dst = sk_dst_get(sk);
597 		if (dst) {
598 			val = dst->pmtu;
599 			dst_release(dst);
600 		}
601 		release_sock(sk);
602 		if (!val)
603 			return -ENOTCONN;
604 		break;
605 	}
606 
607 	case IPV6_V6ONLY:
608 		val = np->ipv6only;
609 		break;
610 
611 	case IPV6_PKTINFO:
612 		val = np->rxopt.bits.rxinfo;
613 		break;
614 	case MCAST_MSFILTER:
615 	{
616 		struct group_filter gsf;
617 		int err;
618 
619 		if (len < GROUP_FILTER_SIZE(0))
620 			return -EINVAL;
621 		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
622 			return -EFAULT;
623 		lock_sock(sk);
624 		err = ip6_mc_msfget(sk, &gsf,
625 			(struct group_filter *)optval, optlen);
626 		release_sock(sk);
627 		return err;
628 	}
629 
630 	case IPV6_HOPLIMIT:
631 		val = np->rxopt.bits.rxhlim;
632 		break;
633 
634 	case IPV6_RTHDR:
635 		val = np->rxopt.bits.srcrt;
636 		break;
637 
638 	case IPV6_HOPOPTS:
639 		val = np->rxopt.bits.hopopts;
640 		break;
641 
642 	case IPV6_AUTHHDR:
643 		val = np->rxopt.bits.authhdr;
644 		break;
645 
646 	case IPV6_DSTOPTS:
647 		val = np->rxopt.bits.dstopts;
648 		break;
649 
650 	case IPV6_FLOWINFO:
651 		val = np->rxopt.bits.rxflow;
652 		break;
653 
654 	case IPV6_UNICAST_HOPS:
655 		val = np->hop_limit;
656 		break;
657 
658 	case IPV6_MULTICAST_HOPS:
659 		val = np->mcast_hops;
660 		break;
661 
662 	case IPV6_MULTICAST_LOOP:
663 		val = np->mc_loop;
664 		break;
665 
666 	case IPV6_MULTICAST_IF:
667 		val = np->mcast_oif;
668 		break;
669 
670 	case IPV6_MTU_DISCOVER:
671 		val = np->pmtudisc;
672 		break;
673 
674 	case IPV6_RECVERR:
675 		val = np->recverr;
676 		break;
677 
678 	case IPV6_FLOWINFO_SEND:
679 		val = np->sndflow;
680 		break;
681 
682 	default:
683 #ifdef CONFIG_NETFILTER
684 		lock_sock(sk);
685 		val = nf_getsockopt(sk, PF_INET6, optname, optval,
686 				    &len);
687 		release_sock(sk);
688 		if (val >= 0)
689 			val = put_user(len, optlen);
690 		return val;
691 #else
692 		return -EINVAL;
693 #endif
694 	}
695 	len = min_t(unsigned int, sizeof(int), len);
696 	if(put_user(len, optlen))
697 		return -EFAULT;
698 	if(copy_to_user(optval,&val,len))
699 		return -EFAULT;
700 	return 0;
701 }
702 
703 #if defined(MODULE) && defined(CONFIG_SYSCTL)
704 
705 /*
706  *	sysctl registration functions defined in sysctl_net_ipv6.c
707  */
708 
709 extern void ipv6_sysctl_register(void);
710 extern void ipv6_sysctl_unregister(void);
711 #endif
712 
ipv6_packet_init(void)713 void __init ipv6_packet_init(void)
714 {
715 	dev_add_pack(&ipv6_packet_type);
716 }
717 
ipv6_netdev_notif_init(void)718 void __init ipv6_netdev_notif_init(void)
719 {
720 	register_netdevice_notifier(&ipv6_dev_notf);
721 }
722 
723 #ifdef MODULE
ipv6_packet_cleanup(void)724 void ipv6_packet_cleanup(void)
725 {
726 	dev_remove_pack(&ipv6_packet_type);
727 }
728 
ipv6_netdev_notif_cleanup(void)729 void ipv6_netdev_notif_cleanup(void)
730 {
731 	unregister_netdevice_notifier(&ipv6_dev_notf);
732 }
733 #endif
734