/***********************************************************************************
    Copyright (C) <2005>  <Hongwei Zhang>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


    Author:
    =======
    Hongwei Zhang
    Department of Computer Science
    Wayne State University, USA

    E-mail: hzhang@cs.wayne.edu

***********************************************************************************/



DESCRIPTION:
============
- Transmit and receive packets, as a proxy to UDPD but providing
  MAC feedback to the user layer.

- It fetches MAC feedback via iwtxstatus. 



NOTE:
=====
- require packet-receipt from UDPD
- implemented mechanisms of detecting no-mac-feedback and 
                            buffering data packets when lu queue is full



DATA STRUCTURE FOR MAC FEEDBACK:
================================
/***  linxy.h  ***/

#define PKT_TYPE_LX_FB (PKT_TYPE_USER0 + 1) //used by clients for registration

typedef struct linxy_fb_pkt {
  link_pkt_type_t client_pkt_type;

  int status;   //1: success       -1: failure
  //int retry;    //number of retries
  long fb_delay; //microseconds
  long bitrate; // bit/second
  struct timeval rcv_time;
  char mac_addr[MAC_ADDR_DISPLAY_LEN];
} linxy_fb_pkt_t;




SAMPLE USER CODE OF LINKPROXY:
==============================
/***  clients of linkproxy  ***/

/*
 * Open the link-layer device to receive MAC feedback
 *
 * If the link-opening succeeds, the link struct is returned to us using the 2nd argument (i.e. written to uniComm_state.link)
 */
void uniComm_open_link_fb(uniComm_state_t *uniComm_state, char *interface)
{
  //Configure the link to receive MAC feedback
  lu_opts_t lu_opts = {
    opts: {
      name: interface,
      data: uniComm_state,
      pkt_type: PKT_TYPE_LX_FB
    },
    receive: fb_receive
  };
 
  if (lu_open(&lu_opts, &(uniComm_state->link_fb)) < 0) {
    elog(LOG_CRIT,"can't open %s for receiving MAC feedback: %m", link_name(&lu_opts.opts, NULL));
    exit(-1);
  }
} //end of uniComm_open_link_fb (...)


/*
 * Called when receiving a MAC feedback
 */
int fb_receive(lu_context_t * link, link_pkt_t * link_pkt, ssize_t data_len)
{
  linxy_fb_pkt_t * fb_pkt = (linxy_fb_pkt_t *) link_pkt->data;

  //check if it is for unicomm data packets
  if (fb_pkt->client_pkt_type != PKT_TYPE_UNICOMM)
    return EVENT_RENEW;

  //check whether the TX is valid, i.e., it is not redundant
  if (fb_pkt->status == 1 && //is TX
       (strstr(fb_pkt->mac_addr, INVALID_FB_MAC_ADDR_TRAIL) != NULL //broadcast mac_addr
        //|| inter_fb_time <= (INVALID_INTER_TX_THRESHOLD_RATIO * r->buf_head_1->inter_pkt_time) 
                                                                                                                                            //too soon TX
       )
      ) {//invalid TX
    return EVENT_RENEW;
  }
  //else  r->last_fb = current_time;

#ifdef DEBUG_MAC_FB
  //print out info on valid TX/TXEXC
  (r->fb_rcvd)++;
  int s = (fb_pkt->rcv_time.tv_sec) % 86400;
  elog(LOG_NOTICE, "%02d:%02d:%02d.%06u   TX=%d   MAC=%s   fbs=%d   sends =%d", s / 3600, (s % 3600) / 60, s % 60, (u_int32_t) fb_pkt->rcv_time.tv_usec, fb_pkt->status, fb_pkt->mac_addr, r->fb_rcvd, r->last_seqno);
  //elog(LOG_NOTICE, "MAC=%s ", fb_pkt->mac_addr);
#endif

  //process the received TX or TXEXC
  if (fb_pkt->status == 1) { //is TX 
    //tune routing decision accordingly
    process_tx(r);
  }
  else if (fb_pkt->status == -1){ //is TXEXC
    //tune routing decision accordingly
    process_txexc(r);
  }
  else {
    elog(LOG_CRIT, "invalid IWTX status");
  }

  free(link_pkt);
  return EVENT_RENEW;
} //end of fb_receive(...)
