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,0))!=NULL)
 287                                 {
 288                                         dev=rt->rt_dev;
 289                                         route_src = rt->rt_src;
 290                                         ATOMIC_DECR(&rt->rt_use);
 291                                         ip_rt_put(rt);
 292                                 }
 293                         }
 294                         else
 295                         {
 296                                 /*
 297                                  *      Find a suitable device.
 298                                  */
 299                                 
 300                                 dev=ip_mc_find_devfor(mreq.imr_interface.s_addr);
 301                         }
 302                         
 303                         /*
 304                          *      No device, no cookies.
 305                          */
 306                          
 307                         if(!dev)
 308                                 return -ENODEV;
 309                                 
 310                         /*
 311                          *      Join group.
 312                          */
 313                          
 314                         return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr);
 315                 }
 316                 
 317                 case IP_DROP_MEMBERSHIP: 
 318                 {
 319                         struct ip_mreq mreq;
 320                         struct rtable *rt;
 321                         __u32 route_src;
 322                         struct device *dev=NULL;
 323 
 324                         /*
 325                          *      Check the arguments
 326                          */
 327                          
 328                         err=verify_area(VERIFY_READ, optval, sizeof(mreq));
 329                         if(err)
 330                                 return err;
 331 
 332                         memcpy_fromfs(&mreq,optval,sizeof(mreq));
 333 
 334                         /*
 335                          *      Get device for use later 
 336                          */
 337  
 338                         if(mreq.imr_interface.s_addr==INADDR_ANY) 
 339                         {
 340                                 if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL)
 341                                 {
 342                                         dev=rt->rt_dev;
 343                                         ATOMIC_DECR(&rt->rt_use);
 344                                         route_src = rt->rt_src;
 345                                         ip_rt_put(rt);
 346                                 }
 347                         }
 348                         else 
 349                         {
 350                         
 351                                 dev=ip_mc_find_devfor(mreq.imr_interface.s_addr);
 352                         }
 353                         
 354                         /*
 355                          *      Did we find a suitable device.
 356                          */
 357                          
 358                         if(!dev)
 359                                 return -ENODEV;
 360                                 
 361                         /*
 362                          *      Leave group
 363                          */
 364                          
 365                         return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr);
 366                 }
 367 #endif                  
 368 #ifdef CONFIG_IP_FIREWALL
 369                 case IP_FW_ADD_BLK:
 370                 case IP_FW_DEL_BLK:
 371                 case IP_FW_ADD_FWD:
 372                 case IP_FW_DEL_FWD:
 373                 case IP_FW_CHK_BLK:
 374                 case IP_FW_CHK_FWD:
 375                 case IP_FW_FLUSH_BLK:
 376                 case IP_FW_FLUSH_FWD:
 377                 case IP_FW_ZERO_BLK:
 378                 case IP_FW_ZERO_FWD:
 379                 case IP_FW_POLICY_BLK:
 380                 case IP_FW_POLICY_FWD:
 381                         if(!suser())
 382                                 return -EPERM;
 383                         if(optlen>sizeof(tmp_fw) || optlen<1)
 384                                 return -EINVAL;
 385                         err=verify_area(VERIFY_READ,optval,optlen);
 386                         if(err)
 387                                 return err;
 388                         memcpy_fromfs(&tmp_fw,optval,optlen);
 389                         err=ip_fw_ctl(optname, &tmp_fw,optlen);
 390                         return -err;    /* -0 is 0 after all */
 391                         
 392 #endif
 393 #ifdef CONFIG_IP_ACCT
 394                 case IP_ACCT_DEL:
 395                 case IP_ACCT_ADD:
 396                 case IP_ACCT_FLUSH:
 397                 case IP_ACCT_ZERO:
 398                         if(!suser())
 399                                 return -EPERM;
 400                         if(optlen>sizeof(tmp_fw) || optlen<1)
 401                                 return -EINVAL;
 402                         err=verify_area(VERIFY_READ,optval,optlen);
 403                         if(err)
 404                                 return err;
 405                         memcpy_fromfs(&tmp_fw, optval,optlen);
 406                         err=ip_acct_ctl(optname, &tmp_fw,optlen);
 407                         return -err;    /* -0 is 0 after all */
 408 #endif
 409                 /* IP_OPTIONS and friends go here eventually */
 410                 default:
 411                         return(-ENOPROTOOPT);
 412         }
 413 }
 414 
 415 /*
 416  *      Get the options. Note for future reference. The GET of IP options gets the
 417  *      _received_ ones. The set sets the _sent_ ones.
 418  */
 419 
 420 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 421 {
 422         int val,err;
 423 #ifdef CONFIG_IP_MULTICAST
 424         int len;
 425 #endif
 426         
 427         if(level!=SOL_IP)
 428                 return -EOPNOTSUPP;
 429 
 430 #ifdef CONFIG_IP_MROUTE
 431         if(optname>=MRT_BASE && optname <=MRT_BASE+10)
 432         {
 433                 return ip_mroute_getsockopt(sk,optname,optval,optlen);
 434         }
 435 #endif
 436 
 437         switch(optname)
 438         {
 439                 case IP_OPTIONS:
 440                         {
 441                                 unsigned char optbuf[sizeof(struct options)+40];
 442                                 struct options * opt = (struct options*)optbuf;
 443                                 err = verify_area(VERIFY_WRITE, optlen, sizeof(int));
 444                                 if (err)
 445                                         return err;
 446                                 cli();
 447                                 opt->optlen = 0;
 448                                 if (sk->opt)
 449                                         memcpy(optbuf, sk->opt, sizeof(struct options)+sk->opt->optlen);
 450                                 sti();
 451                                 if (opt->optlen == 0) 
 452                                 {
 453                                         put_fs_long(0,(unsigned long *) optlen);
 454                                         return 0;
 455                                 }
 456                                 err = verify_area(VERIFY_WRITE, optval, opt->optlen);
 457                                 if (err)
 458                                         return err;
 459 /*
 460  * Now we should undo all the changes done by ip_options_compile().
 461  */
 462                                 if (opt->srr) 
 463                                 {
 464                                         unsigned  char * optptr = opt->__data+opt->srr-sizeof(struct  iphdr);
 465                                         memmove(optptr+7, optptr+4, optptr[1]-7);
 466                                         memcpy(optptr+3, &opt->faddr, 4);
 467                                 }
 468                                 if (opt->rr_needaddr) 
 469                                 {
 470                                         unsigned  char * optptr = opt->__data+opt->rr-sizeof(struct  iphdr);
 471                                         memset(&optptr[optptr[2]-1], 0, 4);
 472                                         optptr[2] -= 4;
 473                                 }
 474                                 if (opt->ts) 
 475                                 {
 476                                         unsigned  char * optptr = opt->__data+opt->ts-sizeof(struct  iphdr);
 477                                         if (opt->ts_needtime) 
 478                                         {
 479                                                 memset(&optptr[optptr[2]-1], 0, 4);
 480                                                 optptr[2] -= 4;
 481                                         }
 482                                         if (opt->ts_needaddr) 
 483                                         {
 484                                                 memset(&optptr[optptr[2]-1], 0, 4);
 485                                                 optptr[2] -= 4;
 486                                         }
 487                                 }
 488                                 put_fs_long(opt->optlen, (unsigned long *) optlen);
 489                                 memcpy_tofs(optval, opt->__data, opt->optlen);
 490                         }
 491                         return 0;
 492                 case IP_TOS:
 493                         val=sk->ip_tos;
 494                         break;
 495                 case IP_TTL:
 496                         val=sk->ip_ttl;
 497                         break;
 498                 case IP_HDRINCL:
 499                         val=sk->ip_hdrincl;
 500                         break;
 501 #ifdef CONFIG_IP_MULTICAST                      
 502                 case IP_MULTICAST_TTL:
 503                         val=sk->ip_mc_ttl;
 504                         break;
 505                 case IP_MULTICAST_LOOP:
 506                         val=sk->ip_mc_loop;
 507                         break;
 508                 case IP_MULTICAST_IF:
 509                         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 510                         if(err)
 511                                 return err;
 512                         len=strlen(sk->ip_mc_name);
 513                         err=verify_area(VERIFY_WRITE, optval, len);
 514                         if(err)
 515                                 return err;
 516                         put_user(len,(int *) optlen);
 517                         memcpy_tofs((void *)optval,sk->ip_mc_name, len);
 518                         return 0;
 519 #endif
 520                 default:
 521                         return(-ENOPROTOOPT);
 522         }
 523         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 524         if(err)
 525                 return err;
 526         put_user(sizeof(int),(int *) optlen);
 527 
 528         err=verify_area(VERIFY_WRITE, optval, sizeof(int));
 529         if(err)
 530                 return err;
 531         put_user(val,(int *) optval);
 532 
 533         return(0);
 534 }

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