root/net/ipv4/ip_sockglue.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ip_mc_procinfo
  2. ip_mc_find_devfor
  3. ip_setsockopt
  4. ip_getsockopt

   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  * Authors:     see ip.c
   9  *
  10  * Fixes:
  11  *              Many            :       Split from ip.c , see ip.c for history.
  12  *              Martin Mares    :       TOS setting fixed.
  13  *              Alan Cox        :       Fixed a couple of oopses in Martins 
  14  *                                      TOS tweaks.
  15  */
  16 
  17 #include <linux/config.h>
  18 #include <linux/types.h>
  19 #include <linux/mm.h>
  20 #include <linux/sched.h>
  21 #include <linux/skbuff.h>
  22 #include <linux/ip.h>
  23 #include <linux/icmp.h>
  24 #include <linux/netdevice.h>
  25 #include <net/sock.h>
  26 #include <net/ip.h>
  27 #include <net/icmp.h>
  28 #include <linux/tcp.h>
  29 #include <linux/udp.h>
  30 #include <linux/firewall.h>
  31 #include <linux/ip_fw.h>
  32 #include <net/checksum.h>
  33 #include <linux/route.h>
  34 #include <linux/mroute.h>
  35 #include <net/route.h>
  36 
  37 #include <asm/segment.h>
  38 
  39 #ifdef CONFIG_IP_MULTICAST
  40 
  41 /*
  42  *      Write an multicast group list table for the IGMP daemon to
  43  *      read.
  44  */
  45  
  46 int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48         off_t pos=0, begin=0;
  49         struct ip_mc_list *im;
  50         unsigned long flags;
  51         int len=0;
  52         struct device *dev;
  53         
  54         len=sprintf(buffer,"Device    : Count\tGroup    Users Timer\n");  
  55         save_flags(flags);
  56         cli();
  57         
  58         for(dev = dev_base; dev; dev = dev->next)
  59         {
  60                 if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST))
  61                 {
  62                         len+=sprintf(buffer+len,"%-10s: %5d\n",
  63                                         dev->name, dev->mc_count);
  64                         for(im = dev->ip_mc_list; im; im = im->next)
  65                         {
  66                                 len+=sprintf(buffer+len,
  67                                         "\t\t\t%08lX %5d %d:%08lX\n",
  68                                         im->multiaddr, im->users,
  69                                         im->tm_running, im->timer.expires-jiffies);
  70                                 pos=begin+len;
  71                                 if(pos<offset)
  72                                 {
  73                                         len=0;
  74                                         begin=pos;
  75                                 }
  76                                 if(pos>offset+length)
  77                                         break;
  78                         }
  79                 }
  80         }
  81         restore_flags(flags);
  82         *start=buffer+(offset-begin);
  83         len-=(offset-begin);
  84         if(len>length)
  85                 len=length;     
  86         return len;
  87 }
  88 
  89 
  90 /*
  91  *      Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
  92  *      an IP socket.
  93  *
  94  *      We implement IP_TOS (type of service), IP_TTL (time to live).
  95  */
  96 
  97 static struct device *ip_mc_find_devfor(unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99         struct device *dev;
 100         for(dev = dev_base; dev; dev = dev->next)
 101         {
 102                 if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
 103                         (dev->pa_addr==addr))
 104                         return dev;
 105         }
 106 
 107         return NULL;
 108 }
 109 
 110 #endif
 111 
 112 int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114         int val,err;
 115         unsigned char ucval;
 116 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
 117         struct ip_fw tmp_fw;
 118 #endif  
 119         if (optval == NULL)
 120         {
 121                 val=0;
 122                 ucval=0;
 123         }
 124         else
 125         {
 126                 err=verify_area(VERIFY_READ, optval, sizeof(int));
 127                 if(err)
 128                         return err;
 129                 val = get_user((int *) optval);
 130                 ucval=get_user((unsigned char *) optval);
 131         }
 132         
 133         if(level!=SOL_IP)
 134                 return -EOPNOTSUPP;
 135 #ifdef CONFIG_IP_MROUTE
 136         if(optname>=MRT_BASE && optname <=MRT_BASE+10)
 137         {
 138                 return ip_mroute_setsockopt(sk,optname,optval,optlen);
 139         }
 140 #endif
 141         
 142         switch(optname)
 143         {
 144                 case IP_OPTIONS:
 145                   {
 146                           struct options * opt = NULL;
 147                           struct options * old_opt;
 148                           if (optlen > 40 || optlen < 0)
 149                                 return -EINVAL;
 150                           err = verify_area(VERIFY_READ, optval, optlen);
 151                           if (err)
 152                                 return err;
 153                           opt = kmalloc(sizeof(struct options)+((optlen+3)&~3), GFP_KERNEL);
 154                           if (!opt)
 155                                 return -ENOMEM;
 156                           memset(opt, 0, sizeof(struct options));
 157                           if (optlen)
 158                                 memcpy_fromfs(opt->__data, optval, optlen);
 159                           while (optlen & 3)
 160                                 opt->__data[optlen++] = IPOPT_END;
 161                           opt->optlen = optlen;
 162                           opt->is_data = 1;
 163                           opt->is_setbyuser = 1;
 164                           if (optlen && ip_options_compile(opt, NULL)) 
 165                           {
 166                                   kfree_s(opt, sizeof(struct options) + optlen);
 167                                   return -EINVAL;
 168                           }
 169                           /*
 170                            * ANK: I'm afraid that receive handler may change
 171                            * options from under us.
 172                            */
 173                           cli();
 174                           old_opt = sk->opt;
 175                           sk->opt = opt;
 176                           sti();
 177                           if (old_opt)
 178                                 kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen);
 179                           return 0;
 180                   }
 181                 case IP_TOS:            /* This sets both TOS and Precedence */
 182                         if (val<0 || val>63)    /* Reject setting of unused bits */
 183                                 return -EINVAL;
 184                         if ((val&3) > 4 && !suser())    /* Only root can set Prec>4 */
 185                                 return -EPERM;
 186                         sk->ip_tos=val;
 187                         switch (val & 0x38) {
 188                                 case IPTOS_LOWDELAY:
 189                                         sk->priority=SOPRI_INTERACTIVE;
 190                                         break;
 191                                 case IPTOS_THROUGHPUT:
 192                                         sk->priority=SOPRI_BACKGROUND;
 193                                         break;
 194                                 default:
 195                                         sk->priority=SOPRI_NORMAL;
 196                                         break;
 197                         }
 198                         return 0;
 199                 case IP_TTL:
 200                         if(val<1||val>255)
 201                                 return -EINVAL;
 202                         sk->ip_ttl=val;
 203                         return 0;
 204                 case IP_HDRINCL:
 205                         if(sk->type!=SOCK_RAW)
 206                                 return -ENOPROTOOPT;
 207                         sk->ip_hdrincl=val?1:0;
 208                         return 0;
 209 #ifdef CONFIG_IP_MULTICAST
 210                 case IP_MULTICAST_TTL: 
 211                 {
 212                         sk->ip_mc_ttl=(int)ucval;
 213                         return 0;
 214                 }
 215                 case IP_MULTICAST_LOOP: 
 216                 {
 217                         if(ucval!=0 && ucval!=1)
 218                                  return -EINVAL;
 219                         sk->ip_mc_loop=(int)ucval;
 220                         return 0;
 221                 }
 222                 case IP_MULTICAST_IF: 
 223                 {
 224                         struct in_addr addr;
 225                         struct device *dev=NULL;
 226                         
 227                         /*
 228                          *      Check the arguments are allowable
 229                          */
 230 
 231                         err=verify_area(VERIFY_READ, optval, sizeof(addr));
 232                         if(err)
 233                                 return err;
 234                                 
 235                         memcpy_fromfs(&addr,optval,sizeof(addr));
 236                         
 237                         
 238                         /*
 239                          *      What address has been requested
 240                          */
 241                         
 242                         if(addr.s_addr==INADDR_ANY)     /* Default */
 243                         {
 244                                 sk->ip_mc_name[0]=0;
 245                                 return 0;
 246                         }
 247                         
 248                         /*
 249                          *      Find the device
 250                          */
 251                          
 252                         dev=ip_mc_find_devfor(addr.s_addr);
 253                                                 
 254                         /*
 255                          *      Did we find one
 256                          */
 257                          
 258                         if(dev) 
 259                         {
 260                                 strcpy(sk->ip_mc_name,dev->name);
 261                                 return 0;
 262                         }
 263                         return -EADDRNOTAVAIL;
 264                 }
 265                 
 266                 case IP_ADD_MEMBERSHIP: 
 267                 {
 268                 
 269 /*
 270  *      FIXME: Add/Del membership should have a semaphore protecting them from re-entry
 271  */
 272                         struct ip_mreq mreq;
 273                         __u32 route_src;
 274                         struct rtable *rt;
 275                         struct device *dev=NULL;
 276                         
 277                         /*
 278                          *      Check the arguments.
 279                          */
 280 
 281                         err=verify_area(VERIFY_READ, optval, sizeof(mreq));
 282                         if(err)
 283                                 return err;
 284 
 285                         memcpy_fromfs(&mreq,optval,sizeof(mreq));
 286 
 287                         /* 
 288                          *      Get device for use later
 289                          */
 290 
 291                         if(mreq.imr_interface.s_addr==INADDR_ANY) 
 292                         {
 293                                 /*
 294                                  *      Not set so scan.
 295                                  */
 296                                 if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL)
 297                                 {
 298                                         dev=rt->rt_dev;
 299                                         route_src = rt->rt_src;
 300                                         ATOMIC_DECR(&rt->rt_use);
 301                                         ip_rt_put(rt);
 302                                 }
 303                         }
 304                         else
 305                         {
 306                                 /*
 307                                  *      Find a suitable device.
 308                                  */
 309                                 
 310                                 dev=ip_mc_find_devfor(mreq.imr_interface.s_addr);
 311                         }
 312                         
 313                         /*
 314                          *      No device, no cookies.
 315                          */
 316                          
 317                         if(!dev)
 318                                 return -ENODEV;
 319                                 
 320                         /*
 321                          *      Join group.
 322                          */
 323                          
 324                         return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr);
 325                 }
 326                 
 327                 case IP_DROP_MEMBERSHIP: 
 328                 {
 329                         struct ip_mreq mreq;
 330                         struct rtable *rt;
 331                         __u32 route_src;
 332                         struct device *dev=NULL;
 333 
 334                         /*
 335                          *      Check the arguments
 336                          */
 337                          
 338                         err=verify_area(VERIFY_READ, optval, sizeof(mreq));
 339                         if(err)
 340                                 return err;
 341 
 342                         memcpy_fromfs(&mreq,optval,sizeof(mreq));
 343 
 344                         /*
 345                          *      Get device for use later 
 346                          */
 347  
 348                         if(mreq.imr_interface.s_addr==INADDR_ANY) 
 349                         {
 350                                 if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL)
 351                                 {
 352                                         dev=rt->rt_dev;
 353                                         ATOMIC_DECR(&rt->rt_use);
 354                                         route_src = rt->rt_src;
 355                                         ip_rt_put(rt);
 356                                 }
 357                         }
 358                         else 
 359                         {
 360                         
 361                                 dev=ip_mc_find_devfor(mreq.imr_interface.s_addr);
 362                         }
 363                         
 364                         /*
 365                          *      Did we find a suitable device.
 366                          */
 367                          
 368                         if(!dev)
 369                                 return -ENODEV;
 370                                 
 371                         /*
 372                          *      Leave group
 373                          */
 374                          
 375                         return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr);
 376                 }
 377 #endif                  
 378 #ifdef CONFIG_IP_FIREWALL
 379                 case IP_FW_INSERT_IN:
 380                 case IP_FW_INSERT_OUT:
 381                 case IP_FW_INSERT_FWD:
 382                 case IP_FW_APPEND_IN:
 383                 case IP_FW_APPEND_OUT:
 384                 case IP_FW_APPEND_FWD:
 385                 case IP_FW_DELETE_IN:
 386                 case IP_FW_DELETE_OUT:
 387                 case IP_FW_DELETE_FWD:
 388                 case IP_FW_CHECK_IN:
 389                 case IP_FW_CHECK_OUT:
 390                 case IP_FW_CHECK_FWD:
 391                 case IP_FW_FLUSH_IN:
 392                 case IP_FW_FLUSH_OUT:
 393                 case IP_FW_FLUSH_FWD:
 394                 case IP_FW_ZERO_IN:
 395                 case IP_FW_ZERO_OUT:
 396                 case IP_FW_ZERO_FWD:
 397                 case IP_FW_POLICY_IN:
 398                 case IP_FW_POLICY_OUT:
 399                 case IP_FW_POLICY_FWD:
 400                 case IP_FW_MASQ_TIMEOUTS:
 401                         if(!suser())
 402                                 return -EPERM;
 403                         if(optlen>sizeof(tmp_fw) || optlen<1)
 404                                 return -EINVAL;
 405                         err=verify_area(VERIFY_READ,optval,optlen);
 406                         if(err)
 407                                 return err;
 408                         memcpy_fromfs(&tmp_fw,optval,optlen);
 409                         err=ip_fw_ctl(optname, &tmp_fw,optlen);
 410                         return -err;    /* -0 is 0 after all */
 411                         
 412 #endif
 413 #ifdef CONFIG_IP_ACCT
 414                 case IP_ACCT_INSERT:
 415                 case IP_ACCT_APPEND:
 416                 case IP_ACCT_DELETE:
 417                 case IP_ACCT_FLUSH:
 418                 case IP_ACCT_ZERO:
 419                         if(!suser())
 420                                 return -EPERM;
 421                         if(optlen>sizeof(tmp_fw) || optlen<1)
 422                                 return -EINVAL;
 423                         err=verify_area(VERIFY_READ,optval,optlen);
 424                         if(err)
 425                                 return err;
 426                         memcpy_fromfs(&tmp_fw, optval,optlen);
 427                         err=ip_acct_ctl(optname, &tmp_fw,optlen);
 428                         return -err;    /* -0 is 0 after all */
 429 #endif
 430                 /* IP_OPTIONS and friends go here eventually */
 431                 default:
 432                         return(-ENOPROTOOPT);
 433         }
 434 }
 435 
 436 /*
 437  *      Get the options. Note for future reference. The GET of IP options gets the
 438  *      _received_ ones. The set sets the _sent_ ones.
 439  */
 440 
 441 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443         int val,err;
 444 #ifdef CONFIG_IP_MULTICAST
 445         int len;
 446 #endif
 447         
 448         if(level!=SOL_IP)
 449                 return -EOPNOTSUPP;
 450 
 451 #ifdef CONFIG_IP_MROUTE
 452         if(optname>=MRT_BASE && optname <=MRT_BASE+10)
 453         {
 454                 return ip_mroute_getsockopt(sk,optname,optval,optlen);
 455         }
 456 #endif
 457 
 458         switch(optname)
 459         {
 460                 case IP_OPTIONS:
 461                         {
 462                                 unsigned char optbuf[sizeof(struct options)+40];
 463                                 struct options * opt = (struct options*)optbuf;
 464                                 err = verify_area(VERIFY_WRITE, optlen, sizeof(int));
 465                                 if (err)
 466                                         return err;
 467                                 cli();
 468                                 opt->optlen = 0;
 469                                 if (sk->opt)
 470                                         memcpy(optbuf, sk->opt, sizeof(struct options)+sk->opt->optlen);
 471                                 sti();
 472                                 if (opt->optlen == 0) 
 473                                 {
 474                                         put_fs_long(0,(unsigned long *) optlen);
 475                                         return 0;
 476                                 }
 477                                 err = verify_area(VERIFY_WRITE, optval, opt->optlen);
 478                                 if (err)
 479                                         return err;
 480 /*
 481  * Now we should undo all the changes done by ip_options_compile().
 482  */
 483                                 if (opt->srr) 
 484                                 {
 485                                         unsigned  char * optptr = opt->__data+opt->srr-sizeof(struct  iphdr);
 486                                         memmove(optptr+7, optptr+3, optptr[1]-7);
 487                                         memcpy(optptr+3, &opt->faddr, 4);
 488                                 }
 489                                 if (opt->rr_needaddr) 
 490                                 {
 491                                         unsigned  char * optptr = opt->__data+opt->rr-sizeof(struct  iphdr);
 492                                         memset(&optptr[optptr[2]-1], 0, 4);
 493                                         optptr[2] -= 4;
 494                                 }
 495                                 if (opt->ts) 
 496                                 {
 497                                         unsigned  char * optptr = opt->__data+opt->ts-sizeof(struct  iphdr);
 498                                         if (opt->ts_needtime) 
 499                                         {
 500                                                 memset(&optptr[optptr[2]-1], 0, 4);
 501                                                 optptr[2] -= 4;
 502                                         }
 503                                         if (opt->ts_needaddr) 
 504                                         {
 505                                                 memset(&optptr[optptr[2]-1], 0, 4);
 506                                                 optptr[2] -= 4;
 507                                         }
 508                                 }
 509                                 put_fs_long(opt->optlen, (unsigned long *) optlen);
 510                                 memcpy_tofs(optval, opt->__data, opt->optlen);
 511                         }
 512                         return 0;
 513                 case IP_TOS:
 514                         val=sk->ip_tos;
 515                         break;
 516                 case IP_TTL:
 517                         val=sk->ip_ttl;
 518                         break;
 519                 case IP_HDRINCL:
 520                         val=sk->ip_hdrincl;
 521                         break;
 522 #ifdef CONFIG_IP_MULTICAST                      
 523                 case IP_MULTICAST_TTL:
 524                         val=sk->ip_mc_ttl;
 525                         break;
 526                 case IP_MULTICAST_LOOP:
 527                         val=sk->ip_mc_loop;
 528                         break;
 529                 case IP_MULTICAST_IF:
 530                         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 531                         if(err)
 532                                 return err;
 533                         len=strlen(sk->ip_mc_name);
 534                         err=verify_area(VERIFY_WRITE, optval, len);
 535                         if(err)
 536                                 return err;
 537                         put_user(len,(int *) optlen);
 538                         memcpy_tofs((void *)optval,sk->ip_mc_name, len);
 539                         return 0;
 540 #endif
 541                 default:
 542                         return(-ENOPROTOOPT);
 543         }
 544         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 545         if(err)
 546                 return err;
 547         put_user(sizeof(int),(int *) optlen);
 548 
 549         err=verify_area(VERIFY_WRITE, optval, sizeof(int));
 550         if(err)
 551                 return err;
 552         put_user(val,(int *) optval);
 553 
 554         return(0);
 555 }

/* [previous][next][first][last][top][bottom][index][help] */