root/net/ipv4/ipmr.c

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

DEFINITIONS

This source file includes following definitions.
  1. vif_delete
  2. ip_mroute_setsockopt
  3. ip_mroute_getsockopt
  4. ipmr_ioctl
  5. mroute_close
  6. ipmr_device_event
  7. ip_mr_init

   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  *      Fixes:
  14  *      Michael Chastain        :       Incorrect size of copying.
  15  *
  16  *
  17  *      Status:
  18  *              Tree building works. Cache manager to be added next.
  19  */
  20 
  21 #include <asm/system.h>
  22 #include <asm/segment.h>
  23 #include <linux/types.h>
  24 #include <linux/sched.h>
  25 #include <linux/errno.h>
  26 #include <linux/timer.h>
  27 #include <linux/mm.h>
  28 #include <linux/kernel.h>
  29 #include <linux/fcntl.h>
  30 #include <linux/socket.h>
  31 #include <linux/in.h>
  32 #include <linux/inet.h>
  33 #include <linux/netdevice.h>
  34 #include <linux/mroute.h>
  35 #include <net/ip.h>
  36 #include <net/protocol.h>
  37 #include <linux/skbuff.h>
  38 #include <net/sock.h>
  39 #include <net/icmp.h>
  40 #include <net/udp.h>
  41 #include <linux/notifier.h>
  42 #include <net/checksum.h>
  43 
  44 #ifdef CONFIG_IP_MROUTE
  45 
  46 /*
  47  *      Multicast router conrol variables
  48  */
  49 
  50 static struct vif_device vif_table[MAXVIFS];
  51 static unsigned long vifc_map;
  52 int mroute_do_pim = 0;
  53 
  54 /*
  55  *      Delete a VIF entry
  56  */
  57  
  58 static void vif_delete(struct vif_device *v)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60         if(!(v->flags&VIFF_TUNNEL))
  61         {
  62                 v->dev->flags&=~IFF_ALLMULTI;
  63                 dev_mc_upload(v->dev);
  64         }
  65         v->dev=NULL;
  66 }
  67  
  68 /*
  69  *      Socket options and virtual interface manipulation. The whole
  70  *      virtual interface system is a complete heap, but unfortunately
  71  *      thats how BSD mrouted happens to think. Maybe one day with a proper
  72  *      MOSPF/PIM router set up we can clean this up.
  73  */
  74  
  75 int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         int err;
  78         struct vifctl vif;
  79         
  80         if(optname!=MRT_INIT)
  81         {
  82                 if(sk!=mroute_socket)
  83                         return -EACCES;
  84         }
  85         
  86         switch(optname)
  87         {
  88                 case MRT_INIT:
  89                         if(sk->type!=SOCK_RAW || sk->num!=IPPROTO_IGMP)
  90                                 return -EOPNOTSUPP;
  91                         if(optlen!=sizeof(int))
  92                                 return -ENOPROTOOPT;
  93                         if((err=verify_area(VERIFY_READ,optval,sizeof(int)))<0)
  94                                 return err;
  95                         if(get_user((int *)optval)!=1)
  96                                 return -ENOPROTOOPT;
  97                         if(mroute_socket)
  98                                 return -EADDRINUSE;
  99                         mroute_socket=sk;
 100                         /* Initialise state */
 101                         return 0;
 102                 case MRT_DONE:
 103                         mroute_close(sk);
 104                         mroute_socket=NULL;
 105                         return 0;
 106                 case MRT_ADD_VIF:
 107                 case MRT_DEL_VIF:
 108                         if(optlen!=sizeof(vif))
 109                                 return -EINVAL;
 110                         if((err=verify_area(VERIFY_READ, optval, sizeof(vif)))<0)
 111                                 return err;
 112                         memcpy_fromfs(&vif,optval,sizeof(vif));
 113                         if(vif.vifc_vifi > MAXVIFS)
 114                                 return -ENFILE;
 115                         if(optname==MRT_ADD_VIF)
 116                         {
 117                                 struct vif_device *v=&vif_table[vif.vifc_vifi];
 118                                 struct device *dev;
 119                                 /* Empty vif ? */
 120                                 if(vifc_map&(1<<vif.vifc_vifi))
 121                                         return -EADDRINUSE;
 122                                 /* Find the interface */
 123                                 dev=ip_dev_find(vif.vifc_lcl_addr.s_addr);
 124                                 if(!dev)
 125                                         return -EADDRNOTAVAIL;
 126                                 /* Must be tunnelled or multicastable */
 127                                 if(vif.vifc_flags&VIFF_TUNNEL)
 128                                 {
 129                                         if(vif.vifc_flags&VIFF_SRCRT)
 130                                                 return -EOPNOTSUPP;
 131                                         /* IPIP will do all the work */
 132                                 }
 133                                 else
 134                                 {
 135                                         if(dev->flags&IFF_MULTICAST)
 136                                         {
 137                                                 /* Most ethernet cards dont know
 138                                                    how to do this yet.. */
 139                                                 dev->flags|=IFF_ALLMULTI;
 140                                                 dev_mc_upload(dev);
 141                                         }
 142                                         else
 143                                         {
 144                                                 /* We are stuck.. */
 145                                                 return -EOPNOTSUPP;
 146                                         }
 147                                 }
 148                                 /*
 149                                  *      Fill in the VIF structures
 150                                  */
 151                                 cli();
 152                                 v->rate_limit=vif.vifc_rate_limit;
 153                                 v->local=vif.vifc_lcl_addr.s_addr;
 154                                 v->remote=vif.vifc_rmt_addr.s_addr;
 155                                 v->flags=vif.vifc_flags;
 156                                 v->threshold=vif.vifc_threshold;
 157                                 v->dev=dev;
 158                                 v->bytes_in = 0;
 159                                 v->bytes_out = 0;
 160                                 v->pkt_in = 0;
 161                                 v->pkt_out = 0;
 162                                 vifc_map|=(1<<vif.vifc_vifi);
 163                                 sti();
 164                                 return 0;
 165                         }
 166                         else
 167                         /*
 168                          *      VIF deletion
 169                          */
 170                         {
 171                                 struct vif_device *v=&vif_table[vif.vifc_vifi];
 172                                 if(vifc_map&(1<<vif.vifc_vifi))
 173                                 {
 174                                         vif_delete(v);
 175                                         vifc_map&=~(1<<vif.vifc_vifi);
 176                                         return 0;                                       
 177                                 }
 178                                 else
 179                                         return -EADDRNOTAVAIL;
 180                         }
 181                 /*
 182                  *      Manipulate the forwarding caches. These live
 183                  *      in a sort of kernel/user symbiosis.
 184                  */
 185                 case MRT_ADD_MFC:
 186                 case MRT_DEL_MFC:
 187                         return -EOPNOTSUPP;
 188                 /*
 189                  *      Control PIM assert.
 190                  */
 191                 case MRT_ASSERT:
 192                         if(optlen!=sizeof(int))
 193                                 return -EINVAL;
 194                         if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0)
 195                                 return err;
 196                         mroute_do_pim= (optval)?1:0;
 197                         return 0;
 198                 /*
 199                  *      Spurious command, or MRT_VERSION which you cannot
 200                  *      set.
 201                  */
 202                 default:
 203                         return -EOPNOTSUPP;
 204         }
 205 }
 206 
 207 /*
 208  *      Getsock opt support for the multicast routing system.
 209  */
 210  
 211 int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213         int olr;
 214         int err;
 215 
 216         if(sk!=mroute_socket)
 217                 return -EACCES;
 218         if(optname!=MRT_VERSION && optname!=MRT_ASSERT)
 219                 return -EOPNOTSUPP;
 220         
 221         olr=get_user(optlen);
 222         if(olr!=sizeof(int))
 223                 return -EINVAL;
 224         err=verify_area(VERIFY_WRITE, optval,sizeof(int));
 225         if(err)
 226                 return err;
 227         put_user(sizeof(int),optlen);
 228         if(optname==MRT_VERSION)
 229                 put_user(0x0305,(int *)optval);
 230         else
 231                 put_user(mroute_do_pim,(int *)optval);
 232         return 0;
 233 }
 234 
 235 /*
 236  *      The IP multicast ioctl support routines.
 237  */
 238  
 239 int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241         int err;
 242         struct sioc_sg_req sr;
 243         struct sioc_vif_req vr;
 244         struct vif_device *vif;
 245         
 246         switch(cmd)
 247         {
 248                 case SIOCGETVIFCNT:
 249                         err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(vr));
 250                         if(err)
 251                                 return err;
 252                         memcpy_fromfs(&vr,(void *)arg,sizeof(vr));
 253                         if(vr.vifi>=MAXVIFS)
 254                                 return -EINVAL;
 255                         vif=&vif_table[vr.vifi];
 256                         if(vifc_map&(1<<vr.vifi))
 257                         {
 258                                 vr.icount=vif->pkt_in;
 259                                 vr.ocount=vif->pkt_out;
 260                                 vr.ibytes=vif->bytes_in;
 261                                 vr.obytes=vif->bytes_out;
 262                                 memcpy_tofs((void *)arg,&vr,sizeof(vr));
 263                                 return 0;
 264                         }
 265                         return -EADDRNOTAVAIL;
 266                 case SIOCGETSGCNT:
 267                         err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(sr));
 268                         if(err)
 269                                 return err;
 270                         memcpy_fromfs(&sr,(void *)arg,sizeof(sr));
 271                         memcpy_tofs((void *)arg,&sr,sizeof(sr));
 272                         return 0;
 273                 default:
 274                         return -EINVAL;
 275         }
 276 }
 277 
 278 /*
 279  *      Close the multicast socket, and clear the vif tables etc
 280  */
 281  
 282 void mroute_close(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284         int i;
 285         struct vif_device *v=&vif_table[0];
 286                 
 287         /*
 288          *      Shut down all active vif entries
 289          */
 290          
 291         for(i=0;i<MAXVIFS;i++)
 292         {
 293                 if(vifc_map&(1<<i))
 294                 {
 295                         if(!(v->flags&VIFF_TUNNEL))
 296                         {
 297                                 v->dev->flags&=~IFF_ALLMULTI;
 298                                 dev_mc_upload(v->dev);
 299                         }
 300                 }
 301                 v++;
 302         }               
 303         vifc_map=0;     
 304 }
 305 
 306 static int ipmr_device_event(unsigned long event, void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308         struct vif_device *v;
 309         int ct;
 310         if(event!=NETDEV_DOWN)
 311                 return NOTIFY_DONE;
 312         v=&vif_table[0];
 313         for(ct=0;ct<MAXVIFS;ct++)
 314         {
 315                 if((vifc_map&(1<<ct)) && v->dev==ptr)
 316                 {
 317                         vif_delete(v);
 318                         vifc_map&=~(1<<ct);
 319                 }
 320                 v++;
 321         }
 322         return NOTIFY_DONE;
 323 }
 324 
 325 
 326 static struct notifier_block ip_mr_notifier={
 327         ipmr_device_event,
 328         NULL,
 329         0
 330 };
 331         
 332 
 333 void ip_mr_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 334 {
 335         printk("Linux IP multicast router 0.00pre-working 8)\n");
 336         register_netdevice_notifier(&ip_mr_notifier);
 337 }
 338 
 339 #endif

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