/* * IPv6 BSD socket options interface * Linux INET6 implementation * * Authors: * Pedro Roque <roque@di.fc.ul.pt> * * Based on linux/net/ipv4/ip_sockglue.c * * 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. * * FIXME: Make the setsockopt code POSIX compliant: That is * * o Truncate getsockopt returns * o Return an optlen of the truncated length if need be * * Changes: * David L Stevens <dlstevens@us.ibm.com>: * - added multicast source filtering API for MLDv2 */#include <linux/module.h>#include <linux/capability.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/in6.h>#include <linux/mroute6.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/init.h>#include <linux/sysctl.h>#include <linux/netfilter.h>#include <linux/slab.h>#include <net/sock.h>#include <net/snmp.h>#include <net/ipv6.h>#include <net/ndisc.h>#include <net/protocol.h>#include <net/transp_v6.h>#include <net/ip6_route.h>#include <net/addrconf.h>#include <net/inet_common.h>#include <net/tcp.h>#include <net/udp.h>#include <net/udplite.h>#include <net/xfrm.h>#include <net/compat.h>#include <asm/uaccess.h>struct ip6_ra_chain *ip6_ra_chain;DEFINE_RWLOCK(ip6_ra_lock);intip6_ra_control(struct sock *sk,int sel){struct ip6_ra_chain *ra, *new_ra, **rap;/* RA packet may be delivered ONLY to IPPROTO_RAW socket */if(sk->sk_type != SOCK_RAW ||inet_sk(sk)->inet_num != IPPROTO_RAW)return-ENOPROTOOPT;
new_ra = (sel>=0) ?kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;write_lock_bh(&ip6_ra_lock);for(rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {if(ra->sk == sk) {if(sel>=0) {write_unlock_bh(&ip6_ra_lock);kfree(new_ra);return-EADDRINUSE;}*rap = ra->next;write_unlock_bh(&ip6_ra_lock);sock_put(sk);kfree(ra);return0;}}if(new_ra == NULL) {write_unlock_bh(&ip6_ra_lock);return-ENOBUFS;}
new_ra->sk = sk;
new_ra->sel = sel;
new_ra->next = ra;*rap = new_ra;sock_hold(sk);write_unlock_bh(&ip6_ra_lock);return0;}staticstruct ipv6_txoptions *ipv6_update_options(struct sock *sk,struct ipv6_txoptions *opt){if(inet_sk(sk)->is_icsk) {if(opt &&!((1<< sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {struct inet_connection_sock *icsk =inet_csk(sk);
icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);}
opt =xchg(&inet6_sk(sk)-><