/* This file is part of Lcrzo.
*/

#if defined LCRZODEF_SYSTEM_Linux || defined LCRZODEF_SYSTEM_FreeBSD || defined LCRZODEF_SYSTEM_OpenBSD || defined LCRZODEF_SYSTEM_Windows
  /* do not need these functions */
#elif defined LCRZODEF_SYSTEM_Solaris

/*-------------------------------------------------------------*/
int lcrzo_priv_dlpi_putmsg(int fd, char *ptr, int len, int flags)
{ struct strbuf ctl;
  int retour;

  ctl.maxlen = 0;
  ctl.len = len;
  ctl.buf = ptr;

  retour=putmsg(fd, &ctl, (struct strbuf *) NULL, flags);
  if ( retour < 0 )
  { return(LCRZO_ERR_FUPUTMSG);
  }
  return(LCRZO_ERR_OK);
}
/*-------------------------------------------------------------*/
int lcrzo_priv_dlpi_getmsg(int fd, int size, char *bufp)
{ union DL_primitives dlp;
  struct strbuf ctl;
  int flags;
  int retour;

  ctl.maxlen = 8192;
  ctl.len = 0;
  ctl.buf = bufp;

  flags = 0;
  retour=getmsg(fd, &ctl, (struct strbuf*)NULL, &flags);
  if ( retour < 0 )
  { return(LCRZO_ERR_FUGETMSG);
  }

  /* on verifie le code de retour */
  memcpy(&dlp, ctl.buf, sizeof(union DL_primitives));
  /* avant j'avais dlp = (union DL_primitives *)ctl.buf;*/
  if ( dlp.dl_primitive == DL_ERROR_ACK )
  { return(LCRZO_ERR_FUGETMSG);
  }
  /* on verifie la taille attendue */
  if ( ctl.len < size )
  { return(LCRZO_ERR_FUGETMSG);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_dlpi_open(const lcrzo_device device, int *pfd)
{ int retour, i;
  dl_info_req_t req;
  dl_bind_req_t	bindreq;
  struct strioctl str;
  register dl_info_ack_t *infop;
  unsigned long buf[8192];
  int ppa, fd;
  lcrzo_device devicepurge, devdevice, devdevicesanschiffre;

  /*parameters verification*/
  lcrzo_er(lcrzo_device_init(device, devicepurge));

  /*creation des devices sous forme de chaine*/
  lcrzo_string_init_text("/dev/", LCRZO_DEVICE_MAXBYTES, devdevice);
  lcrzo_string_append_text(devicepurge, LCRZO_DEVICE_MAXBYTES, devdevice);
  lcrzo_device_init(devdevice, devdevicesanschiffre);
  i=0;
  ppa=0;
  while( devdevicesanschiffre[i] != '\0' )
  { if ( isdigit((int)devdevicesanschiffre[i]) )
    { ppa=devdevicesanschiffre[i]-'0';
      devdevicesanschiffre[i]='\0';
      break;
    }
    i++;
  }

  /* on tente d'ouvrir les devices */
  fd = open(devdevicesanschiffre, O_RDWR);
  if ( fd < 0 )
  { fd = open(devdevice, O_RDWR);
    if ( fd < 0 )
    { return(LCRZO_ERR_FUOPEN);
    }
  }

  /* on attache que si l'on a un style2 */
  /* on pose la question */
  req.dl_primitive = DL_INFO_REQ;
  lcrzo_er(lcrzo_priv_dlpi_putmsg(fd, (char *)&req, sizeof(req), RS_HIPRI));
  lcrzo_er(lcrzo_priv_dlpi_getmsg(fd, DL_INFO_ACK_SIZE, (char *)buf));
  infop = &((union DL_primitives *)buf)->info_ack;
  /* c'est un style 2 */
  if ( infop->dl_provider_style == DL_STYLE2 )
  { dl_attach_req_t attachreq;
    attachreq.dl_primitive = DL_ATTACH_REQ;
    attachreq.dl_ppa       = ppa;
    lcrzo_er(lcrzo_priv_dlpi_putmsg(fd, (char *)&attachreq,
				   sizeof(attachreq), 0));
    lcrzo_er(lcrzo_priv_dlpi_getmsg(fd, DL_OK_ACK_SIZE,  (char *)buf));
  }

  /* on fait un bind */
  memset((char *)&bindreq, 0, sizeof(bindreq));
  bindreq.dl_primitive = DL_BIND_REQ;
  bindreq.dl_sap = 0;
  bindreq.dl_service_mode = DL_CLDLS;
  lcrzo_er(lcrzo_priv_dlpi_putmsg(fd, (char *)&bindreq,
				    sizeof(bindreq), 0));
  lcrzo_er(lcrzo_priv_dlpi_getmsg(fd, DL_BIND_ACK_SIZE, (char *)buf));

  /* appel d'ioctl pour dire que l'on envoie en raw*/
  str.ic_cmd    = DLIOCRAW;
  str.ic_timout = -1;
  str.ic_len    = 0;
  str.ic_dp     = NULL;
  retour = ioctl(fd, I_STR, &str);
  if ( retour < 0 )
  { return(LCRZO_ERR_FUIOCTL);
  }

  if ( pfd==NULL )
  { retour=close(fd);
    if ( retour < 0 ) return(LCRZO_ERR_FUCLOSE);
  }
  else
  { *pfd=fd;
  }

  return(LCRZO_ERR_OK);
}

#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
