nexmon – Rev 1

Subversion Repositories:
Rev:
/* Note : this particular snipset of code is available under
 * the LGPL, MPL or BSD license (at your choice).
 * Jean II
 */

/* --------------------------- INCLUDE --------------------------- */

#define MAX_KEY_SIZE    16
#define MAX_KEYS        8
int     key_on = 0;
int     key_open = 1;
int     key_current = 0;
char    key_table[MAX_KEYS][MAX_KEY_SIZE];
int     key_size[MAX_KEYS];

/* --------------------------- HANDLERS --------------------------- */

static int ioctl_set_encode(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_point *erq,
                            char *key)
{
  int   index = (erq->flags & IW_ENCODE_INDEX) - 1;

  if (erq->length > 0)
    {
      /* Check the size of the key */
      if(erq->length > MAX_KEY_SIZE)
        return(-EINVAL);

      /* Check the index */
      if((index < 0) || (index >= MAX_KEYS))
        index = key_current;

      /* Copy the key in the driver */
      memcpy(key_table[index], key, erq->length);
      key_size[index] = erq->length;
      key_on = 1;
    }
  else
    {
      /* Do we want to just set the current key ? */
      if((index >= 0) && (index < MAX_KEYS))
        {
          if(key_size[index] > 0)
            {
              key_current = index;
              key_on = 1;
            }
          else
            return(-EINVAL);
        }
    }

  /* Read the flags */
  if(erq->flags & IW_ENCODE_DISABLED)
    key_on = 0;         /* disable encryption */
  if(erq->flags & IW_ENCODE_RESTRICTED)
    key_open = 0;       /* disable open mode */
  if(erq->flags & IW_ENCODE_OPEN)
    key_open = 1;       /* enable open mode */

  return(0);
}

static int ioctl_get_encode(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_point *erq,
                            char *key)
{
  int   index = (erq->flags & IW_ENCODE_INDEX) - 1;

  /* Set the flags */
  erq->flags = 0;
  if(key_on == 0)
    erq->flags |= IW_ENCODE_DISABLED;
  if(key_open == 0)
    erq->flags |= IW_ENCODE_RESTRICTED;
  else
    erq->flags |= IW_ENCODE_OPEN;

  /* Which key do we want */
  if((index < 0) || (index >= MAX_KEYS))
    index = key_current;
  erq->flags |= index + 1;

  /* Copy the key to the user buffer */
  erq->length = key_size[index];
  memcpy(key, key_table[index], key_size[index]);

  return(0);
}

static int ioctl_get_range(struct net_device *dev,
                           struct iw_request_info *info,
                           struct iw_point *rrq,
                           char *extra)
{
  struct iw_range *range = (struct iw_range *) extra;

  rrq->length = sizeof(struct iw_range);

  memset(range, 0, sizeof(struct iw_range));

#if WIRELESS_EXT > 10
  /* Version we are compiled with */
  range->we_version_compiled = WIRELESS_EXT;
  /* Minimum version we recommend */
  range->we_version_source = 8;
#endif /* WIRELESS_EXT > 10 */

#if WIRELESS_EXT > 8
  range->encoding_size[0] = 8;  /* DES = 64 bits key */
  range->encoding_size[1] = 16;
  range->num_encoding_sizes = 2;
  range->max_encoding_tokens = 8;
#endif /* WIRELESS_EXT > 8 */
  return(0);
}

/* --------------------------- BINDING --------------------------- */

#if WIRELESS_EXT > 12
static const iw_handler         handler_table[] =
{
        ...
        (iw_handler) ioctl_set_encode,          /* SIOCSIWENCODE */
        (iw_handler) ioctl_get_encode,          /* SIOCGIWENCODE */
};
#else   /* WIRELESS_EXT < 12 */
static int
do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
  struct iwreq *wrq = (struct iwreq *) ifr;
  int           err = 0;

  switch (cmd)
    {
#if WIRELESS_EXT > 8
    case SIOCSIWENCODE:
      {
        char keybuf[MAX_KEY_SIZE];
        if(wrq->u.encoding.pointer)
          {
            /* We actually have a key to set */
            if(wrq->u.encoding.length > MAX_KEY_SIZE)
              {
                err = -E2BIG;
                break;
              }
            if(copy_from_user(keybuf, wrq->u.encoding.pointer,
                              wrq->u.encoding.length))
              {
                err = -EFAULT;
                break;
              }
          }
        else
          if(wrq->u.encoding.length != 0)
            {
              err = -EINVAL;
              break;
            }
        err = ioctl_set_encode(dev, NULL, &(wrq->u.encoding), keybuf);
      }
      break;

    case SIOCGIWENCODE:
      /* only super-user can see encryption key */
      if(! capable(CAP_NET_ADMIN))
        {
          err = -EPERM;
          break;
        }
      {
        char keybuf[MAX_KEY_SIZE];
        err = ioctl_get_encode(dev, NULL, &(wrq->u.encoding), keybuf);
        if(wrq->u.encoding.pointer)
          {
            if (copy_to_user(wrq->u.encoding.pointer, keybuf,
                             wrq->u.encoding.length))
              err= -EFAULT;
          }
      }
      break;
#endif  /* WIRELESS_EXT > 8 */
    }
  return(err);
}
#endif  /* WIRELESS_EXT < 12 */