xref: /openwifi/user_space/side_ch_ctl_src/side_ch_ctl.c (revision e557222ed1ec83169ecebd2c529d7e298efac0dd)
122dd0cc4SXianjun Jiao /*
222dd0cc4SXianjun Jiao  * openwifi side channel user space program
3fe6c78a5SJiao Xianjun  * Author: Xianjun Jiao
4fe6c78a5SJiao Xianjun  * SPDX-FileCopyrightText: 2019 UGent
5a6085186SLina Ceballos  * SPDX-License-Identifier: AGPL-3.0-or-later
622dd0cc4SXianjun Jiao  */
722dd0cc4SXianjun Jiao 
822dd0cc4SXianjun Jiao #include <sys/socket.h>
922dd0cc4SXianjun Jiao #include <linux/netlink.h>
1022dd0cc4SXianjun Jiao #include <stdlib.h>
1122dd0cc4SXianjun Jiao #include <string.h>
1222dd0cc4SXianjun Jiao #include <stdio.h>
1322dd0cc4SXianjun Jiao #include <signal.h>
1422dd0cc4SXianjun Jiao #include <stdbool.h>
1522dd0cc4SXianjun Jiao #include <sys/types.h>
1622dd0cc4SXianjun Jiao #include <unistd.h>
1722dd0cc4SXianjun Jiao #include <sys/socket.h>
1822dd0cc4SXianjun Jiao #include <netinet/in.h>
1922dd0cc4SXianjun Jiao #include <netdb.h>
2022dd0cc4SXianjun Jiao #include <arpa/inet.h>
2122dd0cc4SXianjun Jiao 
2222dd0cc4SXianjun Jiao // #define NETLINK_USER 31
23f71252c5SXianjun Jiao #define MAX_NUM_DMA_SYMBOL 8192   //align with side_ch.v side_ch.h
2422dd0cc4SXianjun Jiao 
2522dd0cc4SXianjun Jiao #define MAX_PAYLOAD (8*MAX_NUM_DMA_SYMBOL) /* maximum payload size*/
2622dd0cc4SXianjun Jiao struct sockaddr_nl src_addr, dest_addr;
2722dd0cc4SXianjun Jiao struct nlmsghdr *nlh = NULL;
2822dd0cc4SXianjun Jiao struct iovec iov;
2922dd0cc4SXianjun Jiao int sock_fd;
3022dd0cc4SXianjun Jiao struct msghdr msg;
3122dd0cc4SXianjun Jiao 
3222dd0cc4SXianjun Jiao //align with side_ch_control.v and all related user space, remote files
3322dd0cc4SXianjun Jiao #define CSI_LEN 56 // length of single CSI
3422dd0cc4SXianjun Jiao #define EQUALIZER_LEN (56-4) // for non HT, four {32767,32767} will be padded to achieve 52 (non HT should have 48)
3522dd0cc4SXianjun Jiao #define HEADER_LEN 2 //timestamp and frequency offset
3622dd0cc4SXianjun Jiao 
3722dd0cc4SXianjun Jiao #define ACTION_INVALID       0
3822dd0cc4SXianjun Jiao #define ACTION_REG_WRITE     1
3922dd0cc4SXianjun Jiao #define ACTION_REG_READ      2
4022dd0cc4SXianjun Jiao #define ACTION_SIDE_INFO_GET 3
4122dd0cc4SXianjun Jiao 
4222dd0cc4SXianjun Jiao #define REG_TYPE_INVALID     0
4322dd0cc4SXianjun Jiao #define REG_TYPE_HARDWARE    1
4422dd0cc4SXianjun Jiao #define REG_TYPE_SOFTWARE    2
4522dd0cc4SXianjun Jiao 
4622dd0cc4SXianjun Jiao #define MAX_PARA_STRING_LEN  31
4722dd0cc4SXianjun Jiao char tmp_str[MAX_PARA_STRING_LEN+1];
take_reg_idx_string_for_write(char * para)4822dd0cc4SXianjun Jiao int take_reg_idx_string_for_write(char *para) { // return into tmp_str till 'd' 'D' 'h' 'H' or 0
4922dd0cc4SXianjun Jiao     int i = 0;
5022dd0cc4SXianjun Jiao 
5122dd0cc4SXianjun Jiao     // while (para[i] != 'd' && para[i] != 'D' && para[i] != 'h' && para[i] != 'H' && para[i] != 0) {
5222dd0cc4SXianjun Jiao     while (para[i] != 'd' && para[i] != 'h' && para[i] != 0) {
5322dd0cc4SXianjun Jiao         tmp_str[i] = para[i];
5422dd0cc4SXianjun Jiao         i++;
5522dd0cc4SXianjun Jiao     }
5622dd0cc4SXianjun Jiao 
5722dd0cc4SXianjun Jiao     if (i==0)
5822dd0cc4SXianjun Jiao         return(-1);
5922dd0cc4SXianjun Jiao 
6022dd0cc4SXianjun Jiao     if (para[i-1] == 0) // we expect d D h H, not 0!
6122dd0cc4SXianjun Jiao         return(-2);
6222dd0cc4SXianjun Jiao 
6322dd0cc4SXianjun Jiao     tmp_str[i] = 0;
6422dd0cc4SXianjun Jiao 
6522dd0cc4SXianjun Jiao     return(i);
6622dd0cc4SXianjun Jiao }
6722dd0cc4SXianjun Jiao 
take_reg_val_string_for_write(char * para)6822dd0cc4SXianjun Jiao int take_reg_val_string_for_write(char *para) {
6922dd0cc4SXianjun Jiao     int i = 0;
7022dd0cc4SXianjun Jiao 
7122dd0cc4SXianjun Jiao     while (para[i] != 0) {
7222dd0cc4SXianjun Jiao         tmp_str[i] = para[i];
7322dd0cc4SXianjun Jiao         i++;
7422dd0cc4SXianjun Jiao     }
7522dd0cc4SXianjun Jiao 
7622dd0cc4SXianjun Jiao     if (i==0)
7722dd0cc4SXianjun Jiao         return(-1);
7822dd0cc4SXianjun Jiao 
7922dd0cc4SXianjun Jiao     tmp_str[i] = 0;
8022dd0cc4SXianjun Jiao 
8122dd0cc4SXianjun Jiao     return(i);
8222dd0cc4SXianjun Jiao }
8322dd0cc4SXianjun Jiao 
all_zero_in_string(char * para)8422dd0cc4SXianjun Jiao int all_zero_in_string(char *para) {
8522dd0cc4SXianjun Jiao     int i;
8622dd0cc4SXianjun Jiao     int check_len = strlen(para);
8722dd0cc4SXianjun Jiao 
8822dd0cc4SXianjun Jiao     if (check_len == 0)
8922dd0cc4SXianjun Jiao         return(-1);
9022dd0cc4SXianjun Jiao 
9122dd0cc4SXianjun Jiao     i = 0;
9222dd0cc4SXianjun Jiao     while (para[i] == '0')
9322dd0cc4SXianjun Jiao         i++;
9422dd0cc4SXianjun Jiao 
9522dd0cc4SXianjun Jiao     if (i == check_len)
9622dd0cc4SXianjun Jiao         return(1);
9722dd0cc4SXianjun Jiao 
9822dd0cc4SXianjun Jiao     return(0);
9922dd0cc4SXianjun Jiao }
10022dd0cc4SXianjun Jiao 
atoi_my(char * para)10122dd0cc4SXianjun Jiao long int atoi_my(char *para) {
10222dd0cc4SXianjun Jiao     long int ret = all_zero_in_string(para);
10322dd0cc4SXianjun Jiao 
10422dd0cc4SXianjun Jiao     if (ret<0)
10522dd0cc4SXianjun Jiao         return(-1);
10622dd0cc4SXianjun Jiao 
10722dd0cc4SXianjun Jiao     if (ret==1)
10822dd0cc4SXianjun Jiao         return(0);
10922dd0cc4SXianjun Jiao 
11022dd0cc4SXianjun Jiao     ret = atol(para);
11122dd0cc4SXianjun Jiao 
11222dd0cc4SXianjun Jiao     if (ret==0)
11322dd0cc4SXianjun Jiao         return(-1);
11422dd0cc4SXianjun Jiao 
11522dd0cc4SXianjun Jiao     return(ret);
11622dd0cc4SXianjun Jiao }
11722dd0cc4SXianjun Jiao 
hextoi_my(char * para)11822dd0cc4SXianjun Jiao long int hextoi_my(char *para) {
11922dd0cc4SXianjun Jiao     long int ret = all_zero_in_string(para);
12022dd0cc4SXianjun Jiao 
12122dd0cc4SXianjun Jiao     if (ret<0)
12222dd0cc4SXianjun Jiao         return(-1);
12322dd0cc4SXianjun Jiao 
12422dd0cc4SXianjun Jiao     if (ret==1)
12522dd0cc4SXianjun Jiao         return(0);
12622dd0cc4SXianjun Jiao 
12722dd0cc4SXianjun Jiao     ret = strtoul(para, NULL, 16);
12822dd0cc4SXianjun Jiao 
12922dd0cc4SXianjun Jiao     if (ret==0)
13022dd0cc4SXianjun Jiao         return(-1);
13122dd0cc4SXianjun Jiao 
13222dd0cc4SXianjun Jiao     return(ret);
13322dd0cc4SXianjun Jiao }
13422dd0cc4SXianjun Jiao 
13522dd0cc4SXianjun Jiao // parameter_string format:
13622dd0cc4SXianjun Jiao // write 987   to hardware register  3: wh3d987  (w--write; h--hardware; 3 --register idx; d--decimal; 987--value)
13722dd0cc4SXianjun Jiao // write 0x3db to software register 19: ws19h3db (w--write; s--software; 19--register idx; h--hex;     3db--value 0x3db)
13822dd0cc4SXianjun Jiao //           read software register 23: rs23     (r-- read; s--software; 23--register idx)
139f71252c5SXianjun Jiao //        get csi and equalizer output: g400     (g--  get; 400--every 400ms; no/wrong input means default 100ms)
parse_para_string(char * para,int * action_flag,int * reg_type,int * reg_idx,unsigned int * reg_val,int * interval_ms)140f71252c5SXianjun Jiao int parse_para_string(char *para, int *action_flag, int *reg_type, int *reg_idx, unsigned int *reg_val, int *interval_ms) {
14122dd0cc4SXianjun Jiao     int i, para_string_len, num_char_reg_idx, num_char_reg_val, hex_flag;
14222dd0cc4SXianjun Jiao 
14322dd0cc4SXianjun Jiao     para_string_len = strlen(para);
14422dd0cc4SXianjun Jiao 
14522dd0cc4SXianjun Jiao     if (para_string_len == 0 || para_string_len>MAX_PARA_STRING_LEN) {
14622dd0cc4SXianjun Jiao         printf("Parameter string is too short/long!\n");
14722dd0cc4SXianjun Jiao         return(-1);
14822dd0cc4SXianjun Jiao     }
14922dd0cc4SXianjun Jiao 
15022dd0cc4SXianjun Jiao     // process the csi/equalizer get command
15122dd0cc4SXianjun Jiao     if ( para[0] == 'g'){// || para[0] == 'G' ) {
15222dd0cc4SXianjun Jiao         (*action_flag) = ACTION_SIDE_INFO_GET;
15322dd0cc4SXianjun Jiao 
154b1dd94e3Sluz paz         if (para_string_len == 1) { // no explicit input
155f71252c5SXianjun Jiao             (*interval_ms) = 100;
156f71252c5SXianjun Jiao             printf("The default 100ms side info getting period is taken!\n");
15722dd0cc4SXianjun Jiao             return(0);
15822dd0cc4SXianjun Jiao         }
15922dd0cc4SXianjun Jiao 
16022dd0cc4SXianjun Jiao         // there is something input
161f71252c5SXianjun Jiao         (*interval_ms) = atoi_my(para+1);
162f71252c5SXianjun Jiao         if ( (*interval_ms)<0 ) { // for invalid input, we set it to the default 100ms
163f71252c5SXianjun Jiao             (*interval_ms) = 100;
16422dd0cc4SXianjun Jiao             printf("Invalid side info getting period!\n");
165f71252c5SXianjun Jiao             printf("The default 100ms side info getting period is taken!\n");
16622dd0cc4SXianjun Jiao         }
16722dd0cc4SXianjun Jiao 
16822dd0cc4SXianjun Jiao         return(0);
16922dd0cc4SXianjun Jiao     }
17022dd0cc4SXianjun Jiao 
17122dd0cc4SXianjun Jiao     if (para_string_len == 2) {// this is invalid, for read and write, the length should be > 2
17222dd0cc4SXianjun Jiao         printf("Lack of input (register index/value) for read/write action\n");
17322dd0cc4SXianjun Jiao         return(-2);
17422dd0cc4SXianjun Jiao     }
17522dd0cc4SXianjun Jiao 
17622dd0cc4SXianjun Jiao     // process the register read command
17722dd0cc4SXianjun Jiao     if ( para[0] == 'r'){// || para[0] == 'R' ) {
17822dd0cc4SXianjun Jiao         (*action_flag) = ACTION_REG_READ;
17922dd0cc4SXianjun Jiao 
18022dd0cc4SXianjun Jiao         if ( para[1] == 'h')// || para[1] == 'H' )
18122dd0cc4SXianjun Jiao             (*reg_type) = REG_TYPE_HARDWARE;
18222dd0cc4SXianjun Jiao         else if ( para[1] == 's')// || para[1] == 'S' )
18322dd0cc4SXianjun Jiao             (*reg_type) = REG_TYPE_SOFTWARE;
18422dd0cc4SXianjun Jiao         else {
18522dd0cc4SXianjun Jiao             (*reg_type) = REG_TYPE_INVALID;
18622dd0cc4SXianjun Jiao             printf("Invalid register type (s/h is expected)!\n");
18722dd0cc4SXianjun Jiao             return(-3);
18822dd0cc4SXianjun Jiao         }
18922dd0cc4SXianjun Jiao 
19022dd0cc4SXianjun Jiao         (*reg_idx) = atoi_my(para+2);
19122dd0cc4SXianjun Jiao         if ( (*reg_idx)<0 || (*reg_idx)>31) {
19222dd0cc4SXianjun Jiao             printf("Invalid register index (should be 0~31)!\n");
19322dd0cc4SXianjun Jiao             return(-4);
19422dd0cc4SXianjun Jiao         }
19522dd0cc4SXianjun Jiao 
19622dd0cc4SXianjun Jiao         return(0);
19722dd0cc4SXianjun Jiao     }
19822dd0cc4SXianjun Jiao 
19922dd0cc4SXianjun Jiao     if (para_string_len < 5) { // this is invalid, for write, the length should be >= 5. example wh3d9
20022dd0cc4SXianjun Jiao         printf("Lack of input (register value/etc) for write action\n");
20122dd0cc4SXianjun Jiao         return(-5);
20222dd0cc4SXianjun Jiao     }
20322dd0cc4SXianjun Jiao 
20422dd0cc4SXianjun Jiao     // process the register write command
20522dd0cc4SXianjun Jiao     if ( para[0] == 'w'){// || para[0] == 'W' ) {
20622dd0cc4SXianjun Jiao         (*action_flag) = ACTION_REG_WRITE;
20722dd0cc4SXianjun Jiao 
20822dd0cc4SXianjun Jiao         if ( para[1] == 'h')// || para[1] == 'H' )
20922dd0cc4SXianjun Jiao             (*reg_type) = REG_TYPE_HARDWARE;
21022dd0cc4SXianjun Jiao         else if ( para[1] == 's')// || para[1] == 'S' )
21122dd0cc4SXianjun Jiao             (*reg_type) = REG_TYPE_SOFTWARE;
21222dd0cc4SXianjun Jiao         else {
21322dd0cc4SXianjun Jiao             (*reg_type) = REG_TYPE_INVALID;
21422dd0cc4SXianjun Jiao             printf("Invalid register type (s/h is expected)!\n");
21522dd0cc4SXianjun Jiao             return(-6);
21622dd0cc4SXianjun Jiao         }
21722dd0cc4SXianjun Jiao 
21822dd0cc4SXianjun Jiao         num_char_reg_idx = take_reg_idx_string_for_write(para+2);
21922dd0cc4SXianjun Jiao         if ( num_char_reg_idx<0 ) {
22022dd0cc4SXianjun Jiao             printf("Invalid register index input!\n");
22122dd0cc4SXianjun Jiao             return(-7);
22222dd0cc4SXianjun Jiao         }
22322dd0cc4SXianjun Jiao 
22422dd0cc4SXianjun Jiao         // if ((num_char_reg_idx+2)==para_string_len) //consume all string already
22522dd0cc4SXianjun Jiao         //     return(-8);
22622dd0cc4SXianjun Jiao 
22722dd0cc4SXianjun Jiao         (*reg_idx) = atoi_my(tmp_str);
22822dd0cc4SXianjun Jiao         if ( (*reg_idx)<0 || (*reg_idx)>31 ) {
22922dd0cc4SXianjun Jiao             printf("Invalid register index (should be 0~31)!\n");
23022dd0cc4SXianjun Jiao             return(-9);
23122dd0cc4SXianjun Jiao         }
23222dd0cc4SXianjun Jiao 
23322dd0cc4SXianjun Jiao         if (para[2+num_char_reg_idx] == 'd')// || para[2+num_char_reg_idx] == 'D')
23422dd0cc4SXianjun Jiao             hex_flag=0;
23522dd0cc4SXianjun Jiao         else if (para[2+num_char_reg_idx] == 'h')// || para[2+num_char_reg_idx] == 'H')
23622dd0cc4SXianjun Jiao             hex_flag=1;
23722dd0cc4SXianjun Jiao         else {
23822dd0cc4SXianjun Jiao             printf("Invalid hex/decimal flag (d/h is expected)!\n");
23922dd0cc4SXianjun Jiao             return(-10);
24022dd0cc4SXianjun Jiao         }
24122dd0cc4SXianjun Jiao 
24222dd0cc4SXianjun Jiao         num_char_reg_val = take_reg_val_string_for_write(para+2+num_char_reg_idx+1);
24322dd0cc4SXianjun Jiao         if ( num_char_reg_val<0 ) {
24422dd0cc4SXianjun Jiao             printf("Invalid register value input!\n");
24522dd0cc4SXianjun Jiao             return(-11);
24622dd0cc4SXianjun Jiao         }
24722dd0cc4SXianjun Jiao 
24822dd0cc4SXianjun Jiao         if (hex_flag==0) {
24922dd0cc4SXianjun Jiao             (*reg_val) = atoi_my(tmp_str);
25022dd0cc4SXianjun Jiao             if ( (*reg_val)<0 ) {
25122dd0cc4SXianjun Jiao                 printf("Invalid register value input of decimal number!\n");
25222dd0cc4SXianjun Jiao                 return(-12);
25322dd0cc4SXianjun Jiao             }
25422dd0cc4SXianjun Jiao         } else {
25522dd0cc4SXianjun Jiao             (*reg_val) = hextoi_my(tmp_str);
25622dd0cc4SXianjun Jiao             // printf("%u %s\n", (*reg_val), tmp_str);
25722dd0cc4SXianjun Jiao             if ( (*reg_val)<0 ) {
25822dd0cc4SXianjun Jiao                 printf("Invalid register value input of hex number!\n");
25922dd0cc4SXianjun Jiao                 return(-13);
26022dd0cc4SXianjun Jiao             }
26122dd0cc4SXianjun Jiao         }
26222dd0cc4SXianjun Jiao         return(0);
26322dd0cc4SXianjun Jiao     }
26422dd0cc4SXianjun Jiao 
26522dd0cc4SXianjun Jiao     return(-14);
26622dd0cc4SXianjun Jiao }
26722dd0cc4SXianjun Jiao 
print_usage(void)26822dd0cc4SXianjun Jiao void print_usage(void) {
26922dd0cc4SXianjun Jiao     printf("Usage: side_ch_ctl parameter_string\n");
27022dd0cc4SXianjun Jiao     printf("Example:\n");
27122dd0cc4SXianjun Jiao     printf("write 987   to hardware register  3: wh3d987  (w--write; h--hardware; 3 --register idx; d--decimal; 987--value)\n");
27222dd0cc4SXianjun Jiao     printf("write 0x3db to software register 19: ws19h3db (w--write; s--software; 19--register idx; h--hex;     3db--value 0x3db)\n");
27322dd0cc4SXianjun Jiao     printf("          read software register 23: rs23     (r-- read; s--software; 23--register idx)\n");
274f71252c5SXianjun Jiao     printf("       get csi and equalizer output: g400     (g--  get; 400--every 400ms; no/wrong input means default 100ms)\n");
27522dd0cc4SXianjun Jiao }
27622dd0cc4SXianjun Jiao 
27722dd0cc4SXianjun Jiao volatile bool do_exit = false;
27822dd0cc4SXianjun Jiao 
sigint_callback_handler(int signum)27922dd0cc4SXianjun Jiao void sigint_callback_handler(int signum)
28022dd0cc4SXianjun Jiao {
28122dd0cc4SXianjun Jiao 	fprintf(stdout, "Caught signal %d\n", signum);
28222dd0cc4SXianjun Jiao 	do_exit = true;
28322dd0cc4SXianjun Jiao }
28422dd0cc4SXianjun Jiao 
main(const int argc,char * const argv[])28522dd0cc4SXianjun Jiao int main(const int argc, char * const argv[])
28622dd0cc4SXianjun Jiao {
287f71252c5SXianjun Jiao     int action_flag, reg_type, reg_idx, interval_ms, s, side_info_size, socket_ok = 1, loop_count=0, side_info_count=0;
28822dd0cc4SXianjun Jiao     unsigned int reg_val, *cmd_buf;
28922dd0cc4SXianjun Jiao     unsigned short port;
29022dd0cc4SXianjun Jiao     struct sockaddr_in server;
291*e557222eSXianjun Jiao     int value_only_flag = 0;
29222dd0cc4SXianjun Jiao     int ret = 0;
29322dd0cc4SXianjun Jiao 
294*e557222eSXianjun Jiao     if (argc<2) {
295*e557222eSXianjun Jiao         printf("1 argument is needed!\n");
29622dd0cc4SXianjun Jiao         print_usage();
29722dd0cc4SXianjun Jiao         return(ret);
29822dd0cc4SXianjun Jiao     }
29922dd0cc4SXianjun Jiao 
300*e557222eSXianjun Jiao     value_only_flag = (argc>2?1:0);
301*e557222eSXianjun Jiao 
302f71252c5SXianjun Jiao     ret = parse_para_string(argv[1], &action_flag, &reg_type, &reg_idx, &reg_val, &interval_ms);
303*e557222eSXianjun Jiao     if (value_only_flag==0) {
30422dd0cc4SXianjun Jiao         printf("parse: ret %d\n", ret);
305f71252c5SXianjun Jiao         printf("   tx: action_flag %d reg_type %d reg_idx %d reg_val %u interval_ms %d\n", action_flag, reg_type, reg_idx, reg_val, interval_ms);
306*e557222eSXianjun Jiao     }
30722dd0cc4SXianjun Jiao     if (ret<0) {
30822dd0cc4SXianjun Jiao         printf("Wrong input!\n");
30922dd0cc4SXianjun Jiao         print_usage();
31022dd0cc4SXianjun Jiao         return(ret);
31122dd0cc4SXianjun Jiao     }
31222dd0cc4SXianjun Jiao 
31322dd0cc4SXianjun Jiao     // if (signal(SIGINT, &sigint_callback_handler)==SIG_ERR ||
31422dd0cc4SXianjun Jiao     //     signal(SIGILL, &sigint_callback_handler)==SIG_ERR ||
31522dd0cc4SXianjun Jiao     //     signal(SIGFPE, &sigint_callback_handler)==SIG_ERR ||
31622dd0cc4SXianjun Jiao     //     signal(SIGSEGV, &sigint_callback_handler)==SIG_ERR ||
31722dd0cc4SXianjun Jiao     //     signal(SIGTERM, &sigint_callback_handler)==SIG_ERR ||
31822dd0cc4SXianjun Jiao     //     signal(SIGABRT, &sigint_callback_handler)==SIG_ERR) {
31922dd0cc4SXianjun Jiao     if (signal(SIGINT, &sigint_callback_handler)==SIG_ERR) {
32022dd0cc4SXianjun Jiao         printf("SIG_ERR!\n");
32122dd0cc4SXianjun Jiao         return(ret);
32222dd0cc4SXianjun Jiao     }
32322dd0cc4SXianjun Jiao 
32422dd0cc4SXianjun Jiao     sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
32522dd0cc4SXianjun Jiao     if(sock_fd<0) {
32622dd0cc4SXianjun Jiao         printf("sock_fd %d\n", sock_fd);
32722dd0cc4SXianjun Jiao         return -1;
32822dd0cc4SXianjun Jiao     }
32922dd0cc4SXianjun Jiao 
33022dd0cc4SXianjun Jiao     memset(&src_addr, 0, sizeof(src_addr));
33122dd0cc4SXianjun Jiao     src_addr.nl_family = AF_NETLINK;
33222dd0cc4SXianjun Jiao     src_addr.nl_pid = getpid(); /* self pid */
33322dd0cc4SXianjun Jiao 
33422dd0cc4SXianjun Jiao     bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
33522dd0cc4SXianjun Jiao 
33622dd0cc4SXianjun Jiao     memset(&dest_addr, 0, sizeof(dest_addr));
33722dd0cc4SXianjun Jiao     memset(&dest_addr, 0, sizeof(dest_addr));
33822dd0cc4SXianjun Jiao     dest_addr.nl_family = AF_NETLINK;
33922dd0cc4SXianjun Jiao     dest_addr.nl_pid = 0; /* For Linux Kernel */
34022dd0cc4SXianjun Jiao     dest_addr.nl_groups = 0; /* unicast */
34122dd0cc4SXianjun Jiao 
34222dd0cc4SXianjun Jiao     nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
34322dd0cc4SXianjun Jiao     // memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
34422dd0cc4SXianjun Jiao 
34522dd0cc4SXianjun Jiao     // nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
34622dd0cc4SXianjun Jiao 
34722dd0cc4SXianjun Jiao     // strcpy(NLMSG_DATA(nlh), "Hello");
34822dd0cc4SXianjun Jiao 
34922dd0cc4SXianjun Jiao     // udp socket setup
35022dd0cc4SXianjun Jiao     port = htons(4000); // port 4000 at remote server
35122dd0cc4SXianjun Jiao     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
35222dd0cc4SXianjun Jiao         printf("socket() error! Will not send info to remote.\n");
35322dd0cc4SXianjun Jiao         socket_ok = 0;
35422dd0cc4SXianjun Jiao     }
35522dd0cc4SXianjun Jiao     server.sin_family      = AF_INET;            /* Internet Domain    */
35622dd0cc4SXianjun Jiao     server.sin_port        = port;               /* Server Port        */
35722dd0cc4SXianjun Jiao     server.sin_addr.s_addr = inet_addr("192.168.10.1"); /* Server's Address   */
35822dd0cc4SXianjun Jiao 
35922dd0cc4SXianjun Jiao     while(do_exit==false) {
36022dd0cc4SXianjun Jiao         nlh->nlmsg_len = NLMSG_SPACE(4*4);
36122dd0cc4SXianjun Jiao         nlh->nlmsg_pid = getpid();
36222dd0cc4SXianjun Jiao         nlh->nlmsg_flags = 0;
36322dd0cc4SXianjun Jiao 
36422dd0cc4SXianjun Jiao         cmd_buf = (unsigned int*)NLMSG_DATA(nlh);
36522dd0cc4SXianjun Jiao         cmd_buf[0] = action_flag;
36622dd0cc4SXianjun Jiao         cmd_buf[1] = reg_type;
36722dd0cc4SXianjun Jiao         cmd_buf[2] = reg_idx;
36822dd0cc4SXianjun Jiao         cmd_buf[3] = reg_val;
36922dd0cc4SXianjun Jiao 
37022dd0cc4SXianjun Jiao         iov.iov_base = (void *)nlh;
37122dd0cc4SXianjun Jiao         iov.iov_len = nlh->nlmsg_len;
37222dd0cc4SXianjun Jiao         msg.msg_name = (void *)&dest_addr;
37322dd0cc4SXianjun Jiao         msg.msg_namelen = sizeof(dest_addr);
37422dd0cc4SXianjun Jiao         msg.msg_iov = &iov;
37522dd0cc4SXianjun Jiao         msg.msg_iovlen = 1;
37622dd0cc4SXianjun Jiao 
37722dd0cc4SXianjun Jiao         // printf("Sending message to kernel\n");
37822dd0cc4SXianjun Jiao         sendmsg(sock_fd,&msg,0);
37922dd0cc4SXianjun Jiao         // printf("Waiting for message from kernel\n");
38022dd0cc4SXianjun Jiao 
38122dd0cc4SXianjun Jiao         nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
38222dd0cc4SXianjun Jiao         iov.iov_len = nlh->nlmsg_len;
38322dd0cc4SXianjun Jiao         /* Read message from kernel */
38422dd0cc4SXianjun Jiao         recvmsg(sock_fd, &msg, 0);
38522dd0cc4SXianjun Jiao         // printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh));
38622dd0cc4SXianjun Jiao 
38722dd0cc4SXianjun Jiao         side_info_size = nlh->nlmsg_len-NLMSG_HDRLEN;
388f71252c5SXianjun Jiao         // printf("num_dma_symbol %d\n", side_info_size/8);
38922dd0cc4SXianjun Jiao 
39022dd0cc4SXianjun Jiao         if (action_flag!=ACTION_SIDE_INFO_GET) {
391*e557222eSXianjun Jiao             if (value_only_flag==0)
39222dd0cc4SXianjun Jiao                 printf("   rx: size %d val %d 0x%08x\n", side_info_size, cmd_buf[0], cmd_buf[0]);
393*e557222eSXianjun Jiao             else
394*e557222eSXianjun Jiao                 printf("%u\n", cmd_buf[0]);
39522dd0cc4SXianjun Jiao             break;
39622dd0cc4SXianjun Jiao         }
39722dd0cc4SXianjun Jiao 
39822dd0cc4SXianjun Jiao         if (socket_ok && (side_info_size >= ((CSI_LEN+0*EQUALIZER_LEN+HEADER_LEN)*8)))
39922dd0cc4SXianjun Jiao             if (sendto(s, cmd_buf, side_info_size, 0, (struct sockaddr *)&server, sizeof(server)) < 0)
40022dd0cc4SXianjun Jiao                 printf("sendto() error!\n");
40122dd0cc4SXianjun Jiao 
40222dd0cc4SXianjun Jiao         side_info_count = side_info_count + (side_info_size>4);
40322dd0cc4SXianjun Jiao         loop_count++;
40422dd0cc4SXianjun Jiao         if ((loop_count%64) == 0)
40522dd0cc4SXianjun Jiao             printf("loop %d side info count %d\n", loop_count, side_info_count);
40622dd0cc4SXianjun Jiao 
407f71252c5SXianjun Jiao         usleep(interval_ms*1000);
40822dd0cc4SXianjun Jiao     }
40922dd0cc4SXianjun Jiao 
41022dd0cc4SXianjun Jiao     close(s);
41122dd0cc4SXianjun Jiao     close(sock_fd);
41222dd0cc4SXianjun Jiao     return(ret);
41322dd0cc4SXianjun Jiao }
414