make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / net / ipv6 / ipv6_sockglue.c
1 /*
2  *      IPv6 BSD socket options interface
3  *      Linux INET6 implementation 
4  *
5  *      Authors:
6  *      Pedro Roque             <roque@di.fc.ul.pt>     
7  *
8  *      Based on linux/net/ipv4/ip_sockglue.c
9  *
10  *      $Id: ipv6_sockglue.c,v 1.1.1.1 2005/04/11 02:51:13 jack 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
24 #define __NO_VERSION__
25 #include <linux/module.h>
26 #include <linux/config.h>
27 #include <linux/errno.h>
28 #include <linux/types.h>
29 #include <linux/socket.h>
30 #include <linux/sockios.h>
31 #include <linux/sched.h>
32 #include <linux/net.h>
33 #include <linux/in6.h>
34 #include <linux/netdevice.h>
35 #include <linux/if_arp.h>
36 #include <linux/init.h>
37 #include <linux/sysctl.h>
38 #include <linux/netfilter.h>
39
40 #include <net/sock.h>
41 #include <net/snmp.h>
42 #include <net/ipv6.h>
43 #include <net/ndisc.h>
44 #include <net/protocol.h>
45 #include <net/transp_v6.h>
46 #include <net/ip6_route.h>
47 #include <net/addrconf.h>
48 #include <net/inet_common.h>
49 #include <net/tcp.h>
50 #include <net/udp.h>
51
52 #include <asm/uaccess.h>
53
54 struct ipv6_mib ipv6_statistics[NR_CPUS*2];
55
56 struct packet_type ipv6_packet_type =
57 {
58         __constant_htons(ETH_P_IPV6), 
59         NULL,                                   /* All devices */
60         ipv6_rcv,
61         (void*)1,
62         NULL
63 };
64
65 /*
66  *      addrconf module should be notifyed of a device going up
67  */
68 static struct notifier_block ipv6_dev_notf = {
69         addrconf_notify,
70         NULL,
71         0
72 };
73
74 struct ip6_ra_chain *ip6_ra_chain;
75 rwlock_t ip6_ra_lock = RW_LOCK_UNLOCKED;
76
77 int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
78 {
79         struct ip6_ra_chain *ra, *new_ra, **rap;
80
81         /* RA packet may be delivered ONLY to IPPROTO_RAW socket */
82         if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
83                 return -EINVAL;
84
85         new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
86
87         write_lock_bh(&ip6_ra_lock);
88         for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
89                 if (ra->sk == sk) {
90                         if (sel>=0) {
91                                 write_unlock_bh(&ip6_ra_lock);
92                                 if (new_ra)
93                                         kfree(new_ra);
94                                 return -EADDRINUSE;
95                         }
96
97                         *rap = ra->next;
98                         write_unlock_bh(&ip6_ra_lock);
99
100                         if (ra->destructor)
101                                 ra->destructor(sk);
102                         sock_put(sk);
103                         kfree(ra);
104                         return 0;
105                 }
106         }
107         if (new_ra == NULL) {
108                 write_unlock_bh(&ip6_ra_lock);
109                 return -ENOBUFS;
110         }
111         new_ra->sk = sk;
112         new_ra->sel = sel;
113         new_ra->destructor = destructor;
114         new_ra->next = ra;
115         *rap = new_ra;
116         sock_hold(sk);
117         write_unlock_bh(&ip6_ra_lock);
118         return 0;
119 }
120
121
122 int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, 
123                     int optlen)
124 {
125         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
126         int val, valbool;
127         int retv = -ENOPROTOOPT;
128
129         if(level==SOL_IP && sk->type != SOCK_RAW)
130                 return udp_prot.setsockopt(sk, level, optname, optval, optlen);
131
132         if(level!=SOL_IPV6)
133                 goto out;
134
135         if (optval == NULL)
136                 val=0;
137         else if (get_user(val, (int *) optval))
138                 return -EFAULT;
139
140         valbool = (val!=0);
141
142         lock_sock(sk);
143
144         switch (optname) {
145
146         case IPV6_ADDRFORM:
147                 if (val == PF_INET) {
148                         struct ipv6_txoptions *opt;
149                         struct sk_buff *pktopt;
150
151                         if (sk->protocol != IPPROTO_UDP &&
152                             sk->protocol != IPPROTO_TCP)
153                                 break;
154
155                         if (sk->state != TCP_ESTABLISHED) {
156                                 retv = -ENOTCONN;
157                                 break;
158                         }
159
160                         if (ipv6_only_sock(sk) ||
161                             !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
162                                 retv = -EADDRNOTAVAIL;
163                                 break;
164                         }
165
166                         fl6_free_socklist(sk);
167                         ipv6_sock_mc_close(sk);
168
169                         if (sk->protocol == IPPROTO_TCP) {
170                                 struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
171
172                                 local_bh_disable();
173                                 sock_prot_dec_use(sk->prot);
174                                 sock_prot_inc_use(&tcp_prot);
175                                 local_bh_enable();
176                                 sk->prot = &tcp_prot;
177                                 tp->af_specific = &ipv4_specific;
178                                 sk->socket->ops = &inet_stream_ops;
179                                 sk->family = PF_INET;
180                                 tcp_sync_mss(sk, tp->pmtu_cookie);
181                         } else {
182                                 local_bh_disable();
183                                 sock_prot_dec_use(sk->prot);
184                                 sock_prot_inc_use(&udp_prot);
185                                 local_bh_enable();
186                                 sk->prot = &udp_prot;
187                                 sk->socket->ops = &inet_dgram_ops;
188                                 sk->family = PF_INET;
189                         }
190                         opt = xchg(&np->opt, NULL);
191                         if (opt)
192                                 sock_kfree_s(sk, opt, opt->tot_len);
193                         pktopt = xchg(&np->pktoptions, NULL);
194                         if (pktopt)
195                                 kfree_skb(pktopt);
196
197                         sk->destruct = inet_sock_destruct;
198 #ifdef INET_REFCNT_DEBUG
199                         atomic_dec(&inet6_sock_nr);
200 #endif
201                         MOD_DEC_USE_COUNT;
202                         retv = 0;
203                         break;
204                 }
205                 goto e_inval;
206
207         case IPV6_V6ONLY:
208                 if (sk->num)
209                         goto e_inval;
210                 np->ipv6only = valbool;
211                 retv = 0;
212                 break;
213
214         case IPV6_PKTINFO:
215                 np->rxopt.bits.rxinfo = valbool;
216                 retv = 0;
217                 break;
218
219         case IPV6_HOPLIMIT:
220                 np->rxopt.bits.rxhlim = valbool;
221                 retv = 0;
222                 break;
223
224         case IPV6_RTHDR:
225                 if (val < 0 || val > 2)
226                         goto e_inval;
227                 np->rxopt.bits.srcrt = val;
228                 retv = 0;
229                 break;
230
231         case IPV6_HOPOPTS:
232                 np->rxopt.bits.hopopts = valbool;
233                 retv = 0;
234                 break;
235
236         case IPV6_AUTHHDR:
237                 np->rxopt.bits.authhdr = valbool;
238                 retv = 0;
239                 break;
240
241         case IPV6_DSTOPTS:
242                 np->rxopt.bits.dstopts = valbool;
243                 retv = 0;
244                 break;
245
246         case IPV6_FLOWINFO:
247                 np->rxopt.bits.rxflow = valbool;
248                 retv = 0;
249                 break;
250
251         case IPV6_PKTOPTIONS:
252         {
253                 struct ipv6_txoptions *opt = NULL;
254                 struct msghdr msg;
255                 struct flowi fl;
256                 int junk;
257
258                 fl.fl6_flowlabel = 0;
259                 fl.oif = sk->bound_dev_if;
260
261                 if (optlen == 0)
262                         goto update;
263
264                 /* 1K is probably excessive
265                  * 1K is surely not enough, 2K per standard header is 16K.
266                  */
267                 retv = -EINVAL;
268                 if (optlen > 64*1024)
269                         break;
270
271                 opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
272                 retv = -ENOBUFS;
273                 if (opt == NULL)
274                         break;
275
276                 memset(opt, 0, sizeof(*opt));
277                 opt->tot_len = sizeof(*opt) + optlen;
278                 retv = -EFAULT;
279                 if (copy_from_user(opt+1, optval, optlen))
280                         goto done;
281
282                 msg.msg_controllen = optlen;
283                 msg.msg_control = (void*)(opt+1);
284
285                 retv = datagram_send_ctl(&msg, &fl, opt, &junk);
286                 if (retv)
287                         goto done;
288 update:
289                 retv = 0;
290                 if (sk->type == SOCK_STREAM) {
291                         if (opt) {
292                                 struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
293                                 if (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
294                                     && sk->daddr != LOOPBACK4_IPV6) {
295                                         tp->ext_header_len = opt->opt_flen + opt->opt_nflen;
296                                         tcp_sync_mss(sk, tp->pmtu_cookie);
297                                 }
298                         }
299                         opt = xchg(&np->opt, opt);
300                         sk_dst_reset(sk);
301                 } else {
302                         write_lock(&sk->dst_lock);
303                         opt = xchg(&np->opt, opt);
304                         write_unlock(&sk->dst_lock);
305                         sk_dst_reset(sk);
306                 }
307
308 done:
309                 if (opt)
310                         sock_kfree_s(sk, opt, opt->tot_len);
311                 break;
312         }
313         case IPV6_UNICAST_HOPS:
314                 if (val > 255 || val < -1)
315                         goto e_inval;
316                 np->hop_limit = val;
317                 retv = 0;
318                 break;
319
320         case IPV6_MULTICAST_HOPS:
321                 if (sk->type == SOCK_STREAM)
322                         goto e_inval;
323                 if (val > 255 || val < -1)
324                         goto e_inval;
325                 np->mcast_hops = val;
326                 retv = 0;
327                 break;
328
329         case IPV6_MULTICAST_LOOP:
330                 np->mc_loop = valbool;
331                 retv = 0;
332                 break;
333
334         case IPV6_MULTICAST_IF:
335                 if (sk->type == SOCK_STREAM)
336                         goto e_inval;
337                 if (sk->bound_dev_if && sk->bound_dev_if != val)
338                         goto e_inval;
339
340                 if (__dev_get_by_index(val) == NULL) {
341                         retv = -ENODEV;
342                         break;
343                 }
344                 np->mcast_oif = val;
345                 retv = 0;
346                 break;
347         case IPV6_ADD_MEMBERSHIP:
348         case IPV6_DROP_MEMBERSHIP:
349         {
350                 struct ipv6_mreq mreq;
351
352                 retv = -EFAULT;
353                 if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
354                         break;
355
356                 if (optname == IPV6_ADD_MEMBERSHIP)
357                         retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
358                 else
359                         retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
360                 break;
361         }
362         case IPV6_ROUTER_ALERT:
363                 retv = ip6_ra_control(sk, val, NULL);
364                 break;
365         case IPV6_MTU_DISCOVER:
366                 if (val<0 || val>2)
367                         goto e_inval;
368                 np->pmtudisc = val;
369                 retv = 0;
370                 break;
371         case IPV6_MTU:
372                 if (val && val < IPV6_MIN_MTU)
373                         goto e_inval;
374                 np->frag_size = val;
375                 retv = 0;
376                 break;
377         case IPV6_RECVERR:
378                 np->recverr = valbool;
379                 if (!val)
380                         skb_queue_purge(&sk->error_queue);
381                 retv = 0;
382                 break;
383         case IPV6_FLOWINFO_SEND:
384                 np->sndflow = valbool;
385                 retv = 0;
386                 break;
387         case IPV6_FLOWLABEL_MGR:
388                 retv = ipv6_flowlabel_opt(sk, optval, optlen);
389                 break;
390
391 #ifdef CONFIG_NETFILTER
392         default:
393                 retv = nf_setsockopt(sk, PF_INET6, optname, optval, 
394                                             optlen);
395                 break;
396 #endif
397
398         }
399         release_sock(sk);
400
401 out:
402         return retv;
403
404 e_inval:
405         release_sock(sk);
406         return -EINVAL;
407 }
408
409 int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, 
410                     int *optlen)
411 {
412         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
413         int len;
414         int val;
415
416         if(level==SOL_IP && sk->type != SOCK_RAW)
417                 return udp_prot.getsockopt(sk, level, optname, optval, optlen);
418         if(level!=SOL_IPV6)
419                 return -ENOPROTOOPT;
420         if (get_user(len, optlen))
421                 return -EFAULT;
422         switch (optname) {
423         case IPV6_PKTOPTIONS:
424         {
425                 struct msghdr msg;
426                 struct sk_buff *skb;
427
428                 if (sk->type != SOCK_STREAM)
429                         return -ENOPROTOOPT;
430
431                 msg.msg_control = optval;
432                 msg.msg_controllen = len;
433                 msg.msg_flags = 0;
434
435                 lock_sock(sk);
436                 skb = np->pktoptions;
437                 if (skb)
438                         atomic_inc(&skb->users);
439                 release_sock(sk);
440
441                 if (skb) {
442                         int err = datagram_recv_ctl(sk, &msg, skb);
443                         kfree_skb(skb);
444                         if (err)
445                                 return err;
446                 } else {
447                         if (np->rxopt.bits.rxinfo) {
448                                 struct in6_pktinfo src_info;
449                                 src_info.ipi6_ifindex = np->mcast_oif;
450                                 ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
451                                 put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
452                         }
453                         if (np->rxopt.bits.rxhlim) {
454                                 int hlim = np->mcast_hops;
455                                 put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
456                         }
457                 }
458                 len -= msg.msg_controllen;
459                 return put_user(len, optlen);
460         }
461         case IPV6_MTU:
462         {
463                 struct dst_entry *dst;
464                 val = 0;        
465                 lock_sock(sk);
466                 dst = sk_dst_get(sk);
467                 if (dst) {
468                         val = dst->pmtu;
469                         dst_release(dst);
470                 }
471                 release_sock(sk);
472                 if (!val)
473                         return -ENOTCONN;
474                 break;
475         }
476
477         case IPV6_V6ONLY:
478                 val = np->ipv6only;
479                 break;
480
481         case IPV6_PKTINFO:
482                 val = np->rxopt.bits.rxinfo;
483                 break;
484
485         case IPV6_HOPLIMIT:
486                 val = np->rxopt.bits.rxhlim;
487                 break;
488
489         case IPV6_RTHDR:
490                 val = np->rxopt.bits.srcrt;
491                 break;
492
493         case IPV6_HOPOPTS:
494                 val = np->rxopt.bits.hopopts;
495                 break;
496
497         case IPV6_AUTHHDR:
498                 val = np->rxopt.bits.authhdr;
499                 break;
500
501         case IPV6_DSTOPTS:
502                 val = np->rxopt.bits.dstopts;
503                 break;
504
505         case IPV6_FLOWINFO:
506                 val = np->rxopt.bits.rxflow;
507                 break;
508
509         case IPV6_UNICAST_HOPS:
510                 val = np->hop_limit;
511                 break;
512
513         case IPV6_MULTICAST_HOPS:
514                 val = np->mcast_hops;
515                 break;
516
517         case IPV6_MULTICAST_LOOP:
518                 val = np->mc_loop;
519                 break;
520
521         case IPV6_MULTICAST_IF:
522                 val = np->mcast_oif;
523                 break;
524
525         case IPV6_MTU_DISCOVER:
526                 val = np->pmtudisc;
527                 break;
528
529         case IPV6_RECVERR:
530                 val = np->recverr;
531                 break;
532
533         case IPV6_FLOWINFO_SEND:
534                 val = np->sndflow;
535                 break;
536
537         default:
538 #ifdef CONFIG_NETFILTER
539                 lock_sock(sk);
540                 val = nf_getsockopt(sk, PF_INET6, optname, optval, 
541                                     &len);
542                 release_sock(sk);
543                 if (val >= 0)
544                         val = put_user(len, optlen);
545                 return val;
546 #else
547                 return -EINVAL;
548 #endif
549         }
550         len = min_t(unsigned int, sizeof(int), len);
551         if(put_user(len, optlen))
552                 return -EFAULT;
553         if(copy_to_user(optval,&val,len))
554                 return -EFAULT;
555         return 0;
556 }
557
558 #if defined(MODULE) && defined(CONFIG_SYSCTL)
559
560 /*
561  *      sysctl registration functions defined in sysctl_net_ipv6.c
562  */
563
564 extern void ipv6_sysctl_register(void);
565 extern void ipv6_sysctl_unregister(void);
566 #endif
567
568 void __init ipv6_packet_init(void)
569 {
570         dev_add_pack(&ipv6_packet_type);
571 }
572
573 void __init ipv6_netdev_notif_init(void)
574 {
575         register_netdevice_notifier(&ipv6_dev_notf);
576 }
577
578 #ifdef MODULE
579 void ipv6_packet_cleanup(void)
580 {
581         dev_remove_pack(&ipv6_packet_type);
582 }
583
584 void ipv6_netdev_notif_cleanup(void)
585 {
586         unregister_netdevice_notifier(&ipv6_dev_notf);
587 }
588 #endif