/***************************************************************************** * bstrm_hdlc_test_multi.c: Multiple Bstrm Test Receive Module * * Author(s): Nenad Corbic * * Copyright: (c) 1995-2006 Sangoma Technologies Inc. * * 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. * ============================================================================ * Description: * * The chdlc_api.c utility will bind to a socket to a chdlc network * interface, and continously tx and rx packets to an from the sockets. * * This example has been written for a single interface in mind, * where the same process handles tx and rx data. * * A real world example, should use different processes to handle * tx and rx spearately. */ #include #include #include #include #include #include #include #include #include #include #define DAHDI_ISSUES 1 #include "zapcompat_user.h" #if 0 #ifdef STANDALONE_ZAPATA #include "kernel/zaptel.h" #else #include #endif #endif #include #define FALSE 0 #define TRUE 1 /* Enable/Disable tx of random frames */ #define RAND_FRAME 0 #define MAX_NUM_OF_TIMESLOTS 32*32 #define LGTH_CRC_BYTES 2 #define MAX_TX_DATA 15000 //MAX_NUM_OF_TIMESLOTS*10 /* Size of tx data */ #define MAX_TX_FRAMES 1000000 /* Number of frames to transmit */ #define BLOCK_SIZE 160 #define WRITE 1 #define MAX_IF_NAME 20 typedef struct { int sock; int rx_cnt; int tx_cnt; int data; int last_error; int frames; int bs; ZT_PARAMS tp; char if_name[MAX_IF_NAME+1]; wanpipe_hdlc_engine_t *hdlc_eng; } timeslot_t; timeslot_t tslot_array[MAX_NUM_OF_TIMESLOTS]; int tx_change_data=0, tx_change_data_cnt=0; int end=0; void print_packet(unsigned char *buf, int len) { int x; printf("{ | "); for (x=0;xsock, DAHDI_ECHOCANCEL_PARAMS, &ecp); if (res) { fprintf(stderr, "Failed to configure ec tap=%i: %s\n", tap, strerror(errno)); } return res; } /*=================================================== * MakeConnection * * o Create a Socket * o Bind a socket to a wanpipe network interface * (Interface name is supplied by the user) *==================================================*/ int MakeConnection(timeslot_t *slot, char *router_name ) { int i; int chan; ZT_BUFFERINFO bi; #ifdef DAHDI_ISSUES sscanf(slot->if_name,"/dev/dahdi/%d",&chan); #else sscanf(slot->if_name,"/dev/zap/%d",&chan); #endif printf("Opening chan %i %s\n",chan,slot->if_name); #ifdef DAHDI_ISSUES slot->sock = open("/dev/dahdi/channel", O_RDWR | O_NONBLOCK, 0600); #else slot->sock = open("/dev/zap/channel", O_RDWR | O_NONBLOCK, 0600); #endif if( slot->sock < 0 ) { perror("Open Span Chan: "); return( FALSE ); } if (ioctl(slot->sock, ZT_SPECIFY, &chan)) { perror("Set Span Chan: "); close(slot->sock); slot->sock=-1; return( FALSE ); } slot->bs=BLOCK_SIZE; if (slot->tp.sigtype != ZT_SIG_HARDHDLC) { if (ioctl(slot->sock, ZT_SET_BLOCKSIZE, &slot->bs)) { fprintf(stderr, "Unable to set block size to %d: %s\n", slot->bs, strerror(errno)); return( FALSE ); } } if (ioctl(slot->sock, ZT_GET_PARAMS, &slot->tp)) { fprintf(stderr, "Unable to get channel parameters\n"); return( FALSE ); } if (slot->tp.sigtype == ZT_SIG_HARDHDLC) { printf("HARDWARE HDLC %s\n",slot->if_name); bi.txbufpolicy = ZT_POLICY_IMMEDIATE; bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; bi.numbufs = 32; bi.bufsize = 1024; if (ioctl(slot->sock, ZT_SET_BUFINFO, &bi)) { fprintf(stderr, "Unable to set appropriate buffering on channel %s\n", slot->if_name); return( FALSE ); } } ioctl(slot->sock, ZT_GETEVENT); i = ZT_FLUSH_ALL; if (ioctl(slot->sock,ZT_FLUSH,&i) == -1){ perror("tor_flush"); return( FALSE ); } #if 0 if (zap_ec_ctrl(slot,32) != 0) { return (FALSE); } #endif printf("Socket bound to dev=%s\n\n",slot->if_name); return (TRUE); } int api_tdm_fe_alarms_callback(int fd, unsigned char alarm) { int fd_found=0; int i; for (i=0;i max_fd){ max_fd=tslot_array[i].sock; } } i=0; tv.tv_usec = 0; tv.tv_sec = 10; Rx_count = 0; for(;;) { FD_ZERO(&ready); max_fd=0; for (i=0;i max_fd){ max_fd=tslot_array[i].sock; } } tv.tv_usec = 0; tv.tv_sec = 10; if (end){ break; } /* The select function must be used to implement flow control. * WANPIPE socket will block the user if the socket cannot send * or there is nothing to receive. * * By using the last socket file descriptor +1 select will wait * for all active sockets. */ slots=0; if((serr=select(max_fd + 1, &ready, NULL, NULL, &tv))){ for (i=0;isock,&ready)){ err = read(slot->sock, Rx_data,slot->bs); //printf("RX DATA HDLC: Len=%i\n",err-sizeof(wp_api_hdr_t)); //print_packet(&Rx_data[sizeof(wp_api_hdr_t)],err-sizeof(wp_api_hdr_t)); /* err indicates bytes received */ if(err >= slot->bs) { unsigned char *rx_frame = (unsigned char *)&Rx_data[0]; int len = err; if (slot->tp.sigtype == ZT_SIG_HARDHDLC) { len=len-2; } /* Rx packet recevied OK * Each rx packet will contain sizeof(wp_api_hdr_t) bytes of * rx header, that must be removed. The * first byte of the sizeof(wp_api_hdr_t) byte header will * indicate an error condition. */ #if 0 printf("RX DATA: Len=%i\n",len); print_packet(rx_frame,len); frame++; if ((frame % 100) == 0) { sangoma_get_full_cfg(slot->sock, &tdm_api); } continue; #endif frame++; print_stats++; slot->frames++; wanpipe_hdlc_decode(slot->hdlc_eng,rx_frame,len); packets+=wanpipe_get_rx_hdlc_packets(slot->hdlc_eng); error_bit+=wanpipe_get_rx_hdlc_errors(slot->hdlc_eng); error_crc+=slot->hdlc_eng->decoder.stats.crc; error_abort+=slot->hdlc_eng->decoder.stats.abort; error_frm+=slot->hdlc_eng->decoder.stats.frame_overflow; #if 1 if (wanpipe_get_rx_hdlc_errors(slot->hdlc_eng) != slot->last_error){ slot->last_error = wanpipe_get_rx_hdlc_errors(slot->hdlc_eng); if (slot->last_error > 1){ printf("\n%s: Errors = %i (crc=%i, abort=%i, frame=%i)\n", slot->if_name, wanpipe_get_rx_hdlc_errors(slot->hdlc_eng), slot->hdlc_eng->decoder.stats.crc, slot->hdlc_eng->decoder.stats.abort, slot->hdlc_eng->decoder.stats.frame_overflow); //wanpipe_hdlc_dump_ring(slot->hdlc_eng); } } if ((slot->frames % 100) == 0 && packets == 0){ printf("\n%s: Frames=%i Rx Packets = %i (crc=%i, abort=%i, frame=%i)\n", slot->if_name, frame, wanpipe_get_rx_hdlc_packets(slot->hdlc_eng), slot->hdlc_eng->decoder.stats.crc, slot->hdlc_eng->decoder.stats.abort, slot->hdlc_eng->decoder.stats.frame_overflow); } #endif #if 0 printf("%s: Received packet %i, length = %i : %s\n", slot->if_name,++Rx_count, err, ((error_bit == 0)? "USR DATA OK" : (error_bit&BOARD_UNDERRUN)? "BRD_UNDR" : (error_bit&TX_ISR_UNDERRUN) ? "TX_UNDR" : "UNKNOWN ERROR")); #endif } else { //printf("\n%s: Error receiving data\n",slot->if_name); } } /* If rx */ } /* for all slots */ if (print_stats > 100*slots){ print_stats=0; putchar('\r'); printf("Slots=%04i frame=%04i packets=%04i errors=%04i (crc=%04i abort=%04i frm=%04i)", slots, frame, packets, error_bit>slots?error_bit:0, error_crc, error_abort, error_frm); fflush(stdout); } packets=0; error_bit=0; error_crc=0; error_abort=0; error_frm=0; } else { printf("\n: Error selecting rx socket rc=0x%x errno=0x%x\n", serr,errno); perror("Select: "); //break; } } for (i=0;ibs; /* Send double of max so that a single big frame gets separated into two actual packets */ Tx_hdlc_len=(max_tx_len*2); Tx_hdlc_len*= 0.75; printf("User MTU/MRU=%i Tx Len = %i \n",max_tx_len,Tx_hdlc_len); /* If running HDLC_STREAMING then the received CRC bytes * will be passed to the application as part of the * received data. The CRC bytes will be appended as the * last two bytes in the rx packet. */ memset(&Tx_data[0],0,MAX_TX_DATA); slot->data=0; for (i=0;idata){ Tx_data[i] = slot->data; }else{ Tx_data[i] = i; } } /* If drivers has been configured in HDLC_STREAMING * mode, the CRC bytes will be included into the * rx packet. Thus, the application should remove * the last two bytes of the frame. * * The no_CRC_bytes_Rx will indicate to the application * how many bytes to cut from the end of the rx frame. * */ printf("%s: Tx Starting to write on sock %i data (0x%X) f=%x l=%x \n", slot->if_name,slot->sock,slot->data,Tx_data[0],Tx_data[Tx_hdlc_len-1]); //pause(); for(;;) { FD_ZERO(&fd_write); FD_SET(slot->sock,&fd_write); if (end){ break; } /* The select function must be used to implement flow control. * WANPIPE socket will block the user if the socket cannot send * or there is nothing to receive. * * By using the last socket file descriptor +1 select will wait * for all active sockets. */ #if 1 /* If we got busy on last frame repeat the frame */ if (tx_ok == 1){ #if 0 printf("TX DATA ORIG: Len=%i\n",Tx_hdlc_len); print_packet(&Tx_data[sizeof(wp_api_hdr_t)],Tx_hdlc_len); #endif wanpipe_hdlc_encode(hdlc_eng,&Tx_data[0],Tx_hdlc_len,&Tx_hdlc_data[0],&Tx_encoded_hdlc_len,&next_idle); if (Tx_encoded_hdlc_len < (max_tx_len*2)){ int j; for (j=0;j<((max_tx_len*2) - Tx_encoded_hdlc_len);j++){ Tx_hdlc_data[Tx_encoded_hdlc_len+j]=next_idle; } Tx_encoded_hdlc_len+=j; } #if 0 printf("TX DATA HDLC: Olen=%i Len=%i\n",Tx_hdlc_len,Tx_encoded_hdlc_len); print_packet(&Tx_hdlc_data[sizeof(wp_api_hdr_t)],Tx_encoded_hdlc_len); #endif if (Tx_encoded_hdlc_len > (max_tx_len*2)){ printf("Tx hdlc len > max %i\n",Tx_encoded_hdlc_len); continue; } Tx_length=max_tx_len; Tx_offset=0; //printf("INITIAL Fragment Chunk tx! %i Tx_encoded =%i \n", Tx_offset,Tx_encoded_hdlc_len); #if 0 if ((Tx_count % 60) == 0){ Tx_hdlc_len++; /* Introduce Error */ } #endif #if 0 printf("Data %i\n",Tx_hdlc_len); for (i=0;isock + 1,NULL, &fd_write, NULL, NULL)){ /* Check if the socket is ready to tx data */ if (FD_ISSET(slot->sock,&fd_write)){ if (slot->tp.sigtype == ZT_SIG_HARDHDLC) { Tx_length+=2; } err=write(slot->sock,&Tx_hdlc_data[Tx_offset],Tx_length ); if (err == Tx_length){ /* Packet sent ok */ //printf("\t\t%s:Packet sent: Len=%i Data=0x%x : %i\n", // slot->if_name,err,slot->data,++Tx_count); //putchar('T'); if (slot->tp.sigtype == ZT_SIG_HARDHDLC) { Tx_length-=2; } Tx_offset+=Tx_length; if (Tx_offset >= Tx_encoded_hdlc_len){ //printf("LAST Chunk tx! %i \n", Tx_offset); Tx_offset=0; Tx_length=max_tx_len; /* Last fragment transmitted */ /* pass throught */ } else { Tx_length = Tx_encoded_hdlc_len - Tx_length; if (Tx_length > max_tx_len) { Tx_length=max_tx_len; } // printf("MIDDLE Fragment Chunk tx! %i \n", Tx_offset); continue; } #if RAND_FRAME if (Tx_count%10 == 0){ Tx_hdlc_len=myrand(max_tx_len*2*0.75); for (i=0;itp.sigtype == ZT_SIG_HARDHDLC) { Tx_length-=2; } if (errno != EBUSY){ printf("Errno = %i EBUSY=%i err=%i txlen=%i\n", errno,-EBUSY,err,Tx_length); perror("Send Failed: "); break; } /* The driver is busy, we must requeue this * tx packet, and try resending it again * later. */ } }else{ printf("Error Tx nothing IFFSET\n"); } #if 0 if (Tx_count > MAX_TX_FRAMES){ break; } #endif #if 0 if (Tx_count % 500){ slot->data=slot->data+1; for (i=0;idata; } tx_change_data=1; tx_change_data_cnt=0; } #endif } else { printf("\nError selecting socket\n"); break; } } printf("\nTx Unloading HDLC\n"); wanpipe_unreg_hdlc_engine(hdlc_eng); } /*************************************************************** * Main: * * o Make a socket connection to the driver. * o Call process_con() to read/write the socket * **************************************************************/ int main(int argc, char* argv[]) { int proceed; char router_name[20]; int x,i; if (argc < 3){ printf("Usage: rec_wan_sock ...\n"); exit(0); } nice(-11); signal(SIGINT,&sig_end); signal(SIGTERM,&sig_end); memset(&tslot_array,0,sizeof(tslot_array)); for (i=0;i= 0){ zap_ec_ctrl(&tslot_array[x],0); close(tslot_array[x].sock); tslot_array[x].sock=0; } } /* Wait for the clear call children */ return 0; };