
/*
 * irda.c:
 *
 * Copyright (c) 2000 James McKenzie <james@fishsoup.dhs.org>.
 * All rights reserved.
 *
 * $Log: irda.c,v $
 * Revision 1.20  2001/10/12 13:51:11  root
 * #
 *
 * Revision 1.19  2001/01/30 06:16:17  root
 * #
 *
 * Revision 1.18  2000/12/01 04:42:09  root
 * #
 *
 * Revision 1.17  2000/12/01 04:13:41  root
 * #
 *
 * Revision 1.16  2000/11/23 23:45:16  root
 * #
 *
 * Revision 1.15  2000/10/07 18:30:02  root
 * #
 *
 * Revision 1.14  2000/10/06 19:52:17  root
 * #
 *
 * Revision 1.13  2000/09/24 01:57:55  root
 * #
 *
 * Revision 1.12  2000/09/24 01:57:53  root
 * #
 *
 * Revision 1.11  2000/09/24 01:57:40  root
 * #
 *
 * Revision 1.10  2000/09/24 01:48:12  root
 * #
 *
 * Revision 1.9  2000/09/24 01:46:04  root
 * #
 *
 * Revision 1.8  2000/09/24 01:12:46  root
 * #
 *
 * Revision 1.7  2000/09/24 01:10:19  root
 * #
 *
 * Revision 1.6  2000/02/21 04:11:26  root
 * #
 *
 * Revision 1.5  2000/02/21 04:01:01  root
 * #
 *
 * Revision 1.4  2000/02/21 02:53:46  root
 * #
 *
 * Revision 1.3  2000/02/21 00:49:53  root
 * #
 *
 * Revision 1.2  2000/02/20 18:22:59  root
 * #
 *
 * Revision 1.1  2000/02/20 14:07:12  root
 * #
 *
 * Revision 1.5  2000/02/20 03:03:57  root
 * #
 *
 * Revision 1.4  2000/02/20 03:03:53  root
 * #
 *
 * Revision 1.3  2000/02/16 13:51:59  root
 * #
 *
 * Revision 1.2  2000/02/16 13:50:11  root
 * *** empty log message ***
 *
 *
 */

static char rcsid[] =
  "$Id: irda.c,v 1.20 2001/10/12 13:51:11 root Exp root $";

#include "hifimsg.h"
#include "hifimsg_private.h"

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <signal.h>

#include <endian.h>

#include <netinet/in.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>

#ifndef AF_PACKET
#define AF_PACKET  17
#define PF_PACKET AF_PACKET
#endif

#ifndef AF_IRDA
#define AF_IRDA    23
#define PF_IRDA    AF_IRDA
#endif /* AF_IRDA */

#define UIC_FRAME  0x03
#define CMD_FRAME  0x01
#define PF_BIT 0x10
#define CBROADCAST 0xfe
#define DEV_DEFAULT "irda0"

struct uic_frame
{
  unsigned char caddr;          /* Connection address */
  unsigned char control;
}
__attribute__ ((packed));


typedef struct irda_struct
{
  int fd;
  struct sockaddr_pkt dest;
}
 *Irda;

static void *
hifimsg_irda_open (void)        //Can't be opened by clients
{
  return NULL;
}


static int
irda_fd (void *_irda)
{
  Irda irda = (Irda) _irda;

  return irda->fd;
}

static int
irda_recv (void *_irda, void *data, int len)
{
  Irda irda = (Irda) _irda;
  struct uic_frame *frame;

  int count;

  unsigned char *buf;

  buf = (unsigned char *) malloc (len + 2);

  count = recv (irda->fd, buf, len + 2, 0);

  if (count < 2)
    {
      free (buf);
      return count;
    }

  frame = (struct uic_frame *) buf;

  if ((frame->caddr & CBROADCAST) != CBROADCAST)
    {
      free (buf);
      return count;
    }

/*
   if (((command == 0) && (frame->caddr & CMD_FRAME)) ||
   ((command == 1) && (!(frame->caddr & CMD_FRAME))) ||

   (frame->control != (PF_BIT | UIC_FRAME)))
   {

   free (buf);
   return 0;
   }
 */

  if (frame->control != (PF_BIT | UIC_FRAME))
    {
      free (buf);
      return 0;
    }

  count -= 2;

  if (count)
    bcopy (buf + 2, data, count);

  free (buf);

  return count;


}

static int
irda_send (void *_irda, void *data, int len)
{
  struct uic_frame *frame;
  void *buf;
  Irda irda = (Irda) _irda;
  int count;


  buf = malloc (len + 2);
  bcopy (data, buf + 2, len);

  len += 2;

  frame = (struct uic_frame *) buf;
  frame->caddr = CBROADCAST | CMD_FRAME;

  frame->control = PF_BIT | UIC_FRAME;


  count = sendto (irda->fd, buf, len, 0,
                  (struct sockaddr *) &irda->dest, sizeof (irda->dest));

  free (buf);

  if (count > 2)
    count -= 2;
  else
    count = 0;

  return (count);
}


static void
irda_close (void *_irda)
{
  Irda irda = (Irda) _irda;

  if (!irda)
    return;
  close (irda->fd);
  free (irda);
}




static void *
open_irda_device (char *name, char *moocow)
{
  struct ifreq ifr;
  struct sockaddr from_sa;
  char device[14];
  Irda irda;


#ifdef DEBUG
  printf ("Opening irda port on device %s\n", name);
#endif

  irda = (Irda) malloc (sizeof (struct irda_struct));

  bzero (device, sizeof (device));
  strncpy (device, moocow, sizeof (device));
  device[sizeof (device) - 1] = 0;



  irda->fd = socket (PF_PACKET, SOCK_PACKET, htons (ETH_P_ALL));
  if (irda->fd < 0)
    {
      free (irda);
      return (NULL);
    }


  bzero (&from_sa, sizeof (from_sa));
  from_sa.sa_family = AF_PACKET;

  strncpy (from_sa.sa_data, device, sizeof (from_sa.sa_data));

  if (bind (irda->fd, &from_sa, sizeof (from_sa)))
    {
      close (irda->fd);
      free (irda);
      return (NULL);
    }

  irda->dest.spkt_family = ARPHRD_IRDA;
  irda->dest.spkt_protocol = htons (AF_IRDA);
  strncpy (irda->dest.spkt_device, device, sizeof (irda->dest.spkt_device));

  return ((void *) irda);
};

Connexion hifimsg_irda_server_open (Connexion c)
{
  void *irda;
  char buf[1024];
  struct ifconf ifc;
  int fd;
  int i;



#ifdef I_AM_NOT_A_BROKEN_IRDA_WEENIE
  ifc.ifc_buf = buf;
  ifc.ifc_len = sizeof (buf);

  fd = socket (PF_IRDA, SOCK_DGRAM, 0);
  if (fd < 0)
    return c;

  if (ioctl (fd, SIOCGIFCONF, &ifc))
    {
      close (fd);
      return c;
    }
  close (fd);

  fd = ifc.ifc_len / sizeof (struct ifreq);

  for (i = 0; i < fd; ++i)
    {
      if (ifc.ifc_req[i].ifr_addr.sa_family == PF_IRDA)
        {
          irda =
            open_irda_device (ifc.ifc_req[i].ifr_name,
                              ifc.ifc_req[i].ifr_name);
          if (irda)
            {
              Connexion n =
                (Connexion) malloc (sizeof (struct connexion_struct));
              n->h = irda;
              n->fd = irda_fd (n->h);
              n->fd2 = 0;
              n->recv = irda_recv;
              n->send = irda_send;
              n->close = irda_close;
              n->next = c;
              c = n;
            }

        }
#else
//FIXME: GAK GAK GAK GAK GAK GAK GAK GAK GAK GAK
  for (i = 0; i < 10; ++i)
    {
      sprintf (buf, "irda%d", i);

      irda = open_irda_device (buf, buf);
      if (irda)
        {
          Connexion n = (Connexion) malloc (sizeof (struct connexion_struct));
          n->h = irda;
          n->fd = irda_fd (n->h);
          n->fd2 = 0;
          n->recv = irda_recv;
          n->send = irda_send;
          n->close = irda_close;
          n->next = c;
          c = n;
        }

    }

#endif

  return c;

}
