/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

#include "local.h"
#include "ioctl.h"
#include "proto_extern.h"

//#include <linux/in.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <asm/uaccess.h>


// Statistic
//---------------------------------------------------------------------------
void nas_set_msg_statistic_reply(struct nas_msg_statistic_reply *msgrep,
                                 struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  msgrep->rx_packets=priv->stats.rx_packets;
  msgrep->tx_packets=priv->stats.tx_packets;
  msgrep->rx_bytes=priv->stats.rx_bytes;
  msgrep->tx_bytes=priv->stats.tx_bytes;
  msgrep->rx_errors=priv->stats.rx_errors;
  msgrep->tx_errors=priv->stats.tx_errors;
  msgrep->rx_dropped=priv->stats.rx_dropped;
  msgrep->tx_dropped=priv->stats.tx_dropped;
}

//---------------------------------------------------------------------------
int nas_ioCTL_statistic_request(struct nas_ioctl *gifr,
                                struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_statistic_reply msgrep;
  printk("NAS_IOCTL_STATISTIC: stat requested\n");
  nas_set_msg_statistic_reply(&msgrep,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_STATISTIC: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Connections List
//---------------------------------------------------------------------------
void nas_set_msg_cx_list_reply(uint8_t *msgrep,
                               struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct cx_entity *cx;
  nasLocalConnectionRef_t lcr;
  struct nas_msg_cx_list_reply *list;
  msgrep[0]=NAS_CX_MAX;
  list=(struct nas_msg_cx_list_reply *)(msgrep+1);

  for(lcr=0; lcr<NAS_CX_MAX; ++lcr) {
    cx=nas_COMMON_search_cx(lcr,priv);
    list[lcr].lcr=lcr;
    list[lcr].state=cx->state;
    list[lcr].cellid=cx->cellid;
    list[lcr].iid4=cx->iid4;
    list[lcr].iid6[0]=cx->iid6[0];
    list[lcr].iid6[1]=cx->iid6[1];
    list[lcr].num_rb=cx->num_rb;
    list[lcr].nsclassifier=cx->nsclassifier;
    printk("NAS_SET_MSG_CX_LIST_REPLY: nsc=%u\n",cx->nsclassifier);
  }
}

//---------------------------------------------------------------------------
int nas_ioCTL_cx_list_request(struct nas_ioctl *gifr,
                              struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  uint8_t msgrep[NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1];
  printk("NAS_IOCTL_CX_LIST: connection list requested\n");
  nas_set_msg_cx_list_reply(msgrep,priv);

  if (copy_to_user(gifr->msg, msgrep, NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1)) {
    printk("NAS_IOCTL_CX_LIST: copy_to_user failure\n");
    return -EFAULT;
  }

  printk("NAS_IOCTL_CX_LIST: end\n");
  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Connection Establishment
//---------------------------------------------------------------------------
void nas_set_msg_cx_establishment_reply(struct nas_msg_cx_establishment_reply *msgrep,
                                        struct nas_msg_cx_establishment_request *msgreq,
                                        struct nas_priv *priv)
{
  //---------------------------------------------------------------------------

  struct cx_entity *cx;
  cx=nas_COMMON_search_cx(msgreq->lcr,priv);

  if (cx!=NULL) {
    cx->cellid=msgreq->cellid;
    msgrep->status=nas_mesh_DC_send_cx_establish_request(cx,priv);
  } else
    msgrep->status=-NAS_ERROR_NOTCORRECTLCR;

}
//---------------------------------------------------------------------------
int nas_ioCTL_cx_establishment_request(struct nas_ioctl *gifr,
                                       struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_cx_establishment_request msgreq;
  struct nas_msg_cx_establishment_reply msgrep;
  printk("NAS_IOCTL_ESTABLISHMENT: connection establishment requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_CX_ESTABLISHMENT: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_cx_establishment_reply(&msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_CX_ESTABLISHMENT: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Connection Release
//---------------------------------------------------------------------------
void nas_set_msg_cx_release_reply(struct nas_msg_cx_release_reply *msgrep,
                                  struct nas_msg_cx_release_request *msgreq,
                                  struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct cx_entity *cx;
  cx=nas_COMMON_search_cx(msgreq->lcr,priv);

  if (cx!=NULL)
    msgrep->status=nas_mesh_DC_send_cx_release_request(cx,priv);
  else
    msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
}

//---------------------------------------------------------------------------
// Request the release of a connection
int nas_ioCTL_cx_release_request(struct nas_ioctl *gifr,struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_cx_release_request msgreq;
  struct nas_msg_cx_release_reply msgrep;

  printk("NAS_IOCTL_CX_RELEASE: connection release requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_CX_RELEASE: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_cx_release_reply(&msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_CX_RELEASE: copy_to_user failure\n");
    return -EFAULT;
  }

  printk("NAS_IOCTL_CX_RELEASE: end\n");
  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Radio Bearer List
//---------------------------------------------------------------------------
void nas_set_msg_rb_list_reply(uint8_t *msgrep,
                               struct nas_msg_rb_list_request *msgreq,
                               struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct cx_entity *cx;
  cx=nas_COMMON_search_cx(msgreq->lcr,priv);

  if (cx!=NULL) {
    uint8_t rbi;
    struct rb_entity *rb;
    struct nas_msg_rb_list_reply *list;

    if (cx->num_rb > NAS_LIST_RB_MAX)
      msgrep[0] = NAS_LIST_RB_MAX;
    else
      msgrep[0] = cx->num_rb;

    list=(struct nas_msg_rb_list_reply *)(msgrep+1);

    for (rb=cx->rb, rbi=0; (rb!=NULL)&&(rbi<msgrep[0]); rb=rb->next, ++rbi) {
      list[rbi].state=rb->state;
      list[rbi].rab_id=rb->rab_id;
      list[rbi].sapi=rb->sapi;
      list[rbi].qos=rb->qos;
    }
  } else
    msgrep[0]=0;
}

//---------------------------------------------------------------------------
int nas_ioCTL_rb_list_request(struct nas_ioctl *gifr,
                              struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  uint8_t msgrep[NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1];
  struct nas_msg_rb_list_request msgreq;
  printk("NAS_IOCTL_RB_LIST: Radio Bearer list requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_RB_LIST: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_rb_list_reply(msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, msgrep, NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1)) {
    printk("NAS_IOCTL_RB_LIST: copy_to_user failure\n");
    return -EFAULT;
  }

  printk("NAS_IOCTL_CX_LIST: end\n");
  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Radio Bearer Establishment
//---------------------------------------------------------------------------
void nas_set_msg_rb_establishment_reply(struct nas_msg_rb_establishment_reply *msgrep,
                                        struct nas_msg_rb_establishment_request *msgreq,
                                        struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  //  if ((msgreq->rab_id<3)||(msgreq->rab_id>127))
  if ((msgreq->rab_id<1)||(msgreq->rab_id>MAX_RABS)) // navid : increase the number
    msgrep->status=-NAS_ERROR_NOTCORRECTRABI;
  else {
    struct cx_entity *cx;
    cx=nas_COMMON_search_cx(msgreq->lcr,priv);

    if (cx==NULL)
      msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
    else {
      struct rb_entity *rb;
      rb=nas_COMMON_add_rb(cx, msgreq->rab_id, msgreq->qos);

      if (rb!=NULL) {
        //          rb->cnxid = msgreq->cnxid;
        //          msgrep->status=nas_rg_DC_send_rb_establish_request(cx, rb);
      } else
        msgrep->status=-NAS_ERROR_NOMEMORY;

      //        msgrep->cnxid  = msgreq->cnxid;
    }
  }
}

//---------------------------------------------------------------------------
int nas_ioCTL_rb_establishment_request(struct nas_ioctl *gifr,
                                       struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_rb_establishment_request msgreq;
  struct nas_msg_rb_establishment_reply msgrep;
  printk("NAS_IOCTL_RB_ESTABLISHMENT: Radio bearer establishment requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_RB_ESTABLISHMENT: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_rb_establishment_reply(&msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_RB_ESTABLISHMENT: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Radio Bearer Release
//---------------------------------------------------------------------------
void nas_set_msg_rb_release_reply(struct nas_msg_rb_release_reply *msgrep,
                                  struct nas_msg_rb_release_request *msgreq,
                                  struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  if (msgreq->lcr<NAS_CX_MAX) {
    struct rb_entity *rb;
    struct cx_entity *cx;
    cx=nas_COMMON_search_cx(msgreq->lcr,priv);
    rb=nas_COMMON_search_rb(cx, msgreq->rab_id);

    if (rb!=NULL) {
      //msgrep->status=nas_rg_DC_send_rb_release_request(cx, rb);
    } else
      msgrep->status=-NAS_ERROR_NOTCONNECTED;

    //      msgrep->cnxid  = msgreq->cnxid;
  } else
    msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
}

//---------------------------------------------------------------------------
int nas_ioCTL_rb_release_request(
  struct nas_ioctl *gifr,
  struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_rb_release_request msgreq;
  struct nas_msg_rb_release_reply msgrep;
  printk("NAS_IOCTL_RB_RELEASE: Radio bearer release requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_RB_RELEASE: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_rb_release_reply(&msgrep, &msgreq, priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_RB_RELEASE: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Classifier List
//---------------------------------------------------------------------------
void nas_set_msg_class_list_reply(
  uint8_t *msgrep,
  struct nas_msg_class_list_request *msgreq,
  struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct cx_entity *cx;
  struct classifier_entity *gc;
  struct nas_msg_class_list_reply *list;
  uint8_t cli;
  list=(struct nas_msg_class_list_reply *)(msgrep+1);

  switch(msgreq->dir) {
  case NAS_DIRECTION_SEND:
    cx=nas_COMMON_search_cx(msgreq->lcr,priv);

    if (cx==NULL) {
      msgrep[0]=0;
      return;
    }

    gc=cx->sclassifier[msgreq->dscp];
    break;

  case NAS_DIRECTION_RECEIVE:
    cx=NULL;
    gc=priv->rclassifier[msgreq->dscp];
    break;

  default:
    cx=NULL;
    msgrep[0]=0;
    return;
  }

  for (cli=0; (gc!=NULL)&&(cli<NAS_LIST_CLASS_MAX); gc=gc->next, ++cli) {
    list[cli].classref=gc->classref;
    list[cli].lcr=msgreq->lcr;
    list[cli].dir=msgreq->dir;
    list[cli].dscp=msgreq->dscp;
    list[cli].rab_id=gc->rab_id;
    list[cli].version=gc->version;

    switch(gc->version) {
    case 4:
      list[cli].saddr.ipv4 = gc->saddr.ipv4;
      list[cli].daddr.ipv4 = gc->daddr.ipv4;
      break;

    case 6:
      list[cli].saddr.ipv6 = gc->saddr.ipv6;
      list[cli].daddr.ipv6 = gc->daddr.ipv6;
      break;
    }

    list[cli].protocol=gc->protocol;
    list[cli].sport=ntohs(gc->sport);
    list[cli].dport=ntohs(gc->dport);
    list[cli].splen=gc->splen;
    list[cli].dplen=gc->dplen;
    list[cli].fct=nas_TOOL_invfct(gc);
  }

  msgrep[0]=cli;
}

//---------------------------------------------------------------------------
int nas_ioCTL_class_list_request(
  struct nas_ioctl *gifr,
  struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  uint8_t msgrep[NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1];
  struct nas_msg_class_list_request msgreq;
  printk("NAS_IOCTL_CLASS_LIST: classifier list requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_CLASS_LIST: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_class_list_reply(msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, msgrep, NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1)) {
    printk("NAS_IOCTL_CLASS_LIST: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Request the addition of a classifier rule
//---------------------------------------------------------------------------
void nas_set_msg_class_add_reply(
  struct nas_msg_class_add_reply   *msgrep,
  struct nas_msg_class_add_request *msgreq,
  struct nas_priv                  *priv)
{
  //---------------------------------------------------------------------------
  struct classifier_entity *gc,*gc2;
  unsigned char *saddr,*daddr;
  unsigned int *saddr32,*daddr32;

  printk("[NAS][CLASS] nas_set_msg_class_add_reply\n");


  if (msgreq->dscp>NAS_DSCP_MAX) {
    printk("NAS_SET_MSG_CLASS_ADD_REPLY: Incoherent parameter value\n");
    msgrep->status=-NAS_ERROR_NOTCORRECTDSCP;
    return;
  }

  if (msgreq->dir==NAS_DIRECTION_SEND) {


    struct cx_entity *cx;
    cx=nas_COMMON_search_cx(msgreq->lcr,priv);

    if (cx!=NULL) {
      printk("NAS_SET_MSG_CLASS_ADD_REPLY: DSCP/EXP %d, Classref %d, RB %u\n", msgreq->dscp, msgreq->classref,msgreq->rab_id );
      gc=nas_CLASS_add_sclassifier(cx, msgreq->dscp, msgreq->classref);

      printk("NAS_SET_MSG_CLASS_ADD_REPLY: %p %p\n" , msgreq, gc);

      if (gc==NULL) {
        msgrep->status=-NAS_ERROR_NOMEMORY;
        return;
      }
    } else {
      msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
      return;
    }

    gc->rab_id=msgreq->rab_id;

    gc->rb=nas_COMMON_search_rb(cx, gc->rab_id);
    printk("NAS_SET_MSG_CLASS_ADD_REPLY: gc_rb %p %u \n", gc->rb, gc->rab_id);
  } else {
    if (msgreq->dir==NAS_DIRECTION_RECEIVE) {
      gc=nas_CLASS_add_rclassifier(msgreq->dscp,
                                   msgreq->classref,
                                   priv);

      if (gc==NULL) {
        msgrep->status=-NAS_ERROR_NOMEMORY;
        return;
      }

      gc->rab_id=msgreq->rab_id;

    } else {
      msgrep->status=-NAS_ERROR_NOTCORRECTDIR;
      return;
    }

    for (gc2 = priv->rclassifier[msgreq->dscp]; gc2!=NULL ; gc2 = gc2->next)
      printk("[NAS][CLASS] Add Receive Classifier dscp %d: rab_id %d (%p,next %p)\n",msgreq->dscp,gc2->rab_id,gc2,gc2->next);
  }

  printk("[NAS][CLASS] Getting addresses ...\n");

  nas_TOOL_fct(gc, msgreq->fct);
  gc->version=msgreq->version;

  switch(gc->version) {
  case 4:
    gc->saddr.ipv4=msgreq->saddr.ipv4;
    gc->daddr.ipv4=msgreq->daddr.ipv4;



    // #ifdef NAS_CLASS_DEBUG
    saddr = (unsigned char *)&gc->saddr.ipv4;
    daddr = (unsigned char *)&gc->daddr.ipv4;

    printk("[NAS][CLASS] Adding IPv4 %d.%d.%d.%d -> %d.%d.%d.%d\n",
           saddr[0],saddr[1],saddr[2],saddr[3],
           daddr[0],daddr[1],daddr[2],daddr[3]);



    //#endif
    gc->splen=msgreq->splen;
    gc->dplen=msgreq->dplen;
    break;

  case 6:
    memcpy(&gc->saddr.ipv6,&msgreq->saddr.ipv6,16);
    memcpy(&gc->daddr.ipv6,&msgreq->daddr.ipv6,16);

    saddr32 = (unsigned int *)&gc->saddr.ipv6;
    daddr32 = (unsigned int *)&gc->daddr.ipv6;

    printk("[NAS][CLASS] Adding IPv6 %X:%X:%X:%X -> %X.%X.%X.%X\n",
           saddr32[0],saddr32[1],saddr32[2],saddr32[3],
           daddr32[0],daddr32[1],daddr32[2],daddr32[3]);
    gc->splen=msgreq->splen;
    gc->dplen=msgreq->dplen;
    break;

  case NAS_MPLS_VERSION_CODE:

    printk("[NAS][CLASS] Adding MPLS label %d with exp %d\n",
           msgreq->daddr.mpls_label,msgreq->dscp);
    gc->daddr.mpls_label = msgreq->daddr.mpls_label;

    break;

  case 0:
    gc->saddr.ipv6.s6_addr32[0]=0;
    gc->daddr.ipv6.s6_addr32[1]=0;
    gc->saddr.ipv6.s6_addr32[2]=0;
    gc->daddr.ipv6.s6_addr32[3]=0;
    gc->splen=0;
    gc->dplen=0;
    break;

  default:
    msgrep->status=-NAS_ERROR_NOTCORRECTVERSION;
    kfree(gc);
    return;
  }

  gc->protocol=msgreq->protocol;
  gc->protocol_message_type=msgreq->protocol_message_type;
  gc->sport=htons(msgreq->sport);
  gc->dport=htons(msgreq->dport);
  msgrep->status=0;
}

//---------------------------------------------------------------------------
int nas_ioCTL_class_add_request(struct nas_ioctl *gifr,
                                struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_class_add_request msgreq;
  struct nas_msg_class_add_reply msgrep;


  printk("NAS_IOCTL_CLASS_ADD: Add classifier components requested\n");
  printk("NAS_IOCTL_CLASS_ADD: size of gifr msg %zd\n", sizeof(gifr->msg));


  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_CLASS_ADD: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_class_add_reply(&msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_CLASS_ADD: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Request the deletion of a classifier rule
//---------------------------------------------------------------------------
void nas_set_msg_class_del_reply(struct nas_msg_class_del_reply *msgrep,
                                 struct nas_msg_class_del_request *msgreq,
                                 struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  if (msgreq->dscp>NAS_DSCP_DEFAULT) {
    printk("NAS_SET_MSG_CLASS_DEL_REPLY: Incoherent parameter value\n");
    msgrep->status=-NAS_ERROR_NOTCORRECTDSCP;
    return;
  }

  if (msgreq->dir==NAS_DIRECTION_SEND) {
    struct cx_entity *cx;
    cx=nas_COMMON_search_cx(msgreq->lcr,priv);

    if (cx!=NULL)
      nas_CLASS_del_sclassifier(cx, msgreq->dscp, msgreq->classref);
    else {
      msgrep->status=-NAS_ERROR_NOTCORRECTLCR;
      return;
    }
  } else {
    if (msgreq->dir==NAS_DIRECTION_RECEIVE)
      nas_CLASS_del_rclassifier(msgreq->dscp, msgreq->classref,priv);
    else {
      msgrep->status=-NAS_ERROR_NOTCORRECTDIR;
      return;
    }
  }

  msgrep->status=0;
}

//---------------------------------------------------------------------------
int nas_ioCTL_class_del_request(struct nas_ioctl *gifr,
                                struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_class_del_request msgreq;
  struct nas_msg_class_del_reply msgrep;
  printk("NAS_IOCTL_CLASS_DEL: Del classifier components requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_CLASS_DEL: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_class_del_reply(&msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_CLASS_DEL: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Measurement
// Messages for Measurement transfer

//---------------------------------------------------------------------------
void nas_set_msg_measure_reply(struct nas_msg_measure_reply *msgrep, struct nas_msg_measure_request *msgreq,
                               struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct cx_entity *cx;
  int lcr=0; // Temp lcr->mt =0
  int i;

  cx=nas_COMMON_search_cx(lcr,priv);

  if (cx!=NULL) {
    msgrep->num_cells = cx->num_measures;

    for (i=0; i<cx->num_measures; i++) {
      msgrep-> measures[i].cell_id = cx->meas_cell_id[i];
      msgrep-> measures[i].level = cx->meas_level[i];
      msgrep-> measures[i].provider_id = cx->provider_id[i];
    }

    msgrep->signal_lost_flag = 0;
  }
}
//---------------------------------------------------------------------------
int nas_ioCTL_measure_request(struct nas_ioctl *gifr,
                              struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_measure_request msgreq;
  struct nas_msg_measure_reply msgrep;
  printk("NAS_IOCTL_MEASURE: Measurement requested\n");

  if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) {
    printk("NAS_IOCTL_MEASURE: copy_from_user failure\n");
    return -EFAULT;
  }

  nas_set_msg_measure_reply(&msgrep, &msgreq,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_MEASURE: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}

///////////////////////////////////////////////////////////////////////////////
// IMEI
// Messages for IMEI transfer
//---------------------------------------------------------------------------
void nas_set_msg_imei_reply(struct nas_msg_l2id_reply *msgrep,
                            struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct cx_entity *cx;
  int lcr=0; // Temp lcr->mt =0

  cx=nas_COMMON_search_cx(lcr,priv);

  if (cx!=NULL) {
    msgrep->l2id[0] = cx->iid6[0];
    msgrep->l2id[1] = cx->iid6[1];
  }
}
//---------------------------------------------------------------------------
int nas_ioCTL_imei_request(struct nas_ioctl *gifr,
                           struct nas_priv *priv)
{
  //---------------------------------------------------------------------------
  struct nas_msg_l2id_reply msgrep;
  printk("NAS_IOCTL_IMEI: IMEI requested\n");
  nas_set_msg_imei_reply(&msgrep,priv);

  if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) {
    printk("NAS_IOCTL_IMEI: copy_to_user failure\n");
    return -EFAULT;
  }

  return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IOCTL command
//---------------------------------------------------------------------------
int nas_CTL_ioctl(struct net_device *dev,
                  struct ifreq *ifr,
                  int cmd)
{
  //---------------------------------------------------------------------------
  struct nas_ioctl *gifr;
  struct nas_priv *priv=netdev_priv(dev);

  int r;

  //  printk("NAS_CTL_IOCTL: begin ioctl for instance %d\n",find_inst(dev));

  switch(cmd) {
  case NAS_IOCTL_RRM:
    gifr=(struct nas_ioctl *)ifr;

    switch(gifr->type) {
    case NAS_MSG_STATISTIC_REQUEST:
      r=nas_ioCTL_statistic_request(gifr,priv);
      break;

    case NAS_MSG_CX_ESTABLISHMENT_REQUEST:
      r=nas_ioCTL_cx_establishment_request(gifr,priv);
      break;

    case NAS_MSG_CX_RELEASE_REQUEST:
      r=nas_ioCTL_cx_release_request(gifr,priv);
      break;

    case NAS_MSG_CX_LIST_REQUEST:
      r=nas_ioCTL_cx_list_request(gifr,priv);
      break;

    case NAS_MSG_RB_ESTABLISHMENT_REQUEST:
      r=nas_ioCTL_rb_establishment_request(gifr,priv);
      break;

    case NAS_MSG_RB_RELEASE_REQUEST:
      r= nas_ioCTL_rb_release_request(gifr,priv);
      break;

    case NAS_MSG_RB_LIST_REQUEST:
      r=nas_ioCTL_rb_list_request(gifr,priv);
      break;

    case NAS_MSG_CLASS_ADD_REQUEST:
      r=nas_ioCTL_class_add_request(gifr,priv);
      break;

    case NAS_MSG_CLASS_LIST_REQUEST:
      r=nas_ioCTL_class_list_request(gifr,priv);
      break;

    case NAS_MSG_CLASS_DEL_REQUEST:
      r=nas_ioCTL_class_del_request(gifr,priv);
      break;

    case NAS_MSG_MEAS_REQUEST:
      r=nas_ioCTL_measure_request(gifr,priv);
      break;

    case NAS_MSG_IMEI_REQUEST:
      r=nas_ioCTL_imei_request(gifr,priv);
      break;

    default:
      //  printk("NAS_IOCTL_RRM: unkwon request type, type=%x\n", gifr->type);
      r=-EFAULT;
    }

    break;

  default:
    //      printk("NAS_CTL_IOCTL: Unknown ioctl command, cmd=%x\n", cmd);
    r=-EFAULT;
  }

  //  printk("NAS_CTL_IOCTL: end\n");
  return r;
}

//---------------------------------------------------------------------------
void nas_CTL_send(struct sk_buff *skb,
                  struct cx_entity *cx,
                  struct classifier_entity *gc, int inst, struct nas_priv *gpriv)
{
  //---------------------------------------------------------------------------
  printk("NAS_CTL_SEND - void \n");
}