root/net/ipv4/ipmr.c

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

DEFINITIONS

This source file includes following definitions.
  1. ip_mroute_setsockopt
  2. ip_mroute_getsockopt
  3. ipmr_ioctl
  4. mroute_close

   1 /*
   2  *      IP multicast routing support for mrouted 3.6
   3  *
   4  *              (c) 1995 Alan Cox, <alan@cymru.net>
   5  *        Linux Consultancy and Custom Driver Development
   6  *
   7  *      This program is free software; you can redistribute it and/or
   8  *      modify it under the terms of the GNU General Public License
   9  *      as published by the Free Software Foundation; either version
  10  *      2 of the License, or (at your option) any later version.
  11  */
  12 
  13 #include <asm/system.h>
  14 #include <asm/segment.h>
  15 #include <linux/types.h>
  16 #include <linux/sched.h>
  17 #include <linux/errno.h>
  18 #include <linux/timer.h>
  19 #include <linux/mm.h>
  20 #include <linux/kernel.h>
  21 #include <linux/fcntl.h>
  22 #include <linux/socket.h>
  23 #include <linux/in.h>
  24 #include <linux/inet.h>
  25 #include <linux/netdevice.h>
  26 #include <linux/mroute.h>
  27 #include <net/ip.h>
  28 #include <net/protocol.h>
  29 #include <linux/skbuff.h>
  30 #include <net/sock.h>
  31 #include <net/icmp.h>
  32 #include <net/udp.h>
  33 #include <net/checksum.h>
  34 
  35 #ifdef CONFIG_IP_MROUTE
  36 
  37 /*
  38  *      Multicast router conrol variables
  39  */
  40 
  41 static struct vif_device vif_table[MAXVIFS];
  42 static unsigned long vifc_map;
  43 int mroute_do_pim = 0;
  44  
  45 /*
  46  *      Socket options and virtual interface manipulation. The whole
  47  *      virtual interface system is a complete heap, but unfortunately
  48  *      thats how BSD mrouted happens to think. Maybe one day with a proper
  49  *      MOSPF/PIM router set up we can clean this up.
  50  */
  51  
  52 int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54         int err;
  55         struct vifctl vif;
  56         
  57         if(optname!=MRT_INIT)
  58         {
  59                 if(sk!=mroute_socket)
  60                         return -EACCES;
  61         }
  62         
  63         switch(optname)
  64         {
  65                 case MRT_INIT:
  66                         if(sk->type!=SOCK_RAW || sk->num!=IPPROTO_IGMP)
  67                                 return -EOPNOTSUPP;
  68                         if(optlen!=sizeof(int))
  69                                 return -ENOPROTOOPT;
  70                         if((err=verify_area(VERIFY_READ,optval,sizeof(int)))<0)
  71                                 return err;
  72                         if(get_user((int *)optval)!=1)
  73                                 return -ENOPROTOOPT;
  74                         if(mroute_socket)
  75                                 return -EADDRINUSE;
  76                         mroute_socket=sk;
  77                         /* Initialise state */
  78                         return 0;
  79                 case MRT_DONE:
  80                         mroute_close(sk);
  81                         mroute_socket=NULL;
  82                         return 0;
  83                 case MRT_ADD_VIF:
  84                 case MRT_DEL_VIF:
  85                         if(optlen!=sizeof(vif))
  86                                 return -EINVAL;
  87                         if((err=verify_area(VERIFY_READ, optval, sizeof(vif)))<0)
  88                                 return err;
  89                         memcpy_fromfs(&vif,optval,sizeof(vif));
  90                         if(vif.vifc_vifi > MAXVIFS)
  91                                 return -ENFILE;
  92                         if(optname==MRT_ADD_VIF)
  93                         {
  94                                 struct vif_device *v=&vif_table[vif.vifc_vifi];
  95                                 struct device *dev;
  96                                 /* Empty vif ? */
  97                                 if(vifc_map&(1<<vif.vifc_vifi))
  98                                         return -EADDRINUSE;
  99                                 /* Find the interface */
 100                                 dev=ip_dev_find(vif.vifc_lcl_addr.s_addr);
 101                                 if(!dev)
 102                                         return -EADDRNOTAVAIL;
 103                                 /* Must be tunnelled or multicastable */
 104                                 if(vif.vifc_flags&VIFF_TUNNEL)
 105                                 {
 106                                         if(vif.vifc_flags&VIFF_SRCRT)
 107                                                 return -EOPNOTSUPP;
 108                                         /* IPIP will do all the work */
 109                                 }
 110                                 else
 111                                 {
 112                                         if(dev->flags&IFF_MULTICAST)
 113                                         {
 114                                                 /* Most ethernet cards dont know
 115                                                    how to do this yet.. */
 116                                                 dev->flags|=IFF_ALLMULTI;
 117                                                 dev_mc_upload(dev);
 118                                         }
 119                                         else
 120                                         {
 121                                                 /* We are stuck.. */
 122                                                 return -EOPNOTSUPP;
 123                                         }
 124                                 }
 125                                 /*
 126                                  *      Fill in the VIF structures
 127                                  */
 128                                 cli();
 129                                 v->rate_limit=vif.vifc_rate_limit;
 130                                 v->local=vif.vifc_lcl_addr.s_addr;
 131                                 v->remote=vif.vifc_rmt_addr.s_addr;
 132                                 v->flags=vif.vifc_flags;
 133                                 v->threshold=vif.vifc_threshold;
 134                                 v->dev=dev;
 135                                 v->bytes_in = 0;
 136                                 v->bytes_out = 0;
 137                                 v->pkt_in = 0;
 138                                 v->pkt_out = 0;
 139                                 vifc_map|=(1<<vif.vifc_vifi);
 140                                 sti();
 141                                 return 0;
 142                         }
 143                         else
 144                         /*
 145                          *      VIF deletion
 146                          */
 147                         {
 148                                 struct vif_device *v=&vif_table[vif.vifc_vifi];
 149                                 if(vifc_map&(1<<vif.vifc_vifi))
 150                                 {
 151                                         if(!(v->flags&VIFF_TUNNEL))
 152                                         {
 153                                                 v->dev->flags&=~IFF_ALLMULTI;
 154                                                 dev_mc_upload(v->dev);
 155                                         }
 156                                         vifc_map&=~(1<<vif.vifc_vifi);
 157                                         return 0;                                       
 158                                 }
 159                                 else
 160                                         return -EADDRNOTAVAIL;
 161                         }
 162                 /*
 163                  *      Manipulate the forwarding caches. These live
 164                  *      in a sort of kernel/user symbiosis.
 165                  */
 166                 case MRT_ADD_MFC:
 167                 case MRT_DEL_MFC:
 168                         return -EOPNOTSUPP;
 169                 /*
 170                  *      Control PIM assert.
 171                  */
 172                 case MRT_ASSERT:
 173                         if(optlen!=sizeof(int))
 174                                 return -EINVAL;
 175                         if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0)
 176                                 return err;
 177                         mroute_do_pim= (optval)?1:0;
 178                         return 0;
 179                 /*
 180                  *      Spurious command, or MRT_VERSION which you cannot
 181                  *      set.
 182                  */
 183                 default:
 184                         return -EOPNOTSUPP;
 185         }
 186 }
 187 
 188 /*
 189  *      Getsock opt support for the multicast routing system.
 190  */
 191  
 192 int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         int olr;
 195         int err;
 196 
 197         if(sk!=mroute_socket)
 198                 return -EACCES;
 199         if(optname!=MRT_VERSION && optname!=MRT_ASSERT)
 200                 return -EOPNOTSUPP;
 201         
 202         olr=get_user(optlen);
 203         if(olr!=sizeof(int))
 204                 return -EINVAL;
 205         err=verify_area(VERIFY_WRITE, optval,sizeof(int));
 206         if(err)
 207                 return err;
 208         put_user(sizeof(int),optlen);
 209         if(optname==MRT_VERSION)
 210                 put_user(0x0305,(int *)optval);
 211         else
 212                 put_user(mroute_do_pim,(int *)optval);
 213         return 0;
 214 }
 215 
 216 /*
 217  *      The IP multicast ioctl support routines.
 218  */
 219  
 220 int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222         int err;
 223         struct sioc_sg_req sr;
 224         struct sioc_vif_req vr;
 225         struct vif_device *vif;
 226         
 227         switch(cmd)
 228         {
 229                 case SIOCGETVIFCNT:
 230                         err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(vr));
 231                         if(err)
 232                                 return err;
 233                         memcpy_fromfs(&vr,(void *)arg,sizeof(sr));
 234                         if(vr.vifi>=MAXVIFS)
 235                                 return -EINVAL;
 236                         vif=&vif_table[vr.vifi];
 237                         if(vifc_map&(1<<vr.vifi))
 238                         {
 239                                 vr.icount=vif->pkt_in;
 240                                 vr.ocount=vif->pkt_out;
 241                                 vr.ibytes=vif->bytes_in;
 242                                 vr.obytes=vif->bytes_out;
 243                                 memcpy_tofs((void *)arg,&vr,sizeof(sr));
 244                                 return 0;
 245                         }
 246                         return -EADDRNOTAVAIL;
 247                 case SIOCGETSGCNT:
 248                         err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(sr));
 249                         if(err)
 250                                 return err;
 251                         memcpy_fromfs(&sr,(void *)arg,sizeof(sr));
 252                         memcpy_tofs((void *)arg,&sr,sizeof(sr));
 253                         return 0;
 254                 default:
 255                         return -EINVAL;
 256         }
 257 }
 258 
 259 /*
 260  *      Close the multicast socket, and clear the vif tables etc
 261  */
 262  
 263 void mroute_close(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265         int i;
 266         struct vif_device *v=&vif_table[0];
 267                 
 268         /*
 269          *      Shut down all active vif entries
 270          */
 271          
 272         for(i=0;i<MAXVIFS;i++)
 273         {
 274                 if(vifc_map&(1<<i))
 275                 {
 276                         if(!(v->flags&VIFF_TUNNEL))
 277                         {
 278                                 v->dev->flags&=~IFF_ALLMULTI;
 279                                 dev_mc_upload(v->dev);
 280                         }
 281                 }
 282                 v++;
 283         }               
 284         vifc_map=0;     
 285 }
 286 
 287 #endif

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