linux-bk/net/ipv4/ip_sockglue.c
<<
>>
Prefs
   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.62 2002/02/01 22:01:04 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/module.h>
  22#include <linux/types.h>
  23#include <linux/mm.h>
  24#include <linux/sched.h>
  25#include <linux/skbuff.h>
  26#include <linux/ip.h>
  27#include <linux/icmp.h>
  28#include <linux/netdevice.h>
  29#include <net/sock.h>
  30#include <net/ip.h>
  31#include <net/icmp.h>
  32#include <net/tcp.h>
  33#include <linux/tcp.h>
  34#include <linux/udp.h>
  35#include <linux/igmp.h>
  36#include <linux/netfilter.h>
  37#include <linux/route.h>
  38#include <linux/mroute.h>
  39#include <net/route.h>
  40#include <net/xfrm.h>
  41#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  42#include <net/transp_v6.h>
  43#endif
  44
  45#include <linux/errqueue.h>
  46#include <asm/uaccess.h>
  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
  58static 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
  75static 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
  81static 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
  86static 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
  95void 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
 113void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 114{
 115        struct inet_opt *inet = inet_sk(skb->sk);
 116        unsigned flags = inet->cmsg_flags;
 117
 118        /* Ordered by supposed usage frequency */
 119        if (flags & 1)
 120                ip_cmsg_recv_pktinfo(msg, skb);
 121        if ((flags>>=1) == 0)
 122                return;
 123
 124        if (flags & 1)
 125                ip_cmsg_recv_ttl(msg, skb);
 126        if ((flags>>=1) == 0)
 127                return;
 128
 129        if (flags & 1)
 130                ip_cmsg_recv_tos(msg, skb);
 131        if ((flags>>=1) == 0)
 132                return;
 133
 134        if (flags & 1)
 135                ip_cmsg_recv_opts(msg, skb);
 136        if ((flags>>=1) == 0)
 137                return;
 138
 139        if (flags & 1)
 140                ip_cmsg_recv_retopts(msg, skb);
 141}
 142
 143int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
 144{
 145        int err;
 146        struct cmsghdr *cmsg;
 147
 148        for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
 149                if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
 150                    (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
 151                                    + cmsg->cmsg_len) > msg->msg_controllen) {
 152                        return -EINVAL;
 153                }
 154                if (cmsg->cmsg_level != SOL_IP)
 155                        continue;
 156                switch (cmsg->cmsg_type) {
 157                case IP_RETOPTS:
 158                        err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
 159                        err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, 0);
 160                        if (err)
 161                                return err;
 162                        break;
 163                case IP_PKTINFO:
 164                {
 165                        struct in_pktinfo *info;
 166                        if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
 167                                return -EINVAL;
 168                        info = (struct in_pktinfo *)CMSG_DATA(cmsg);
 169                        ipc->oif = info->ipi_ifindex;
 170                        ipc->addr = info->ipi_spec_dst.s_addr;
 171                        break;
 172                }
 173                default:
 174                        return -EINVAL;
 175                }
 176        }
 177        return 0;
 178}
 179
 180
 181/* Special input handler for packets caught by router alert option.
 182   They are selected only by protocol field, and then processed likely
 183   local ones; but only if someone wants them! Otherwise, router
 184   not running rsvpd will kill RSVP.
 185
 186   It is user level problem, what it will make with them.
 187   I have no idea, how it will masquearde or NAT them (it is joke, joke :-)),
 188   but receiver should be enough clever f.e. to forward mtrace requests,
 189   sent to multicast group to reach destination designated router.
 190 */
 191struct ip_ra_chain *ip_ra_chain;
 192rwlock_t ip_ra_lock = RW_LOCK_UNLOCKED;
 193
 194int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *))
 195{
 196        struct ip_ra_chain *ra, *new_ra, **rap;
 197
 198        if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num == IPPROTO_RAW)
 199                return -EINVAL;
 200
 201        new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 202
 203        write_lock_bh(&ip_ra_lock);
 204        for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
 205                if (ra->sk == sk) {
 206                        if (on) {
 207                                write_unlock_bh(&ip_ra_lock);
 208                                if (new_ra)
 209                                        kfree(new_ra);
 210                                return -EADDRINUSE;
 211                        }
 212                        *rap = ra->next;
 213                        write_unlock_bh(&ip_ra_lock);
 214
 215                        if (ra->destructor)
 216                                ra->destructor(sk);
 217                        sock_put(sk);
 218                        kfree(ra);
 219                        return 0;
 220                }
 221        }
 222        if (new_ra == NULL) {
 223                write_unlock_bh(&ip_ra_lock);
 224                return -ENOBUFS;
 225        }
 226        new_ra->sk = sk;
 227        new_ra->destructor = destructor;
 228
 229        new_ra->next = ra;
 230        *rap = new_ra;
 231        sock_hold(sk);
 232        write_unlock_bh(&ip_ra_lock);
 233
 234        return 0;
 235}
 236
 237void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
 238                   u16 port, u32 info, u8 *payload)
 239{
 240        struct inet_opt *inet = inet_sk(sk);
 241        struct sock_exterr_skb *serr;
 242
 243        if (!inet->recverr)
 244                return;
 245
 246        skb = skb_clone(skb, GFP_ATOMIC);
 247        if (!skb)
 248                return;
 249
 250        serr = SKB_EXT_ERR(skb);  
 251        serr->ee.ee_errno = err;
 252        serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
 253        serr->ee.ee_type = skb->h.icmph->type; 
 254        serr->ee.ee_code = skb->h.icmph->code;
 255        serr->ee.ee_pad = 0;
 256        serr->ee.ee_info = info;
 257        serr->ee.ee_data = 0;
 258        serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw;
 259        serr->port = port;
 260
 261        skb->h.raw = payload;
 262        if (!skb_pull(skb, payload - skb->data) ||
 263            sock_queue_err_skb(sk, skb))
 264                kfree_skb(skb);
 265}
 266
 267void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
 268{
 269        struct inet_opt *inet = inet_sk(sk);
 270        struct sock_exterr_skb *serr;
 271        struct iphdr *iph;
 272        struct sk_buff *skb;
 273
 274        if (!inet->recverr)
 275                return;
 276
 277        skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
 278        if (!skb)
 279                return;
 280
 281        iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr));
 282        skb->nh.iph = iph;
 283        iph->daddr = daddr;
 284
 285        serr = SKB_EXT_ERR(skb);  
 286        serr->ee.ee_errno = err;
 287        serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
 288        serr->ee.ee_type = 0; 
 289        serr->ee.ee_code = 0;
 290        serr->ee.ee_pad = 0;
 291        serr->ee.ee_info = info;
 292        serr->ee.ee_data = 0;
 293        serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
 294        serr->port = port;
 295
 296        skb->h.raw = skb->tail;
 297        __skb_pull(skb, skb->tail - skb->data);
 298
 299        if (sock_queue_err_skb(sk, skb))
 300                kfree_skb(skb);
 301}
 302
 303/* 
 304 *      Handle MSG_ERRQUEUE
 305 */
 306int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
 307{
 308        struct sock_exterr_skb *serr;
 309        struct sk_buff *skb, *skb2;
 310        struct sockaddr_in *sin;
 311        struct {
 312                struct sock_extended_err ee;
 313                struct sockaddr_in       offender;
 314        } errhdr;
 315        int err;
 316        int copied;
 317
 318        err = -EAGAIN;
 319        skb = skb_dequeue(&sk->sk_error_queue);
 320        if (skb == NULL)
 321                goto out;
 322
 323        copied = skb->len;
 324        if (copied > len) {
 325                msg->msg_flags |= MSG_TRUNC;
 326                copied = len;
 327        }
 328        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 329        if (err)
 330                goto out_free_skb;
 331
 332        sock_recv_timestamp(msg, sk, skb);
 333
 334        serr = SKB_EXT_ERR(skb);
 335
 336        sin = (struct sockaddr_in *)msg->msg_name;
 337        if (sin) {
 338                sin->sin_family = AF_INET;
 339                sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
 340                sin->sin_port = serr->port;
 341                memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 342        }
 343
 344        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
 345        sin = &errhdr.offender;
 346        sin->sin_family = AF_UNSPEC;
 347        if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
 348                struct inet_opt *inet = inet_sk(sk);
 349
 350                sin->sin_family = AF_INET;
 351                sin->sin_addr.s_addr = skb->nh.iph->saddr;
 352                sin->sin_port = 0;
 353                memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 354                if (inet->cmsg_flags)
 355                        ip_cmsg_recv(msg, skb);
 356        }
 357
 358        put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
 359
 360        /* Now we could try to dump offended packet options */
 361
 362        msg->msg_flags |= MSG_ERRQUEUE;
 363        err = copied;
 364
 365        /* Reset and regenerate socket error */
 366        spin_lock_irq(&sk->sk_error_queue.lock);
 367        sk->sk_err = 0;
 368        if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
 369                sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
 370                spin_unlock_irq(&sk->sk_error_queue.lock);
 371                sk->sk_error_report(sk);
 372        } else
 373                spin_unlock_irq(&sk->sk_error_queue.lock);
 374
 375out_free_skb:   
 376        kfree_skb(skb);
 377out:
 378        return err;
 379}
 380
 381
 382/*
 383 *      Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
 384 *      an IP socket.
 385 */
 386
 387int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
 388{
 389        struct inet_opt *inet = inet_sk(sk);
 390        int val=0,err;
 391
 392        if (level != SOL_IP)
 393                return -ENOPROTOOPT;
 394
 395        if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 
 396                            (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 
 397                            (1<<IP_RETOPTS) | (1<<IP_TOS) | 
 398                            (1<<IP_TTL) | (1<<IP_HDRINCL) | 
 399                            (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
 400                            (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 
 401                                optname == IP_MULTICAST_TTL || 
 402                                optname == IP_MULTICAST_LOOP) { 
 403                if (optlen >= sizeof(int)) {
 404                        if (get_user(val, (int *) optval))
 405                                return -EFAULT;
 406                } else if (optlen >= sizeof(char)) {
 407                        unsigned char ucval;
 408
 409                        if (get_user(ucval, (unsigned char *) optval))
 410                                return -EFAULT;
 411                        val = (int) ucval;
 412                }
 413        }
 414
 415        /* If optlen==0, it is equivalent to val == 0 */
 416
 417#ifdef CONFIG_IP_MROUTE
 418        if (optname >= MRT_BASE && optname <= (MRT_BASE + 10))
 419                return ip_mroute_setsockopt(sk,optname,optval,optlen);
 420#endif
 421
 422        err = 0;
 423        lock_sock(sk);
 424
 425        switch (optname) {
 426                case IP_OPTIONS:
 427                {
 428                        struct ip_options * opt = NULL;
 429                        if (optlen > 40 || optlen < 0)
 430                                goto e_inval;
 431                        err = ip_options_get(&opt, optval, optlen, 1);
 432                        if (err)
 433                                break;
 434                        if (sk->sk_type == SOCK_STREAM) {
 435                                struct tcp_opt *tp = tcp_sk(sk);
 436#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 437                                if (sk->sk_family == PF_INET ||
 438                                    (!((1 << sk->sk_state) &
 439                                       (TCPF_LISTEN | TCPF_CLOSE)) &&
 440                                     inet->daddr != LOOPBACK4_IPV6)) {
 441#endif
 442                                        if (inet->opt)
 443                                                tp->ext_header_len -= inet->opt->optlen;
 444                                        if (opt)
 445                                                tp->ext_header_len += opt->optlen;
 446                                        tcp_sync_mss(sk, tp->pmtu_cookie);
 447#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 448                                }
 449#endif
 450                        }
 451                        opt = xchg(&inet->opt, opt);
 452                        if (opt)
 453                                kfree(opt);
 454                        break;
 455                }
 456                case IP_PKTINFO:
 457                        if (val)
 458                                inet->cmsg_flags |= IP_CMSG_PKTINFO;
 459                        else
 460                                inet->cmsg_flags &= ~IP_CMSG_PKTINFO;
 461                        break;
 462                case IP_RECVTTL:
 463                        if (val)
 464                                inet->cmsg_flags |=  IP_CMSG_TTL;
 465                        else
 466                                inet->cmsg_flags &= ~IP_CMSG_TTL;
 467                        break;
 468                case IP_RECVTOS:
 469                        if (val)
 470                                inet->cmsg_flags |=  IP_CMSG_TOS;
 471                        else
 472                                inet->cmsg_flags &= ~IP_CMSG_TOS;
 473                        break;
 474                case IP_RECVOPTS:
 475                        if (val)
 476                                inet->cmsg_flags |=  IP_CMSG_RECVOPTS;
 477                        else
 478                                inet->cmsg_flags &= ~IP_CMSG_RECVOPTS;
 479                        break;
 480                case IP_RETOPTS:
 481                        if (val)
 482                                inet->cmsg_flags |= IP_CMSG_RETOPTS;
 483                        else
 484                                inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
 485                        break;
 486                case IP_TOS:    /* This sets both TOS and Precedence */
 487                        if (sk->sk_type == SOCK_STREAM) {
 488                                val &= ~3;
 489                                val |= inet->tos & 3;
 490                        }
 491                        if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && 
 492                            !capable(CAP_NET_ADMIN)) {
 493                                err = -EPERM;
 494                                break;
 495                        }
 496                        if (inet->tos != val) {
 497                                inet->tos = val;
 498                                sk->sk_priority = rt_tos2priority(val);
 499                                sk_dst_reset(sk); 
 500                        }
 501                        break;
 502                case IP_TTL:
 503                        if (optlen<1)
 504                                goto e_inval;
 505                        if (val != -1 && (val < 1 || val>255))
 506                                goto e_inval;
 507                        inet->uc_ttl = val;
 508                        break;
 509                case IP_HDRINCL:
 510                        if (sk->sk_type != SOCK_RAW) {
 511                                err = -ENOPROTOOPT;
 512                                break;
 513                        }
 514                        inet->hdrincl = val ? 1 : 0;
 515                        break;
 516                case IP_MTU_DISCOVER:
 517                        if (val<0 || val>2)
 518                                goto e_inval;
 519                        inet->pmtudisc = val;
 520                        break;
 521                case IP_RECVERR:
 522                        inet->recverr = !!val;
 523                        if (!val)
 524                                skb_queue_purge(&sk->sk_error_queue);
 525                        break;
 526                case IP_MULTICAST_TTL:
 527                        if (sk->sk_type == SOCK_STREAM)
 528                                goto e_inval;
 529                        if (optlen<1)
 530                                goto e_inval;
 531                        if (val==-1)
 532                                val = 1;
 533                        if (val < 0 || val > 255)
 534                                goto e_inval;
 535                        inet->mc_ttl = val;
 536                        break;
 537                case IP_MULTICAST_LOOP: 
 538                        if (optlen<1)
 539                                goto e_inval;
 540                        inet->mc_loop = !!val;
 541                        break;
 542                case IP_MULTICAST_IF: 
 543                {
 544                        struct ip_mreqn mreq;
 545                        struct net_device *dev = NULL;
 546
 547                        if (sk->sk_type == SOCK_STREAM)
 548                                goto e_inval;
 549                        /*
 550                         *      Check the arguments are allowable
 551                         */
 552
 553                        err = -EFAULT;
 554                        if (optlen >= sizeof(struct ip_mreqn)) {
 555                                if (copy_from_user(&mreq,optval,sizeof(mreq)))
 556                                        break;
 557                        } else {
 558                                memset(&mreq, 0, sizeof(mreq));
 559                                if (optlen >= sizeof(struct in_addr) &&
 560                                    copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
 561                                        break;
 562                        }
 563
 564                        if (!mreq.imr_ifindex) {
 565                                if (mreq.imr_address.s_addr == INADDR_ANY) {
 566                                        inet->mc_index = 0;
 567                                        inet->mc_addr  = 0;
 568                                        err = 0;
 569                                        break;
 570                                }
 571                                dev = ip_dev_find(mreq.imr_address.s_addr);
 572                                if (dev) {
 573                                        mreq.imr_ifindex = dev->ifindex;
 574                                        dev_put(dev);
 575                                }
 576                        } else
 577                                dev = __dev_get_by_index(mreq.imr_ifindex);
 578
 579
 580                        err = -EADDRNOTAVAIL;
 581                        if (!dev)
 582                                break;
 583
 584                        err = -EINVAL;
 585                        if (sk->sk_bound_dev_if &&
 586                            mreq.imr_ifindex != sk->sk_bound_dev_if)
 587                                break;
 588
 589                        inet->mc_index = mreq.imr_ifindex;
 590                        inet->mc_addr  = mreq.imr_address.s_addr;
 591                        err = 0;
 592                        break;
 593                }
 594
 595                case IP_ADD_MEMBERSHIP:
 596                case IP_DROP_MEMBERSHIP: 
 597                {
 598                        struct ip_mreqn mreq;
 599
 600                        if (optlen < sizeof(struct ip_mreq))
 601                                goto e_inval;
 602                        err = -EFAULT;
 603                        if (optlen >= sizeof(struct ip_mreqn)) {
 604                                if(copy_from_user(&mreq,optval,sizeof(mreq)))
 605                                        break;
 606                        } else {
 607                                memset(&mreq, 0, sizeof(mreq));
 608                                if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
 609                                        break; 
 610                        }
 611
 612                        if (optname == IP_ADD_MEMBERSHIP)
 613                                err = ip_mc_join_group(sk, &mreq);
 614                        else
 615                                err = ip_mc_leave_group(sk, &mreq);
 616                        break;
 617                }
 618                case IP_MSFILTER:
 619                {
 620                        struct ip_msfilter *msf;
 621
 622                        if (optlen < IP_MSFILTER_SIZE(0))
 623                                goto e_inval;
 624                        msf = (struct ip_msfilter *)kmalloc(optlen, GFP_KERNEL);
 625                        if (msf == 0) {
 626                                err = -ENOBUFS;
 627                                break;
 628                        }
 629                        err = -EFAULT;
 630                        if (copy_from_user(msf, optval, optlen)) {
 631                                kfree(msf);
 632                                break;
 633                        }
 634                        err = ip_mc_msfilter(sk, msf, 0);
 635                        kfree(msf);
 636                        break;
 637                }
 638                case IP_BLOCK_SOURCE:
 639                case IP_UNBLOCK_SOURCE:
 640                case IP_ADD_SOURCE_MEMBERSHIP:
 641                case IP_DROP_SOURCE_MEMBERSHIP:
 642                {
 643                        struct ip_mreq_source mreqs;
 644                        int omode, add;
 645
 646                        if (optlen != sizeof(struct ip_mreq_source))
 647                                goto e_inval;
 648                        if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {
 649                                err = -EFAULT;
 650                                break;
 651                        }
 652                        if (optname == IP_BLOCK_SOURCE) {
 653                                omode = MCAST_EXCLUDE;
 654                                add = 1;
 655                        } else if (optname == IP_UNBLOCK_SOURCE) {
 656                                omode = MCAST_EXCLUDE;
 657                                add = 0;
 658                        } else if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
 659                                struct ip_mreqn mreq;
 660
 661                                mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
 662                                mreq.imr_address.s_addr = mreqs.imr_interface;
 663                                mreq.imr_ifindex = 0;
 664                                err = ip_mc_join_group(sk, &mreq);
 665                                if (err)
 666                                        break;
 667                                omode = MCAST_INCLUDE;
 668                                add = 1;
 669                        } else /*IP_DROP_SOURCE_MEMBERSHIP */ {
 670                                omode = MCAST_INCLUDE;
 671                                add = 0;
 672                        }
 673                        err = ip_mc_source(add, omode, sk, &mreqs, 0);
 674                        break;
 675                }
 676                case MCAST_JOIN_GROUP:
 677                case MCAST_LEAVE_GROUP: 
 678                {
 679                        struct group_req greq;
 680                        struct sockaddr_in *psin;
 681                        struct ip_mreqn mreq;
 682
 683                        if (optlen < sizeof(struct group_req))
 684                                goto e_inval;
 685                        err = -EFAULT;
 686                        if(copy_from_user(&greq, optval, sizeof(greq)))
 687                                break;
 688                        psin = (struct sockaddr_in *)&greq.gr_group;
 689                        if (psin->sin_family != AF_INET)
 690                                goto e_inval;
 691                        memset(&mreq, 0, sizeof(mreq));
 692                        mreq.imr_multiaddr = psin->sin_addr;
 693                        mreq.imr_ifindex = greq.gr_interface;
 694
 695                        if (optname == MCAST_JOIN_GROUP)
 696                                err = ip_mc_join_group(sk, &mreq);
 697                        else
 698                                err = ip_mc_leave_group(sk, &mreq);
 699                        break;
 700                }
 701                case MCAST_JOIN_SOURCE_GROUP:
 702                case MCAST_LEAVE_SOURCE_GROUP:
 703                case MCAST_BLOCK_SOURCE:
 704                case MCAST_UNBLOCK_SOURCE:
 705                {
 706                        struct group_source_req greqs;
 707                        struct ip_mreq_source mreqs;
 708                        struct sockaddr_in *psin;
 709                        int omode, add;
 710
 711                        if (optlen != sizeof(struct group_source_req))
 712                                goto e_inval;
 713                        if (copy_from_user(&greqs, optval, sizeof(greqs))) {
 714                                err = -EFAULT;
 715                                break;
 716                        }
 717                        if (greqs.gsr_group.ss_family != AF_INET ||
 718                            greqs.gsr_source.ss_family != AF_INET) {
 719                                err = -EADDRNOTAVAIL;
 720                                break;
 721                        }
 722                        psin = (struct sockaddr_in *)&greqs.gsr_group;
 723                        mreqs.imr_multiaddr = psin->sin_addr.s_addr;
 724                        psin = (struct sockaddr_in *)&greqs.gsr_source;
 725                        mreqs.imr_sourceaddr = psin->sin_addr.s_addr;
 726                        mreqs.imr_interface = 0; /* use index for mc_source */
 727
 728                        if (optname == MCAST_BLOCK_SOURCE) {
 729                                omode = MCAST_EXCLUDE;
 730                                add = 1;
 731                        } else if (optname == MCAST_UNBLOCK_SOURCE) {
 732                                omode = MCAST_EXCLUDE;
 733                                add = 0;
 734                        } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
 735                                struct ip_mreqn mreq;
 736
 737                                psin = (struct sockaddr_in *)&greqs.gsr_group;
 738                                mreq.imr_multiaddr = psin->sin_addr;
 739                                mreq.imr_address.s_addr = 0;
 740                                mreq.imr_ifindex = greqs.gsr_interface;
 741                                err = ip_mc_join_group(sk, &mreq);
 742                                if (err)
 743                                        break;
 744                                omode = MCAST_INCLUDE;
 745                                add = 1;
 746                        } else /* MCAST_LEAVE_SOURCE_GROUP */ {
 747                                omode = MCAST_INCLUDE;
 748                                add = 0;
 749                        }
 750                        err = ip_mc_source(add, omode, sk, &mreqs,
 751                                greqs.gsr_interface);
 752                        break;
 753                }
 754                case MCAST_MSFILTER:
 755                {
 756                        struct sockaddr_in *psin;
 757                        struct ip_msfilter *msf = 0;
 758                        struct group_filter *gsf = 0;
 759                        int msize, i, ifindex;
 760
 761                        if (optlen < GROUP_FILTER_SIZE(0))
 762                                goto e_inval;
 763                        gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
 764                        if (gsf == 0) {
 765                                err = -ENOBUFS;
 766                                break;
 767                        }
 768                        err = -EFAULT;
 769                        if (copy_from_user(gsf, optval, optlen)) {
 770                                goto mc_msf_out;
 771                        }
 772                        if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) {
 773                                err = EINVAL;
 774                                goto mc_msf_out;
 775                        }
 776                        msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
 777                        msf = (struct ip_msfilter *)kmalloc(msize,GFP_KERNEL);
 778                        if (msf == 0) {
 779                                err = -ENOBUFS;
 780                                goto mc_msf_out;
 781                        }
 782                        ifindex = gsf->gf_interface;
 783                        psin = (struct sockaddr_in *)&gsf->gf_group;
 784                        if (psin->sin_family != AF_INET) {
 785                                err = -EADDRNOTAVAIL;
 786                                goto mc_msf_out;
 787                        }
 788                        msf->imsf_multiaddr = psin->sin_addr.s_addr;
 789                        msf->imsf_interface = 0;
 790                        msf->imsf_fmode = gsf->gf_fmode;
 791                        msf->imsf_numsrc = gsf->gf_numsrc;
 792                        err = -EADDRNOTAVAIL;
 793                        for (i=0; i<gsf->gf_numsrc; ++i) {
 794                                psin = (struct sockaddr_in *)&gsf->gf_slist[i];
 795
 796                                if (psin->sin_family != AF_INET)
 797                                        goto mc_msf_out;
 798                                msf->imsf_slist[i] = psin->sin_addr.s_addr;
 799                        }
 800                        kfree(gsf);
 801                        gsf = 0;
 802
 803                        err = ip_mc_msfilter(sk, msf, ifindex);
 804mc_msf_out:
 805                        if (msf)
 806                                kfree(msf);
 807                        if (gsf)
 808                                kfree(gsf);
 809                        break;
 810                }
 811                case IP_ROUTER_ALERT:   
 812                        err = ip_ra_control(sk, val ? 1 : 0, NULL);
 813                        break;
 814
 815                case IP_FREEBIND:
 816                        if (optlen<1)
 817                                goto e_inval;
 818                        inet->freebind = !!val; 
 819                        break;                  
 820 
 821                case IP_IPSEC_POLICY:
 822                case IP_XFRM_POLICY:
 823                        err = xfrm_user_policy(sk, optname, optval, optlen);
 824                        break;
 825
 826                default:
 827#ifdef CONFIG_NETFILTER
 828                        err = nf_setsockopt(sk, PF_INET, optname, optval, 
 829                                            optlen);
 830#else
 831                        err = -ENOPROTOOPT;
 832#endif
 833                        break;
 834        }
 835        release_sock(sk);
 836        return err;
 837
 838e_inval:
 839        release_sock(sk);
 840        return -EINVAL;
 841}
 842
 843/*
 844 *      Get the options. Note for future reference. The GET of IP options gets the
 845 *      _received_ ones. The set sets the _sent_ ones.
 846 */
 847
 848int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
 849{
 850        struct inet_opt *inet = inet_sk(sk);
 851        int val;
 852        int len;
 853        
 854        if(level!=SOL_IP)
 855                return -EOPNOTSUPP;
 856
 857#ifdef CONFIG_IP_MROUTE
 858        if(optname>=MRT_BASE && optname <=MRT_BASE+10)
 859        {
 860                return ip_mroute_getsockopt(sk,optname,optval,optlen);
 861        }
 862#endif
 863
 864        if(get_user(len,optlen))
 865                return -EFAULT;
 866        if(len < 0)
 867                return -EINVAL;
 868                
 869        lock_sock(sk);
 870
 871        switch(optname) {
 872                case IP_OPTIONS:
 873                        {
 874                                unsigned char optbuf[sizeof(struct ip_options)+40];
 875                                struct ip_options * opt = (struct ip_options*)optbuf;
 876                                opt->optlen = 0;
 877                                if (inet->opt)
 878                                        memcpy(optbuf, inet->opt,
 879                                               sizeof(struct ip_options)+
 880                                               inet->opt->optlen);
 881                                release_sock(sk);
 882
 883                                if (opt->optlen == 0) 
 884                                        return put_user(0, optlen);
 885
 886                                ip_options_undo(opt);
 887
 888                                len = min_t(unsigned int, len, opt->optlen);
 889                                if(put_user(len, optlen))
 890                                        return -EFAULT;
 891                                if(copy_to_user(optval, opt->__data, len))
 892                                        return -EFAULT;
 893                                return 0;
 894                        }
 895                case IP_PKTINFO:
 896                        val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0;
 897                        break;
 898                case IP_RECVTTL:
 899                        val = (inet->cmsg_flags & IP_CMSG_TTL) != 0;
 900                        break;
 901                case IP_RECVTOS:
 902                        val = (inet->cmsg_flags & IP_CMSG_TOS) != 0;
 903                        break;
 904                case IP_RECVOPTS:
 905                        val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0;
 906                        break;
 907                case IP_RETOPTS:
 908                        val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
 909                        break;
 910                case IP_TOS:
 911                        val = inet->tos;
 912                        break;
 913                case IP_TTL:
 914                        val = (inet->uc_ttl == -1 ?
 915                               sysctl_ip_default_ttl :
 916                               inet->uc_ttl);
 917                        break;
 918                case IP_HDRINCL:
 919                        val = inet->hdrincl;
 920                        break;
 921                case IP_MTU_DISCOVER:
 922                        val = inet->pmtudisc;
 923                        break;
 924                case IP_MTU:
 925                {
 926                        struct dst_entry *dst;
 927                        val = 0;
 928                        dst = sk_dst_get(sk);
 929                        if (dst) {
 930                                val = dst_pmtu(dst) - dst->header_len;
 931                                dst_release(dst);
 932                        }
 933                        if (!val) {
 934                                release_sock(sk);
 935                                return -ENOTCONN;
 936                        }
 937                        break;
 938                }
 939                case IP_RECVERR:
 940                        val = inet->recverr;
 941                        break;
 942                case IP_MULTICAST_TTL:
 943                        val = inet->mc_ttl;
 944                        break;
 945                case IP_MULTICAST_LOOP:
 946                        val = inet->mc_loop;
 947                        break;
 948                case IP_MULTICAST_IF:
 949                {
 950                        struct in_addr addr;
 951                        len = min_t(unsigned int, len, sizeof(struct in_addr));
 952                        addr.s_addr = inet->mc_addr;
 953                        release_sock(sk);
 954
 955                        if(put_user(len, optlen))
 956                                return -EFAULT;
 957                        if(copy_to_user((void *)optval, &addr, len))
 958                                return -EFAULT;
 959                        return 0;
 960                }
 961                case IP_MSFILTER:
 962                {
 963                        struct ip_msfilter msf;
 964                        int err;
 965
 966                        if (len < IP_MSFILTER_SIZE(0)) {
 967                                release_sock(sk);
 968                                return -EINVAL;
 969                        }
 970                        if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
 971                                release_sock(sk);
 972                                return -EFAULT;
 973                        }
 974                        err = ip_mc_msfget(sk, &msf,
 975                                (struct ip_msfilter *)optval, optlen);
 976                        release_sock(sk);
 977                        return err;
 978                }
 979                case MCAST_MSFILTER:
 980                {
 981                        struct group_filter gsf;
 982                        int err;
 983
 984                        if (len < GROUP_FILTER_SIZE(0)) {
 985                                release_sock(sk);
 986                                return -EINVAL;
 987                        }
 988                        if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
 989                                release_sock(sk);
 990                                return -EFAULT;
 991                        }
 992                        err = ip_mc_gsfget(sk, &gsf,
 993                                (struct group_filter *)optval, optlen);
 994                        release_sock(sk);
 995                        return err;
 996                }
 997                case IP_PKTOPTIONS:             
 998                {
 999                        struct msghdr msg;
1000
1001                        release_sock(sk);
1002
1003                        if (sk->sk_type != SOCK_STREAM)
1004                                return -ENOPROTOOPT;
1005
1006                        msg.msg_control = optval;
1007                        msg.msg_controllen = len;
1008                        msg.msg_flags = 0;
1009
1010                        if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
1011                                struct in_pktinfo info;
1012
1013                                info.ipi_addr.s_addr = inet->rcv_saddr;
1014                                info.ipi_spec_dst.s_addr = inet->rcv_saddr;
1015                                info.ipi_ifindex = inet->mc_index;
1016                                put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
1017                        }
1018                        if (inet->cmsg_flags & IP_CMSG_TTL) {
1019                                int hlim = inet->mc_ttl;
1020                                put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
1021                        }
1022                        len -= msg.msg_controllen;
1023                        return put_user(len, optlen);
1024                }
1025                case IP_FREEBIND: 
1026                        val = inet->freebind; 
1027                        break; 
1028                default:
1029#ifdef CONFIG_NETFILTER
1030                        val = nf_getsockopt(sk, PF_INET, optname, optval, 
1031                                            &len);
1032                        release_sock(sk);
1033                        if (val >= 0)
1034                                val = put_user(len, optlen);
1035                        return val;
1036#else
1037                        release_sock(sk);
1038                        return -ENOPROTOOPT;
1039#endif
1040        }
1041        release_sock(sk);
1042        
1043        if (len < sizeof(int) && len > 0 && val>=0 && val<255) {
1044                unsigned char ucval = (unsigned char)val;
1045                len = 1;
1046                if(put_user(len, optlen))
1047                        return -EFAULT;
1048                if(copy_to_user(optval,&ucval,1))
1049                        return -EFAULT;
1050        } else {
1051                len = min_t(unsigned int, sizeof(int), len);
1052                if(put_user(len, optlen))
1053                        return -EFAULT;
1054                if(copy_to_user(optval,&val,len))
1055                        return -EFAULT;
1056        }
1057        return 0;
1058}
1059
1060EXPORT_SYMBOL(ip_cmsg_recv);
1061
1062#ifdef CONFIG_IP_SCTP_MODULE
1063EXPORT_SYMBOL(ip_getsockopt);
1064EXPORT_SYMBOL(ip_setsockopt);
1065#endif
1066
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.