~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipv4/ip_sockglue.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
  3  *              operating system.  INET is implemented using the  BSD Socket
  4  *              interface as the means of communication with the user level.
  5  *
  6  *              The IP to API glue.
  7  *              
  8  * Version:     $Id: ip_sockglue.c,v 1.54 2000/11/28 13:34:56 davem Exp $
  9  *
 10  * Authors:     see ip.c
 11  *
 12  * Fixes:
 13  *              Many            :       Split from ip.c , see ip.c for history.
 14  *              Martin Mares    :       TOS setting fixed.
 15  *              Alan Cox        :       Fixed a couple of oopses in Martin's 
 16  *                                      TOS tweaks.
 17  *              Mike McLagan    :       Routing by source
 18  */
 19 
 20 #include <linux/config.h>
 21 #include <linux/types.h>
 22 #include <linux/mm.h>
 23 #include <linux/sched.h>
 24 #include <linux/skbuff.h>
 25 #include <linux/ip.h>
 26 #include <linux/icmp.h>
 27 #include <linux/netdevice.h>
 28 #include <net/sock.h>
 29 #include <net/ip.h>
 30 #include <net/icmp.h>
 31 #include <net/tcp.h>
 32 #include <linux/tcp.h>
 33 #include <linux/udp.h>
 34 #include <linux/igmp.h>
 35 #include <linux/netfilter.h>
 36 #include <linux/route.h>
 37 #include <linux/mroute.h>
 38 #include <net/route.h>
 39 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 40 #include <net/transp_v6.h>
 41 #endif
 42 
 43 #include <linux/errqueue.h>
 44 #include <asm/uaccess.h>
 45 
 46 #define MAX(a,b) ((a)>(b)?(a):(b))
 47 
 48 #define IP_CMSG_PKTINFO         1
 49 #define IP_CMSG_TTL             2
 50 #define IP_CMSG_TOS             4
 51 #define IP_CMSG_RECVOPTS        8
 52 #define IP_CMSG_RETOPTS         16
 53 
 54 /*
 55  *      SOL_IP control messages.
 56  */
 57 
 58 static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 59 {
 60         struct in_pktinfo info;
 61         struct rtable *rt = (struct rtable *)skb->dst;
 62 
 63         info.ipi_addr.s_addr = skb->nh.iph->daddr;
 64         if (rt) {
 65                 info.ipi_ifindex = rt->rt_iif;
 66                 info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
 67         } else {
 68                 info.ipi_ifindex = 0;
 69                 info.ipi_spec_dst.s_addr = 0;
 70         }
 71 
 72         put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
 73 }
 74 
 75 static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
 76 {
 77         int ttl = skb->nh.iph->ttl;
 78         put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
 79 }
 80 
 81 static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
 82 {
 83         put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos);
 84 }
 85 
 86 static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
 87 {
 88         if (IPCB(skb)->opt.optlen == 0)
 89                 return;
 90 
 91         put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen, skb->nh.iph+1);
 92 }
 93 
 94 
 95 void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
 96 {
 97         unsigned char optbuf[sizeof(struct ip_options) + 40];
 98         struct ip_options * opt = (struct ip_options*)optbuf;
 99 
100         if (IPCB(skb)->opt.optlen == 0)
101                 return;
102 
103         if (ip_options_echo(opt, skb)) {
104                 msg->msg_flags |= MSG_CTRUNC;
105                 return;
106         }
107         ip_options_undo(opt);
108 
109         put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
110 }
111 
112 
113 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
114 {
115         unsigned flags = skb->sk->protinfo.af_inet.cmsg_flags;
116 
117         /* Ordered by supposed usage frequency */
118         if (flags & 1)
119                 ip_cmsg_recv_pktinfo(msg, skb);
120         if ((flags>>=1) == 0)
121                 return;
122 
123         if (flags & 1)
124                 ip_cmsg_recv_ttl(msg, skb);
125         if ((flags>>=1) == 0)
126                 return;
127 
128         if (flags & 1)
129                 ip_cmsg_recv_tos(msg, skb);
130         if ((flags>>=1) == 0)
131                 return;
132 
133         if (flags & 1)
134                 ip_cmsg_recv_opts(msg, skb);
135         if ((flags>>=1) == 0)
136                 return;
137 
138         if (flags & 1)
139                 ip_cmsg_recv_retopts(msg, skb);
140 }
141 
142 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
143 {
144         int err;
145         struct cmsghdr *cmsg;
146 
147         for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
148                 if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
149                     (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
150                                     + cmsg->cmsg_len) > msg->msg_controllen) {
151                         return -EINVAL;
152                 }
153                 if (cmsg->cmsg_level != SOL_IP)
154                         continue;
155                 switch (cmsg->cmsg_type) {
156                 case IP_RETOPTS:
157                         err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
158                         err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, 0);
159                         if (err)
160                                 return err;
161                         break;
162                 case IP_PKTINFO:
163                 {
164                         struct in_pktinfo *info;
165                         if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
166                                 return -EINVAL;
167                         info = (struct in_pktinfo *)CMSG_DATA(cmsg);
168                         ipc->oif = info->ipi_ifindex;
169                         ipc->addr = info->ipi_spec_dst.s_addr;
170                         break;
171                 }
172                 default:
173                         return -EINVAL;
174                 }
175         }
176         return 0;
177 }
178 
179 
180 /* Special input handler for packets catched by router alert option.
181    They are selected only by protocol field, and then processed likely
182    local ones; but only if someone wants them! Otherwise, router
183    not running rsvpd will kill RSVP.
184 
185    It is user level problem, what it will make with them.
186    I have no idea, how it will masquearde or NAT them (it is joke, joke :-)),
187    but receiver should be enough clever f.e. to forward mtrace requests,
188    sent to multicast group to reach destination designated router.
189  */
190 struct ip_ra_chain *ip_ra_chain;
191 rwlock_t ip_ra_lock = RW_LOCK_UNLOCKED;
192 
193 int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *))
194 {
195         struct ip_ra_chain *ra, *new_ra, **rap;
196 
197         if (sk->type != SOCK_RAW || sk->num == IPPROTO_RAW)
198                 return -EINVAL;
199 
200         new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
201 
202         write_lock_bh(&ip_ra_lock);
203         for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
204                 if (ra->sk == sk) {
205                         if (on) {
206                                 write_unlock_bh(&ip_ra_lock);
207                                 if (new_ra)
208                                         kfree(new_ra);
209                                 return -EADDRINUSE;
210                         }
211                         *rap = ra->next;
212                         write_unlock_bh(&ip_ra_lock);
213 
214                         if (ra->destructor)
215                                 ra->destructor(sk);
216                         sock_put(sk);
217                         kfree(ra);
218                         return 0;
219                 }
220         }
221         if (new_ra == NULL) {
222                 write_unlock_bh(&ip_ra_lock);
223                 return -ENOBUFS;
224         }
225         new_ra->sk = sk;
226         new_ra->destructor = destructor;
227 
228         new_ra->next = ra;
229         *rap = new_ra;
230         sock_hold(sk);
231         write_unlock_bh(&ip_ra_lock);
232 
233         return 0;
234 }
235 
236 void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
237                    u16 port, u32 info, u8 *payload)
238 {
239         struct sock_exterr_skb *serr;
240 
241         if (!sk->protinfo.af_inet.recverr)
242                 return;
243 
244         skb = skb_clone(skb, GFP_ATOMIC);
245         if (!skb)
246                 return;
247 
248         serr = SKB_EXT_ERR(skb);  
249         serr->ee.ee_errno = err;
250         serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
251         serr->ee.ee_type = skb->h.icmph->type; 
252         serr->ee.ee_code = skb->h.icmph->code;
253         serr->ee.ee_pad = 0;
254         serr->ee.ee_info = info;
255         serr->ee.ee_data = 0;
256         serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw;
257         serr->port = port;
258 
259         skb->h.raw = payload;
260         skb_pull(skb, payload - skb->data);
261 
262         if (sock_queue_err_skb(sk, skb))
263                 kfree_skb(skb);
264 }
265 
266 void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
267 {
268         struct sock_exterr_skb *serr;
269         struct iphdr *iph;
270         struct sk_buff *skb;
271 
272         if (!sk->protinfo.af_inet.recverr)
273                 return;
274 
275         skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
276         if (!skb)
277                 return;
278 
279         iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr));
280         skb->nh.iph = iph;
281         iph->daddr = daddr;
282 
283         serr = SKB_EXT_ERR(skb);  
284         serr->ee.ee_errno = err;
285         serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
286         serr->ee.ee_type = 0; 
287         serr->ee.ee_code = 0;
288         serr->ee.ee_pad = 0;
289         serr->ee.ee_info = info;
290         serr->ee.ee_data = 0;
291         serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
292         serr->port = port;
293 
294         skb->h.raw = skb->tail;
295         skb_pull(skb, skb->tail - skb->data);
296 
297         if (sock_queue_err_skb(sk, skb))
298                 kfree_skb(skb);
299 }
300 
301 /* 
302  *      Handle MSG_ERRQUEUE
303  */
304 int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
305 {
306         struct sock_exterr_skb *serr;
307         struct sk_buff *skb, *skb2;
308         struct sockaddr_in *sin;
309         struct {
310                 struct sock_extended_err ee;
311                 struct sockaddr_in       offender;
312         } errhdr;
313         int err;
314         int copied;
315 
316         err = -EAGAIN;
317         skb = skb_dequeue(&sk->error_queue);
318         if (skb == NULL)
319                 goto out;
320 
321         copied = skb->len;
322         if (copied > len) {
323                 msg->msg_flags |= MSG_TRUNC;
324                 copied = len;
325         }
326         err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
327         if (err)
328                 goto out_free_skb;
329 
330         sock_recv_timestamp(msg, sk, skb);
331 
332         serr = SKB_EXT_ERR(skb);
333 
334         sin = (struct sockaddr_in *)msg->msg_name;
335         if (sin) {
336                 sin->sin_family = AF_INET; 
337                 sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
338                 sin->sin_port = serr->port; 
339         }
340 
341         memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
342         sin = &errhdr.offender;
343         sin->sin_family = AF_UNSPEC;
344         if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
345                 sin->sin_family = AF_INET;
346                 sin->sin_addr.s_addr = skb->nh.iph->saddr;
347                 if (sk->protinfo.af_inet.cmsg_flags)
348                         ip_cmsg_recv(msg, skb);
349         }
350 
351         put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
352 
353         /* Now we could try to dump offended packet options */
354 
355         msg->msg_flags |= MSG_ERRQUEUE;
356         err = copied;
357 
358         /* Reset and regenerate socket error */
359         spin_lock_irq(&sk->error_queue.lock);
360         sk->err = 0;
361         if ((skb2 = skb_peek(&sk->error_queue)) != NULL) {
362                 sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno;
363                 spin_unlock_irq(&sk->error_queue.lock);
364                 sk->error_report(sk);
365         } else {
366                 spin_unlock_irq(&sk->error_queue.lock);
367         }
368 
369 out_free_skb:   
370         kfree_skb(skb);
371 out:
372         return err;
373 }
374 
375 
376 /*
377  *      Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
378  *      an IP socket.
379  */
380 
381 int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
382 {
383         int val=0,err;
384 
385         if (level != SOL_IP)
386                 return -ENOPROTOOPT;
387 
388         if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 
389                             (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 
390                             (1<<IP_RETOPTS) | (1<<IP_TOS) | 
391                             (1<<IP_TTL) | (1<<IP_HDRINCL) | 
392                             (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
393                             (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 
394                                 optname == IP_MULTICAST_TTL || 
395                                 optname == IP_MULTICAST_LOOP) { 
396                 if (optlen >= sizeof(int)) {
397                         if (get_user(val, (int *) optval))
398                                 return -EFAULT;
399                 } else if (optlen >= sizeof(char)) {
400                         unsigned char ucval;
401 
402                         if (get_user(ucval, (unsigned char *) optval))
403                                 return -EFAULT;
404                         val = (int) ucval;
405                 }
406         }
407 
408         /* If optlen==0, it is equivalent to val == 0 */
409 
410 #ifdef CONFIG_IP_MROUTE
411         if (optname >= MRT_BASE && optname <= (MRT_BASE + 10))
412                 return ip_mroute_setsockopt(sk,optname,optval,optlen);
413 #endif
414 
415         err = 0;
416         lock_sock(sk);
417 
418         switch (optname) {
419                 case IP_OPTIONS:
420                 {
421                         struct ip_options * opt = NULL;
422                         if (optlen > 40 || optlen < 0)
423                                 goto e_inval;
424                         err = ip_options_get(&opt, optval, optlen, 1);
425                         if (err)
426                                 break;
427                         if (sk->type == SOCK_STREAM) {
428                                 struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
429 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
430                                 if (sk->family == PF_INET ||
431                                     (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
432                                      && sk->daddr != LOOPBACK4_IPV6)) {
433 #endif
434                                         if (opt)
435                                                 tp->ext_header_len = opt->optlen;
436                                         tcp_sync_mss(sk, tp->pmtu_cookie);
437 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
438                                 }
439 #endif
440                         }
441                         opt = xchg(&sk->protinfo.af_inet.opt, opt);
442                         if (opt)
443                                 kfree(opt);
444                         break;
445                 }
446                 case IP_PKTINFO:
447                         if (val)
448                                 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_PKTINFO;
449                         else
450                                 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_PKTINFO;
451                         break;
452                 case IP_RECVTTL:
453                         if (val)
454                                 sk->protinfo.af_inet.cmsg_flags |=  IP_CMSG_TTL;
455                         else
456                                 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TTL;
457                         break;
458                 case IP_RECVTOS:
459                         if (val)
460                                 sk->protinfo.af_inet.cmsg_flags |=  IP_CMSG_TOS;
461                         else
462                                 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TOS;
463                         break;
464                 case IP_RECVOPTS:
465                         if (val)
466                                 sk->protinfo.af_inet.cmsg_flags |=  IP_CMSG_RECVOPTS;
467                         else
468                                 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RECVOPTS;
469                         break;
470                 case IP_RETOPTS:
471                         if (val)
472                                 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RETOPTS;
473                         else
474                                 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RETOPTS;
475                         break;
476                 case IP_TOS:    /* This sets both TOS and Precedence */
477                           /* Reject setting of unused bits */
478 #ifndef CONFIG_INET_ECN
479                         if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK))
480                                 goto e_inval;
481 #else
482                         if (sk->type == SOCK_STREAM) {
483                                 val &= ~3;
484                                 val |= sk->protinfo.af_inet.tos & 3;
485                         }
486 #endif
487                         if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && 
488                             !capable(CAP_NET_ADMIN)) {
489                                 err = -EPERM;
490                                 break;
491                         }
492                         if (sk->protinfo.af_inet.tos != val) {
493                                 sk->protinfo.af_inet.tos=val;
494                                 sk->priority = rt_tos2priority(val);
495                                 sk_dst_reset(sk); 
496                         }
497                         break;
498                 case IP_TTL:
499                         if (optlen<1)
500                                 goto e_inval;
501                         if(val==-1)
502                                 val = sysctl_ip_default_ttl;
503                         if(val<1||val>255)
504                                 goto e_inval;
505                         sk->protinfo.af_inet.ttl=val;
506                         break;
507                 case IP_HDRINCL:
508                         if(sk->type!=SOCK_RAW) {
509                                 err = -ENOPROTOOPT;
510                                 break;
511                         }
512                         sk->protinfo.af_inet.hdrincl=val?1:0;
513                         break;
514                 case IP_MTU_DISCOVER:
515                         if (val<0 || val>2)
516                                 goto e_inval;
517                         sk->protinfo.af_inet.pmtudisc = val;
518                         break;
519                 case IP_RECVERR:
520                         sk->protinfo.af_inet.recverr = !!val;
521                         if (!val)
522                                 skb_queue_purge(&sk->error_queue);
523                         break;
524                 case IP_MULTICAST_TTL:
525                         if (sk->type == SOCK_STREAM)
526                                 goto e_inval;
527                         if (optlen<1)
528                                 goto e_inval;
529                         if (val==-1)
530                                 val = 1;
531                         if (val < 0 || val > 255)
532                                 goto e_inval;
533                         sk->protinfo.af_inet.mc_ttl=val;
534                         break;
535                 case IP_MULTICAST_LOOP: 
536                         if (optlen<1)
537                                 goto e_inval;
538                         sk->protinfo.af_inet.mc_loop = val ? 1 : 0;
539                         break;
540                 case IP_MULTICAST_IF: 
541                 {
542                         struct ip_mreqn mreq;
543                         struct net_device *dev = NULL;
544 
545                         if (sk->type == SOCK_STREAM)
546                                 goto e_inval;
547                         /*
548                          *      Check the arguments are allowable
549                          */
550 
551                         err = -EFAULT;
552                         if (optlen >= sizeof(struct ip_mreqn)) {
553                                 if (copy_from_user(&mreq,optval,sizeof(mreq)))
554                                         break;
555                         } else {
556                                 memset(&mreq, 0, sizeof(mreq));
557                                 if (optlen >= sizeof(struct in_addr) &&
558                                     copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
559                                         break;
560                         }
561 
562                         if (!mreq.imr_ifindex) {
563                                 if (mreq.imr_address.s_addr == INADDR_ANY) {
564                                         sk->protinfo.af_inet.mc_index = 0;
565                                         sk->protinfo.af_inet.mc_addr  = 0;
566                                         err = 0;
567                                         break;
568                                 }
569                                 dev = ip_dev_find(mreq.imr_address.s_addr);
570                                 if (dev) {
571                                         mreq.imr_ifindex = dev->ifindex;
572                                         dev_put(dev);
573                                 }
574                         } else
575                                 dev = __dev_get_by_index(mreq.imr_ifindex);
576 
577 
578                         err = -EADDRNOTAVAIL;
579                         if (!dev)
580                                 break;
581 
582                         err = -EINVAL;
583                         if (sk->bound_dev_if && mreq.imr_ifindex != sk->bound_dev_if)
584                                 break;
585 
586                         sk->protinfo.af_inet.mc_index = mreq.imr_ifindex;
587                         sk->protinfo.af_inet.mc_addr  = mreq.imr_address.s_addr;
588                         err = 0;
589                         break;
590                 }
591 
592                 case IP_ADD_MEMBERSHIP:
593                 case IP_DROP_MEMBERSHIP: 
594                 {
595                         struct ip_mreqn mreq;
596 
597                         if (optlen < sizeof(struct ip_mreq))
598                                 goto e_inval;
599                         err = -EFAULT;
600                         if (optlen >= sizeof(struct ip_mreqn)) {
601                                 if(copy_from_user(&mreq,optval,sizeof(mreq)))
602                                         break;
603                         } else {
604                                 memset(&mreq, 0, sizeof(mreq));
605                                 if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
606                                         break; 
607                         }
608 
609                         if (optname == IP_ADD_MEMBERSHIP)
610                                 err = ip_mc_join_group(sk,&mreq);
611                         else
612                                 err = ip_mc_leave_group(sk,&mreq);
613                         break;
614                 }
615                 case IP_ROUTER_ALERT:   
616                         err = ip_ra_control(sk, val ? 1 : 0, NULL);
617                         break;
618 
619                 case IP_FREEBIND:
620                         if (optlen<1)
621                                 goto e_inval;
622                         sk->protinfo.af_inet.freebind = !!val; 
623                         break;                  
624  
625                 default:
626 #ifdef CONFIG_NETFILTER
627                         err = nf_setsockopt(sk, PF_INET, optname, optval, 
628                                             optlen);
629 #else
630                         err = -ENOPROTOOPT;
631 #endif
632                         break;
633         }
634         release_sock(sk);
635         return err;
636 
637 e_inval:
638         release_sock(sk);
639         return -EINVAL;
640 }
641 
642 /*
643  *      Get the options. Note for future reference. The GET of IP options gets the
644  *      _received_ ones. The set sets the _sent_ ones.
645  */
646 
647 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
648 {
649         int val;
650         int len;
651         
652         if(level!=SOL_IP)
653                 return -EOPNOTSUPP;
654 
655 #ifdef CONFIG_IP_MROUTE
656         if(optname>=MRT_BASE && optname <=MRT_BASE+10)
657         {
658                 return ip_mroute_getsockopt(sk,optname,optval,optlen);
659         }
660 #endif
661 
662         if(get_user(len,optlen))
663                 return -EFAULT;
664 
665         lock_sock(sk);
666 
667         switch(optname) {
668                 case IP_OPTIONS:
669                         {
670                                 unsigned char optbuf[sizeof(struct ip_options)+40];
671                                 struct ip_options * opt = (struct ip_options*)optbuf;
672                                 opt->optlen = 0;
673                                 if (sk->protinfo.af_inet.opt)
674                                         memcpy(optbuf, sk->protinfo.af_inet.opt,
675                                                sizeof(struct ip_options)+
676                                                sk->protinfo.af_inet.opt->optlen);
677                                 release_sock(sk);
678 
679                                 if (opt->optlen == 0) 
680                                         return put_user(0, optlen);
681 
682                                 ip_options_undo(opt);
683 
684                                 len=min(len, opt->optlen);
685                                 if(put_user(len, optlen))
686                                         return -EFAULT;
687                                 if(copy_to_user(optval, opt->__data, len))
688                                         return -EFAULT;
689                                 return 0;
690                         }
691                 case IP_PKTINFO:
692                         val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_PKTINFO) != 0;
693                         break;
694                 case IP_RECVTTL:
695                         val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TTL) != 0;
696                         break;
697                 case IP_RECVTOS:
698                         val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TOS) != 0;
699                         break;
700                 case IP_RECVOPTS:
701                         val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RECVOPTS) != 0;
702                         break;
703                 case IP_RETOPTS:
704                         val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RETOPTS) != 0;
705                         break;
706                 case IP_TOS:
707                         val=sk->protinfo.af_inet.tos;
708                         break;
709                 case IP_TTL:
710                         val=sk->protinfo.af_inet.ttl;
711                         break;
712                 case IP_HDRINCL:
713                         val=sk->protinfo.af_inet.hdrincl;
714                         break;
715                 case IP_MTU_DISCOVER:
716                         val=sk->protinfo.af_inet.pmtudisc;
717                         break;
718                 case IP_MTU:
719                 {
720                         struct dst_entry *dst;
721                         val = 0;
722                         dst = sk_dst_get(sk);
723                         if (dst) {
724                                 val = dst->pmtu;
725                                 dst_release(dst);
726                         }
727                         if (!val) {
728                                 release_sock(sk);
729                                 return -ENOTCONN;
730                         }
731                         break;
732                 }
733                 case IP_RECVERR:
734                         val=sk->protinfo.af_inet.recverr;
735                         break;
736                 case IP_MULTICAST_TTL:
737                         val=sk->protinfo.af_inet.mc_ttl;
738                         break;
739                 case IP_MULTICAST_LOOP:
740                         val=sk->protinfo.af_inet.mc_loop;
741                         break;
742                 case IP_MULTICAST_IF:
743                 {
744                         struct in_addr addr;
745                         len = min(len,sizeof(struct in_addr));
746                         addr.s_addr = sk->protinfo.af_inet.mc_addr;
747                         release_sock(sk);
748 
749                         if(put_user(len, optlen))
750                                 return -EFAULT;
751                         if(copy_to_user((void *)optval, &addr, len))
752                                 return -EFAULT;
753                         return 0;
754                 }
755                 case IP_PKTOPTIONS:             
756                 {
757                         struct msghdr msg;
758 
759                         release_sock(sk);
760 
761                         if (sk->type != SOCK_STREAM)
762                                 return -ENOPROTOOPT;
763 
764                         msg.msg_control = optval;
765                         msg.msg_controllen = len;
766                         msg.msg_flags = 0;
767 
768                         if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_PKTINFO) {
769                                 struct in_pktinfo info;
770 
771                                 info.ipi_addr.s_addr = sk->rcv_saddr;
772                                 info.ipi_spec_dst.s_addr = sk->rcv_saddr;
773                                 info.ipi_ifindex = sk->protinfo.af_inet.mc_index;
774                                 put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
775                         }
776                         if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_TTL) {
777                                 int hlim = sk->protinfo.af_inet.mc_ttl;
778                                 put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
779                         }
780                         len -= msg.msg_controllen;
781                         return put_user(len, optlen);
782                 }
783                 case IP_FREEBIND: 
784                         val = sk->protinfo.af_inet.freebind; 
785                         break; 
786                 default:
787 #ifdef CONFIG_NETFILTER
788                         val = nf_getsockopt(sk, PF_INET, optname, optval, 
789                                             &len);
790                         release_sock(sk);
791                         if (val >= 0)
792                                 val = put_user(len, optlen);
793                         return val;
794 #else
795                         release_sock(sk);
796                         return -ENOPROTOOPT;
797 #endif
798         }
799         release_sock(sk);
800         
801         if (len < sizeof(int) && len > 0 && val>=0 && val<255) {
802                 unsigned char ucval = (unsigned char)val;
803                 len = 1;
804                 if(put_user(len, optlen))
805                         return -EFAULT;
806                 if(copy_to_user(optval,&ucval,1))
807                         return -EFAULT;
808         } else {
809                 len=min(sizeof(int),len);
810                 if(put_user(len, optlen))
811                         return -EFAULT;
812                 if(copy_to_user(optval,&val,len))
813                         return -EFAULT;
814         }
815         return 0;
816 }
817 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.