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

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