diff options
Diffstat (limited to 'package/librtk-inband/src/inband_if.c')
-rw-r--r-- | package/librtk-inband/src/inband_if.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/package/librtk-inband/src/inband_if.c b/package/librtk-inband/src/inband_if.c new file mode 100644 index 000000000..a3ce40996 --- /dev/null +++ b/package/librtk-inband/src/inband_if.c @@ -0,0 +1,443 @@ +/* + * IOH daemon + * Copyright (C)2010, Realtek Semiconductor Corp. All rights reserved + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <sys/ioctl.h> + +#include <linux/if_packet.h> +#include "ioh.h" +#include "inband_if.h" + +struct inband_header { + struct ioh_header raw_header; + unsigned char rrcp_type; // should be RRCP_P_IOH + unsigned char inband_cmd; + unsigned short inband_seq; + unsigned short inband_frag; + unsigned char inband_reserved[2]; + unsigned short inband_data_len; +} __attribute__((packed)); + +struct fragment_info{ + unsigned char inband_cmd; + unsigned short inband_seq; + unsigned short inband_frag; + char *buf_ptr; + char *buf; + unsigned int data_len; +}; + +struct inband_class { + struct ioh_class ioh_obj; + struct inband_header *tx_header; + struct inband_header *rx_header; + unsigned char *tx_data; + unsigned char *rx_data; + struct fragment_info frag_info; + unsigned int in_used; +}; + +//header : 4 sign , 4 opttion , 4 offset, 4 len +#define FM_HEADER_LEN_OFFSET 12 + +#define MAX_INBAND_CHAN 1 +#define MAX_PREALLOC_INBAND_CHAN MAX_INBAND_CHAN + +int inband_rcv_timeout=0; //mark_issue, not implement now + +static struct inband_class inband_obj[MAX_INBAND_CHAN]; +static int inband_ready=0; + +static void init_inband_obj(struct inband_class *ib_obj) +{ + struct ioh_class *obj=&ib_obj->ioh_obj; + + ib_obj->tx_header = (struct inband_header *)obj->tx_header; + ib_obj->rx_header = (struct inband_header *)obj->rx_header; + + ib_obj->tx_data = (unsigned char *) obj->tx_buffer + sizeof(struct inband_header); + ib_obj->rx_data = (unsigned char *) obj->rx_buffer + sizeof(struct inband_header); + + //frag_info? +} + +static unsigned int get_free_chan() +{ + int i; + int chan=-1; + + for(i=0;i<MAX_INBAND_CHAN;i++) + { + if(inband_obj[i].in_used ==0 ) + { + inband_obj[i].in_used =1; + chan = i; + break; + } + } + return chan; +} + +static struct inband_class *get_chan_obj(unsigned int chan) +{ + return (struct inband_class *)&inband_obj[chan]; +} + +static void inband_init_all() +{ + memset(&inband_obj[0],0,sizeof(struct inband_class)*MAX_INBAND_CHAN); +} + +int inband_open(char *netif_name,char *slave_mac,unsigned short eth_type,int debug) +{ + int ret; + unsigned int chan; + struct inband_class *inband_obj_p; + struct ioh_class *ioh_obj_p; + + if(inband_ready == 0) + { + inband_init_all(); + inband_ready =1 ; + } + + chan = get_free_chan(); + if(chan < 0) + return -1; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + + ioh_obj_p = &inband_obj_p->ioh_obj; + + ret = ioh_open(ioh_obj_p, netif_name, slave_mac,eth_type, debug); + + if(ret < 0 ) + return -1; + + init_inband_obj(inband_obj_p); + + return chan; +} + +int get_inband_socket(int chan) +{ + struct inband_class *inband_obj_p; + struct ioh_class *ioh_obj_p; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + ioh_obj_p = &inband_obj_p->ioh_obj; + + return ioh_obj_p->sockfd; +} + +int get_inband_destMac(int chan,char *destmac) //mark_test +{ + struct inband_class *inband_obj_p; + struct ioh_class *ioh_obj_p; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + ioh_obj_p = &inband_obj_p->ioh_obj; + + memcpy(destmac,ioh_obj_p->dest_mac,6); + + return 0; +} + +void inband_close(int chan) +{ + //clear frag_info + struct inband_class *inband_obj_p; + struct ioh_class *ioh_obj_p; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + ioh_obj_p = &inband_obj_p->ioh_obj; + ioh_close(ioh_obj_p); + inband_obj_p->in_used =0; //free the obj +} + +static int inband_recv(struct inband_class *ib_obj,int timeout) +{ + struct ioh_class *ioh_obj_p = &ib_obj->ioh_obj; + int rx_len; + + rx_len = ioh_recv(ioh_obj_p, timeout); + if (rx_len < 0) + return ERROR_TIMOUT; + if(ib_obj->rx_header->rrcp_type != RRCP_P_IOH) + return -1; + + return rx_len; +} + +static int send_frag_ack(struct inband_class *ib_obj) +{ + struct ioh_class *ioh_obj_p = &ib_obj->ioh_obj; + + ib_obj->tx_header->rrcp_type = RRCP_P_IOH; //mark_inband + ib_obj->tx_header->inband_cmd = ib_obj->rx_header->inband_cmd; + ib_obj->tx_header->inband_seq = ib_obj->rx_header->inband_seq; + ib_obj->tx_header->inband_frag = ib_obj->rx_header->inband_frag; + ib_obj->tx_header->inband_data_len = 0; + + return ioh_send(ioh_obj_p,sizeof(struct inband_header)); //only send header for ack +} +static int check_frag_ack(struct inband_class *ib_obj) +{ + int rx_len; + + rx_len = inband_recv(ib_obj, PER_FRAME_TIMEOUT); // -1 = wait until rec + if (rx_len < 0) + { + perror("check_frag_ack fail:"); + return 0; + } + if((ib_obj->rx_header->inband_cmd == ib_obj->tx_header->inband_cmd) && + (ib_obj->rx_header->inband_seq == ib_obj->tx_header->inband_seq) && + (ib_obj->rx_header->inband_frag == ib_obj->tx_header->inband_frag) ) + return 1; //ok + + return 0; //fail +} +static char *inband_alloc_buf(struct inband_class *ib_obj) +{ + char *buf=NULL; + unsigned int buf_size=MAX_APP_DATA_SIZE; + unsigned char *image_len,header_len_offset=FM_HEADER_LEN_OFFSET; +#if 1 //it's for firmware file + if(ib_obj->rx_header->inband_cmd == id_firm_upgrade) + { + //read firmware length from it's header + image_len = (char *)ib_obj->rx_data; + buf_size =(unsigned int)( ( image_len[header_len_offset+0] <<24 ) + + ( image_len[header_len_offset+1] <<16 ) + + ( image_len[header_len_offset+2] <<8 ) + + ( image_len[header_len_offset+3] <<0 ) + 16 ) ; + + //printf("inband_alloc_buf buf_size=%x , image_len[0]= %x\n",buf_size,image_len[header_len_offset+0]); + } +#endif + buf = (char *)malloc(buf_size); + return buf; +} +//mark_issue,defragment_reset +static int init_defragment_process(struct inband_class *ib_obj) +{ + struct fragment_info *p_frag_info = &ib_obj->frag_info; + + //check if the it is first fragment id + if(ib_obj->rx_header->inband_frag != FIRST_FRAG_ID) + return ERROR_DEFRAGMENT; + + if((p_frag_info->buf = (char *)inband_alloc_buf(ib_obj)) == NULL) + { + printf("init_defragment_process : data buffer allocation failed!\n"); + return ERROR_DEFRAGMENT; + } + p_frag_info->buf_ptr = p_frag_info->buf; + p_frag_info->inband_frag = FIRST_FRAG_ID; + +#ifdef WPAS_INB + p_frag_info->inband_cmd = ntohs(ib_obj->rx_header->inband_cmd); + p_frag_info->inband_seq = ntohs(ib_obj->rx_header->inband_seq); +#else + p_frag_info->inband_cmd = ib_obj->rx_header->inband_cmd; + p_frag_info->inband_seq = ib_obj->rx_header->inband_seq; +#endif + + //copy first frame to buffer + memcpy(p_frag_info->buf,ib_obj->rx_data,ntohs(ib_obj->rx_header->inband_data_len)); + p_frag_info->buf += ntohs(ib_obj->rx_header->inband_data_len); + p_frag_info->data_len = ntohs(ib_obj->rx_header->inband_data_len); + send_frag_ack(ib_obj); + + return 0; //init ok +} + +static int do_defragment_process(struct inband_class *ib_obj) +{ + int ret=0; + struct fragment_info *p_frag_info = &ib_obj->frag_info; + + if(p_frag_info->inband_seq != ntohs(ib_obj->rx_header->inband_seq) ) + return ERROR_DEFRAGMENT; + + if( (p_frag_info->inband_frag+1) != (ntohs(ib_obj->rx_header->inband_frag) & FRAG_ID_MASK)) + return ERROR_DEFRAGMENT; + else + p_frag_info->inband_frag = ntohs(ib_obj->rx_header->inband_frag); + + memcpy(p_frag_info->buf,ib_obj->rx_data,ntohs(ib_obj->rx_header->inband_data_len)); + p_frag_info->buf += (ntohs(ib_obj->rx_header->inband_data_len)); + p_frag_info->data_len+= (ntohs(ib_obj->rx_header->inband_data_len)); + + if( (p_frag_info->inband_frag & EOF_BIT) == EOF_BIT) + ret = 1; + + return ret; // return 1 means EOF rcv , return 0 means conitiune +} + +static int get_defragment_info(struct inband_class *ib_obj,char *cmd_type,char **data) +{ + struct fragment_info *p_frag_info = &ib_obj->frag_info; + + *cmd_type = p_frag_info->inband_cmd; + *data = p_frag_info->buf_ptr; //mark_issue,hwo to free the buffer ? + return p_frag_info->data_len; +} + +static int inband_rcv_fragment(struct inband_class *ib_obj,char *cmd_type,char **data) +{ + int rx_len,ret=0; + + ret = init_defragment_process(ib_obj) ; + + if(ret < 0) + return ret; + + while( (inband_rcv_timeout!=1)) + { + rx_len = inband_recv(ib_obj, PER_FRAME_TIMEOUT); + if (rx_len < 0) + return ERROR_TIMOUT; + ret = do_defragment_process(ib_obj); + if (ret < 0) + return ret; + else if(ret == 1) //ret == 1 means defragment end , ret=0 means contiune + { + ret = get_defragment_info(ib_obj,cmd_type,data); + break; + } + send_frag_ack(ib_obj); + } + return ret; +} +void inband_free_buf(char *data_buf,int data_len) +{ + //only free allocated buffer from deframet process. + if( (data_buf != NULL) && ( data_len > MAX_INBAND_PAYLOAD_LEN ) ) + free(data_buf); +} +int inband_rcv_data(int chan,char *cmd_type,char **data,int timout_ms) //return data length +{ + int rx_len,data_len=0; + struct inband_class *inband_obj_p; + struct ioh_class *ioh_obj_p; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + ioh_obj_p = &inband_obj_p->ioh_obj; + + + //timout_ms will be used only for the first pkt. if the pkt is fragmented then every packet will + //follow fragment_timout_ms + rx_len = inband_recv(inband_obj_p, timout_ms); // -1 = wait until rec + if (rx_len < 0) + { + perror("inband_rcv_data:"); + return -1; + } + //printf("inband_rcv_data:\n"); + //hex_dump(ioh_obj_p->rx_buffer, ntohs(inband_obj_p->rx_header->inband_data_len) + sizeof(*inband_obj_p->rx_header)); //mark_test + + //cache for tx dest mac + if( memcmp(ioh_obj_p->dest_mac,ioh_obj_p->rx_header->sa,6)) //mark_test + memcpy(ioh_obj_p->dest_mac,ioh_obj_p->rx_header->sa,6); + + //single pkt + if( inband_obj_p->rx_header->inband_frag == ntohs(SINGLE_FRAME)) //mark_endian + { + *cmd_type = inband_obj_p->rx_header->inband_cmd; + data_len = ntohs(inband_obj_p->rx_header->inband_data_len); + *data = inband_obj_p->rx_data ; //or memcpy; + } + else //fragment process + data_len = inband_rcv_fragment(inband_obj_p,cmd_type,data); + + return data_len; + +} + +//if seq is need in your application +int inband_rcv_data_and_seq(int chan,unsigned int *seq,char *cmd_type,char **data,int timout_ms) //return data length +{ + struct inband_class *inband_obj_p; + int ret=0; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + ret = inband_rcv_data(chan,cmd_type,data, timout_ms); //return data length + if(ret < 0) + return -1; + + *seq = ntohs(inband_obj_p->rx_header->inband_seq); + return ret; +} + +static int inband_send_data(struct inband_class *ib_obj,char *data,int data_len) +{ + char *frag_ptr; + unsigned short id=0,total_frag=0; + unsigned int last_num; + struct ioh_class *ioh_obj_p = &ib_obj->ioh_obj; + + total_frag = (unsigned short)(data_len / MAX_INBAND_PAYLOAD_LEN); + + if( total_frag > MAX_FRAG_ID) + return -1; + + ib_obj->tx_header->inband_frag =0; + frag_ptr = data; + + for(id=0;id<total_frag;id++) + { + ib_obj->tx_header->inband_data_len = htons(MAX_INBAND_PAYLOAD_LEN); + ib_obj->tx_header->inband_frag = htons(id ); + memcpy(&ib_obj->tx_data[0], frag_ptr,MAX_INBAND_PAYLOAD_LEN ); + if( ioh_send(ioh_obj_p, sizeof(struct inband_header) + MAX_INBAND_PAYLOAD_LEN ) < 0) + return -1; + //if(id>= 1){ + if(check_frag_ack(ib_obj) != 1) + return -1; + //} + frag_ptr += MAX_INBAND_PAYLOAD_LEN; + } + last_num = data_len % MAX_INBAND_PAYLOAD_LEN; + //EOF fragment + ib_obj->tx_header->inband_frag = id; + ib_obj->tx_header->inband_frag |=EOF_BIT; + ib_obj->tx_header->inband_frag = htons(ib_obj->tx_header->inband_frag); + ib_obj->tx_header->inband_data_len = htons(last_num); + if(last_num >0) + memcpy(&ib_obj->tx_data[0], frag_ptr,last_num ); + + return ioh_send(ioh_obj_p,sizeof(struct inband_header)+last_num); +} + +int inband_write(int chan,unsigned int seq,char cmd,char *data,int data_len,int reply) +{ + struct inband_class *inband_obj_p; + + inband_obj_p = (struct inband_class *)get_chan_obj(chan); + + inband_obj_p->tx_header->rrcp_type = RRCP_P_IOH; //mark_inband + //fill inband header , cmd + inband_obj_p->tx_header->inband_cmd = cmd; + + //reply = 0(request) ,reply = 1(good reply),reply = 2(bad reply) + if(reply == 2) + inband_obj_p->tx_header->inband_cmd |= CMD_ERROR_REPLY_BIT; + + //fill inband header , seq + if(!reply) + inband_obj_p->tx_header->inband_seq = htons(seq); + else //seq is not used when the packet is for reply + inband_obj_p->tx_header->inband_seq = inband_obj_p->rx_header->inband_seq; + + //fill data, data_len , and send + return inband_send_data(inband_obj_p,data,data_len); +} + |