diff --git a/doc/testie.1 b/doc/testie.1 index d368d591fa..99dd5f0af1 100644 --- a/doc/testie.1 +++ b/doc/testie.1 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) +.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== @@ -38,6 +38,8 @@ . ds PI \(*p . ds L" `` . ds R" '' +. ds C` +. ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. @@ -48,17 +50,24 @@ .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX .. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{ +. if \nF \{ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. +. if !\nF==2 \{ +. nr % 0 +. nr F 2 +. \} +. \} .\} +.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -124,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "TESTIE 1" -.TH TESTIE 1 "2013-06-19" "perl v5.14.2" "" +.TH TESTIE 1 "2017-01-18" "perl v5.18.2" "" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -133,214 +142,230 @@ testie \- simple test harness .SH "SYNOPSIS" .IX Header "SYNOPSIS" -.Vb 1 -\& testie [OPTIONS] [FILE]... -.Ve +testie [\s-1OPTIONS\s0] [\s-1FILE\s0]... .SH "DESCRIPTION" .IX Header "DESCRIPTION" -Testie is a simple test harness. Each testie test file incorporates a shell -script to be run and, optionally, input and expected output files for that -script. Testie runs the script; the test fails if any of the script -commands fail, or if the script generates unexpected output. +Testie is a simple test harness. A testie test comprises a shell +script and, optionally, input and expected output files for that +script. Testie runs the script; the test succeeds if all of the script +commands succeed, and the actual output files match expectations. .PP -To run testie, pass it one or more test filenames. It will print useful -error messages for failed tests. Alternatively, give it directory names; -the directories are recursively searched for '\fI*.testie\fR' files. +Testie accepts test filenames and directories as arguments. +Directories are recursively searched for \fI*.testie\fR files. It +reports problems for failed tests, plus a summary. .PP -Return status is 0 if all tests succeed, 1 if any test fails, and 2 if a -test fails due to an internal error. Tests whose \f(CW%require\fR prerequisites -fail do not affect the return status, except that if all tests' -prerequisites fail, the return status is 1 instead of 0. +Testie exits with status 0 if all tests succeed, 1 if any test fails, +and 2 if a test fails due to an internal error. Tests whose \fB\f(CB%require\fB\fR +prerequisites fail do not affect the exit status, except that if all +tests' prerequisites fail, the return status is 1 instead of 0. .SH "OPTIONS" .IX Header "OPTIONS" +.IP "\fB\-j\fR\fIN\fR, \fB\-\-jobs\fR=\fIN\fR" 8 +.IX Item "-jN, --jobs=N" +Run up to \fIN\fR tests simultaneously. Like Make's \fB\-j\fR option. .IP "\fI\s-1VARIABLE\s0\fR=\fI\s-1VALUE\s0\fR" 8 .IX Item "VARIABLE=VALUE" Provide an environment variable setting for \fI\s-1VARIABLE\s0\fR within the script. -.IP "\-V, \-\-verbose" 8 +.IP "\fB\-s\fR, \fB\-\-show\fR \fI\s-1FILE\s0\fR" 8 +.IX Item "-s, --show FILE" +Echo the contents of \fI\s-1FILE\s0\fR on completion. \fI\s-1FILE\s0\fR should be one of the +filenames specified by \fB\f(CB%file\fB\fR or \fB\f(CB%expect\fB\fR, or \fBstdout\fR or \fBstderr\fR. +Leaves out any ignored lines. +.IP "\fB\-S\fR, \fB\-\-show\-raw\fR \fI\s-1FILE\s0\fR" 8 +.IX Item "-S, --show-raw FILE" +Like \fB\-\-show\fR, but includes any ignored lines. +.IP "\fB\-\-show\-all\fR" 8 +.IX Item "--show-all" +Calls \fB\-\-show\fR for all filenames specified by any \fB\f(CB%expect\fB\fR, plus \fBstdout\fR +and \fBstderr\fR. Leaves out any ignored lines. +.IP "\fB\-\-show\-all\-raw\fR" 8 +.IX Item "--show-all-raw" +Like \fB\-\-show\-all\fR, but includes any ignored lines. +.IP "\fB\-e\fR, \fB\-\-expand\fR" 8 +.IX Item "-e, --expand" +Don't run the given test; instead, expand its files into the current +directory. The script is stored in a file called \fI\f(CI%script\fI\fR. +.IP "\fB\-\-preserve\-temporaries\fR" 8 +.IX Item "--preserve-temporaries" +Preserve temporary test directories. Testie runs each test in its own +subdirectory of the current directory. Test directories are named +\&\fItestieNNNNN\fR, and are typically removed on test completion. +Examining the contents of a test directory can be useful when +debugging a test. +.IP "\fB\-p\fR, \fB\-\-path\fR \fI\s-1DIR\s0\fR" 8 +.IX Item "-p, --path DIR" +Prepend \fI\s-1DIR\s0\fR to the \f(CW\*(C`PATH\*(C'\fR environment variable before running the +test script. +.IP "\fB\-V\fR, \fB\-\-verbose\fR" 8 .IX Item "-V, --verbose" Print information to standard error about successful tests as well as unsuccessful tests. -.IP "\-VV, \-\-superverbose" 8 +.IP "\fB\-VV\fR, \fB\-\-superverbose\fR" 8 .IX Item "-VV, --superverbose" -Like \-\-verbose, but use a slightly different format, and additionally print -every test's \f(CW%info\fR section before the test results. -.IP "\-q, \-\-quiet" 8 +Like \fB\-\-verbose\fR, but use a slightly different format, and +additionally print every test's \fB\f(CB%info\fB\fR section before the test results. +.IP "\fB\-q\fR, \fB\-\-quiet\fR" 8 .IX Item "-q, --quiet" Don't print information to the terminal while running multiple tests. -.IP "\-v, \-\-version" 8 +.IP "\fB\-v\fR, \fB\-\-version\fR" 8 .IX Item "-v, --version" Print version number information and exit. -.IP "\-\-help" 8 +.IP "\fB\-\-help\fR" 8 .IX Item "--help" Print help information and exit. -.IP "\-\-preserve\-temporaries" 8 -.IX Item "--preserve-temporaries" -Preserve the temporary directory created for the test. -.IP "\-s, \-\-show \s-1FILE\s0" 8 -.IX Item "-s, --show FILE" -Echo the contents of \s-1FILE\s0 on completion. \s-1FILE\s0 should be one of the -filenames specified by \f(CW%file\fR or \f(CW%expect\fR*, or 'stdout' or 'stderr'. -Leaves out any ignored lines. -.IP "\-S, \-\-show\-raw \s-1FILE\s0" 8 -.IX Item "-S, --show-raw FILE" -Like \-\-show, but includes any ignored lines. -.IP "\-\-show\-all" 8 -.IX Item "--show-all" -Like '\-\-show' for all filenames specified by any \f(CW%expect\fR*, plus 'stdout' -and 'stderr'. Leaves out any ignored lines. -.IP "\-\-show\-all\-raw" 8 -.IX Item "--show-all-raw" -Like '\-\-show\-raw' for all filenames specified by any \f(CW%expect\fR*, -plus 'stdout' and 'stderr'. Includes any ignored lines. -.IP "\-e, \-\-expand" 8 -.IX Item "-e, --expand" -Don't run the given test; instead, expand its files into the current -directory. The script is stored in a file called '+script+'. -.IP "\-j\fIN\fR, \-\-jobs=\fIN\fR" 8 -.IX Item "-jN, --jobs=N" -Run up to \fIN\fR tests simultaneously. Like Make's '\-j' option. .SH "FILE FORMAT" .IX Header "FILE FORMAT" Testie test files consist of several sections, each introduced by a line -starting with %. There must be, at least, a \f(CW%script\fR section. -.PP -The \f(CW%file\fR and \f(CW%expect\fR* sections define input and/or output files by -name. Testie runs its script in a private directory in \fI/tmp\fR; any files -mentioned in \f(CW%file\fR or \f(CW%expect\fR* are placed in that directory. -.ie n .IP "%script" 8 -.el .IP "\f(CW%script\fR" 8 +starting with \fB%\fR. There must be, at least, a \fB\f(CB%script\fB\fR section. +The \fB\f(CB%file\fB\fR and \fB\f(CB%expect\fB\fR sections define input and output files by +name. +.ie n .IP "\fB\fB%script\fB\fR" 8 +.el .IP "\fB\f(CB%script\fB\fR" 8 .IX Item "%script" -The shell script (in sh syntax) that controls the test. Testie will run -each command in sequence. Every command in the script must succeed, with -exit status 0, or the test will fail. Use \f(CW%file\fR sections to define script -input files and \f(CW%expect\fR* sections to check script output files for expected -values. +The \fBsh\fR shell script that controls the test. Testie will run each +command in sequence. Every command in the script must succeed, with +exit status 0, or the test will fail. Use \fB\f(CB%file\fB\fR sections to define +script input files and \fB\f(CB%expect\fB\fR sections to check script output files +for expected values. +.Sp +The \fB\f(CB%script\fB\fR section can contain subtests. To start a new subtest, +execute a command like \f(CW\*(C`testie_subtest\ SECTIONNAME\*(C'\fR. Testie will +report the problematic \f(CW\*(C`SECTIONNAME\*(C'\fR when standard output or error +doesn't match an expected value. .Sp -The \f(CW%script\fR section can contain multiple subtests. To start a new subtest, -execute a command like \*(L"testie_subtest \s-1SECTIONNAME\s0\*(R". Testie will report the -offending \s-1SECTIONNAME\s0 when standard output or error doesn't match an -expected value. -.ie n .IP "%require [\-q]" 8 -.el .IP "\f(CW%require\fR [\-q]" 8 +The script's environment is populated with any \fI\s-1VARIABLE\s0\fRs set on the +testie command line with \fB\f(BI\s-1VARIABLE\s0\fB=\f(BI\s-1VALUE\s0\fB\fR syntax. Also, the +\&\fB\f(CB$rundir\fB\fR environment variable is set to the directory in which +testie was originally run. +.ie n .IP "\fB\fB%require\fB [\-q]\fR" 8 +.el .IP "\fB\f(CB%require\fB [\-q]\fR" 8 .IX Item "%require [-q]" -A shell script (in sh syntax) defining prerequisites that must be satisfied +An \fBsh\fR shell script defining prerequisites that must be satisfied before the test can run. Every command in the script must succeed, with exit status 0, for the test to run. Standard output and error are not -checked, however. The \f(CW\*(C`\-q\*(C'\fR flag tells testie not to print an error message +checked, however. The \fB\-q\fR flag tells testie not to print an error message if a requirement fails. .Sp Testie runs the requirement script before creating any other test files. -For example, contents of \f(CW%file\fR sections are not available. -.ie n .IP "%info" 8 -.el .IP "\f(CW%info\fR" 8 +For example, contents of \fB\f(CB%file\fB\fR sections are not available. +.ie n .IP "\fB\fB%info\fB\fR" 8 +.el .IP "\fB\f(CB%info\fB\fR" 8 .IX Item "%info" -A short description of the test. In \-\-superverbose mode, the first +A short description of the test. In \fB\-\-superverbose\fR mode, the first paragraph of its contents is printed before the test results. -.ie n .IP "%cut" 8 -.el .IP "\f(CW%cut\fR" 8 +.ie n .IP "\fB\fB%cut\fB\fR" 8 +.el .IP "\fB\f(CB%cut\fB\fR" 8 .IX Item "%cut" This section is ignored. It is intended to comment out obsolete parts of the test. -.ie n .IP "%file [\-d] [+LENGTH] \s-1FILENAME\s0..." 8 -.el .IP "\f(CW%file\fR [\-d] [+LENGTH] \s-1FILENAME\s0..." 8 -.IX Item "%file [-d] [+LENGTH] FILENAME..." -Create an input file for the script. \s-1FILENAME\s0 can be 'stdin', which sets -the script's standard input. If \s-1LENGTH\s0 is provided, the file data consists -of the \s-1LENGTH\s0 bytes following this line. Otherwise, it consists of the data -up to the next section. The \f(CW\*(C`\-d\*(C'\fR flag tells testie to delete the -first character of each line in the section; this makes it possible to -include files that have lines that start with %. -.ie n .IP "%expectv [\-ad] [+LENGTH] \s-1FILENAME\s0..." 8 -.el .IP "\f(CW%expectv\fR [\-ad] [+LENGTH] \s-1FILENAME\s0..." 8 -.IX Item "%expectv [-ad] [+LENGTH] FILENAME..." -An expected output file for the script. \s-1FILENAME\s0 can be 'stdout', for -standard output. If \s-1LENGTH\s0 is provided, the file data consists of the -\&\s-1LENGTH\s0 bytes following this line; otherwise, it consists of the data up to -the next section. +.ie n .IP "\fB\fB%file\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%file\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.IX Item "%file [-de] [+LENGTH] FILENAME..." +Create an input file for the script. \fI\s-1FILENAME\s0\fR can be \fBstdin\fR, +which sets the script's standard input. If \fB+\fR\fI\s-1LENGTH\s0\fR is provided, +the file data consists of the \fI\s-1LENGTH\s0\fR bytes following this line; +otherwise, it consists of the data up to the next section. The \fB\-d\fR +flag tells testie to delete the first character of each line in the +section. The \fB\-e\fR flag indicates that the section was \s-1MIME\s0 +Base64\-encoded (see \fIbase64\fR\|(1)); it is decoded before use. To +include a file with lines that start with \fB%\fR (which would normally +start a new section), use \fB\-d\fR and preface each line of the file with +a space, or use \fB\-e\fR. +.ie n .IP "\fB\fB%expect\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%expect\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.IX Item "%expect [-adeiw] [+LENGTH] FILENAME..." +Define an expected output file. Differences between the script's +output \fI\s-1FILENAME\s0\fR and the contents of the \fB\f(CB%expect\fB\fR section will +cause the test to fail. .Sp -Testie will run the script, then compare the script's output file with the -provided data. They must match exactly or the test fails. +\&\fI\s-1FILENAME\s0\fR can be \fBstdout\fR, for standard output. If \fB+\fR\fI\s-1LENGTH\s0\fR is +provided, the file data consists of the \fI\s-1LENGTH\s0\fR bytes following this +line; otherwise, it consists of the data up to the next section. .Sp -The \f(CW\*(C`\-a\*(C'\fR flag marks this expected output as an alternate. Testie will -compare the script's output file with each provided alternate; the test -succeeds if any of the alternates match. The \f(CW\*(C`\-d\*(C'\fR flag behaves as in -\&\f(CW%file\fR. -.ie n .IP "%expect [\-adiw] [+LENGTH] \s-1FILENAME\s0..." 8 -.el .IP "\f(CW%expect\fR [\-adiw] [+LENGTH] \s-1FILENAME\s0..." 8 -.IX Item "%expect [-adiw] [+LENGTH] FILENAME..." -An expected output file for the script. Arguments are as for \f(CW%expectv\fR. +After running the script, testie compares the \fI\s-1FILENAME\s0\fR generated by +the script with the provided data. The files are compared +line-by-line. Testie ignores blank lines, differences in trailing +whitespace, and lines in the script output that match \fB\f(CB%ignore\fB\fR +patterns (see below). The \fB\-w\fR flag causes testie to ignore +differences in amount of whitespace within each line. .Sp -Testie will run the script, then compare the file generated by script -with the provided data. The files are compared line-by-line. Testie -ignores blank lines and trailing whitespace on each line. It also -ignores lines in the script output that match \f(CW%ignore\fR patterns (see below). -\&\f(CW%expect\fR lines can contain Perl regular expressions, enclosed by two -sets of braces; so the \f(CW%expect\fR line +\&\fB\f(CB%expect\fB\fR lines can contain Perl regular expressions, enclosed by two +sets of braces. The \fB\f(CB%expect\fB\fR line .Sp .Vb 1 \& foo{{(bar)?}} .Ve .Sp -matches either 'foo' or 'foobar'. +matches either \f(CW\*(C`foo\*(C'\fR or \f(CW\*(C`foobar\*(C'\fR. The \fB\-i\fR flag makes all such +regular expressions case-insensitive. (Text outside of regular +expressions must match case.) .Sp -Document an \f(CW%expect\fR line with \*(L"{{?comment}}\*(R" blocks. For example: +Document an \fB\f(CB%expect\fB\fR line with \f(CW\*(C`{{?comment}}\*(C'\fR blocks. For example: .Sp .Vb 1 \& foo {{? the sort was in the right order}} .Ve .Sp -Testie ignores whitespace before and after the \*(L"{{?comment}}\*(R" block, and if +Testie ignores whitespace before and after the \f(CW\*(C`{{?comment}}\*(C'\fR block, and if the actual output differs from this expected line, it prints the comment in addition to the line differences. .Sp -The \f(CW\*(C`\-a\*(C'\fR and \f(CW\*(C`\-d\*(C'\fR flags may also be used for \f(CW%expect\fR sections. Also, the -\&\f(CW\*(C`\-i\*(C'\fR flag makes any regular expressions case-insensitive (text outside of -regular expressions must match case), and the \f(CW\*(C`\-w\*(C'\fR flag ignores any -differences in amount of whitespace within a line. -.ie n .IP "%expectx [\-adiw] [+LENGTH] \s-1FILENAME\s0..." 8 -.el .IP "\f(CW%expectx\fR [\-adiw] [+LENGTH] \s-1FILENAME\s0..." 8 +The \fB\-a\fR flag marks this expected output as an alternate. Testie will +compare the script's output file with each provided alternate; the +test succeeds if any of the alternates match. The \fB\-d\fR flag behaves +as in \fB\f(CB%file\fB\fR. +.ie n .IP "\fB\fB%expectv\fB [\-ade] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%expectv\fB [\-ade] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.IX Item "%expectv [-ade] [+LENGTH] FILENAME..." +Define a literal expected output file. This behaves like \fB\f(CB%expect\fB\fR, +except that the script's output file must match the provided data +\&\fIexactly\fR: \fB\f(CB%expectv\fB\fR never ignores whitespace differences, does not +treat \f(CW\*(C`{{}}\*(C'\fR blocks as regular expressions, and does not parse +\&\fB\f(CB%ignore\fB\fR patterns. +.ie n .IP "\fB\fB%expectx\fB [\-adiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%expectx\fB [\-adiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 .IX Item "%expectx [-adiw] [+LENGTH] FILENAME..." -\&\f(CW%expectx\fR is just like \f(CW%expect\fR, except that every line is treated as a -regular expression. The input is parsed for \*(L"{{?comment}}\*(R" blocks, but -other brace pairs are treated according to the normal regular expression -rules. -.ie n .IP "%stdin [+LENGTH]" 8 -.el .IP "\f(CW%stdin\fR [+LENGTH]" 8 -.IX Item "%stdin [+LENGTH]" -Same as '%file stdin [\s-1ARGS\s0]'. -.ie n .IP "%stdout [\-adiw] [+LENGTH]" 8 -.el .IP "\f(CW%stdout\fR [\-adiw] [+LENGTH]" 8 -.IX Item "%stdout [-adiw] [+LENGTH]" -Same as '%expect stdout'. -.ie n .IP "%stderr [\-adiw] [+LENGTH]" 8 -.el .IP "\f(CW%stderr\fR [\-adiw] [+LENGTH]" 8 -.IX Item "%stderr [-adiw] [+LENGTH]" -Same as '%expect stderr'. -.ie n .IP "%ignorex [\-di] [+LENGTH] [\s-1FILENAME\s0]" 8 -.el .IP "\f(CW%ignorex\fR [\-di] [+LENGTH] [\s-1FILENAME\s0]" 8 +Define a regular-expression expected output file. This behaves like +\&\fB\f(CB%expect\fB\fR, except that every line is treated as a regular expression. +\&\f(CW\*(C`{{?comment}}\*(C'\fR blocks are ignored, but other brace pairs are treated +according to the normal regular expression rules. +.ie n .IP "\fB\fB%stdin\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%stdin\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.IX Item "%stdin [-de] [+LENGTH]" +Same as \fB\f(CB%file\fB stdin\fR. +.ie n .IP "\fB\fB%stdout\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%stdout\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.IX Item "%stdout [-adeiw] [+LENGTH]" +Same as \fB\f(CB%expect\fB stdout\fR. +.ie n .IP "\fB\fB%stderr\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%stderr\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.IX Item "%stderr [-adeiw] [+LENGTH]" +Same as \fB\f(CB%expect\fB stderr\fR. +.ie n .IP "\fB\fB%ignorex\fB [\-di] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%ignorex\fB [\-di] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 .IX Item "%ignorex [-di] [+LENGTH] [FILENAME]" -Each line in the \f(CW%ignorex\fR section is a Perl regular expression. Lines in -the supplied \s-1FILENAME\s0 that match any of those regular expressions will not -be considered when comparing files with \f(CW%expect\fR data. The regular -expression must match the whole line. \s-1FILENAME\s0 may be 'all', in which case -the regular expressions will apply to all \f(CW%expect\fR files. \*(L"{{?comment}}\*(R" +Each line in the \fB\f(CB%ignorex\fB\fR section is a Perl regular expression. Lines in +the supplied \fI\s-1FILENAME\s0\fR that match any of those regular expressions will not +be considered when comparing files with \fB\f(CB%expect\fB\fR data. The regular +expression must match the whole line. \fI\s-1FILENAME\s0\fR may be \fBall\fR, in which case +the regular expressions will apply to all \fB\f(CB%expect\fB\fR files. \f(CW\*(C`{{?comment}}\*(C'\fR blocks are ignored. -.ie n .IP "%ignore, %ignorev" 8 -.el .IP "\f(CW%ignore\fR, \f(CW%ignorev\fR" 8 -.IX Item "%ignore, %ignorev" -Like '%ignorex', but '%ignore' parses regular expressions only inside -double braces (\*(L"{{ }}\*(R"), and '%ignorev' lines must match exactly. -.ie n .IP "%include \s-1FILENAME\s0" 8 -.el .IP "\f(CW%include\fR \s-1FILENAME\s0" 8 +.ie n .IP "\fB\fB%ignore\fB\fR, \fB\fB%ignorev\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%ignore\fB\fR, \fB\f(CB%ignorev\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.IX Item "%ignore, %ignorev [-adeiw] [+LENGTH] [FILENAME]" +Like \fB\f(CB%ignorex\fB\fR, but \fB\f(CB%ignore\fB\fR parses regular expressions only inside +double braces (\f(CW\*(C`{{ }}\*(C'\fR), and \fB\f(CB%ignorev\fB\fR lines must match exactly. +.ie n .IP "\fB\fB%include\fB \f(BI\s-1FILENAME\s0\fB\fR" 8 +.el .IP "\fB\f(CB%include\fB \f(BI\s-1FILENAME\s0\fB\fR" 8 .IX Item "%include FILENAME" Interpolate the contents of another testie file. -.ie n .IP "%eot" 8 -.el .IP "\f(CW%eot\fR" 8 +.ie n .IP "\fB\fB%eot\fB\fR" 8 +.el .IP "\fB\f(CB%eot\fB\fR" 8 .IX Item "%eot" -Marks the end of the current test. The rest of the file will be parsed for +Marks the end of the current test. The rest of the file will be parsed for additional tests. -.ie n .IP "%eof" 8 -.el .IP "\f(CW%eof\fR" 8 +.ie n .IP "\fB\fB%eof\fB\fR" 8 +.el .IP "\fB\f(CB%eof\fB\fR" 8 .IX Item "%eof" The rest of the file is ignored. .SH "EXAMPLE" @@ -360,8 +385,8 @@ file. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" By default, testie sets the \f(CW\*(C`LC_ALL\*(C'\fR environment variable to \*(L"C\*(R"; without -this setting commands like 'sort' have unpredictable effects. To set -\&\f(CW\*(C`LC_ALL\*(C'\fR to another value, set it in the \f(CW%script\fR section. +this setting commands like \fBsort\fR have unpredictable effects. To set +\&\f(CW\*(C`LC_ALL\*(C'\fR to another value, set it in the \fB\f(CB%script\fB\fR section. .SH "AUTHOR" .IX Header "AUTHOR" Eddie Kohler, diff --git a/elements/grid/airoinfo.cc b/elements/grid/airoinfo.cc index aa2acd85d3..3fe4d385b2 100644 --- a/elements/grid/airoinfo.cc +++ b/elements/grid/airoinfo.cc @@ -42,7 +42,7 @@ #endif #ifdef __linux__ -#include +// #include #ifdef IW_MAX_SPY #undef IW_MAX_SPY #define IW_MAX_SPY 40 /* more fuckation -- this constant must be the same across all the drivers as well */ @@ -74,18 +74,18 @@ AiroInfo::configure(Vector &conf, ErrorHandler *errh) int AiroInfo::initialize(ErrorHandler *errh) { - memset(&_ifr, 0, sizeof(_ifr)); - strncpy(_ifr.ifr_name, _ifname.c_str(), sizeof(_ifr.ifr_name)); - _ifr.ifr_name[sizeof(_ifr.ifr_name) - 1] = 0; -#ifdef __linux__ - memset(&_ifr2, 0, sizeof(_ifr2)); - strncpy(_ifr2.ifr_name, _ifname.c_str(), sizeof(_ifr2.ifr_name)); - _ifr2.ifr_name[sizeof(_ifr2.ifr_name) - 1] = 0; -#endif - - _fd = socket(AF_INET, SOCK_DGRAM, 0); - if (_fd < 0) - return errh->error("Unable to open socket to %s device", _ifr.ifr_name); +// memset(&_ifr, 0, sizeof(_ifr)); +// strncpy(_ifr.ifr_name, _ifname.c_str(), sizeof(_ifr.ifr_name)); +// _ifr.ifr_name[sizeof(_ifr.ifr_name) - 1] = 0; +// #ifdef __linux__ +// memset(&_ifr2, 0, sizeof(_ifr2)); +// strncpy(_ifr2.ifr_name, _ifname.c_str(), sizeof(_ifr2.ifr_name)); +// _ifr2.ifr_name[sizeof(_ifr2.ifr_name) - 1] = 0; +// #endif + +// _fd = socket(AF_INET, SOCK_DGRAM, 0); +// if (_fd < 0) +// return errh->error("Unable to open socket to %s device", _ifr.ifr_name); return 0; } @@ -95,36 +95,36 @@ AiroInfo::initialize(ErrorHandler *errh) bool AiroInfo::get_signal_info(const EtherAddress &e, int &dbm, int &quality) { - struct an_req areq; - memset(&areq, 0, sizeof(areq)); - - areq.an_len = AN_MAX_DATALEN; - areq.an_type = AN_RID_READ_CACHE; - - - /* due to AN_MAX_DATALEN = 512 16-bit vals, we could only ever get - ~56 entries from the card's cache. however, since the current - driver mod has only 30 entries, that's cool... but this could be - a problem in big (e.g. > 30 nodes) networks... */ - _ifr.ifr_data = (char *) &areq; - int res = ioctl(_fd, SIOCGAIRONET, &_ifr); - if (res == -1) { - click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading signal cache: %s\n", - strerror(errno)); - return false; - } - - int *num_entries = (int *) &areq.an_val; - char *p = (char *) &areq.an_val; - p += sizeof(int); - struct an_sigcache *entries = (struct an_sigcache *) p; - for (int i = 0; i < *num_entries; i++) { - if (e == EtherAddress((unsigned char *) entries[i].macsrc)) { - dbm = entries[i].signal; - quality = entries[i].quality; - return true; - } - } + // struct an_req areq; + // memset(&areq, 0, sizeof(areq)); + + // areq.an_len = AN_MAX_DATALEN; + // areq.an_type = AN_RID_READ_CACHE; + + + // /* due to AN_MAX_DATALEN = 512 16-bit vals, we could only ever get + // ~56 entries from the card's cache. however, since the current + // driver mod has only 30 entries, that's cool... but this could be + // a problem in big (e.g. > 30 nodes) networks... */ + // _ifr.ifr_data = (char *) &areq; + // int res = ioctl(_fd, SIOCGAIRONET, &_ifr); + // if (res == -1) { + // click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading signal cache: %s\n", + // strerror(errno)); + // return false; + // } + + // int *num_entries = (int *) &areq.an_val; + // char *p = (char *) &areq.an_val; + // p += sizeof(int); + // struct an_sigcache *entries = (struct an_sigcache *) p; + // for (int i = 0; i < *num_entries; i++) { + // if (e == EtherAddress((unsigned char *) entries[i].macsrc)) { + // dbm = entries[i].signal; + // quality = entries[i].quality; + // return true; + // } + // } return false; } @@ -132,68 +132,68 @@ AiroInfo::get_signal_info(const EtherAddress &e, int &dbm, int &quality) bool AiroInfo::get_tx_stats(const EtherAddress &e, int &num_successful, int &num_failed) { - struct an_req areq; - memset(&areq, 0, sizeof(areq)); - - areq.an_len = AN_MAX_DATALEN; - areq.an_type = AN_RID_READ_LLFAIL; - - _ifr.ifr_data = (char *) &areq; - int res = ioctl(_fd, SIOCGAIRONET, &_ifr); - if (res == -1) { - click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading tx stats cache: %s\n", - strerror(errno)); - return false; - } - - int *num_entries = (int *) &areq.an_val; - char *p = (char *) &areq.an_val; - p += sizeof(int); - struct an_llfailcache *entries = (struct an_llfailcache *) p; - for (int i = 0; i < *num_entries; i++) { - if (e == EtherAddress((unsigned char *) entries[i].macdst)) { - num_failed = entries[i].num_fail; - num_successful = entries[i].num_succeed; - return true; - } - } + // struct an_req areq; + // memset(&areq, 0, sizeof(areq)); + + // areq.an_len = AN_MAX_DATALEN; + // areq.an_type = AN_RID_READ_LLFAIL; + + // _ifr.ifr_data = (char *) &areq; + // int res = ioctl(_fd, SIOCGAIRONET, &_ifr); + // if (res == -1) { + // click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading tx stats cache: %s\n", + // strerror(errno)); + // return false; + // } + + // int *num_entries = (int *) &areq.an_val; + // char *p = (char *) &areq.an_val; + // p += sizeof(int); + // struct an_llfailcache *entries = (struct an_llfailcache *) p; + // for (int i = 0; i < *num_entries; i++) { + // if (e == EtherAddress((unsigned char *) entries[i].macdst)) { + // num_failed = entries[i].num_fail; + // num_successful = entries[i].num_succeed; + // return true; + // } + // } return false; } bool AiroInfo::get_noise(int &max_over_sec, int &avg_over_minute, int &max_over_minute) { - struct an_req areq; - memset(&areq, 0, sizeof(areq)); - - areq.an_len = AN_MAX_DATALEN; - areq.an_type = AN_RID_STATUS; - - _ifr.ifr_data = (char *) &areq; - int res = ioctl(_fd, SIOCGAIRONET, &_ifr); - if (res == -1) { - click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading noise from status struct: %s\n", - strerror(errno)); - return false; - } - - // noise info from Marco Molteni (molter@tin.it) - // u_int8_t an_noise_prev_sec_pc; /* 0x7A */ - // u_int8_t an_noise_prev_sec_db; /* 0x7B */ - // u_int8_t an_avg_noise_prev_min_pc; /* 0x7C */ - // u_int8_t an_avg_noise_prev_min_db; /* 0x7D */ - // u_int8_t an_max_noise_prev_min_pc; /* 0x7E */ - // u_int8_t an_max_noise_prev_min_db; /* 0x7F */ - - u_int8_t *base = (u_int8_t *) _ifr.ifr_data; - u_int8_t *u8 = base + 0x7B; - max_over_sec = *u8; - - u8 = base + 0x7D; - avg_over_minute = *u8; - - u8 = base + 0x7F; - max_over_minute = *u8; + // struct an_req areq; + // memset(&areq, 0, sizeof(areq)); + + // areq.an_len = AN_MAX_DATALEN; + // areq.an_type = AN_RID_STATUS; + + // _ifr.ifr_data = (char *) &areq; + // int res = ioctl(_fd, SIOCGAIRONET, &_ifr); + // if (res == -1) { + // click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when reading noise from status struct: %s\n", + // strerror(errno)); + // return false; + // } + + // // noise info from Marco Molteni (molter@tin.it) + // // u_int8_t an_noise_prev_sec_pc; /* 0x7A */ + // // u_int8_t an_noise_prev_sec_db; /* 0x7B */ + // // u_int8_t an_avg_noise_prev_min_pc; /* 0x7C */ + // // u_int8_t an_avg_noise_prev_min_db; /* 0x7D */ + // // u_int8_t an_max_noise_prev_min_pc; /* 0x7E */ + // // u_int8_t an_max_noise_prev_min_db; /* 0x7F */ + + // u_int8_t *base = (u_int8_t *) _ifr.ifr_data; + // u_int8_t *u8 = base + 0x7B; + // max_over_sec = *u8; + + // u8 = base + 0x7D; + // avg_over_minute = *u8; + + // u8 = base + 0x7F; + // max_over_minute = *u8; return true; } @@ -203,29 +203,29 @@ AiroInfo::get_noise(int &max_over_sec, int &avg_over_minute, int &max_over_minut bool AiroInfo::get_signal_info(const EtherAddress &e, int &dbm, int &quality) { - char buf[(sizeof(struct iw_quality) + sizeof(struct sockaddr)) * IW_MAX_SPY]; - - _ifr.u.data.pointer = buf; - _ifr.u.data.length = 0; - _ifr.u.data.flags = 0; - int res = ioctl(_fd, SIOCGIWSPY, &_ifr); - if (res == -1) { - click_chatter("AiroInfo: ioctl(SIOCGIWSPY) error when reading signal info: %s\n", - strerror(errno)); - return false; - } - - int n = _ifr.u.data.length; - - for (int i = 0; i < n; i++) { - struct sockaddr *sa = (struct sockaddr *) (buf + i * sizeof(struct sockaddr)); - if (e == EtherAddress((unsigned char *) &sa->sa_data)) { - struct iw_quality *q = (struct iw_quality *) (buf + n*sizeof(struct sockaddr) + i*sizeof(struct iw_quality)); - dbm = ((int) q->level) - 256; - quality = q->qual; - return true; - } - } + // char buf[(sizeof(struct iw_quality) + sizeof(struct sockaddr)) * IW_MAX_SPY]; + + // _ifr.u.data.pointer = buf; + // _ifr.u.data.length = 0; + // _ifr.u.data.flags = 0; + // int res = ioctl(_fd, SIOCGIWSPY, &_ifr); + // if (res == -1) { + // click_chatter("AiroInfo: ioctl(SIOCGIWSPY) error when reading signal info: %s\n", + // strerror(errno)); + // return false; + // } + + // int n = _ifr.u.data.length; + + // for (int i = 0; i < n; i++) { + // struct sockaddr *sa = (struct sockaddr *) (buf + i * sizeof(struct sockaddr)); + // if (e == EtherAddress((unsigned char *) &sa->sa_data)) { + // struct iw_quality *q = (struct iw_quality *) (buf + n*sizeof(struct sockaddr) + i*sizeof(struct iw_quality)); + // dbm = ((int) q->level) - 256; + // quality = q->qual; + // return true; + // } + // } return false; } @@ -250,25 +250,25 @@ struct aironet_ioctl_t { bool AiroInfo::get_noise(int &max_over_sec, int &avg_over_minute, int &max_over_minute) { - u_int8_t buf[0x80]; - memset(buf, 69, sizeof(buf)); - - aironet_ioctl_t airo_cmd; - airo_cmd.command = AIROGSTAT; - airo_cmd.data = buf; - airo_cmd.len = sizeof(buf); - _ifr2.ifr_data = (char *) &airo_cmd; - - int res = ioctl(_fd, AIROIOCTL, &_ifr2); - if (res == -1) { - click_chatter("AiroInfo: ioctl(AIROIOCTL) error when reading noise info: %s\n", - strerror(errno)); - return false; - } - - max_over_sec = -buf[0x7B]; - avg_over_minute = -buf[0x7D]; - max_over_minute = -buf[0x7F]; + // u_int8_t buf[0x80]; + // memset(buf, 69, sizeof(buf)); + + // aironet_ioctl_t airo_cmd; + // airo_cmd.command = AIROGSTAT; + // airo_cmd.data = buf; + // airo_cmd.len = sizeof(buf); + // _ifr2.ifr_data = (char *) &airo_cmd; + + // int res = ioctl(_fd, AIROIOCTL, &_ifr2); + // if (res == -1) { + // click_chatter("AiroInfo: ioctl(AIROIOCTL) error when reading noise info: %s\n", + // strerror(errno)); + // return false; + // } + + // max_over_sec = -buf[0x7B]; + // avg_over_minute = -buf[0x7D]; + // max_over_minute = -buf[0x7F]; return true; } @@ -304,17 +304,17 @@ void AiroInfo::clear_tx_stats() { #ifdef __OpenBSD__ - struct an_req areq; - memset(&areq, 0, sizeof(areq)); - areq.an_len = 0; - areq.an_type = AN_RID_ZERO_LLFAIL; - - _ifr.ifr_data = (char *) &areq; - int res = ioctl(_fd, SIOCGAIRONET, &_ifr); - if (res == -1) { - click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when resetting tx stats cache: %s\n", - strerror(errno)); - } + // struct an_req areq; + // memset(&areq, 0, sizeof(areq)); + // areq.an_len = 0; + // areq.an_type = AN_RID_ZERO_LLFAIL; + + // _ifr.ifr_data = (char *) &areq; + // int res = ioctl(_fd, SIOCGAIRONET, &_ifr); + // if (res == -1) { + // click_chatter("AiroInfo: ioctl(SIOCGAIRONET) error when resetting tx stats cache: %s\n", + // strerror(errno)); + // } #endif } diff --git a/elements/grid/airoinfo.hh b/elements/grid/airoinfo.hh index 7f1d57a2d1..9e4ea64afb 100644 --- a/elements/grid/airoinfo.hh +++ b/elements/grid/airoinfo.hh @@ -4,14 +4,14 @@ #include #ifdef __linux__ #include -#include -#include +// #include +// #include #else /* OpenBSD 2.9 doesn't protect from multiple inclusion, but later versions do */ #ifndef CLICK_NET_IF_H #define CLICK_NET_IF_H -#include +// #include #endif #endif CLICK_DECLS @@ -69,12 +69,12 @@ private: int _fd; String _ifname; -#ifdef __linux__ - struct iwreq _ifr; - struct ifreq _ifr2; -#else - struct ifreq _ifr; -#endif +// #ifdef __linux__ +// struct iwreq _ifr; +// struct ifreq _ifr2; +// #else +// struct ifreq _ifr; +// #endif }; diff --git a/elements/ip/80211r/rapcontrol.cc b/elements/ip/80211r/rapcontrol.cc new file mode 100755 index 0000000000..5ef776ea4b --- /dev/null +++ b/elements/ip/80211r/rapcontrol.cc @@ -0,0 +1,272 @@ +/* + element for 802.11r ap, + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "rapcontrol.hh" +#include +#include +#include +#include +#include + + CLICK_DECLS + +int +RAPControl::configure(Vector &conf, ErrorHandler *errh) +{ + int i,tmp_id; + + openlog("RAPControl", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + + _ethh = new click_ether[MAX_N_CLIENT+1];//first MAX_N_CLIENT: ap->client; ap->controller + if (Args(conf, this, errh) + .read_p("IDENTITY", IntArg(), tmp_id) + .read_p("FIRSTSTART1", IntArg(), tmp_start[0]) + .read_p("FIRSTSTART2", IntArg(), tmp_start[1]) + .read_p("FIRSTSTART3", IntArg(), tmp_start[2]) + .complete() < 0) + return -1; + + //down control pkt + identity = tmp_id; + for(i=0;idata(), &control_content, 4); + + syslog (LOG_DEBUG, "ap %d pass ant req for client %d, ap_ori %d, ap_tar %d\n", identity, c+1, ori+1, tar+1); + output(0).push(p); + } + else if(t == 0x0a) //(state[c] == INACTIVE && t == 0x0a && tar == identity - 1) + { + control_content[0] = 0x0b; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(4); + // // data part + memcpy(p->data(), &control_content, 4); + + syslog (LOG_DEBUG, "ap %d pass reas for client %d, ap_ori %d, ap_tar %d\n", identity, c+1, ori+1, tar+1); + output(0).push(p); + } + else if(t == 0xff) + { + + for(i=0;idata(), &control_content, 4); + + syslog (LOG_DEBUG, "ap %d pass reset\n", identity); + output(0).push(p); + + + } + p_in -> kill(); + +} + +void RAPControl::push_down_control(Packet*p_in) +{ + int i; + const unsigned char & t = r_control_type(p_in); + const unsigned char & c = r_control_client(p_in); + const unsigned char & ori = r_control_ori(p_in); + const unsigned char & tar = r_control_tar(p_in); + syslog (LOG_DEBUG, "AP %d receive down control: state %d, type %X, client %d, ap_ori %d, ap_tar %d\n", identity, state[c], t, c+1, ori+1, tar+1); + + if(state[c] == INACTIVE && t == 0x06 && tar == identity-1) + { + control_content[0] = 0x07; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(4); + // // data part + memcpy(p->data(), &control_content, 4); + + syslog (LOG_DEBUG, "ap %d send ant ack for client %d, ap_ori %d, ap_tar %d\n", identity, c+1, ori+1, tar+1); + output(0).push(p); + } + else if(state[c] == IDLE && t == 0x08 && ori == identity-1) + { + state[c] = INACTIVE; + control_content[0] = 0x09; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), &(_ethh[c]), sizeof(click_ether)); + syslog (LOG_DEBUG, "ap %d pass ant ack for client %d, ap_ori %d, ap_tar %d\n", identity, c+1, ori+1, tar+1); + output(2).push(p); + } + else if(state[c] == INACTIVE && t == 0x0c && tar == identity-1) + { + state[c] = IDLE; + control_content[0] = 0x0d; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), &(_ethh[c]), sizeof(click_ether)); + syslog (LOG_DEBUG, "ap %d pass reas ack for client %d, ap_ori %d, ap_tar %d\n", identity, c+1, ori+1, tar+1); + output(2).push(p); + } + else if(t == 0xff) + { + + for(i=0;i kill(); + +} + +void RAPControl::push_down_data(Packet*p_in) +{ + static unsigned char c; + switch(r_dst_mac_suffix(p_in)) + { + case CLIENT1_MAC_SUFFIX: c = 0;break; + case CLIENT2_MAC_SUFFIX: c = 1;break; + case CLIENT3_MAC_SUFFIX: c = 2;break; + } + if(state[c] == INACTIVE) + p_in -> kill(); + else + output(2).push(p_in); +} + +void RAPControl::push_up_data(Packet*p_in) +{ + static unsigned char c; + switch(r_src_mac_suffix(p_in)) + { + case CLIENT1_MAC_SUFFIX: c = 0;break; + case CLIENT2_MAC_SUFFIX: c = 1;break; + case CLIENT3_MAC_SUFFIX: c = 2;break; + } + if(state[c] == INACTIVE) + p_in -> kill(); + else + { + WritablePacket *p = p_in->uniqueify(); + p->push(sizeof(click_ether)); + memcpy(p->data(), &(_ethh[MAX_N_CLIENT]), sizeof(click_ether)); + output(1).push(p); + } +} + + + +CLICK_ENDDECLS +EXPORT_ELEMENT(RAPControl) +ELEMENT_MT_SAFE(RAPControl) diff --git a/elements/ip/80211r/rapcontrol.hh b/elements/ip/80211r/rapcontrol.hh new file mode 100755 index 0000000000..421fbab348 --- /dev/null +++ b/elements/ip/80211r/rapcontrol.hh @@ -0,0 +1,47 @@ +/* + element for 802.11r ap, + Created by Zhenyu Song: sunnyszy@gmail.com + */ +#ifndef CLICK_RAPCONTROL_HH +#define CLICK_RAPCONTROL_HH +#include +#include +#include +#include +#include +#include + +CLICK_DECLS + + +class RAPControl : public Element { public: + + + const char *class_name() const { return "RAPControl"; } + const char *port_count() const { return "4/3"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int port, Packet *); + void push_up_control(Packet *); + void push_up_data(Packet *); + void push_down_control(Packet *); + void push_down_data(Packet *); + + + private: + unsigned char identity; + unsigned char state[MAX_N_CLIENT]; + unsigned char first_start[MAX_N_CLIENT]; + + click_ether * _ethh; + unsigned char control_content[4]; + int tmp_start[3];//set this fix because # of click configuration interface + + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/80211r/rclientcontrol.cc b/elements/ip/80211r/rclientcontrol.cc new file mode 100755 index 0000000000..0a9142efce --- /dev/null +++ b/elements/ip/80211r/rclientcontrol.cc @@ -0,0 +1,253 @@ +/* + element for 802.11r client, + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "rclientcontrol.hh" +#include +#include +#include +#include +#include + + CLICK_DECLS + +int +RClientControl::configure(Vector &conf, ErrorHandler *errh) +{ + int i, tmp_start[3],tmp_id; + char tmp_rssi_threshold; + openlog("RClientControl", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + for(i=0;iether_type = htons(CONTROL_SUFFIX+ETHER_PROTO_BASE); + + switch(identity) + { + case 1: cp_ethernet_address(CLIENT1_MAC, _ethh->ether_shost);break; + case 2: cp_ethernet_address(CLIENT2_MAC, _ethh->ether_shost);break; + case 3: cp_ethernet_address(CLIENT3_MAC, _ethh->ether_shost);break; + } + cp_ethernet_address(CONTROLLER_IN_MAC, _ethh->ether_dhost); + + time_lock = false; + last_time = 0; + syslog (LOG_DEBUG, "finish configure, ready to start\n"); + return 0; +} + +void RClientControl::reset() +{ + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + + control_content[0] = 0xff; + control_content[1] = 0xff; + control_content[2] = 0xff; + control_content[3] = 0xff; + + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "client issue reset\n"); + output(0).push(p); + +} + +void +RClientControl::push(int port, Packet *p_in) +{ + + // here is a small bug, I can not put the reset function in the initial function + static unsigned char lock = 0; + if(!lock) + { + lock++; + reset(); + } + + switch(port) + { + case 0: push_updata(p_in);break; + case 1: push_control(p_in);break; + case 2: push_downdata(p_in);break; + case 3: push_80211(p_in);break; + } +} + + +void RClientControl::push_control(Packet*p_in) +{ + const unsigned char & t = r_control_type(p_in); + const unsigned char & c = r_control_client(p_in); + const unsigned char & ori = r_control_ori(p_in); + const unsigned char & tar = r_control_tar(p_in); + + if(state == ANT && t == 0x09) + { + state = INACTIVE; + control_content[0] = 0x0a; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "client send reas for client %d, ap_ori %d, ap_tar %d\n", c+1, ori+1, tar+1); + output(0).push(p); + } + else if(state == INACTIVE && t == 0x0d) + { + state = IDLE; + syslog (LOG_DEBUG, "client finish reas for client %d, ap_ori %d, ap_tar %d\n", c+1, ori+1, tar+1); + } + p_in -> kill(); + +} + +void RClientControl::push_downdata(Packet*p_in) +{ + WritablePacket *p = p_in->uniqueify(); + //printf("ether type: %u\n", r_ether_type_suffix(p)); + if(r_ether_type_suffix(p) == 0x03) + { + memcpy(p->data()+13, ðer_type_ip_suffix, 1); + } + + if(state == INACTIVE) + p -> kill(); + else + output(1).push(p); + +} + +void RClientControl::push_updata(Packet*p_in) +{ + if(state == INACTIVE) + p_in -> kill(); + else + output(0).push(p_in); +} +void RClientControl::push_80211(Packet*p_in) +{ + //TODO: filter and parse from click or here? + const char & rssi_this = status_score(p_in); + const unsigned char ap = status_ap(p_in) - 1; + static unsigned char c; + switch(status_mac(p_in)) + { + case CLIENT1_MAC_SUFFIX: c = 1;break; + case CLIENT2_MAC_SUFFIX: c = 2;break; + case CLIENT3_MAC_SUFFIX: c = 3;break; + } + + if(c == identity) + rssi[ap] = (1-alpha)*rssi[ap] + alpha*rssi_this; + else + return; + // printf("ap:%u, rssi:%d\n", ap, rssi_this); + + //if not update, return + if(rssi[current_ap] < -80) + return; + // if IDLE, considering switching + static unsigned int tmp_counter = 0; + tmp_counter++; + if(!(tmp_counter%print_interval)) + { + syslog (LOG_DEBUG, "receive becon, ap %d, client %d, rssi %d\n", + ap+1, c, rssi_this); + } + + gettimeofday(&tv, NULL); + double now_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; + if(now_time - last_time > K_SWITCH_MIN) + time_lock = false; + + + if(c == identity && state == IDLE && !time_lock) + { + unsigned i; + unsigned max_id; + + if(interval > 0) + { + max_id = current_ap; + if(!(tmp_counter%interval)) + { + max_id = (max_id + 1)% 2; + syslog (LOG_DEBUG, "manually switch to ap %X\n", max_id+1); + } + } + else + { + if(rssi[current_ap] >= rssi_threshold) + return; + + double max_rssi = -127; + // find max rssi + for(i=0;i max_rssi) + { + max_rssi = rssi[i]; + max_id = i; + } + } + if(max_id == current_ap) + return; + syslog (LOG_DEBUG, "Considering to switch, current rssi: %f\n", rssi[current_ap]); + control_content[0] = 0x04; + control_content[1] = identity-1; + control_content[2] = current_ap; + control_content[3] = max_id; + + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "client send ant req for client %d, ap_ori %d, ap_tar %d\n", identity, current_ap+1, max_id+1); + current_ap = max_id; + state = ANT; + time_lock = true; + gettimeofday(&tv, NULL); + last_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; + + output(0).push(p); + } + +} + + +CLICK_ENDDECLS +EXPORT_ELEMENT(RClientControl) +ELEMENT_MT_SAFE(RClientControl) diff --git a/elements/ip/80211r/rclientcontrol.hh b/elements/ip/80211r/rclientcontrol.hh new file mode 100755 index 0000000000..c40ead6184 --- /dev/null +++ b/elements/ip/80211r/rclientcontrol.hh @@ -0,0 +1,61 @@ +/* + element for 802.11r client, + Created by Zhenyu Song: sunnyszy@gmail.com + */ +#ifndef CLICK_RCLIENTCONTROL_HH +#define CLICK_RCLIENTCONTROL_HH +#include +#include +#include +#include +#include +#include +#include + +CLICK_DECLS + + +class RClientControl : public Element { public: + + + const char *class_name() const { return "RClientControl"; } + const char *port_count() const { return "4/2"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int port, Packet *); + void push_control(Packet *); + void push_80211(Packet *); + void push_downdata(Packet *); + void push_updata(Packet *); + void reset(); + + private: + double rssi[MAX_N_AP]; + char rssi_threshold; + double alpha; + + unsigned char identity; + unsigned char state; + unsigned char current_ap; + + click_ether * _ethh; + unsigned char control_content[4]; + + const unsigned char ether_type_ip_suffix = 0x00; + + + int interval; + int print_interval; + // after issue switch, a time lock will be set for 1 second + bool time_lock; + double last_time; + struct timeval tv; + + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/80211r/rcontrollercontrol.cc b/elements/ip/80211r/rcontrollercontrol.cc new file mode 100755 index 0000000000..b64f125358 --- /dev/null +++ b/elements/ip/80211r/rcontrollercontrol.cc @@ -0,0 +1,186 @@ +/* + element for 802.11r ap, + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "rcontrollercontrol.hh" +#include +#include +#include +#include +#include + + CLICK_DECLS + +int +RControlerControl::configure(Vector &conf, ErrorHandler *errh) +{ + int i; + openlog("RControlerControl", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + _ethh = new click_ether[MAX_N_AP*2]; + if (Args(conf, this, errh) + .read_p("FIRSTSTART1", IntArg(), tmp_start[0]) + .read_p("FIRSTSTART2", IntArg(), tmp_start[1]) + .read_p("FIRSTSTART3", IntArg(), tmp_start[2]) + .complete() < 0) + return -1; + + for(i=0;idata()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), &(_ethh[tar]), sizeof(click_ether)); + + syslog (LOG_DEBUG, "controller pass ant req for client %d, ap_ori %d, ap_tar %d\n", c+1, ori+1, tar+1); + output(0).push(p); + } + else if(t == 0x07) + { + control_content[0] = 0x08; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), &(_ethh[ori]), sizeof(click_ether)); + + syslog (LOG_DEBUG, "controller pass ant ack for client %d, ap_ori %d, ap_tar %d\n", c+1, ori+1, tar+1); + output(0).push(p); + } + else if(t == 0x0b) + { + control_content[0] = 0x0c; + control_content[1] = c; + control_content[2] = ori; + control_content[3] = tar; + + WritablePacket *p = Packet::make(sizeof(click_ether)+4); + // // data part + memcpy(p->data()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), &(_ethh[tar]), sizeof(click_ether)); + + outport[c] = tar; + syslog (LOG_DEBUG, "controller ack reas for client %d, ap_ori %d, ap_tar %d\n", c+1, ori+1, tar+1); + output(0).push(p); + } + else if(t == 0xff) + { + + for(i=0;idata()+sizeof(click_ether), &control_content, 4); + + memcpy(p->data(), &(_ethh[i]), sizeof(click_ether)); + + syslog (LOG_DEBUG, "controller reset and broadcast reset\n"); + output(0).push(p); + } + + } + p_in -> kill(); + +} + +void RControlerControl::push_down_data(Packet*p_in, int port) +{ + WritablePacket *p = p_in->uniqueify(); + p->push(sizeof(click_ether)); + + //eth + memcpy(p->data(), &(_ethh[outport[port-1]+MAX_N_AP]), sizeof(click_ether)); + //syslog (LOG_DEBUG, "port: %d\n", port); + //syslog (LOG_DEBUG, "outport: %d\n", outport[port-1]); + output(0).push(p); +} + + + +CLICK_ENDDECLS +EXPORT_ELEMENT(RControlerControl) +ELEMENT_MT_SAFE(RControlerControl) diff --git a/elements/ip/80211r/rcontrollercontrol.hh b/elements/ip/80211r/rcontrollercontrol.hh new file mode 100755 index 0000000000..c426883769 --- /dev/null +++ b/elements/ip/80211r/rcontrollercontrol.hh @@ -0,0 +1,42 @@ +/* + element for 802.11r ap, + Created by Zhenyu Song: sunnyszy@gmail.com + */ +#ifndef CLICK_RCONTROLLERCONTROL_HH +#define CLICK_RCONTROLLERCONTROL_HH +#include +#include +#include +#include +#include +#include + +CLICK_DECLS + + +class RControlerControl : public Element { public: + + + const char *class_name() const { return "RControlerControl"; } + const char *port_count() const { return "4/2"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int port, Packet *); + void push_up_control(Packet *); + void push_down_data(Packet *, int); + + + private: + unsigned char outport[MAX_N_CLIENT]; + unsigned char control_content[4]; + click_ether * _ethh; + int tmp_start[3]; + + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/80211r/rssibecon.cc b/elements/ip/80211r/rssibecon.cc new file mode 100644 index 0000000000..c7ce5cf91b --- /dev/null +++ b/elements/ip/80211r/rssibecon.cc @@ -0,0 +1,113 @@ +/* + element for 802.11r becon sending, + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "rssibecon.hh" +#include +#include +#include + +CLICK_DECLS + +RSSIBecon::RSSIBecon() +{ +#ifdef __mips__ + openlog("RSSIBecon", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + syslog (LOG_DEBUG, "finish init\n"); +#endif + +} + +RSSIBecon::~RSSIBecon() +{ +#ifdef __mips__ + iwinfo_finish(); +#endif +} + +int +RSSIBecon::configure(Vector &conf, ErrorHandler *errh) +{ + int wlan_port; + if (Args(conf, this, errh) + .read_p("WLANPORT", IntArg(), wlan_port) + .complete() < 0) + return -1; + +#ifdef __mips__ + strcpy(ifname, "wlan0"); + + iw = iwinfo_backend(ifname); + if (!iw) + syslog (LOG_DEBUG, "can not connect to backend iwinfo\n"); +#endif + syslog (LOG_DEBUG, "finish configure, ready to start\n"); + return 0; +} + +void +RSSIBecon::fragment(Packet *p_in) +{ +#ifdef __mips__ + int i,j; + // syslog (LOG_DEBUG, "in fragment\n"); + if(!(iw->assoclist(ifname, buf, &len))) + // // syslog (LOG_DEBUG, "can not find associlist\n"); + // else if (len <= 0) + // // syslog (LOG_DEBUG, "associ number < 0\n"); + // else if (len) + { + // syslog (LOG_DEBUG, "prepare to send, len: %d\n", len); + // WritablePacket *p_csi = Packet::make(sizeof(my_test_struct)*N_CLIENT); + + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) + // if(len>0) + { + //one pkt per client + WritablePacket *p_csi = Packet::make(11); + // syslog (LOG_DEBUG, "creating pkt\n"); + j=0; + e = (struct iwinfo_assoclist_entry *) &buf[i]; + uint8_t & mac = e->mac[5]; + int8_t & signal = e->signal; + int8_t & noise = e->noise; + uint32_t & rx_rate = (e->rx_rate).rate; + uint32_t & tx_rate = (e->tx_rate).rate; + // syslog (LOG_DEBUG, "parsing\n"); + memcpy(p_csi->data()+j, &(mac), 1); + j += 1; + memcpy(p_csi->data()+j, &(signal), 1); + j += 1; + memcpy(p_csi->data()+j, &(noise), 1); + j += 1; + memcpy(p_csi->data()+j, &(rx_rate), 4); + j += 4; + memcpy(p_csi->data()+j, &(tx_rate), 4); + j += 4; + // syslog (LOG_DEBUG, "copying\n"); + output(0).push(p_csi); + } + } + // else + // syslog (LOG_DEBUG, "can not find associlist\n"); + // if (len <= 0) + // syslog (LOG_DEBUG, "associ number < 0\n"); +#endif + p_in -> kill(); +} + +void +RSSIBecon::push(int, Packet *p) +{ + // syslog (LOG_DEBUG, "enter push\n"); +#ifdef __mips__ + // syslog (LOG_DEBUG, "in push\n"); + fragment(p); +#endif +} + + +CLICK_ENDDECLS +EXPORT_ELEMENT(RSSIBecon) \ No newline at end of file diff --git a/elements/ip/80211r/rssibecon.hh b/elements/ip/80211r/rssibecon.hh new file mode 100644 index 0000000000..0bebae1705 --- /dev/null +++ b/elements/ip/80211r/rssibecon.hh @@ -0,0 +1,56 @@ +/* + element for 802.11r becon sending, + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#ifndef CLICK_RSSIBECON_HH +#define CLICK_RSSIBECON_HH +#include +#include +#include +#include +#include +#include +// #include +#ifdef __mips__ +#include +extern "C" +{ + #include "iwinfo.h" +} +#endif + + +CLICK_DECLS + + +class RSSIBecon : public Element { public: + + RSSIBecon() CLICK_COLD; + ~RSSIBecon() CLICK_COLD; + + const char *class_name() const { return "RSSIBecon"; } + const char *port_count() const { return "1/1"; } + const char *processing() const { return PUSH; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int, Packet *); + void fragment(Packet *); + + private: + + +#ifdef __mips__ + int len; + char ifname[20]; + const struct iwinfo_ops *iw; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_assoclist_entry *e; +#endif + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/csicollect.cc b/elements/ip/wgtt/csicollect.cc new file mode 100755 index 0000000000..c2929b31d6 --- /dev/null +++ b/elements/ip/wgtt/csicollect.cc @@ -0,0 +1,127 @@ +/* + sample csi, rssi from TP-Link router + Input: data pkt + Output: port 0: csi pkt, port 1: rssi pkt + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "csicollect.hh" +#include +#include +#include + +CLICK_DECLS + +CSICollect::CSICollect() +{ +#ifdef __mips__ + openlog("APControl_CSICollect", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + syslog (LOG_DEBUG, "finish init\n"); + // total_msg_cnt = 0; + sample_counter = 0; +#endif + +} + +CSICollect::~CSICollect() +{ +#ifdef __mips__ + iwinfo_finish(); +#endif +} + +int +CSICollect::configure(Vector &conf, ErrorHandler *errh) +{ + int wlan_port; + if (Args(conf, this, errh) + .read_p("SAMPLERATE", IntArg(), sample_rate) + .read_p("WLANPORT", IntArg(), wlan_port) + .complete() < 0) + return -1; + +#ifdef __mips__ + if(wlan_port == 0) + strcpy(ifname, "wlan0"); + else if(wlan_port == 1) + strcpy(ifname, "wlan1"); + else + syslog (LOG_DEBUG, "Invalid wlan_port argument\n"); + iw = iwinfo_backend(ifname); + if (!iw) + syslog (LOG_DEBUG, "Can not connect to backend iwinfo\n"); +#endif + syslog (LOG_DEBUG, "Finish configure, ready to start\n"); + return 0; +} + +void +CSICollect::fragment(Packet *p_in) +{ +#ifdef __mips__ + int i,j; + sample_counter ++; + if(sample_counter>sample_rate) + { + sample_counter = 0; + + if(!(iw->assoclist(ifname, buf, &len))) + // // syslog (LOG_DEBUG, "CSICollect: can not find associlist\n"); + // else if (len <= 0) + // // syslog (LOG_DEBUG, "CSICollect: associ number < 0\n"); + // else if (len) + { + // WritablePacket *p_csi = Packet::make(sizeof(my_test_struct)*N_CLIENT); + + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) + { + //one pkt per client + WritablePacket *p_csi = Packet::make(11); + j=0; + e = (struct iwinfo_assoclist_entry *) &buf[i]; + uint8_t & mac = e->mac[5]; + int8_t & signal = e->signal; + int8_t & noise = e->noise; + uint32_t & rx_rate = (e->rx_rate).rate; + uint32_t & tx_rate = (e->tx_rate).rate; + + memcpy(p_csi->data()+j, &(mac), 1); + j += 1; + memcpy(p_csi->data()+j, &(signal), 1); + j += 1; + memcpy(p_csi->data()+j, &(noise), 1); + j += 1; + memcpy(p_csi->data()+j, &(rx_rate), 4); + j += 4; + memcpy(p_csi->data()+j, &(tx_rate), 4); + j += 4; + output(1).push(p_csi); + } + + } + } + + if(p_in->length() > 141) + { + p_in->pull(p_in->length() - 140); + output(0).push(p_in); + } + else + p_in -> kill(); + +#endif +} + +void +CSICollect::push(int, Packet *p) +{ +#ifdef __mips__ + // syslog (LOG_DEBUG, "CSICollect: in push\n"); + fragment(p); +#endif +} + + +CLICK_ENDDECLS +EXPORT_ELEMENT(CSICollect) \ No newline at end of file diff --git a/elements/ip/wgtt/csicollect.hh b/elements/ip/wgtt/csicollect.hh new file mode 100755 index 0000000000..6ed56dde8c --- /dev/null +++ b/elements/ip/wgtt/csicollect.hh @@ -0,0 +1,58 @@ +/* + sample csi, rssi from TP-Link router + Input: data pkt + Output: port 0: csi pkt, port 1: rssi pkt + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#ifndef CLICK_CSICOLLECT_HH +#define CLICK_CSICOLLECT_HH +#include +#include +#include +#include +#include +#include +#ifdef __mips__ +#include +extern "C" +{ + #include "iwinfo.h" +} +#endif + + +CLICK_DECLS + +class CSICollect : public Element { public: + + CSICollect() CLICK_COLD; + ~CSICollect() CLICK_COLD; + + const char *class_name() const { return "CSICollect"; } + const char *port_count() const { return PORTS_1_1X2; } + const char *processing() const { return PUSH; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int, Packet *); + void fragment(Packet *); + + private: + + int sample_rate; + int sample_counter; + +#ifdef __mips__ + int len; + char ifname[20]; + const struct iwinfo_ops *iw; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_assoclist_entry *e; +#endif + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/deduptcppacket.cc b/elements/ip/wgtt/deduptcppacket.cc new file mode 100755 index 0000000000..83bbfacd60 --- /dev/null +++ b/elements/ip/wgtt/deduptcppacket.cc @@ -0,0 +1,81 @@ +/* + Deduplication. + Input: upload raw data packet (eth+ip+x), must checkIPHeader first + Output: deduplicated data packet + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "deduptcppacket.hh" +#include +#include +#include +#include +CLICK_DECLS + +DeDupTCPPacket::DeDupTCPPacket() +{ + _set.clear(); + while (!_queue.empty()) + _queue.pop(); +} + + + +Packet * +DeDupTCPPacket::drop(Packet *p) +{ + //click_chatter("TCP: duplicate, dropping"); + if (noutputs() == 2) + output(1).push(p); + else + p->kill(); + + return 0; +} + +void +DeDupTCPPacket::push(int port, Packet *p_in) +{ + // syslog (LOG_DEBUG, "Packet in\n"); + // construct link_key + WritablePacket *p = p_in->uniqueify(); + struct click_ip *iph = p->ip_header(); + + // syslog (LOG_DEBUG, "IP id: %x", iph->ip_id); + uint64_t tmp_link_key = ((((uint64_t)(iph->ip_id))&0x000000000000ffff)<<32)+ + (((uint64_t)((iph->ip_src).s_addr))&0x00000000ffffffff); + // syslog (LOG_DEBUG, "key: %lx\n", tmp_link_key); + std::set::iterator it; + it = _set.find(tmp_link_key); + if((iph -> ip_id) != 0) + { + if( it != _set.end()) + { + // syslog (LOG_DEBUG, "Packet out.drop\n"); + drop(p); + return; + } + else + { + //if (_set.size() >= max_elem_num) + if (_queue.size() >= max_elem_num) + { + // syslog (LOG_DEBUG, "exceed the max size\n"); + uint64_t & link_key_tobe_delete = _queue.front(); + _queue.pop(); + it = _set.find(link_key_tobe_delete); + _set.erase(it); + // delete link_key_tobe_delete; + } + _set.insert(tmp_link_key); + _queue.push(tmp_link_key); + } + } + // syslog (LOG_DEBUG, "Packet out.push\n"); + output(0).push(p); +} + + +CLICK_ENDDECLS +EXPORT_ELEMENT(DeDupTCPPacket) diff --git a/elements/ip/wgtt/deduptcppacket.hh b/elements/ip/wgtt/deduptcppacket.hh new file mode 100755 index 0000000000..f5885420d8 --- /dev/null +++ b/elements/ip/wgtt/deduptcppacket.hh @@ -0,0 +1,41 @@ +/* + Deduplication. + Input: upload raw data packet (eth+ip+x), must checkIPHeader first + Output: deduplicated data packet + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#ifndef CLICK_DEDUPTCPPACKET_HH +#define CLICK_DEDUPTCPPACKET_HH +#include +#include +#include +#include +#include +CLICK_DECLS + + + +class DeDupTCPPacket : public Element { public: + + DeDupTCPPacket(); + + const char *class_name() const { return "DeDupTCPPacket"; } + const char *port_count() const { return PORTS_1_1X2; } + const char *processing() const { return PUSH; } + + void push(int, Packet *); + + + private: + + std::set _set; + std::queue _queue; + static const uint16_t max_elem_num = 1000; + + Packet *drop(Packet *); + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/idadder.cc b/elements/ip/wgtt/idadder.cc new file mode 100755 index 0000000000..b10b419f0b --- /dev/null +++ b/elements/ip/wgtt/idadder.cc @@ -0,0 +1,70 @@ +/* + idadder program, add id and push for queue ring in ap processing. + Input: [data pkt] + Output:[eth][id][data pkt], id is one Byte + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "idadder.hh" +#include +#include +#include + +CLICK_DECLS + +IDAdder::IDAdder() +{ + int i; + openlog("IDAdder", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + for(i=0; i uniqueify(); + // *(p_base -> data()+13) |= 0x10; // add a flag to the packet + p_base->push(sizeof(click_ether)); // tunneling head + p_base->put(2); //mac80211 seq + for(int i = 0;iclone(); + WritablePacket *p = p_tmp->uniqueify(); + // eth + switch(i) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh.ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh.ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh.ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh.ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh.ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh.ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh.ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh.ether_dhost);break; + } + memcpy(p->data(), &_ethh, sizeof(click_ether)); + // data + uint16_t net_form_seq = htons(counter[port]); + memcpy(p->end_data()-2, &net_form_seq, 2); + // syslog (LOG_DEBUG, "idadder push %dth\n", i); + output(0).push(p); + } + counter[port] = (counter[port] + 1) & 0xfff; +} + + + +CLICK_ENDDECLS +EXPORT_ELEMENT(IDAdder) +ELEMENT_MT_SAFE(IDAdder) diff --git a/elements/ip/wgtt/idadder.hh b/elements/ip/wgtt/idadder.hh new file mode 100755 index 0000000000..fa44542927 --- /dev/null +++ b/elements/ip/wgtt/idadder.hh @@ -0,0 +1,43 @@ +/* + idadder program, add id and push for queue ring in ap processing. + Input: [data pkt] + Output:[eth][id][data pkt], id is one Byte + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#ifndef CLICK_IDADDER_HH +#define CLICK_IDADDER_HH +#include +#include +#include +#include +#include +#include +CLICK_DECLS + + +class IDAdder : public Element { public: + + + IDAdder() CLICK_COLD; + + const char *class_name() const { return "IDAdder"; } + const char *port_count() const { return "1/1"; } + const char *flags() const { return "A"; } + + void push(int port, Packet *p_in); + + + private: + + uint16_t counter[MAX_N_CLIENT]; + click_ether _ethh; + + +}; + + + + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/packetselectionSerial.cc b/elements/ip/wgtt/packetselectionSerial.cc new file mode 100755 index 0000000000..53de324142 --- /dev/null +++ b/elements/ip/wgtt/packetselectionSerial.cc @@ -0,0 +1,335 @@ +/* + Controller program, issusing switching between different ap. + Input: control/status packet + Output: control packet + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "packetselectionSerial.hh" +#include +#include +#include +#include + +CLICK_DECLS + +int comp (const void * elem1, const void * elem2) +{ + int f = *((int*)elem1); + int s = *((int*)elem2); + if (f > s) return 1; + if (f < s) return -1; + return 0; +} + + + + +PacketSelectionSerial::PacketSelectionSerial() +{ + int i,j,k; + openlog("PacketSelectionSerial", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + score = new int**[MAX_N_CLIENT]; + next_score_id = new unsigned char*[MAX_N_CLIENT]; + for(i=0; iether_type = htons(CONTROL_SUFFIX+ETHER_PROTO_BASE); + cp_ethernet_address(CONTROLLER_IN_MAC, _ethh->ether_shost); + + syslog (LOG_DEBUG, "Init finish, ready to start\n"); +} + +int PacketSelectionSerial::configure(Vector &conf, ErrorHandler *errh) +{ + int i,tmp[3]; + if (Args(conf, this, errh) + .read_p("INTERVAL", IntArg(), interval) + .read_p("FIRSTSTART1", IntArg(), tmp[0]) + .read_p("FIRSTSTART2", IntArg(), tmp[1]) + .read_p("FIRSTSTART3", IntArg(), tmp[2]) + .read_p("PRINTINTERVAL", IntArg(), print_interval) + .complete() < 0) + return -1; + + for(i=0; idata()+sizeof(click_ether), &control_content, 2); + //ether part + switch(i) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh->ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh->ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh->ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh->ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh->ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh->ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh->ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh->ether_dhost);break; + } + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "Controller reset ap %X\n", i+1); + output(0).push(p); + } +} + + +void PacketSelectionSerial::push_control(Packet *p_in) +{ + const unsigned char & c = client_ip(p_in); + + state[c-CLIENT1_IP_SUFFIX] = IDLE; + + syslog (LOG_DEBUG, "Switch request ack, ip: %d.\n", c); + p_in -> kill(); +} + +void PacketSelectionSerial::push_status(Packet *p_in) +{ + const unsigned char a = status_ap(p_in) - 1; + unsigned char c; + switch(status_mac(p_in)) + { + case CLIENT1_MAC_SUFFIX: c = 0;break; + case CLIENT2_MAC_SUFFIX: c = 1;break; + case CLIENT3_MAC_SUFFIX: c = 2;break; + } + //since the score are minus, we minus again + //TODO: smaller is better? + score[c][a][next_score_id[c][a]] = - status_score(p_in); + next_score_id[c][a] = (next_score_id[c][a] + 1)%n_compare; + // able to change state + + static unsigned int tmp_counter = 0; + tmp_counter++; + if(!(tmp_counter%print_interval)) + { + int rx_rate = status_rxrate(p_in); + int tx_rate = status_txrate(p_in); + syslog (LOG_DEBUG, "client mac: %X, ap id: %X\n", status_mac(p_in), status_ap(p_in)); + syslog (LOG_DEBUG, "signal: %d, noise: %d\n", status_score(p_in), status_noise(p_in)); + // syslog (LOG_DEBUG, "rx_rate: %d.%dMb/s, tx_rate: %d.%d Mb/s\n", + // rx_rate / 1000, rx_rate / 100, tx_rate / 1000, tx_rate / 100); + } + + gettimeofday(&tv, NULL); + double now_time = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; + if(now_time - last_time[c] > SWITCH_MIN) + time_lock[c] = false; + + + if(state[c] == IDLE && !time_lock[c]) + { + // syslog (LOG_DEBUG, "state idle\n"); + unsigned char best_ap; + // syslog (LOG_DEBUG, "current_state: %d, time_lock: %d\n", state[c], time_lock[c]); + // WGTT + if(interval>0) + { + best_ap = output_port[c]; + if(!(tmp_counter%interval)) + { + best_ap = (best_ap + 1)% 3; + syslog (LOG_DEBUG, "prepare manually switch to ap %X\n", best_ap+1); + } + } + else + best_ap = find_best_ap_global(c); + + if(best_ap != output_port[c]) + { + // send_meg(best_ap) + WritablePacket *p = Packet::make(sizeof(click_ether)+2); + // click_ip *ip = reinterpret_cast(p->data()+sizeof(click_ether)); + // // data part + control_content[0] = CLIENT1_IP_SUFFIX + c; + control_content[1] = best_ap; + memcpy(p->data()+sizeof(click_ether), &control_content, 2); + //ether part + switch(output_port[c]) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh->ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh->ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh->ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh->ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh->ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh->ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh->ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh->ether_dhost);break; + } + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "issu switch. for client: %d to ap: %d\n", c+1, best_ap+1); + state[c] = SWITCH_REQ; + output_port[c] = best_ap; + + // after issue switch, time lock will be turn on, and turned off after 1 s + time_lock[c] = true; + gettimeofday(&tv, NULL); + last_time[c] = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; + output(0).push(p); + } + } + p_in -> kill(); + +} + +// incomplete version, only for 2 ap and 1 client +unsigned char PacketSelectionSerial::find_best_ap_neighbor(unsigned char c) +{ + unsigned char ¤t = output_port[c]; + bool switch_to_left = true, switch_to_right = true; + int i,j; + int num_bigger; + // copy to tmp: current, sort + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +CLICK_DECLS + +int comp (const void *, const void *); + +class PacketSelectionSerial : public Element { public: + + + PacketSelectionSerial() CLICK_COLD; + + const char *class_name() const { return "PacketSelectionSerial"; } + const char *port_count() const { return "1/1"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + + void reset_ap(); + void push(int port, Packet *p_in); + void push_control(Packet *p_in); + void push_status(Packet *p_in); + // find best ap for client c + unsigned char find_best_ap_neighbor(unsigned char c); + unsigned char find_best_ap_global(unsigned char c); + + private: + + unsigned char state[MAX_N_CLIENT]; + static const unsigned char n_compare = 5; + static const unsigned char MAJOR = 3; + // [client, ap, n_compare] + int ***score; + int **tmp_score; //every time just need 3 ap * n_compare + // [client, ap] + unsigned char ** next_score_id; + unsigned char output_port[MAX_N_CLIENT]; + unsigned char control_content[2]; + // which ap will first start + unsigned char first_start[MAX_N_CLIENT]; + + // used for debug. + // By setting a positive number, manually switch after every ${interval} pkt + // Between ap 1 - 2 + int interval; + // Printing screen after ${print_interval} pkt + int print_interval; + + // after issue switch, a time lock will be set for 1 second + bool time_lock[MAX_N_CLIENT]; + double last_time[MAX_N_CLIENT]; + struct timeval tv; + + click_ether * _ethh; + + +}; + + + + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/seqgen.cc b/elements/ip/wgtt/seqgen.cc new file mode 100755 index 0000000000..1e870b0d53 --- /dev/null +++ b/elements/ip/wgtt/seqgen.cc @@ -0,0 +1,142 @@ +/* + Controller program, generate simple data and switch control + Input: trigger packet + Output: control & data + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "seqgen.hh" +#include +#include +#include +#include + +CLICK_DECLS + +SeqGen::SeqGen() +{ + openlog("SeqGen", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + + _ethh = new click_ether; + _ethh->ether_type = htons(CONTROL_SUFFIX+ETHER_PROTO_BASE); + cp_ethernet_address(CONTROLLER_IN_MAC, _ethh->ether_shost); + output_port = 0; + counter = 100; + + syslog (LOG_DEBUG, "Init finish, ready to start\n"); +} + +int SeqGen::configure(Vector &conf, ErrorHandler *errh) +{ + if (Args(conf, this, errh) + .read_p("SWITCHINTERVAL", IntArg(), interval) + .read_p("PACKETLENGTH", IntArg(), pkt_len) + .complete() < 0) + return -1; + + syslog (LOG_DEBUG, "Finish configure. Switch interval: %d\n", interval); + return 0; +} + +void SeqGen::push(int port, Packet *p_in) +{ + // here is a small bug, I can not put the reset function in the initial function + static unsigned char lock = 0; + if(!lock) + { + lock++; + reset_ap(); + } + + // syslog (LOG_DEBUG, "pkt_type: %x\n", pkt_type(p_in)); + push_status(p_in); + +} + +void SeqGen::reset_ap() +{ + control_content[0] = RESET_CONTENT; + control_content[1] = RESET_CONTENT; + for(int i=0;idata()+sizeof(click_ether), &control_content, 2); + //ether part + switch(i) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh->ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh->ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh->ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh->ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh->ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh->ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh->ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh->ether_dhost);break; + } + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "Controller reset ap %X\n", i+1); + output(1).push(p); + } +} + +void SeqGen::push_status(Packet *p_in) +{ + unsigned char c = 2; + // syslog (LOG_DEBUG, "state idle\n"); + unsigned char best_ap; + // syslog (LOG_DEBUG, "current_state: %d, time_lock: %d\n", state[c], time_lock[c]); + // WGTT + // increment by 1 + counter = (counter >= 4095)? 0: counter + 1; + + if(!(counter%interval)) + { + best_ap = output_port; + best_ap = 1 - best_ap; //only switch between 0, 1 + syslog (LOG_DEBUG, "prepare manually switch to ap %X\n", best_ap+1); + + // send_meg(best_ap) + WritablePacket *p = Packet::make(sizeof(click_ether)+2); + // click_ip *ip = reinterpret_cast(p->data()+sizeof(click_ether)); + // // data part + control_content[0] = CLIENT1_IP_SUFFIX + c; + control_content[1] = best_ap; + memcpy(p->data()+sizeof(click_ether), &control_content, 2); + //ether part + switch(output_port) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh->ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh->ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh->ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh->ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh->ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh->ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh->ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh->ether_dhost);break; + } + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "issu switch. for client: %d to ap: %d\n", c+1, best_ap+1); + output_port = best_ap; + + output(1).push(p); + } + + //data packet + WritablePacket *p_data = p_in -> put(sizeof(uint16_t)); + uint16_t tmp_seq = htons(counter); + memcpy(p_data->end_data()-sizeof(uint16_t), &tmp_seq, sizeof(uint16_t)); + + //syslog (LOG_DEBUG, "issu switch. for client: %d to ap: %d\n", c+1, best_ap+1); + //output_port = best_ap; + output(0).push(p_data); + +} + + + +CLICK_ENDDECLS +EXPORT_ELEMENT(SeqGen) +ELEMENT_MT_SAFE(SeqGen) diff --git a/elements/ip/wgtt/seqgen.hh b/elements/ip/wgtt/seqgen.hh new file mode 100755 index 0000000000..3c8050d129 --- /dev/null +++ b/elements/ip/wgtt/seqgen.hh @@ -0,0 +1,58 @@ +/* + generate a sequence of seq/ switch signal + Input: trigger packet + Output: control & data + Created by Zhenyu Song: sunnyszy@gmail.com + */ +#ifndef CLICK_SEQGEN_HH +#define CLICK_SEQGEN_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include +CLICK_DECLS + +class SeqGen : public Element { public: + + + SeqGen() CLICK_COLD; + + const char *class_name() const { return "SeqGen"; } + const char *port_count() const { return "1/2"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void reset_ap(); + void push(int port, Packet *p_in); + + void push_status(Packet *p_in); + + private: + + unsigned char output_port; + unsigned char control_content[2]; + + // used for debug. + // By setting a positive number, manually switch after every ${interval} pkt + // Between ap 1 - 2 + int interval; + + click_ether * _ethh; + uint16_t counter; + + int pkt_len; + + +}; + + + + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/simpleControllerSwitch.cc b/elements/ip/wgtt/simpleControllerSwitch.cc new file mode 100755 index 0000000000..f701ad6fe8 --- /dev/null +++ b/elements/ip/wgtt/simpleControllerSwitch.cc @@ -0,0 +1,143 @@ +/* + Controller program, generate simple data and switch control + Input: trigger packet + Output: control & data + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "simpleControllerSwitch.hh" +#include +#include +#include +#include + +CLICK_DECLS + +SimpleControllerSwitch::SimpleControllerSwitch() +{ + openlog("SimpleControllerSwitch", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + + _ethh = new click_ether; + _ethh->ether_type = htons(CONTROL_SUFFIX+ETHER_PROTO_BASE); + cp_ethernet_address(CONTROLLER_IN_MAC, _ethh->ether_shost); + output_port = 3; + + syslog (LOG_DEBUG, "Init finish, ready to start\n"); +} + +int SimpleControllerSwitch::configure(Vector &conf, ErrorHandler *errh) +{ + if (Args(conf, this, errh) + .read_p("SWITCHINTERVAL", IntArg(), interval) + .complete() < 0) + return -1; + + syslog (LOG_DEBUG, "Finish configure. Switch interval: %d\n", interval); + return 0; +} + +void SimpleControllerSwitch::push(int port, Packet *p_in) +{ + // here is a small bug, I can not put the reset function in the initial function + static unsigned char lock = 0; + if(!lock) + { + lock++; + reset_ap(); + } + + // syslog (LOG_DEBUG, "pkt_type: %x\n", pkt_type(p_in)); + push_status(p_in); + +} + +void SimpleControllerSwitch::reset_ap() +{ + control_content[0] = RESET_CONTENT; + control_content[1] = RESET_CONTENT; + for(int i=0;idata()+sizeof(click_ether), &control_content, 2); + //ether part + switch(i) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh->ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh->ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh->ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh->ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh->ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh->ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh->ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh->ether_dhost);break; + } + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "Controller reset ap %X\n", i+1); + output(1).push(p); + } +} + +void SimpleControllerSwitch::push_status(Packet *p_in) +{ + const unsigned char a = status_ap(p_in) - 1; + unsigned char c = 0; + static uint32_t tmp_counter = 0; + tmp_counter++; + + p_in -> kill(); + // syslog (LOG_DEBUG, "state idle\n"); + unsigned char best_ap; + // syslog (LOG_DEBUG, "current_state: %d, time_lock: %d\n", state[c], time_lock[c]); + // WGTT + + + if(!(tmp_counter%interval)) + { + best_ap = output_port; + best_ap = 7 - best_ap; //only switch between 3,4 + syslog (LOG_DEBUG, "prepare manually switch to ap %X\n", best_ap+1); + + // send_meg(best_ap) + WritablePacket *p = Packet::make(sizeof(click_ether)+2); + // click_ip *ip = reinterpret_cast(p->data()+sizeof(click_ether)); + // // data part + control_content[0] = CLIENT1_IP_SUFFIX + c; + control_content[1] = best_ap; + memcpy(p->data()+sizeof(click_ether), &control_content, 2); + //ether part + switch(output_port) + { + case 0:cp_ethernet_address(AP1_MAC, _ethh->ether_dhost);break; + case 1:cp_ethernet_address(AP2_MAC, _ethh->ether_dhost);break; + case 2:cp_ethernet_address(AP3_MAC, _ethh->ether_dhost);break; + case 3:cp_ethernet_address(AP4_MAC, _ethh->ether_dhost);break; + case 4:cp_ethernet_address(AP5_MAC, _ethh->ether_dhost);break; + case 5:cp_ethernet_address(AP6_MAC, _ethh->ether_dhost);break; + case 6:cp_ethernet_address(AP7_MAC, _ethh->ether_dhost);break; + case 7:cp_ethernet_address(AP8_MAC, _ethh->ether_dhost);break; + } + memcpy(p->data(), _ethh, sizeof(click_ether)); + + syslog (LOG_DEBUG, "issu switch. for client: %d to ap: %d\n", c+1, best_ap+1); + output_port = best_ap; + + output(1).push(p); + } + + //data packet + WritablePacket *p_data = Packet::make(100); + _tcp.th_seq = htonl(tmp_counter); + memcpy(p_data->data(), &_tcp, sizeof(_tcp)); + //syslog (LOG_DEBUG, "issu switch. for client: %d to ap: %d\n", c+1, best_ap+1); + //output_port = best_ap; + output(0).push(p_data); + +} + + + +CLICK_ENDDECLS +EXPORT_ELEMENT(SimpleControllerSwitch) +ELEMENT_MT_SAFE(SimpleControllerSwitch) diff --git a/elements/ip/wgtt/simpleControllerSwitch.hh b/elements/ip/wgtt/simpleControllerSwitch.hh new file mode 100755 index 0000000000..5761ab01e3 --- /dev/null +++ b/elements/ip/wgtt/simpleControllerSwitch.hh @@ -0,0 +1,56 @@ +/* + Controller program, generate simple data and switch control + Input: trigger packet + Output: control & data + Created by Zhenyu Song: sunnyszy@gmail.com + */ +#ifndef CLICK_SIMPLECONTROLLERSWITCH_HH +#define CLICK_SIMPLECONTROLLERSWITCH_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include +CLICK_DECLS + +class SimpleControllerSwitch : public Element { public: + + + SimpleControllerSwitch() CLICK_COLD; + + const char *class_name() const { return "SimpleControllerSwitch"; } + const char *port_count() const { return "1/2"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void reset_ap(); + void push(int port, Packet *p_in); + + void push_status(Packet *p_in); + + private: + + unsigned char output_port; + unsigned char control_content[2]; + + // used for debug. + // By setting a positive number, manually switch after every ${interval} pkt + // Between ap 1 - 2 + int interval; + + click_ether * _ethh; + click_tcp _tcp; + + +}; + + + + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/statuscollect.cc b/elements/ip/wgtt/statuscollect.cc new file mode 100755 index 0000000000..f37e4a81e5 --- /dev/null +++ b/elements/ip/wgtt/statuscollect.cc @@ -0,0 +1,118 @@ +/* + sample rssi/noise/txrate/rxrate + Input: data pkt + Output: port 0: data pkt, port 1: status + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "statuscollect.hh" +#include +#include +#include + +CLICK_DECLS + +StatusCollect::StatusCollect() +{ +#ifdef __mips__ + openlog("APControl_StatusCollect", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + syslog (LOG_DEBUG, "finish init\n"); + // total_msg_cnt = 0; + sample_counter = 0; +#endif + +} + +StatusCollect::~StatusCollect() +{ +#ifdef __mips__ + iwinfo_finish(); +#endif +} + +int +StatusCollect::configure(Vector &conf, ErrorHandler *errh) +{ + syslog (LOG_DEBUG, "in configure\n"); + int wlan_port; + if (Args(conf, this, errh) + .read_p("SAMPLERATE", IntArg(), sample_rate) + .read_p("WLANPORT", IntArg(), wlan_port) + .complete() < 0) + return -1; + // syslog (LOG_DEBUG, "finish parsing arguments\n"); +#ifdef __mips__ + strcpy(ifname, "wlan0"); + // syslog (LOG_DEBUG, "finish copying\n"); + iw = iwinfo_backend(ifname); + if (!iw) + syslog (LOG_DEBUG, "Can not connect to backend iwinfo\n"); +#endif + syslog (LOG_DEBUG, "Finish configure, ready to start\n"); + return 0; +} + +void +StatusCollect::fragment(Packet *p_in) +{ +#ifdef __mips__ + int i,j; + sample_counter ++; + if(sample_counter>sample_rate) + { + sample_counter = 0; + + if(!(iw->assoclist(ifname, buf, &len))) + // // syslog (LOG_DEBUG, "StatusCollect: can not find associlist\n"); + // else if (len <= 0) + // // syslog (LOG_DEBUG, "StatusCollect: associ number < 0\n"); + // else if (len) + { + // syslog (LOG_DEBUG, "Len: %d\n", len); + // WritablePacket *p_csi = Packet::make(sizeof(my_test_struct)*N_CLIENT); + + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) + { + //one pkt per client + WritablePacket *p_csi = Packet::make(11); + j=0; + e = (struct iwinfo_assoclist_entry *) &buf[i]; + uint8_t & mac = e->mac[5]; + int8_t & signal = e->signal; + int8_t & noise = e->noise; + uint32_t & rx_rate = (e->rx_rate).rate; + uint32_t & tx_rate = (e->tx_rate).rate; + + memcpy(p_csi->data()+j, &(mac), 1); + j += 1; + memcpy(p_csi->data()+j, &(signal), 1); + j += 1; + memcpy(p_csi->data()+j, &(noise), 1); + j += 1; + memcpy(p_csi->data()+j, &(rx_rate), 4); + j += 4; + memcpy(p_csi->data()+j, &(tx_rate), 4); + j += 4; + output(1).push(p_csi); + } + + } + } +#endif + output(0).push(p_in); + +} + +void +StatusCollect::push(int, Packet *p) +{ +#ifdef __mips__ + // syslog (LOG_DEBUG, "StatusCollect: in push\n"); + fragment(p); +#endif +} + + +CLICK_ENDDECLS +EXPORT_ELEMENT(StatusCollect) \ No newline at end of file diff --git a/elements/ip/wgtt/statuscollect.hh b/elements/ip/wgtt/statuscollect.hh new file mode 100755 index 0000000000..e3bcf5af2a --- /dev/null +++ b/elements/ip/wgtt/statuscollect.hh @@ -0,0 +1,60 @@ +/* + sample rssi/noise/txrate/rxrate + Input: data pkt + Output: port 0: data pkt, port 1: status + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#ifndef CLICK_STATUSCOLLECT_HH +#define CLICK_STATUSCOLLECT_HH +#include +#include +#include +#include +#include +#include +// #include +#ifdef __mips__ +#include +extern "C" +{ + #include "iwinfo.h" +} +#endif + + + +CLICK_DECLS + +class StatusCollect : public Element { public: + + StatusCollect() CLICK_COLD; + ~StatusCollect() CLICK_COLD; + + const char *class_name() const { return "StatusCollect"; } + const char *port_count() const { return PORTS_1_1X2; } + const char *processing() const { return PUSH; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int, Packet *); + void fragment(Packet *); + + private: + + int sample_rate; + int sample_counter; + +#ifdef __mips__ + int len; + char ifname[20]; + const struct iwinfo_ops *iw; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_assoclist_entry *e; +#endif + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip/wgtt/wgttqueue.cc b/elements/ip/wgtt/wgttqueue.cc new file mode 100644 index 0000000000..5b36638be5 --- /dev/null +++ b/elements/ip/wgtt/wgttqueue.cc @@ -0,0 +1,295 @@ +/* + A queue store data pkt for each client. Cache the pkt in a ring buffer + Input: data pkt, control pkt + Output: data pkt, control pkt + Created by Zhenyu Song: sunnyszy@gmail.com + */ + +#include +#include "wgttqueue.hh" +#include +#include +CLICK_DECLS + +WGTTQueue::WGTTQueue() +{ + int i, j; + openlog("APControl_WGTTQueue", LOG_PERROR | LOG_CONS | LOG_NDELAY, 0); + _q = new Packet **[MAX_N_CLIENT]; + for(i=0; i &conf, ErrorHandler *errh) +{ + int tmp[3], i; + if (Args(conf, this, errh) + .read_p("IDENTITY", IntArg(), identity) + .read_p("FIRSTSTART1", IntArg(), tmp[0]) + .read_p("FIRSTSTART2", IntArg(), tmp[1]) + .read_p("FIRSTSTART3", IntArg(), tmp[2]) + .complete() < 0) + return -1; + for(i=0;ierror("out of memory"); + syslog (LOG_DEBUG, "initialize succeed, ready to start\n"); + return 0; +} + + +inline void +WGTTQueue::enRing(unsigned char c, Packet *p) +{ + if((_tail[c]+1)%RING_SIZE == _head[c])//override + { + // syslog (LOG_DEBUG, "WGTTQueue override\n"); + if(_q[c][_head[c]]) + _q[c][_head[c]] -> kill(); + _head[c] = (_head[c]+1)%RING_SIZE; + } + // syslog (LOG_DEBUG, "WGTTQueue before _q[_tail] = p\n"); + // Packet *tmp = _q[_tail]; + // syslog (LOG_DEBUG, "_tail: %x\n", _tail); + _q[c][_tail[c]] = p; + // syslog (LOG_DEBUG, "WGTTQueue finish _q[_tail] = p\n"); + _tail[c] = (_tail[c]+1)%RING_SIZE; + // syslog (LOG_DEBUG, "WGTTQueue finish enRing\n"); +} + +inline Packet * +WGTTQueue::deRing() +{ + int i; + bool flag = false;//no pick out + Packet *p; + //next_client after function + if(_block[0] || _head[0]==_tail[0]) + { + // if(_block[next_client]) + // syslog (LOG_DEBUG, "wgttQueue: queue %d is inactive\n", next_client+1); + // if(_head[next_client]==_tail[next_client]) + // syslog (LOG_DEBUG, "wgttQueue: queue %d is empty\n", next_client+1); + return 0; + } + while(((_head[0]+1)%MAX_N_CLIENT) != _tail[0] && !_head[0]) + _head[0] = (_head[0]+1)%RING_SIZE; + p = _q[0][_head[0]]; + _head[0] = (_head[0]+1)%RING_SIZE; + // syslog (LOG_DEBUG, "deque pkt from queue: %d\n", next_client+1); + + if(p) + { + // syslog (LOG_DEBUG, "wgttQueue: deque succeed\n"); + return p; + } + else + return 0; +} + + +void +WGTTQueue::push(int, Packet *p_in) +{ + // syslog (LOG_DEBUG, "in push\n"); + switch(pkt_type(p_in)) + { + case CONTROL_SUFFIX: push_control(p_in);break; + case DATA_SUFFIX: push_data(p_in);break; + } + // syslog (LOG_DEBUG, "out push\n"); +} + +void WGTTQueue::push_control(Packet *p_in) +{ + int i,j; + unsigned char c = client_ip(p_in)- CLIENT1_IP_SUFFIX; //index for client + if(status_ap(p_in) == CONTROLLER_IN_MAC_SUFFIX) //from controller + { + if(client_ip(p_in) == RESET_CONTENT) //reset + { + syslog (LOG_DEBUG, "receive reset req\n"); + for(i=0; i kill(); + } + syslog (LOG_DEBUG, "receive reset req for client: %d, counter %d\n", i, tmp_counter); + } + syslog (LOG_DEBUG, "finish reset req\n"); + } + else + { + syslog (LOG_DEBUG, "receive switch req for client: %d\n", c+1); + _block[c] = true; + const unsigned char & dst_ap = start_ap(p_in); + WritablePacket *p = Packet::make(sizeof(click_ether)+2); + // // data part + control_content[0] = client_ip(p_in); + control_content[1] = _head[c]; + syslog (LOG_DEBUG, "switch to ap: %d\n", dst_ap+1); + syslog (LOG_DEBUG, "switch id: %X\n", _head[c]); + memcpy(p->data()+sizeof(click_ether), &control_content, 2); + memcpy(p->data(), &(_ethh[dst_ap+1]), sizeof(click_ether)); + + p_in -> kill(); + syslog (LOG_DEBUG, "send ap-ap seq\n"); + checked_output_push(1, p); + } + + } + else //from ap + { + syslog (LOG_DEBUG, "receive ap-ap seq for client: %d\n", c+1); + + const unsigned char & start_seq = start_seq(p_in); + while(_head[c] != start_seq) + { + if(_q[c][_head[c]] != 0) + _q[c][_head[c]] -> kill(); + _head[c] = (_head[c]+1)%RING_SIZE; + } + // syslog (LOG_DEBUG, "wgttQueue finish ap-ap dequeue\n"); + + + WritablePacket *p = Packet::make(sizeof(click_ether)+2); + // click_ip *ip = reinterpret_cast(p->data()+sizeof(click_ether)); + // // data part + control_content[0] = client_ip(p_in); + control_content[1] = 0; + memcpy(p->data()+sizeof(click_ether), &control_content, 2); + + //ether part + memcpy(p->data(), &(_ethh[0]), sizeof(click_ether)); + + p_in -> kill(); + // syslog (LOG_DEBUG, "ap-c packet push\n"); + _block[c] = false; + syslog (LOG_DEBUG, "send switch ack\n"); + checked_output_push(1, p); + } +} + +void WGTTQueue::push_data(Packet *p_in) +{ + // syslog (LOG_DEBUG, "begin push_data\n"); + unsigned char seq = *(p_in -> end_data()-3); + // const unsigned char * p_c; + // int i; + // for (p_c = p_in->data(); p_c+i != p_in ->end_data(); i++) + // printf("%x", *(p_c+i)); + // printf("\n"); + // printf("-1 %x\n", *(p_in->end_data()-1)); + // printf("-2 %x\n", *(p_in->end_data()-2)); + // printf("-3 %x\n", *(p_in->end_data()-3)); + // printf("-4 %x\n", *(p_in->end_data()-4)); + + + // syslog (LOG_DEBUG, "seq: %x\n", seq); + unsigned char c; + switch(data_client(p_in)) + { + case CLIENT1_MAC_SUFFIX: c=0;break; + case CLIENT2_MAC_SUFFIX: c=1;break; + case CLIENT3_MAC_SUFFIX: c=2;break; + } + // if(_tail[c]) + // syslog (LOG_DEBUG, "wgttQueue in push data for active client: %d\n", c+1); + // else + // syslog (LOG_DEBUG, "wgttQueue in push data for inactive client: %d\n", c+1); + while(_tail[c] != seq) + { + // syslog (LOG_DEBUG, "wgttQueue: before for client: %d\n", c+1); + enRing(c, 0); + } + p_in -> pull(14); + // syslog (LOG_DEBUG, "enring client %d, after enring, _head: %X, _tail: %X\n", c+1, _head[c], _tail[c]); + enRing(c, p_in); +} + +Packet * +WGTTQueue::pull(int port) +{ + return deRing(); +} + + + + +CLICK_ENDDECLS +ELEMENT_PROVIDES(Storage) +EXPORT_ELEMENT(WGTTQueue) diff --git a/elements/ip/wgtt/wgttqueue.hh b/elements/ip/wgtt/wgttqueue.hh new file mode 100644 index 0000000000..33ae83b67b --- /dev/null +++ b/elements/ip/wgtt/wgttqueue.hh @@ -0,0 +1,61 @@ +/* + idadder program, add id and push for queue ring in ap processing. + Input: [data pkt] + Output:[eth][id][data pkt], id is one Byte + Created by Zhenyu Song: sunnyszy@gmail.com + */ +// -*- c-basic-offset: 4 -*- +#ifndef CLICK_WGTTQUEUE_HH +#define CLICK_WGTTQUEUE_HH +#include +#include +#include +#include +#include +#include +CLICK_DECLS + +class WGTTQueue : public Element, public Storage { public: + + WGTTQueue() CLICK_COLD; + + inline void enRing(unsigned char, Packet*);//flag: whether override + inline Packet* deRing(); + inline void enque(Packet*);//flag: whether override + inline Packet* deque(); + + const char *class_name() const { return "WGTTQueue"; } + const char *port_count() const { return "1/2"; } + const char *processing() const { return "h/lh"; } + + int configure(Vector&, ErrorHandler*) CLICK_COLD; + int initialize(ErrorHandler*) CLICK_COLD; + + void push(int port, Packet*); + void push_control(Packet *p_in); + void push_data(Packet *p_in); + Packet* pull(int port); + + protected: + + Packet** volatile * _q; + + volatile unsigned char _head[MAX_N_CLIENT]; + volatile unsigned char _tail[MAX_N_CLIENT]; + volatile bool _block[MAX_N_CLIENT]; + volatile unsigned char next_client; + + int identity; + int first_start[MAX_N_CLIENT]; + unsigned char control_content[2]; + + click_ether * _ethh; + +}; + + + + + +CLICK_ENDDECLS +#endif \ No newline at end of file diff --git a/elements/tcpudp/deduptcppacket.cc b/elements/tcpudp/deduptcppacket.cc deleted file mode 100644 index 973cd95a49..0000000000 --- a/elements/tcpudp/deduptcppacket.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* - * deduptcppacket.{cc,hh} -- deduplicates identical TCP packets - * (checksums, lengths) - * Hansen Qian (hq@cs.princeton.edu) - * - * Copyright (c) 1999-2000 Massachusetts Institute of Technology - * Copyright (c) 2016 Princeton University - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, subject to the conditions - * listed in the Click LICENSE file. These conditions include: you must - * preserve this copyright notice, and you cannot mention the copyright - * holders in advertising related to the Software without their permission. - * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This - * notice is a summary of the Click LICENSE file; the license in that file is - * legally binding. - */ - -#include -#include "deduptcppacket.hh" -#include -#include -#include -#include -CLICK_DECLS - -DeDupTCPPacket::DeDupTCPPacket() - : _set(0, 512), _timer(this) -{ - // sets _timer to call this->run_timer(&_timer) when it fires. -} - -DeDupTCPPacket::~DeDupTCPPacket() -{ - // Does something need to be here? -} - -int -DeDupTCPPacket::configure(Vector &conf, ErrorHandler *errh) -{ - return 0; -} - -int -DeDupTCPPacket::initialize(ErrorHandler *) -{ - _timer.initialize(this); - _timer.schedule_now(); - return 0; -} - -void -DeDupTCPPacket::cleanup(CleanupStage) -{ - -} - -void -DeDupTCPPacket::run_timer(Timer *timer) -{ - assert(timer == &_timer); - if (_set.size() > 0) { - _set.clear(); - } - _timer.reschedule_after_sec(2); -} - -Packet * -DeDupTCPPacket::drop(Packet *p) -{ -// click_chatter("TCP: duplicate, dropping"); - if (noutputs() == 2) - output(1).push(p); - else - p->kill(); - - return 0; -} - -Packet * -DeDupTCPPacket::simple_action(Packet *p_in) -{ - WritablePacket *p = p_in->uniqueify(); - struct click_ip *iph = p->ip_header(); - struct click_tcp *tcph = p->tcp_header(); - uint64_t key; - unsigned len, iph_len, tcph_len, plen; - click_tcp temp_tcph; - - memcpy(&temp_tcph, tcph, sizeof(struct click_tcp)); - - plen = ntohs(iph->ip_len) - (iph->ip_hl << 2); - if (!p->has_network_header() || iph->ip_p != IP_PROTO_TCP - || !p->has_transport_header() || plen < sizeof(click_tcp) - || plen > (unsigned)p->transport_length()) { - return drop(p); - } - - iph_len = iph->ip_hl << 2; - len = ntohs(iph->ip_len) - iph_len; - tcph_len = tcph->th_off << 2; - if (tcph_len < sizeof(click_tcp) || len < tcph_len - || p->length() < len + iph_len + p->network_header_offset()) { - return drop(p); - } - - // Deduplication Code here: - - key = build_key(iph, tcph, plen); - - if (_set.get(key) != _set.default_value()) { - // In the table - return drop(p); - } -// click_chatter("TCP: successful"); - - _set.set(key, 1); - // Cleared every 2 seconds by the timer. - - return p; -} - -uint64_t -DeDupTCPPacket::build_key(struct click_ip *iph, struct click_tcp *tcph, unsigned plen) -{ - uint16_t csum, th_sum; - uint64_t key; - uint16_t temp_sport, temp_sum; - struct in_addr temp_src; - - // Save - memcpy(&temp_src, &(iph->ip_src), sizeof(struct in_addr)); - temp_sport = tcph->th_sport; - temp_sum = tcph->th_sum; - - // Replace - inet_pton(AF_INET, "127.0.0.1", &(iph->ip_src)); - tcph->th_sport = 1234; - tcph->th_sum = 0; - - // Calculate - csum = click_in_cksum((unsigned char *)tcph, plen); - th_sum = click_in_cksum_pseudohdr(csum, iph, plen); - - // Restore - memcpy(&(iph->ip_src), &temp_src, sizeof(struct in_addr)); - tcph->th_sport = temp_sport; - tcph->th_sum = temp_sum; - - key = tcph->th_seq; - key = key << 32; - - key = key | (uint64_t) tcph->th_dport; - key = key << 16; - - key = key | (uint64_t) th_sum; - - return key; -} - -void -DeDupTCPPacket::add_handlers() -{ - -} - -CLICK_ENDDECLS -EXPORT_ELEMENT(DeDupTCPPacket) diff --git a/elements/tcpudp/deduptcppacket.hh b/elements/tcpudp/deduptcppacket.hh deleted file mode 100644 index 2b31408fb9..0000000000 --- a/elements/tcpudp/deduptcppacket.hh +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef CLICK_DEDUPTCPPACKET_HH -#define CLICK_DEDUPTCPPACKET_HH -#include -#include -#include -#include -CLICK_DECLS - -/* -=c - -DeDupTCPPacket() - -=s tcp - -drops duplicate TCP packets - -=d - -Deduplicates TCP packets, if the same one is seen multiple times. - -Expects TCP/IP packets as input. Checks that the TCP header length is valid. -Keys each packet on the TCP sequence number, destination port, and -checksum (ignoring source IP or source Port). If the key has been seen before, -the packet is dropped. -Otherwise, the packet is allowed through, and the key is stored for a maximum -of two seconds. The memory usage is reset every two seconds to prevent -memory usage. - -Install with - - make elemlist - make install - -=a DedupIPPacket, DedupUDPPacket, CheckTCPHeader, CheckIPHeader, -CheckUDPHeader, MarkIPHeader */ - -class DeDupTCPPacket : public Element { public: - - typedef HashTable Set; - - DeDupTCPPacket(); - ~DeDupTCPPacket(); - - const char *class_name() const { return "DeDupTCPPacket"; } - const char *port_count() const { return PORTS_1_1X2; } - const char *processing() const { return AGNOSTIC; } - - int configure(Vector &, ErrorHandler *); - void add_handlers(); - - Packet *simple_action(Packet *); - - int initialize(ErrorHandler *); - void cleanup(CleanupStage); - - void run_timer(Timer *); - - private: - - Set _set; - Timer _timer; - - Packet *drop(Packet *); - - uint64_t build_key(struct click_ip *, struct click_tcp *, unsigned); - -}; - -CLICK_ENDDECLS -#endif diff --git a/elements/tcpudp/packetselection.cc b/elements/tcpudp/packetselection.cc new file mode 100755 index 0000000000..caad8bf629 --- /dev/null +++ b/elements/tcpudp/packetselection.cc @@ -0,0 +1,209 @@ +/* + * udpipencaptun.{cc,hh} -- element encapsulates packet in UDP/IP header + * Benjie Chen, Eddie Kohler, Hansen Qian + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * Copyright (c) 2007 Regents of the University of California + * Copyright (c) 2016 Princeton University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#include +#include "packetselection.hh" +#include +#include +#include +#include +#include + + CLICK_DECLS + +PacketSelection::PacketSelection() +{ + int i; + score = new double[n_outport]; + fresh_counter = 0; + bigger_counter = 0; + for(i=0; i &conf, ErrorHandler *errh) +{ + if (Args(conf, this, errh) + .read_p("ALPHA", DoubleArg(), alpha) + .read_p("FRESHTIME", IntArg(), fresh_time) + .read_p("BIGGERTIME", IntArg(), bigger_time) + .read_p("FIX", IntArg(), fix) + .complete() < 0) + return -1; + + if(fix >= 0) + { + lock = true; + output_port = fix; + } + + return 0; +} + +void +PacketSelection::push(int port, Packet *p_in) +{ + if(portdata(); + /* init bits_left + * we process 16 bits at a time*/ + bits_left = 16; + + /* according to the h/w, we have 10 bit resolution + * for each real and imag value of the csi matrix H + */ + bitmask = (1 << 10) - 1; + idx = 0; + /* get 16 bits for processing */ + h_data = csi_addr[idx++]; + h_data += (csi_addr[idx++] << 8); + current_data = h_data & ((1 << 16) -1); + + /* bits number less than 10, get next 16 bits */ + if((bits_left - 10) < 0){ + h_data = csi_addr[idx++]; + h_data += (csi_addr[idx++] << 8); + current_data += h_data << bits_left; + bits_left += 16; + } + + imag = current_data & bitmask; + imag = bit_convert(imag, 10); + + bits_left -= 10; + current_data = current_data >> 10; + + /* bits number less than 10, get next 16 bits */ + if((bits_left - 10) < 0){ + h_data = csi_addr[idx++]; + h_data += (csi_addr[idx++] << 8); + current_data += h_data << bits_left; + bits_left += 16; + } + + real = current_data & bitmask; + real = bit_convert(real,10); + return (real*real+imag*imag); +} + + + + +void +PacketSelection::state_change(int port, Packet *p_in) +{ + WritablePacket *p = p_in->uniqueify(); + + + + uint16_t csi_score; + memcpy(&csi_score, p_in->data(), 2); + //csi_score = ((csi_score&0x00ff)<<8)+((csi_score&0xff00)>>8); + print_counter ++; + if(print_counter%10==0) + { + //printf("port: %d, csi_score: %u, output_port: %d\n", port, csi_score, output_port); + //printf("port: %d, csi_score1: %u, output_port: %d\n", port, csi_score1, output_port); + //printf("port: %d, csi_score2: %x, output_port: %d\n", port, csi_score2, output_port); + printf("port: %d, csi_score: %u, hex: %x, output_port: %d\n", port, csi_score, csi_score, output_port); + + + } + + + score[port] = alpha*csi_score + (1-alpha)*score[port]; + + if(fresh_counter kill(); + +} + +void +PacketSelection::destination_change(Packet *p_in) +{ + + WritablePacket *p_master = p_in->uniqueify(); + //if(print_counter%1000==0) + //printf("choose router id: %d\n", output_port); + output(output_port).push(p_master); +} + +CLICK_ENDDECLS +EXPORT_ELEMENT(PacketSelection) +ELEMENT_MT_SAFE(PacketSelection) diff --git a/elements/tcpudp/packetselection.hh b/elements/tcpudp/packetselection.hh new file mode 100755 index 0000000000..d9bf0f13fc --- /dev/null +++ b/elements/tcpudp/packetselection.hh @@ -0,0 +1,47 @@ +#ifndef CLICK_PACKETSELECTION_HH +#define CLICK_PACKETSELECTION_HH +#include +#include +#include + +CLICK_DECLS + + +class PacketSelection : public Element { public: + + + PacketSelection() CLICK_COLD; + ~PacketSelection() CLICK_COLD; + + const char *class_name() const { return "PacketSelection"; } + const char *port_count() const { return "4/3"; } + const char *flags() const { return "A"; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + + void push(int port, Packet *p_in); + + void state_change(int, Packet *); + void destination_change(Packet *); + int csi_get_score(Packet *); + int bit_convert(int, int); + + private: + double alpha; + double *score; + int print_counter; + + static const int n_outport = 3; + int fresh_time; + int fresh_counter; + int bigger_time; + int bigger_counter; + int output_port; + bool lock; + int fix; + + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/tcpudp/udpipencaptun.cc b/elements/tcpudp/udpipencaptun.cc old mode 100644 new mode 100755 index bb3338f39d..bde25fbace --- a/elements/tcpudp/udpipencaptun.cc +++ b/elements/tcpudp/udpipencaptun.cc @@ -79,7 +79,7 @@ UDPIPEncapTun::run_timer(Timer *timer) inet_ntop(AF_INET, &_daddr, strbuf, INET6_ADDRSTRLEN); - click_chatter("============================== Changing Tunnel Destination: %s", strbuf); + click_chatter("Tunneling through AP address: %s", strbuf); _timer.reschedule_after_sec(1.5); } @@ -190,7 +190,6 @@ UDPIPEncapTun::push(int port, Packet *p_in) if (cmpres != 0) { // If this comes from a different AP _counter++; - // Only change _daddr after we've seen 5 packets that confirm the new // _daddr is closer if (_counter >= 10) { @@ -216,6 +215,7 @@ UDPIPEncapTun::simple_action(Packet *p_in) WritablePacket *p = p_in->push(sizeof(click_udp) + sizeof(click_ip)); struct click_ip *ip = reinterpret_cast(p->data()); struct click_udp *udp = reinterpret_cast(ip + 1); + char strbuf[INET6_ADDRSTRLEN]; #if !HAVE_INDIFFERENT_ALIGNMENT assert((uintptr_t)ip % 4 == 0); @@ -237,6 +237,9 @@ UDPIPEncapTun::simple_action(Packet *p_in) ip->ip_off = 0; ip->ip_ttl = 250; + inet_ntop(AF_INET, &ip->ip_dst, strbuf, INET6_ADDRSTRLEN); + //click_chatter("============================== transmitting to: %s", strbuf); + ip->ip_sum = 0; #if HAVE_FAST_CHECKSUM && FAST_CHECKSUM_ALIGNED if (_aligned) diff --git a/elements/tcpudp/udpipencaptun.hh b/elements/tcpudp/udpipencaptun.hh old mode 100644 new mode 100755 diff --git a/fake.sh b/fake.sh new file mode 100755 index 0000000000..541f69c5be --- /dev/null +++ b/fake.sh @@ -0,0 +1,7 @@ +#!/bin/bash +#sudo ifconfig fake0 down +#sudo ifconfig fake0 172.17.2.135 +sudo route add default gw 172.17.2.68 fake0 +sudo ifconfig fake0 hw ether 44:c3:06:31:5b:07 +#sudo ifconfig fake0 hw ether 00:11:22:33:44:55 +sudo ifconfig fake0 up diff --git a/include/clicknet/wgtt.h b/include/clicknet/wgtt.h new file mode 100644 index 0000000000..40fadecc59 --- /dev/null +++ b/include/clicknet/wgtt.h @@ -0,0 +1,132 @@ +/* + Parameter of WGTT project, + Created by Zhenyu Song: sunnyszy@gmail.com + */ +#ifndef _WGTT_H_ +#define _WGTT_H_ + + +// #define WGTT_DEBUG +// #ifdef WGTT_DEBUG +// #define DPRINT(fmt, args...) syslog (LOG_DEBUG, "%s: " fmt, __func__ , ## args) +// #else +// #define DPRINT(fmt, args...) do {} while (0) +// #endif +// #define NDPRINT(fmt, args...) do {} while(0) + +// #ifdef WGTT_DEBUG +// #define DASSERT(expr) \ +// if (!(expr)) { \ +// syslog("Assertion failed! %s,%s,%s,line=%d\n", \ +// #expr, __FILE__, __func__, __LINE__); \ +// } +// #else +// #define DASSERT(expr) do {} while (0) +// #endif + +// #ifdef WGTT_DEBUG +// #define DASSERT2(expr1, expr2) \ +// if (expr1 != expr2) { \ +// syslog("Assertion failed! %s,%016lx,%s,%016lx,%s,%s,line=%d\n", \ +// #expr1, expr1, #expr2, expr2, __FILE__, __func__, __LINE__); \ +// } +// #else +// #define DASSERT2(expr1, expr2) do {} while (0) +// #endif + + +struct my_test_struct { + uint8_t mac; + int8_t signal; + int8_t noise; + uint32_t rx_rate; + uint32_t tx_rate; + +}; + +// ether type +#define ETHER_PROTO_BASE 0x0800 +#define CONTROL_SUFFIX 0x1 +#define STATUS_SUFFIX 0x2 +#define DATA_SUFFIX 0x3 + +// ip +#define IP_BASE 0xac110200 + +// controller state +#define IDLE 0 +#define SWITCH_REQ 1 +#define INACTIVE 2 +#define ANT 3 + +// client 1 ip +#define MAX_N_CLIENT 1 +//currently unused +// #define RSSI_THRESHOLD -67 + +#define CLIENT1_MAC_SUFFIX 0x07 +#define CLIENT2_MAC_SUFFIX 0x0b +#define CLIENT3_MAC_SUFFIX 0x0d +#define CLIENT1_MAC "44:c3:06:31:5b:07" +#define CLIENT2_MAC "44:c3:06:31:5b:0b" +#define CLIENT3_MAC "44:c3:06:31:5b:0d" +// ap +#define MAX_N_AP 3 +#define CLIENT1_IP_SUFFIX 135 +#define CLIENT2_IP_SUFFIX 136 +#define CLIENT3_IP_SUFFIX 137 +#define AP1_MAC "70:88:6b:80:60:01" +#define AP2_MAC "70:88:6b:80:60:02" +#define AP3_MAC "70:88:6b:80:60:03" +#define AP4_MAC "70:88:6b:80:60:04" +#define AP5_MAC "70:88:6b:80:60:05" +#define AP6_MAC "70:88:6b:80:60:06" +#define AP7_MAC "70:88:6b:80:60:07" +#define AP8_MAC "70:88:6b:80:60:08" + +// controller +#define CONTROLLER_IN_IP_SUFFIX 68 + +#define CONTROLLER_IN_MAC "70:88:6b:80:60:7d" +#define CONTROLLER_IN_MAC_SUFFIX 0x7d + +#define RING_SIZE 256 +// unit ms +#define SWITCH_MIN 60 +#define K_SWITCH_MIN 1000 +// content encapsulated in mac header +#define RESET_CONTENT 0xff + +// mac header indicates the packet type +#define pkt_type(p) *(p->data()+13) +#define client_ip(p) *(p->data()+14) + +#define status_ap(p) *(p->data()+11) +// when can use status mac to know client +#define status_mac(p) *((unsigned char *)(p->data()+14)) +#define status_score(p) *((char *)(p->data()+15)) +#define status_noise(p) *((char *)(p->data()+16)) +#define status_rxrate(p) *((int *)(p->data()+17)) +#define status_txrate(p) *((int *)(p->data()+21)) + +// I think we don't need this +// #define ip_id(p) *(p->data()+20) +// start ap in controll-ap command +#define start_ap(p) *(p->data()+15) +// seq number in ap-ap command +#define start_seq(p) *(p->data()+15) +// seq in data pkt +#define queue_seq(p) *(p->data()+14) +#define data_client(p) *(p->data()+20) + +//for 80211r +#define r_control_type(p) *(p->data()+14) +#define r_control_client(p) *(p->data()+15) +#define r_control_ori(p) *(p->data()+16) +#define r_control_tar(p) *(p->data()+17) +#define r_src_mac_suffix(p) *(p->data()+11) +#define r_dst_mac_suffix(p) *(p->data()+5) +#define r_ether_type_suffix(p) *(p->data()+13) + + +#endif \ No newline at end of file diff --git a/macro_test/main.c b/macro_test/main.c new file mode 100644 index 0000000000..61ee2dc5de --- /dev/null +++ b/macro_test/main.c @@ -0,0 +1,31 @@ +/* + * iwinfo - Wireless Information Library - Command line frontend + * + * Copyright (C) 2011 Jo-Philipp Wich + * + * The iwinfo library is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * The iwinfo library 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 the iwinfo library. If not, see http://www.gnu.org/licenses/. + */ + +#include + + +int main(int argc, char **argv) +{ + #ifdef __arm__ + printf("__arm__ is defined"); + #else + printf("__arm__ is not defined"); + #endif + + return 0; +} diff --git a/macro_test/main.o b/macro_test/main.o new file mode 100644 index 0000000000..469d050dd7 Binary files /dev/null and b/macro_test/main.o differ diff --git a/macro_test/test b/macro_test/test new file mode 100755 index 0000000000..270c1f90b7 Binary files /dev/null and b/macro_test/test differ diff --git a/make.sh b/make.sh new file mode 100755 index 0000000000..3352d9099a --- /dev/null +++ b/make.sh @@ -0,0 +1,6 @@ +#!/bin/bash +git pull +sudo rm ./bin/click +sudo make ./elemlist +sudo make +sudo make install diff --git a/tmp.log b/tmp.log new file mode 100644 index 0000000000..9f4a210e54 --- /dev/null +++ b/tmp.log @@ -0,0 +1,137 @@ +rm: ./bin/click: No such file or directory + LINK click +ld: warning: ld: warning: ignoring file /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libpcap.so, file was built for unsupported file format ( 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ) which is not the architecture being linked (x86_64): /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libpcap.soignoring file /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libiwinfo.so, file was built for unsupported file format ( 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ) which is not the architecture being linked (x86_64): /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libiwinfo.so + +Undefined symbols for architecture x86_64: + "_pcap_activate", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_close", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + FromDevice::cleanup(Element::CleanupStage) in fromdevice.o + IPFlowRawSockets::Flow::~Flow() in ipflowrawsockets.o + IPFlowRawSockets::Flow::~Flow() in ipflowrawsockets.o + IPFlowRawSockets::end_flow(IPFlowRawSockets::Flow*, ErrorHandler*) in ipflowrawsockets.o + IPFlowRawSockets::find_aggregate(unsigned int, Packet const*) in ipflowrawsockets.o + ToDevice::cleanup(Element::CleanupStage) in todevice.o + ... + "_pcap_compile", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_create", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_datalink", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_dispatch", referenced from: + FromDevice::selected(int, int) in fromdevice.o + FromDevice::run_task(Task*) in fromdevice.o + IPFlowRawSockets::selected(int, int) in ipflowrawsockets.o + "_pcap_fileno", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + ToDevice::initialize(ErrorHandler*) in todevice.o + "_pcap_geterr", referenced from: + FromDevice::fetch_pcap_error(pcap*, char const*) in fromdevice.o + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + FromDevice::initialize(ErrorHandler*) in fromdevice.o + FromDevice::selected(int, int) in fromdevice.o + FromDevice::run_task(Task*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_inject", referenced from: + ToDevice::send_packet(Packet*) in todevice.o + "_pcap_lookupnet", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + "_pcap_open_live", referenced from: + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_set_datalink", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + "_pcap_set_immediate_mode", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_set_promisc", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_set_snaplen", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_set_timeout", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_setdirection", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + "_pcap_setfilter", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_setnonblock", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_stats", referenced from: + FromDevice::kernel_drops(bool&, int&) const in fromdevice.o + FromDevice::read_handler(Element*, void*) in fromdevice.o +ld: symbol(s) not found for architecture x86_64 +clang: error: linker command failed with exit code 1 (use -v to see invocation) +make[1]: *** [click] Error 1 +make: *** [userlevel] Error 2 + LINK click +ld: warning: ignoring file /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libpcap.so, file was built for unsupported file format ( 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ) which is not the architecture being linked (x86_64): /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libpcap.so +ld: warning: ignoring file /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libiwinfo.so, file was built for unsupported file format ( 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ) which is not the architecture being linked (x86_64): /Volumes/BasicWrt/openwrt_linksys/staging_dir/target-arm_cortex-a9+vfpv3_uClibc-0.9.33.2_eabi/usr/lib/libiwinfo.so +Undefined symbols for architecture x86_64: + "_pcap_activate", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_close", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + FromDevice::cleanup(Element::CleanupStage) in fromdevice.o + IPFlowRawSockets::Flow::~Flow() in ipflowrawsockets.o + IPFlowRawSockets::Flow::~Flow() in ipflowrawsockets.o + IPFlowRawSockets::end_flow(IPFlowRawSockets::Flow*, ErrorHandler*) in ipflowrawsockets.o + IPFlowRawSockets::find_aggregate(unsigned int, Packet const*) in ipflowrawsockets.o + ToDevice::cleanup(Element::CleanupStage) in todevice.o + ... + "_pcap_compile", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_create", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_datalink", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_dispatch", referenced from: + FromDevice::selected(int, int) in fromdevice.o + FromDevice::run_task(Task*) in fromdevice.o + IPFlowRawSockets::selected(int, int) in ipflowrawsockets.o + "_pcap_fileno", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + ToDevice::initialize(ErrorHandler*) in todevice.o + "_pcap_geterr", referenced from: + FromDevice::fetch_pcap_error(pcap*, char const*) in fromdevice.o + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + FromDevice::initialize(ErrorHandler*) in fromdevice.o + FromDevice::selected(int, int) in fromdevice.o + FromDevice::run_task(Task*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_inject", referenced from: + ToDevice::send_packet(Packet*) in todevice.o + "_pcap_lookupnet", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + "_pcap_open_live", referenced from: + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_set_datalink", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + "_pcap_set_immediate_mode", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_set_promisc", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_set_snaplen", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_set_timeout", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_setdirection", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + "_pcap_setfilter", referenced from: + FromDevice::initialize(ErrorHandler*) in fromdevice.o + IPFlowRawSockets::Flow::initialize(ErrorHandler*, int, bool) in ipflowrawsockets.o + "_pcap_setnonblock", referenced from: + FromDevice::open_pcap(String, int, bool, ErrorHandler*) in fromdevice.o + "_pcap_stats", referenced from: + FromDevice::kernel_drops(bool&, int&) const in fromdevice.o + FromDevice::read_handler(Element*, void*) in fromdevice.o +ld: symbol(s) not found for architecture x86_64 +clang: error: linker command failed with exit code 1 (use -v to see invocation) +make[1]: *** [click] Error 1 +make: *** [install-userlevel] Error 2