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_INSERT_IN:
 370                 case IP_FW_INSERT_OUT:
 371                 case IP_FW_INSERT_FWD:
 372                 case IP_FW_APPEND_IN:
 373                 case IP_FW_APPEND_OUT:
 374                 case IP_FW_APPEND_FWD:
 375                 case IP_FW_DELETE_IN:
 376                 case IP_FW_DELETE_OUT:
 377                 case IP_FW_DELETE_FWD:
 378                 case IP_FW_CHECK_IN:
 379                 case IP_FW_CHECK_OUT:
 380                 case IP_FW_CHECK_FWD:
 381                 case IP_FW_FLUSH_IN:
 382                 case IP_FW_FLUSH_OUT:
 383                 case IP_FW_FLUSH_FWD:
 384                 case IP_FW_ZERO_IN:
 385                 case IP_FW_ZERO_OUT:
 386                 case IP_FW_ZERO_FWD:
 387                 case IP_FW_POLICY_IN:
 388                 case IP_FW_POLICY_OUT:
 389                 case IP_FW_POLICY_FWD:
 390                 case IP_FW_MASQ_TIMEOUTS:
 391                         if(!suser())
 392                                 return -EPERM;
 393                         if(optlen>sizeof(tmp_fw) || optlen<1)
 394                                 return -EINVAL;
 395                         err=verify_area(VERIFY_READ,optval,optlen);
 396                         if(err)
 397                                 return err;
 398                         memcpy_fromfs(&tmp_fw,optval,optlen);
 399                         err=ip_fw_ctl(optname, &tmp_fw,optlen);
 400                         return -err;    /* -0 is 0 after all */
 401                         
 402 #endif
 403 #ifdef CONFIG_IP_ACCT
 404                 case IP_ACCT_INSERT:
 405                 case IP_ACCT_APPEND:
 406                 case IP_ACCT_DELETE:
 407                 case IP_ACCT_FLUSH:
 408                 case IP_ACCT_ZERO:
 409                         if(!suser())
 410                                 return -EPERM;
 411                         if(optlen>sizeof(tmp_fw) || optlen<1)
 412                                 return -EINVAL;
 413                         err=verify_area(VERIFY_READ,optval,optlen);
 414                         if(err)
 415                                 return err;
 416                         memcpy_fromfs(&tmp_fw, optval,optlen);
 417                         err=ip_acct_ctl(optname, &tmp_fw,optlen);
 418                         return -err;    /* -0 is 0 after all */
 419 #endif
 420                 /* IP_OPTIONS and friends go here eventually */
 421                 default:
 422                         return(-ENOPROTOOPT);
 423         }
 424 }
 425 
 426 /*
 427  *      Get the options. Note for future reference. The GET of IP options gets the
 428  *      _received_ ones. The set sets the _sent_ ones.
 429  */
 430 
 431 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 432 {
 433         int val,err;
 434 #ifdef CONFIG_IP_MULTICAST
 435         int len;
 436 #endif
 437         
 438         if(level!=SOL_IP)
 439                 return -EOPNOTSUPP;
 440 
 441 #ifdef CONFIG_IP_MROUTE
 442         if(optname>=MRT_BASE && optname <=MRT_BASE+10)
 443         {
 444                 return ip_mroute_getsockopt(sk,optname,optval,optlen);
 445         }
 446 #endif
 447 
 448         switch(optname)
 449         {
 450                 case IP_OPTIONS:
 451                         {
 452                                 unsigned char optbuf[sizeof(struct options)+40];
 453                                 struct options * opt = (struct options*)optbuf;
 454                                 err = verify_area(VERIFY_WRITE, optlen, sizeof(int));
 455                                 if (err)
 456                                         return err;
 457                                 cli();
 458                                 opt->optlen = 0;
 459                                 if (sk->opt)
 460                                         memcpy(optbuf, sk->opt, sizeof(struct options)+sk->opt->optlen);
 461                                 sti();
 462                                 if (opt->optlen == 0) 
 463                                 {
 464                                         put_fs_long(0,(unsigned long *) optlen);
 465                                         return 0;
 466                                 }
 467                                 err = verify_area(VERIFY_WRITE, optval, opt->optlen);
 468                                 if (err)
 469                                         return err;
 470 /*
 471  * Now we should undo all the changes done by ip_options_compile().
 472  */
 473                                 if (opt->srr) 
 474                                 {
 475                                         unsigned  char * optptr = opt->__data+opt->srr-sizeof(struct  iphdr);
 476                                         memmove(optptr+7, optptr+3, optptr[1]-7);
 477                                         memcpy(optptr+3, &opt->faddr, 4);
 478                                 }
 479                                 if (opt->rr_needaddr) 
 480                                 {
 481                                         unsigned  char * optptr = opt->__data+opt->rr-sizeof(struct  iphdr);
 482                                         memset(&optptr[optptr[2]-1], 0, 4);
 483                                         optptr[2] -= 4;
 484                                 }
 485                                 if (opt->ts) 
 486                                 {
 487                                         unsigned  char * optptr = opt->__data+opt->ts-sizeof(struct  iphdr);
 488                                         if (opt->ts_needtime) 
 489                                         {
 490                                                 memset(&optptr[optptr[2]-1], 0, 4);
 491                                                 optptr[2] -= 4;
 492                                         }
 493                                         if (opt->ts_needaddr) 
 494                                         {
 495                                                 memset(&optptr[optptr[2]-1], 0, 4);
 496                                                 optptr[2] -= 4;
 497                                         }
 498                                 }
 499                                 put_fs_long(opt->optlen, (unsigned long *) optlen);
 500                                 memcpy_tofs(optval, opt->__data, opt->optlen);
 501                         }
 502                         return 0;
 503                 case IP_TOS:
 504                         val=sk->ip_tos;
 505                         break;
 506                 case IP_TTL:
 507                         val=sk->ip_ttl;
 508                         break;
 509                 case IP_HDRINCL:
 510                         val=sk->ip_hdrincl;
 511                         break;
 512 #ifdef CONFIG_IP_MULTICAST                      
 513                 case IP_MULTICAST_TTL:
 514                         val=sk->ip_mc_ttl;
 515                         break;
 516                 case IP_MULTICAST_LOOP:
 517                         val=sk->ip_mc_loop;
 518                         break;
 519                 case IP_MULTICAST_IF:
 520                         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 521                         if(err)
 522                                 return err;
 523                         len=strlen(sk->ip_mc_name);
 524                         err=verify_area(VERIFY_WRITE, optval, len);
 525                         if(err)
 526                                 return err;
 527                         put_user(len,(int *) optlen);
 528                         memcpy_tofs((void *)optval,sk->ip_mc_name, len);
 529                         return 0;
 530 #endif
 531                 default:
 532                         return(-ENOPROTOOPT);
 533         }
 534         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 535         if(err)
 536                 return err;
 537         put_user(sizeof(int),(int *) optlen);
 538 
 539         err=verify_area(VERIFY_WRITE, optval, sizeof(int));
 540         if(err)
 541                 return err;
 542         put_user(val,(int *) optval);
 543 
 544         return(0);
 545 }

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