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

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