From 51696f73411f1c815b3c3789e7ab5510f3c63e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiesner=20Andr=C3=A1s?= Date: Tue, 17 Jan 2023 08:19:29 +0100 Subject: [PATCH] - MemoryPool allocation-deallocation bug fixed - generic Queue implemented - PacketRegistry allocation bug fixed - TCP implementation initials - ALIGN to type macros added --- Doxyfile | 10 +- arp_cache.c | 2 +- docs/customdoxygen.css | 1868 ++++++++++++++++++++++++ gen_queue.c | 58 + gen_queue.h | 65 + global_state.c | 9 + memory_pool.c | 59 +- memory_pool.h | 18 + packet_registry.c | 3 +- packet_registry.h | 3 +- packet_sieve.c | 40 +- prefab/conn_blocks/tcp/tcp_window.c | 52 + prefab/conn_blocks/tcp/tcp_window.h | 26 + prefab/conn_blocks/tcp_connblock.c | 115 ++ prefab/conn_blocks/tcp_connblock.h | 31 + prefab/packet_parsers/icmp_packet.c | 9 +- prefab/packet_parsers/igmp_packet.c | 4 +- prefab/packet_parsers/ipv4_packet.c | 5 +- prefab/packet_parsers/tcp_segment.c | 179 +++ prefab/packet_parsers/tcp_segment.h | 81 + prefab/packet_parsers/tcp_udp_common.c | 12 + prefab/packet_parsers/tcp_udp_common.h | 23 + prefab/packet_parsers/udp_packet.c | 30 +- utils.c | 6 +- utils.h | 4 +- 25 files changed, 2648 insertions(+), 64 deletions(-) create mode 100644 docs/customdoxygen.css create mode 100644 gen_queue.c create mode 100644 gen_queue.h create mode 100644 prefab/conn_blocks/tcp/tcp_window.c create mode 100644 prefab/conn_blocks/tcp/tcp_window.h create mode 100644 prefab/conn_blocks/tcp_connblock.c create mode 100644 prefab/conn_blocks/tcp_connblock.h create mode 100644 prefab/packet_parsers/tcp_segment.c create mode 100644 prefab/packet_parsers/tcp_segment.h create mode 100644 prefab/packet_parsers/tcp_udp_common.c create mode 100644 prefab/packet_parsers/tcp_udp_common.h diff --git a/Doxyfile b/Doxyfile index 0e9640e..06ab2ca 100644 --- a/Doxyfile +++ b/Doxyfile @@ -485,7 +485,7 @@ NUM_PROC_THREADS = 1 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = NO +EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. @@ -1283,7 +1283,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = ./docs/customdoxygen.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1582,7 +1582,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. @@ -2476,7 +2476,7 @@ TEMPLATE_RELATIONS = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDE_GRAPH = YES +INCLUDE_GRAPH = NO # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing @@ -2485,7 +2485,7 @@ INCLUDE_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDED_BY_GRAPH = YES +INCLUDED_BY_GRAPH = NO # If the CALL_GRAPH tag is set to YES then doxygen will generate a call # dependency graph for every global function or class method. diff --git a/arp_cache.c b/arp_cache.c index 48c1b84..2c87fb8 100644 --- a/arp_cache.c +++ b/arp_cache.c @@ -28,7 +28,7 @@ static int arpc_recv_cb(const Pckt * pckt, PcktSieveLayerTag tag) { ArpCache *arpc_new(EthInterface * intf, uint16_t size) { // allocate table - ArpCache * arcp = (ArpCache *) dynmem_alloc(2 * sizeof(uint16_t) + sizeof(ConnBlock) + size * sizeof(ArpEntry)); + ArpCache * arcp = (ArpCache *) dynmem_alloc(sizeof(ArpCache) + size * sizeof(ArpEntry)); arcp->size = size; arcp->fill = 0; diff --git a/docs/customdoxygen.css b/docs/customdoxygen.css new file mode 100644 index 0000000..e19998a --- /dev/null +++ b/docs/customdoxygen.css @@ -0,0 +1,1868 @@ +/* The standard CSS for doxygen 1.9.1 */ + +@import url('https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,700;1,400&family=Fira+Code:wght@300;400;500;600;700&display=swap'); + +body { + /*--eggplant: #52414cff; + --dark-liver: #565152ff; + --ebony: #596157ff; + --middle-green: #5b8c5aff; + --olivine: #95af70ff; + --green-yellow-crayola: #cfd186ff; + --dark-khaki: #d2c481ff; + --light-french-beige: #d4b67cff; + --tan-crayola: #d99b71ff; + --fire-opal: #e3655bff;*/ + + + --eggplant: #52414cff; + --ebony: #596157ff; + --middle-green: #5b8c5aff; + --green-yellow-crayola: #cfd186ff; + --fire-opal: #e3655bff; + --dark-liver: #565152; + + --light-green-yellow-crayola: #feffea; + --dark-middle-green: hsl(119, 30%, 30%); + --deep-fire-opal: #aa4941; + --light-middle-green: rgb(243, 250, 243); +} + +body, table, div, p, dl { + font: 400 14px/22px 'Fira Code',Roboto,sans-serif; +} + +dt { + font: 400 17px/22px 'Crimson Text',Roboto,sans-serif; + color: var(--deep-fire-opal); +} + +dl td.paramname + td { + font: 400 16px/22px 'Crimson Text',Roboto,sans-serif; + padding-left: 1em; +} + +.sm-dox { + background-image: none; + background-color: var(--light-green-yellow-crayola); +} + +.sm-dox a, .sm-dox ul a { + color: var(--dark-liver); + background-image: none; +} + +.sm-dox a:hover, .sm-dox ul a:hover { + color: var(--light-green-yellow-crayola); + background-image: none; + background-color: var(--eggplant); +} + +p.reference, p.definition { + font: 400 14px/22px 'Crimson Text',Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px 'Fira Code',Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; + color: var(--dark-middle-green); +} + +h2.groupheader { + border-bottom: 1px solid var(--ebony); + color: var(--dark-middle-green); + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +th p.starttd, th p.intertd, th p.endtd { + font-size: 100%; + font-weight: 700; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.navtab { + border-right: 1px solid #A3B4D7; + padding-right: 15px; + text-align: right; + line-height: 110%; +} + +div.navtab table { + border-spacing: 0; +} + +td.navtab { + padding-right: 6px; + padding-left: 6px; +} +td.navtabHL { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + padding-right: 6px; + padding-left: 6px; +} + +td.navtabHL a, td.navtabHL a:visited { + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} + +a.navtab { + font-weight: bold; +} + +div.qindex{ + text-align: center; + width: 100%; + line-height: 140%; + font-size: 130%; + color: #A0A0A0; +} + +dt.alphachar{ + font-size: 180%; + font-weight: bold; +} + +.alphachar a{ + color: black; +} + +.alphachar a:hover, .alphachar a:visited{ + text-decoration: none; +} + +.classindex dl { + padding: 25px; + column-count:1 +} + +.classindex dd { + display:inline-block; + margin-left: 50px; + width: 90%; + line-height: 1.15em; +} + +.classindex dl.odd { + background-color: #F8F9FC; +} + +@media(min-width: 1120px) { + .classindex dl { + column-count:2 + } +} + +@media(min-width: 1320px) { + .classindex dl { + column-count:3 + } +} + + +/* @group Link Styling */ + +a { + /* color: #3D578C; */ + color: var(--ebony); + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + /* color: #4665A2; */ + color: var(--ebony); +} + +a:hover { + text-decoration: underline; +} + +.contents a.qindexHL:visited { + color: #FFFFFF; +} + +a.el { + font-weight: bold; + font-family: 'Fira Code', monospace; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-y: hidden; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: 'Fira Code',monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: 'Fira Code', monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #FFFFFF; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +blockquote.DocNodeRTL { + border-left: 0; + border-right: 2px solid #9CAFD4; + margin: 0 4px 0 24px; + padding: 0 16px 0 12px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid var(--ebony); +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight, .memTemplItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + /* border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; */ + border-top: 1px solid var(--ebony); + border-left: 1px solid var(--ebony); + border-right: 1px solid var(--ebony); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + /* background-image: url('nav_f.png'); */ + background-image: none; + background-repeat: repeat-x; + background-color: var(--light-green-yellow-crayola); + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; + + border-spacing: 0; + border-collapse: collapse; +} + +.memname td { + vertical-align: bottom; + padding: 0; +} + +.memproto, dl.reflist dt { + /* border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; */ + border-top: 1px solid var(--ebony); + border-left: 1px solid var(--ebony); + border-right: 1px solid var(--ebony); + padding: 6px 0px 6px 0px; + color: var(--dark-middle-green); + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* background-color: #DFE5F1; */ + background-color: var(--light-green-yellow-crayola); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: 'Fira Code', "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + /* border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; */ + border-bottom: 1px solid var(--ebony); + border-left: 1px solid var(--ebony); + border-right: 1px solid var(--ebony); + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; + /* font-style: italic; */ +} + +.paramname { + color: var(--dark-liver); + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: 'Fira Code', "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + /* background-color: #F7F8FB; */ + background-color: var(--light-middle-green); +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px 'Crimson Text',Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image: none; + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.section.DocNodeRTL { + margin-right: 0px; + padding-right: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.note.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.deprecated.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.todo.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.test.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +dl.bug.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% 'Fira Code',sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% 'Fira Code',sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% 'Fira Code',sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid var(--ebony); +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; + text-align:right; + width:52px; +} + +dl.citelist dd { + margin:2px 0 2px 72px; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +.PageDocRTL-title div.toc { + float: left !important; + text-align: right; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +.PageDocRTL-title div.toc li { + background-position-x: right !important; + padding-left: 0 !important; + padding-right: 10px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +span.emoji { + /* font family used at the site: https://unicode.org/emoji/charts/full-emoji-list.html + * font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; + */ +} + +.PageDocRTL-title div.toc li.level1 { + margin-left: 0 !important; + margin-right: 0; +} + +.PageDocRTL-title div.toc li.level2 { + margin-left: 0 !important; + margin-right: 15px; +} + +.PageDocRTL-title div.toc li.level3 { + margin-left: 0 !important; + margin-right: 30px; +} + +.PageDocRTL-title div.toc li.level4 { + margin-left: 0 !important; + margin-right: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px 'Crimson Text',Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +.DocNodeRTL { + text-align: right; + direction: rtl; +} + +.DocNodeLTR { + text-align: left; + direction: ltr; +} + +table.DocNodeRTL { + width: auto; + margin-right: 0; + margin-left: auto; +} + +table.DocNodeLTR { + width: auto; + margin-right: auto; + margin-left: 0; +} + +tt, code, kbd, samp +{ + display: inline-block; + direction:ltr; +} +/* @end */ + +u { + text-decoration: underline; +} + diff --git a/gen_queue.c b/gen_queue.c new file mode 100644 index 0000000..af9dd77 --- /dev/null +++ b/gen_queue.c @@ -0,0 +1,58 @@ +// +// Created by epagris on 2023.01.13.. +// + +#include +#include +#include "gen_queue.h" +#include "dynmem.h" + +Queue *q_create(uint32_t length, uint32_t elemSize) { + Queue * q = (Queue *) dynmem_alloc(sizeof(Queue) + length * elemSize); + q->length = length; + q->elemSize = elemSize; + q->readIdx = 0; + q->writeIdx = 0; + memset(q->elements, 0, length * elemSize); + + return q; +} + +void q_clear(Queue * q) { + q->readIdx = 0; + q->writeIdx = 0; + memset(q->elements, 0, q->length * q->elemSize); +} + +uint32_t q_avail(const Queue * q) { + return q->writeIdx - q->readIdx; +} + +#define MQ_NEXT(size,current) (((current)+1)%(size)) + +bool q_push(Queue * q, const void * src) { + if (MQ_NEXT(q->length, q->writeIdx) == q->readIdx) { // cannot push, queue is full + return false; + } + + // can push + memcpy(q->elements + q->writeIdx * q->elemSize, src, q->elemSize); + q->writeIdx++; + + // advance write pointer + q->writeIdx = MQ_NEXT(q->length, q->writeIdx); + + return true; +} + +void q_top(Queue * q, void * dest) { + memcpy(dest, q->elements + q->readIdx, q->elemSize); +} + +void q_pop(Queue * q) { + if (q_avail(q) > 0) { // if there's something to pop + q->readIdx = MQ_NEXT(q->length, q->readIdx); + } +} + + diff --git a/gen_queue.h b/gen_queue.h new file mode 100644 index 0000000..bb2d419 --- /dev/null +++ b/gen_queue.h @@ -0,0 +1,65 @@ +#ifndef ETHERLIB_TEST_QUEUE_H +#define ETHERLIB_TEST_QUEUE_H + +#include +#include + +/** + * Generic Queue. + */ +typedef struct { + uint32_t writeIdx; ///< Next block to write + uint32_t readIdx; ///< Next block to read + uint32_t length; ///< Size of circular buffer + uint32_t elemSize; ///< Element size + uint8_t elements[]; ///< Array of packets +} Queue; + +/** + * Create Queue. + * @param length length of circular buffer + * @param elemSize element size + * @return pointer to Queue instance OR NULL on failure + */ +Queue * q_create(uint32_t length, uint32_t elemSize); + +/** + * Create Queue based on storage type. + */ +#define Q_CREATE_T(length,T) q_create((length), sizeof(T)) + +/** + * Clear circular buffer. + * @param q pointer to Queue + */ +void q_clear(Queue * q); + +/** + * Get number of available elements. + * @param q pointer to Queue + * @return number of available elements + */ +uint32_t q_avail(const Queue * q); + +/** + * Push element to the Queue. + * @param q pointer to Queue + * @param raw pointer to raw packet + * @return true on success, false on failure (e.g.: queue full) + */ +bool q_push(Queue * q, const void * src); + +/** + * Get top element. + * @param q pointer to Queue + * @return top element (COPY, NOT POINTER!) + */ +void q_top(Queue * q, void * dest); + +/** + * Pop top element. + * @param q pointer to Queue + */ +void q_pop(Queue * q); + +#endif //ETHERLIB_TEST_QUEUE_H diff --git a/global_state.c b/global_state.c index d8c61fa..3eb5e84 100644 --- a/global_state.c +++ b/global_state.c @@ -7,6 +7,7 @@ #include "prefab/packet_parsers/arp_packet.h" #include "prefab/packet_parsers/icmp_packet.h" #include "etherlib/prefab/packet_parsers/igmp_packet.h" +#include "etherlib/prefab/packet_parsers/tcp_segment.h" EthState gEthState; @@ -59,6 +60,14 @@ static void register_packet_parsers() { cdesc.hdrInsFn = insert_igmp_header; cdesc.propertySize = sizeof(IgmpProps); packreg_add_class(E.pcktReg, &cdesc); + + // TCP packet parser + cdesc.class = ETH_TCP_PACKET_CLASS; + cdesc.containerClass = ETH_IPv4_PACKET_CLASS; + cdesc.procFun = parse_tcp; + cdesc.hdrInsFn = insert_tcp_header; + cdesc.propertySize = sizeof(TcpProps); + packreg_add_class(E.pcktReg, &cdesc); } void ethlib_init() { diff --git a/memory_pool.c b/memory_pool.c index 01105a3..91f3c52 100644 --- a/memory_pool.c +++ b/memory_pool.c @@ -8,11 +8,12 @@ MP *mp_init(uint8_t *p, uint32_t size) { ASSERT_BAD_ALIGN(p); // check for alignment + size = FLOOR_TO_4(size); // force alignment on size MP *pool = (MP *) p; // fill in properties pool->p = p + sizeof(MP); // compute beginning of the allocatable area pool->poolSize = size; // save total pool size - pool->blockRegistry = (MPAllocRecord *) ALIGN((p + size - sizeof(MPAllocRecord)), uint32_t); // determine block registry address - pool->freeSpace = ((uint8_t *) pool->blockRegistry) - pool->p - sizeof(MPAllocRecord); // calculate free space size + pool->blockRegistry = (MPAllocRecord *) (p + size - sizeof(MPAllocRecord)); // determine block registry address (points to the TOPMOST record, NOT one block further!) + pool->freeSpace = ((uint8_t *) pool->blockRegistry) - pool->p - 1 * sizeof(MPAllocRecord); // calculate free space size (with SENTRY and first FREE block) // place sentry element pool->blockRegistry[-1].addrStart = 0; @@ -34,19 +35,19 @@ uint8_t *mp_alloc(MP *mp, uint32_t size) { // contiguous block // round size to make it divisible by 4 - size = ALIGN(size, uint32_t); + size = CEIL_TO_4(size); - // badness = area left free on the candidate free block after allocating the requested block + // badness = area left unclaimed on the candidate free block after allocating the requested block MPAllocRecord *bestBlock = NULL; uint32_t leastBadness = ~0; MPAllocRecord *recIter = mp->blockRegistry; // allocation record while (recIter->type != MPRT_SENTRY && leastBadness > 0) { // at badness = 0 just break, since it's a perfectly fitting block // look for suitable free block - if (recIter->type == MPRT_FREE && recIter->size > size) { + if (recIter->type == MPRT_FREE && recIter->size >= size) { uint32_t iterBadness = recIter->size - size; if (iterBadness < leastBadness) { // calculate badness bestBlock = recIter; - leastBadness = recIter->size - size; + leastBadness = iterBadness; } } recIter--; // step to next block @@ -58,15 +59,20 @@ uint8_t *mp_alloc(MP *mp, uint32_t size) { bestBlock->type = MPRT_ALLOCATED; ptr = bestBlock->addrStart; } else { // if there are some bytes left between allocated blocks + // examine, that an allocated block was not blocking registry table downward growth + if (mp->blockRegistry[0].type != MPRT_FREE) { // if cannot allocate, return NULL + return NULL; + } + // shift the registry below best block - MPAllocRecord *rec = mp->blockRegistry - (mp->blockRecCnt + 1); // bottom of the registry + MPAllocRecord *rec = mp->blockRegistry - (mp->blockRecCnt); // bottom of the FILLED registry (there's one unfilled entry below this point, the new record) while (rec != bestBlock) { - *(rec) = *(rec + 1); + *(rec - 1) = *(rec); rec++; } // store information on allocated - MPAllocRecord *allocated = bestBlock - 1; + MPAllocRecord *allocated = bestBlock - 1; // don't copy best block! allocated->type = MPRT_ALLOCATED; allocated->size = size; allocated->addrStart = bestBlock->addrStart; @@ -76,6 +82,9 @@ uint8_t *mp_alloc(MP *mp, uint32_t size) { bestBlock->size -= size; bestBlock->addrStart += size; + // decrease last free block (adjacent to block registry) size with the increase in the block registry + mp->blockRegistry[0].size -= sizeof(MPAllocRecord); + // decrease free size with the increase in the registry size mp->freeSpace -= sizeof(MPAllocRecord); @@ -105,6 +114,7 @@ static void mp_join_free_blocks(MP *mp) { joinIter--; } mp->freeSpace += sizeof(MPAllocRecord); + mp->blockRegistry[0].size += sizeof(MPAllocRecord); // grow the last record size mp->blockRecCnt--; } else { recIter--; @@ -117,8 +127,7 @@ void mp_free(MP *mp, const uint8_t *p) { bool success = false; MPAllocRecord *recIter = mp->blockRegistry; while (recIter->type != MPRT_SENTRY) { - if ((recIter->type == MPRT_ALLOCATED) && - ((recIter->addrStart <= p) && ((recIter->addrStart + recIter->size) > p))) { // ...block found + if ((recIter->type == MPRT_ALLOCATED) && (recIter->addrStart == p)) { // ...block found recIter->type = MPRT_FREE; mp->freeSpace += recIter->size; success = true; @@ -142,7 +151,33 @@ void mp_report(MP *mp) { recIter--; bi++; } + INFO("%05u %s\n", bi, "SENTRY"); + INFO("----------------------\n"); INFO("Used: %u (mgmt: %u)\nFree: %u of %u\n\n", (mp->poolSize - mp->freeSpace), - (mp->blockRecCnt + 1) * sizeof(MPAllocRecord), mp->freeSpace, mp->poolSize); + (mp->blockRecCnt) * sizeof(MPAllocRecord), mp->freeSpace, mp->poolSize); +} + +uint32_t mp_largest_free_block_size(MP *mp) { + MPAllocRecord *recIter = mp->blockRegistry; + if (recIter->type == MPRT_ALLOCATED) { // if topmost block is allocated, then registry table cannot be grown + return 0; + } + + uint32_t largestFreeSize = 0; + while (recIter->type != MPRT_SENTRY) { + largestFreeSize = (recIter->size > largestFreeSize) ? recIter->size : largestFreeSize; + recIter--; + } + return largestFreeSize; +} + +void mp_foreach_block(MP * mp, MPForeachFn * fn, void * userData, bool inclFree) { + MPAllocRecord *recIter = mp->blockRegistry; + while (recIter->type != MPRT_SENTRY) { + if (recIter->type != MPRT_FREE || inclFree) { + fn(mp, recIter, userData); + } + recIter--; + } } \ No newline at end of file diff --git a/memory_pool.h b/memory_pool.h index 84ecea2..35e0332 100644 --- a/memory_pool.h +++ b/memory_pool.h @@ -76,4 +76,22 @@ void mp_free(MP * mp, const uint8_t * p); */ void mp_report(MP * mp); +/** + * Get largest contiguous free block size. + * @param mp pointer to memory pool + * @return largest block size (zero if no more allocatable space is available) + */ +uint32_t mp_largest_free_block_size(MP *mp); + +typedef void (MPForeachFn)(MP * mp, const MPAllocRecord * rec, void * userData); + +/** + * Run function on each block. + * @param mp pointer to memory pool + * @param fn callback function pointer + * @param userData data passed to callback function + * @param inclFree if true, free blocks are also included into the enumeration + */ +void mp_foreach_block(MP * mp, MPForeachFn * fn, void * userData, bool inclFree); + #endif //ETHERLIB_MEMORY_POOL_H diff --git a/packet_registry.c b/packet_registry.c index 4cc884b..e76398b 100644 --- a/packet_registry.c +++ b/packet_registry.c @@ -23,12 +23,13 @@ PcktRegistry * packreg_new() { void packreg_add_class(PcktRegistry * packReg, const PcktClassDesc * classDesc) { // if buffer is full and reallocation and resize is needed if (packReg->reservedCnt == packReg->entCnt) { - PcktClassDesc * newEnts = (PcktClassDesc *) dynmem_alloc(packReg->reservedCnt * 2); + PcktClassDesc * newEnts = (PcktClassDesc *) dynmem_alloc(packReg->reservedCnt * 2 * sizeof(PcktClassDesc)); ASSERT_NULL(newEnts); memcpy(newEnts, packReg->ents, packReg->reservedCnt * sizeof(PcktClassDesc)); PcktClassDesc * oldEnts = packReg->ents; packReg->ents = newEnts; dynmem_free(oldEnts); + packReg->reservedCnt *= 2; } // append new item diff --git a/packet_registry.h b/packet_registry.h index a67bb06..0255fd1 100644 --- a/packet_registry.h +++ b/packet_registry.h @@ -36,7 +36,8 @@ typedef void (*PcktHeaderInsertFn)(uint8_t * hdr, const struct PcktHeaderElement uint16_t headerSize; /**< Header size in bytes */ \ uint16_t containedPacketClass; /**< Class of contained packet. Zero if no packet contained. */ \ uint16_t ownPacketClass; /**< Our own packet class */ \ - uint16_t accumulatedOffset; /** Accumulated offset from the beginning of the packet */ \ + uint16_t accumulatedOffset; /** Accumulated offset from the beginning of the packet */ \ + uint16_t bytesToEnd; /** Remaining bytes to the end of payload */ \ bool8_t validityOK; /**< Indicates that checksum is OK. */ \ typedef struct { diff --git a/packet_sieve.c b/packet_sieve.c index 8b83443..64ea2db 100644 --- a/packet_sieve.c +++ b/packet_sieve.c @@ -8,11 +8,11 @@ #include "dynmem.h" #include "utils.h" -bool packfiltcond_cmp(const PcktSieveFilterCondition * c1, const PcktSieveFilterCondition * c2) { +bool packfiltcond_cmp(const PcktSieveFilterCondition *c1, const PcktSieveFilterCondition *c2) { return !memcmp(c1, c2, sizeof(PcktSieveFilterCondition)); } -void packfiltcond_zero(PcktSieveFilterCondition * cond) { +void packfiltcond_zero(PcktSieveFilterCondition *cond) { memset(cond, 0, sizeof(PcktSieveFilterCondition)); } @@ -25,7 +25,7 @@ PcktSieve *packsieve_new() { void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt, struct EthInterface_ *intf) { // extract fields - uint8_t * data = rawPckt->payload; + uint8_t *data = rawPckt->payload; uint32_t size = rawPckt->size; // process payload, fetch packet class etc. @@ -63,29 +63,35 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt, struct EthI } offset += header->props.headerSize; header->props.accumulatedOffset = offset; + header->props.bytesToEnd = size - header->props.accumulatedOffset; + header->props.hdrInsFn = cdesc->hdrInsFn; ownClass = containedClass; lastHeader = header; - } while (ownClass != 0); + } while ((ownClass != 0) && lastHeader->props.validityOK); // ------------------------------------ + if (!lastHeader->props.validityOK) { // if packet is not valid, then drop + goto header_release; // GOTO here! + } + Pckt packet; packet.time_s = rawPckt->time_s; packet.time_ns = rawPckt->time_ns; // lookup headers in the sieve - const PcktHeaderElement * headerIter = outermostHeader; + const PcktHeaderElement *headerIter = outermostHeader; const PcktSieveLayer *layer = &sieve->layer0; // innermost matched sieve layer bool found = true; // first structure is always an Ethernet-frame while (found && headerIter) { - const PcktSieveLayer * nodeIter = layer->nodes; + const PcktSieveLayer *nodeIter = layer->nodes; found = false; while (nodeIter && !found) { found |= nodeIter->matchAny || nodeIter->filtFn(&nodeIter->filtCond, &headerIter->props, &headerIter->next->props, intf); // specific or general match if (found) { layer = nodeIter; // advance in the sieve tree - const PcktHeaderElement * containedHeader = headerIter->next; // advance on headers + const PcktHeaderElement *containedHeader = headerIter->next; // advance on headers if (layer->cbFn != NULL) { // if defined, invoke layer callback function offset = containedHeader->props.accumulatedOffset; // accumulated offset + own header size packet.header = containedHeader; @@ -107,10 +113,12 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt, struct EthI // INFO("Packet headers not fully processed!\n"); // } + // release header chain blocks - PcktHeaderElement * iter = outermostHeader; + header_release:; // empty line, solely for label placement + PcktHeaderElement *iter = outermostHeader; while (iter != NULL) { - PcktHeaderElement * next = iter->next; + PcktHeaderElement *next = iter->next; dynmem_free(iter); iter = next; } @@ -118,7 +126,7 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt, struct EthI PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, bool matchAny, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass) { // search for matching layer - PcktSieveLayer * nodeIter = parent->nodes; + PcktSieveLayer *nodeIter = parent->nodes; bool alreadyExists = false; while (nodeIter != NULL && !alreadyExists) { if ((packfiltcond_cmp(&nodeIter->filtCond, filtCond) || (nodeIter->matchAny && matchAny)) && (nodeIter->filtFn == filtFn)) { // if matching... [search for specific match OR any match] @@ -147,7 +155,7 @@ PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte layer->prev = layer; } } else { // for 'any' match if at least a single node is already present - PcktSieveLayer * iter = parent->nodes; + PcktSieveLayer *iter = parent->nodes; while (iter->next != NULL) { // find the last node iter = iter->next; } @@ -167,14 +175,14 @@ PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte } } -bool packsieve_remove_layer(PcktSieveLayer * layer) { +bool packsieve_remove_layer(PcktSieveLayer *layer) { // avoid NULL-operations if (layer == NULL) { return true; } // remove parent elements if their only subnode is the one we're deleting - PcktSieveLayer * parent; + PcktSieveLayer *parent; while (layer != NULL && layer->nodes == NULL) { parent = layer->parent; // store parent @@ -208,8 +216,8 @@ void packsieve_report(const PcktSieveLayer *layer, uint32_t indent) { } else { INFO("%*c└─┤%d├───\n", indent, ' ', layer->packetClass); } - const PcktSieveLayer * nodeIter = layer->nodes; - while(nodeIter) { + const PcktSieveLayer *nodeIter = layer->nodes; + while (nodeIter) { packsieve_report(nodeIter, indent + ETH_SIEVE_LAYER_INDENT_PER_LEVEL); nodeIter = nodeIter->next; } @@ -222,7 +230,7 @@ void pckthdr_chain_free(PcktHeaderElement *hdr) { } // free - PcktHeaderElement * next; + PcktHeaderElement *next; while (hdr != NULL) { next = hdr->next; dynmem_free(hdr); diff --git a/prefab/conn_blocks/tcp/tcp_window.c b/prefab/conn_blocks/tcp/tcp_window.c new file mode 100644 index 0000000..a582436 --- /dev/null +++ b/prefab/conn_blocks/tcp/tcp_window.c @@ -0,0 +1,52 @@ +// +// Created by epagris on 2023.01.16.. +// + +#include +#include +#include "tcp_window.h" +#include "etherlib/dynmem.h" + +TcpWindow *tcpw_create(uint32_t size) { + uint32_t allocSize = sizeof(TcpWindow) + size; // calculate full allocation size + TcpWindow * win = (TcpWindow *) dynmem_alloc(allocSize); // allocate data block at the end + mp_init(win->data, size); // initialize memory pool + + return win; +} + +#define TCP_WINDOW_MAX_WINSIZE_PADDING (16) // keep-out zone, this way allocated blocks will not block registry table growth TODO: not the best solution + +uint32_t tcpw_get_max_window_size(TcpWindow * tcpw) { + return mp_largest_free_block_size(&tcpw->pool) - sizeof(TcpWindowSegment) - TCP_WINDOW_MAX_WINSIZE_PADDING; +} + +TcpWindowSegment * tcpw_store_segment(TcpWindow * tcpw, const uint8_t * data, uint32_t size, uint32_t seqNum) { + TcpWindowSegment * seg = (TcpWindowSegment *) mp_alloc(&tcpw->pool, sizeof(TcpWindowSegment) + size); + if (seg == NULL) { // could not store... + return NULL; + } + + // store segment descriptor + seg->size = size; + seg->seqNum = seqNum; + + // store segment + memcpy(seg->data, data, size); + + return seg; +} + +static void tcpw_segment_search(MP *mp, const MPAllocRecord * rec, void * userData) { + TcpWindow * tcpw = (TcpWindow *) userData; + +} + +uint32_t tcpw_get_acknowledge(TcpWindow * tcpw) { + mp_foreach_block(&tcpw->pool, tcpw_segment_search, tcpw, false); + return 0; +} + +void tcpw_set_sequence_number(TcpWindow * tcpw, uint32_t seqNum) { + tcpw->seqNum = seqNum; +} diff --git a/prefab/conn_blocks/tcp/tcp_window.h b/prefab/conn_blocks/tcp/tcp_window.h new file mode 100644 index 0000000..8543dd0 --- /dev/null +++ b/prefab/conn_blocks/tcp/tcp_window.h @@ -0,0 +1,26 @@ +#ifndef ETHERLIB_TEST_TCP_WINDOW_H +#define ETHERLIB_TEST_TCP_WINDOW_H + +#include +#include "etherlib/memory_pool.h" + +/** + * TCP segment descriptor + */ +typedef struct { + uint32_t seqNum; ///< sequence number (sequence number of the first octet) + uint32_t size; ///< segment size + uint8_t data[]; ///< Segment data +} TcpWindowSegment; + +typedef struct { + bool ackAvail; ///< acknowledge is available + uint32_t seqNum; ///< Sequence number + uint32_t lastAcked; ///< last acknowledged byte + MP pool; ///< Pool for segment management + uint8_t data[]; ///< Window data storage +} TcpWindow; + +TcpWindow * tcpw_create(uint32_t size); + +#endif //ETHERLIB_TEST_TCP_WINDOW_H diff --git a/prefab/conn_blocks/tcp_connblock.c b/prefab/conn_blocks/tcp_connblock.c new file mode 100644 index 0000000..f076dad --- /dev/null +++ b/prefab/conn_blocks/tcp_connblock.c @@ -0,0 +1,115 @@ +#include "tcp_connblock.h" + +#include +#include + +#include "../packet_parsers/packet_parsers.h" +#include "../../utils.h" +#include "../../dynmem.h" +#include "etherlib/pckt_assembler.h" +#include "etherlib/eth_interface.h" +#include "ipv4_connblock.h" +#include "etherlib/prefab/packet_parsers/tcp_segment.h" +#include "etherlib/gen_queue.h" +#include "etherlib_options.h" + +static bool filtTcp(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface *intf) { + IPv4Props *ipProps = (IPv4Props *) contProps; + TcpProps *tcpProps = (TcpProps *) ownProps; + + return ipProps->Protocol == ETH_UDP_PACKET_CLASS && (TCP_PORT_FROM_FILTCOND(filtCond) == tcpProps->DestinationPort); +} + +/** + * TCP state. + */ +typedef struct { + uint16_t localPort; + uint16_t remotePort; + ip4_addr remoteAddr; + uint32_t sequenceNumber; + uint32_t ackNumber; + uint16_t window; + uint8_t * txWindow; + uint8_t * rxWindow; + Queue * txQueue; + Queue * rxQueue; +} TcpState; + +void tcps_init(TcpState *tcps, uint16_t localPort) { + tcps->sequenceNumber = (uint32_t) rand(); + tcps->localPort = localPort; + tcps->remotePort = 0; + tcps->remoteAddr = 0; + tcps->ackNumber = 0; + tcps->window = 0; + tcps->txWindow = dynmem_alloc(ETHLIB_DEF_TCP_WINDOW_SIZE); + tcps->rxWindow = dynmem_alloc(ETHLIB_DEF_TCP_WINDOW_SIZE); + /*tcps->txQueue = Q_CREATE_T(ETHLIB_DEF_TCP_QUEUE_SIZE, TcpQueueTicker); + tcps->rxQueue = Q_CREATE_T(ETHLIB_DEF_TCP_QUEUE_SIZE, TcpQueueTicker);*/ +} + +void tcp_bind(ConnBlock * connBlock, ip4_addr remoteAddr, uint16_t remotePort) { + TcpState * tcps = (TcpState *) connBlock->tag; + tcps->remoteAddr = remoteAddr; + tcps->remotePort = remotePort; +} + +int tcps_receive_data_segment(TcpState * tcps, const Pckt * pckt) { + +} + +ConnBlock tcp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) { + ConnBlock tcpConnB; + ConnBlock ipConnB = ipv4_new_connblock(intf, ipAddr, NULL); // create new IPv4 connection block + + PcktSieveFilterCondition filtCond; + packfiltcond_zero(&filtCond); + TCP_PORT_TO_FILTCOND(&filtCond, port); + + PcktSieveLayerTag tag; // store TCP state into sieve layer's tag + tag.p = dynmem_alloc(sizeof(TcpState)); + memset(tag.p, 0, sizeof(TcpState)); + + tcpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, &filtCond, false, filtTcp, cbFn, tag, ETH_TCP_PACKET_CLASS); + ASSERT_NULL(tcpConnB.sieveLayer); + + tcpConnB.intf = intf; + + SNPRINTF(tcpConnB.sieveLayer->infoTag, PCKT_SIEVE_INFOTAG_LEN, "TCP port: %d", port); + + return tcpConnB; +} + +int tcp_send_segment(const struct ConnBlock_ *connBlock, const uint8_t *data, uint32_t size) { + // allocate headers + PcktHeaderElement *tcpHeader = ALLOC_HEADER_ELEMENT(TcpProps); + PcktHeaderElement *ipHeader = ALLOC_HEADER_ELEMENT(IPv4Props); + PcktHeaderElement *ethHeader = ALLOC_HEADER_ELEMENT(EthernetProps); + tcpHeader->next = NULL; + tcpHeader->prev = ipHeader; + ipHeader->next = tcpHeader; + ipHeader->prev = ethHeader; + ethHeader->next = ipHeader; + ethHeader->prev = NULL; + + // prepare headers + TcpProps *tcpProps = HEADER_FETCH_PROPS(TcpProps, tcpHeader); + IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, ipHeader); + EthernetProps *ethProps = HEADER_FETCH_PROPS(EthernetProps, ethHeader); + + // get TCP state + PcktSieveLayer *layer = connBlock->sieveLayer; // TCP layer + TcpState *tcpState = (TcpState *) layer->tag.p; + + // fetch sieve layers and fill transmit headers + tcpProps->SourcePort = tcpState->localPort; + tcpProps->DestinationPort = tcpState->remotePort; + tcpProps->SequenceNumber = tcpState->sequenceNumber; + tcpProps->AcknowledgementNumber = tcpState->ackNumber; + tcpProps->Window = tcpState->window; + tcpProps->Checksum = 0; + tcpProps->UrgentPtr = 0; + + return 0; +} diff --git a/prefab/conn_blocks/tcp_connblock.h b/prefab/conn_blocks/tcp_connblock.h new file mode 100644 index 0000000..01f44b4 --- /dev/null +++ b/prefab/conn_blocks/tcp_connblock.h @@ -0,0 +1,31 @@ +#ifndef ETHERLIB_TEST_TCP_CONNBLOCK_H +#define ETHERLIB_TEST_TCP_CONNBLOCK_H + +#define TCP_PORT_FROM_FILTCOND(fc) ((fc)->uw[7]) +#define TCP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[7]) = (port)) + +#include +#include "../packet_parsers/ipv4_types.h" +#include "../../connection_block.h" + +struct EthInterface_; + +/** + * Create new TCP connection block + * @param intf associated Ethernet interface + * @param ipAddr local IP-address + * @param port local port + * @param cbFn receive callback function + * @return TCP connection block + */ +ConnBlock tcp_new_connblock(struct EthInterface_ *intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn); + +/** + * Bind TCP connection to remote socket. + * @param connBlock pointer to TCP connection block + * @param remoteAddr remote socket address + * @param remotePort remote socket port + */ +void tcp_bind(ConnBlock * connBlock, ip4_addr remoteAddr, uint16_t remotePort); + +#endif //ETHERLIB_TEST_TCP_CONNBLOCK_H diff --git a/prefab/packet_parsers/icmp_packet.c b/prefab/packet_parsers/icmp_packet.c index 34bb337..00a9a35 100644 --- a/prefab/packet_parsers/icmp_packet.c +++ b/prefab/packet_parsers/icmp_packet.c @@ -7,6 +7,8 @@ #include "ipv4_packet.h" int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + const uint8_t * hdrStart = hdr; + // parse header IcmpProps *icmpProps = HEADER_FETCH_PROPS(IcmpProps, pcktHdrLe); FETCH_BYTE_ADVANCE(&icmpProps->type, hdr); @@ -16,7 +18,8 @@ int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, FETCH_WORD_ADVANCE(&icmpProps->sequenceNumber, hdr); // fill-in common fields - icmpProps->validityOK = true; // TODO... + IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe->prev); + icmpProps->validityOK = chksum(hdrStart, ipProps->TotalLength - ETH_IPv4_HEADER_SIZE, false) == 0; icmpProps->containedPacketClass = 0; icmpProps->headerSize = ETH_ICMP_HEADER_SIZE; @@ -35,8 +38,8 @@ void insert_icmp_header(uint8_t *hdr, const PcktHeaderElement *headers) { FILL_ADVANCE(hdr, &icmpProps->sequenceNumber, 2); IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, headers->prev); - icmpProps->checksum = chksum(hdrStart, ipProps->TotalLength - ETH_IPv4_HEADER_SIZE); - FILL_WORD_H2N_ADVANCE(ChkSumPtr, icmpProps->checksum); + icmpProps->checksum = chksum(hdrStart, ipProps->TotalLength - ETH_IPv4_HEADER_SIZE, false); + FILL_WORD_ADVANCE(ChkSumPtr, icmpProps->checksum); } diff --git a/prefab/packet_parsers/igmp_packet.c b/prefab/packet_parsers/igmp_packet.c index 0ca7041..0f7c3cb 100644 --- a/prefab/packet_parsers/igmp_packet.c +++ b/prefab/packet_parsers/igmp_packet.c @@ -36,7 +36,7 @@ void insert_igmp_header(uint8_t *hdr, const PcktHeaderElement *headers) { FILL_WORD_ADVANCE(hdr, igmpProps->checksum); FILL_DWORD_ADVANCE(hdr, igmpProps->groupAddr); - igmpProps->checksum = chksum(hdrBeg, ETH_IGMP_HEADER_SIZE); + igmpProps->checksum = chksum(hdrBeg, ETH_IGMP_HEADER_SIZE, false); memcpy(ChkSumPtr, &igmpProps->checksum, 2); } @@ -49,7 +49,7 @@ int parse_igmp(const uint8_t * hdr, uint32_t size, PcktHeaderElement * pcktHdrLe FETCH_WORD_ADVANCE(&igmpProps->groupAddr, hdr); // fill-in common fields - uint16_t calcChkSum = chksum(hdr, ETH_IGMP_HEADER_SIZE); + uint16_t calcChkSum = chksum(hdr, ETH_IGMP_HEADER_SIZE, false); igmpProps->validityOK = (calcChkSum == 0); igmpProps->containedPacketClass = 0; igmpProps->headerSize = ETH_IGMP_HEADER_SIZE; diff --git a/prefab/packet_parsers/ipv4_packet.c b/prefab/packet_parsers/ipv4_packet.c index 2eb9d72..a90133c 100644 --- a/prefab/packet_parsers/ipv4_packet.c +++ b/prefab/packet_parsers/ipv4_packet.c @@ -15,7 +15,8 @@ static bool check_ipv4_validity(const uint8_t * hdr, const IPv4Props *ipProps) { bool valid = (ipProps->Version == 4) && (ipProps->IHL == (ETH_IP_HEADER_LENGTH / 4)) && - (ntohs(ipProps->HeaderChecksum) == chksum(hdr, ETH_IPv4_HEADER_SIZE)); + (chksum(hdr, ETH_IPv4_HEADER_SIZE, false) == 0) && + (ipProps->FragmentOffset == 0) && !(ipProps->Flags & 0x02); // discard if fragmented return valid; } @@ -77,7 +78,7 @@ void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers) { FILL_ADVANCE(hdr, &ipProps->DestIPAddr, 4); // calculate checksum after filling header - ipProps->HeaderChecksum = chksum(hdrOrig, ETH_IPv4_HEADER_SIZE); + ipProps->HeaderChecksum = chksum(hdrOrig, ETH_IPv4_HEADER_SIZE, false); memcpy(ChkSumPtr, &ipProps->HeaderChecksum, 2); } diff --git a/prefab/packet_parsers/tcp_segment.c b/prefab/packet_parsers/tcp_segment.c new file mode 100644 index 0000000..3fd186d --- /dev/null +++ b/prefab/packet_parsers/tcp_segment.c @@ -0,0 +1,179 @@ +// +// Created by epagris on 2023.01.14.. +// + +#include "tcp_segment.h" +#include "etherlib/utils.h" +#include "ethernet_frame.h" +#include "etherlib/dynmem.h" + +#include "tcp_udp_common.h" +#include "ipv4_packet.h" + +#define TCP_SINGLE_BYTE_OPTION(kind) (((kind) == TCP_OPT_KIND_EOL) || ((kind) == TCP_OPT_KIND_NOP)) + +static int tcp_fetch_options(const uint8_t * hdr, uint8_t size, TcpOption ** optLe) { + uint8_t idx = 0; + TcpOption * lastOpt = NULL; + int optCnt = 0; + while (idx < size) { + uint8_t kind = hdr[idx + 0]; // read option kind + + // skip further reading when EOL or NOP has been detected + if (TCP_SINGLE_BYTE_OPTION(kind)) { + idx++; + continue; + } + + uint8_t valueSize = hdr[idx + 1] - 2; // read option length + + TcpOption * opt = (TcpOption *) dynmem_alloc(sizeof(TcpOption) + valueSize); // allocate option + + // fill-in + opt->kind = kind; + opt->size = valueSize; + memcpy(opt->value, hdr + idx + 2, opt->size); // copy option value + opt->next = NULL; + + // store option + if (*optLe == NULL) { + *optLe = opt; + } else { + lastOpt->next = opt; + } + + lastOpt = opt; // advance last opt + idx += opt->size + 2; // advance index + optCnt++; // increase opt count + } + + return optCnt; +} + +static void tcp_insert_options(uint8_t * hdr, uint8_t size, TcpOption * optLe) { + TcpOption * opt = optLe; + uint8_t idx = 0; + while (opt != NULL && idx < size) { + hdr[idx + 0] = opt->kind; // insert kind + + // skip further reading when EOL or NOP has been detected + if (TCP_SINGLE_BYTE_OPTION(opt->kind)) { + idx++; + opt = opt->next; + continue; + } + + uint8_t length = opt->size + 2; // insert length + hdr[idx + 1] = length; + memcpy(hdr + idx + 2, opt->value, opt->size); // insert value + + idx += length; // advance idx + opt = opt->next; // advance iterator + } + + // insert NOP padding if needed + if (idx < (size - 1)) { + uint8_t paddingNop = size - idx - 1; + memset(hdr + idx, 1, paddingNop); + } + + // insert EOL if needed + if (idx < size) { + memset(hdr + idx, 0, 1); + } +} + +static uint32_t tcp_get_options_size(TcpOption * optLe) { + TcpOption * opt = optLe; + uint32_t size = 0; + while (opt != NULL) { + if (TCP_SINGLE_BYTE_OPTION(opt->kind)) { + size += 1; + } else { + size += opt->size + 2; + } + opt = opt->next; + } + + // round up to the neareast integer multiple of four bytes + size = CEIL_TO_4(size); + + return size; +} + +int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + const uint8_t * hdrBegin = hdr; + + // fetch fixed portion of the segment header + TcpProps * tcpProps = HEADER_FETCH_PROPS(TcpProps, pcktHdrLe); + FETCH_WORD_H2N_ADVANCE(&tcpProps->SourcePort, hdr); + FETCH_WORD_H2N_ADVANCE(&tcpProps->DestinationPort, hdr); + FETCH_DWORD_H2N_ADVANCE(&tcpProps->SequenceNumber, hdr); + FETCH_DWORD_H2N_ADVANCE(&tcpProps->AcknowledgementNumber, hdr); + uint8_t dataOffset_Flags; + FETCH_BYTE_ADVANCE(&dataOffset_Flags, hdr); + tcpProps->DataOffset = dataOffset_Flags >> 4; + uint8_t flagsLower; + FETCH_BYTE_ADVANCE(&flagsLower, hdr); + tcpProps->Flags = flagsLower | ((dataOffset_Flags & 0x01) << 8); + FETCH_WORD_H2N_ADVANCE(&tcpProps->Window, hdr); + FETCH_WORD_H2N_ADVANCE(&tcpProps->Checksum, hdr); + FETCH_WORD_H2N_ADVANCE(&tcpProps->UrgentPtr, hdr); + + // fetch options + tcpProps->options = NULL; // no options by default + uint8_t fullHeaderSize = tcpProps->DataOffset * 4; + if (fullHeaderSize > ETH_TCP_HEADER_LENGTH) { + uint8_t optSize = fullHeaderSize - ETH_TCP_HEADER_LENGTH; + tcp_fetch_options(hdr, optSize, &tcpProps->options); + } + + // verify checksum + const IPv4Props *ipProps = (IPv4Props *) &pcktHdrLe->prev->props; + uint16_t headerAndPayloadLength = ipProps->bytesToEnd; + IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_TCP_PACKET_CLASS, htons(headerAndPayloadLength)}; + uint16_t chkSum = tcp_udp_checksum(&ph, hdrBegin, headerAndPayloadLength); + + tcpProps->headerSize = fullHeaderSize; + tcpProps->validityOK = (chkSum == 0); + tcpProps->containedPacketClass = 0; + + return tcpProps->validityOK ? 0 : -1; +} + +void insert_tcp_header(uint8_t *hdr, const PcktHeaderElement *headers) { + uint8_t * hdrBegin = hdr; + TcpProps * tcpProps = HEADER_FETCH_PROPS(TcpProps, headers); // fetch header + + // get option area size and computer full area size + uint32_t optSize = tcp_get_options_size(tcpProps->options); + uint32_t fullHeaderSize = ETH_TCP_HEADER_LENGTH + optSize; + tcpProps->DataOffset = fullHeaderSize >> 2; + + // fill beginning of the header + FILL_WORD_H2N_ADVANCE(hdr, tcpProps->SourcePort); + FILL_WORD_H2N_ADVANCE(hdr, tcpProps->DestinationPort); + FILL_DWORD_H2N_ADVANCE(hdr, tcpProps->SequenceNumber); + FILL_DWORD_H2N_ADVANCE(hdr, tcpProps->AcknowledgementNumber); + uint8_t dataOffset_Flags = (tcpProps->DataOffset << 4) | (tcpProps->Flags >> 8); + FILL_BYTE_ADVANCE(hdr, &dataOffset_Flags); + uint8_t flagsLower = tcpProps->Flags & 0xFF; + FILL_BYTE_ADVANCE(hdr, &flagsLower); + FILL_WORD_H2N_ADVANCE(hdr, tcpProps->Window); + tcpProps->Checksum = 0; + uint8_t * ChkSumPtr = hdr; + FILL_WORD_H2N_ADVANCE(hdr, tcpProps->Checksum); + FILL_WORD_H2N_ADVANCE(hdr, tcpProps->UrgentPtr); + + // fill options + tcp_insert_options(hdr, optSize, tcpProps->options); + + // calculate checksum + const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props; + uint16_t headerAndPayloadLength = fullHeaderSize + headers->props.bytesToEnd; + IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_TCP_PACKET_CLASS, htons(headerAndPayloadLength)}; + tcpProps->Checksum = tcp_udp_checksum(&ph, hdrBegin, headerAndPayloadLength); + memcpy(ChkSumPtr, &tcpProps->Checksum, 2); +} + + diff --git a/prefab/packet_parsers/tcp_segment.h b/prefab/packet_parsers/tcp_segment.h new file mode 100644 index 0000000..943e89f --- /dev/null +++ b/prefab/packet_parsers/tcp_segment.h @@ -0,0 +1,81 @@ +#ifndef ETHERLIB_TEST_TCP_SEGMENT_H +#define ETHERLIB_TEST_TCP_SEGMENT_H + +#include +#include "../../packet_sieve.h" + +#define ETH_TCP_PACKET_CLASS (6) +#define ETH_TCP_HEADER_LENGTH (20) + +#define TCP_MAX_OPT_VAL_LEN (8) + +/** + * TCP option kinds. + */ +typedef enum { + TCP_OPT_KIND_EOL = 0, // End of Operation List Option + TCP_OPT_KIND_NOP = 1, // No-Operation + TCP_OPT_KIND_MSS = 2 // Maximum Segment Size +} TcpOptionKind; + +/** + * TCP options + */ +typedef struct TcpOption_ { + uint8_t kind; ///< Kind of the specific option (~type) + uint8_t size; ///< Size of value (NOT including 'kind' and 'length' fields) [=TCP opt length - 2] + struct TcpOption_ * next; ///< Next option in the list + uint8_t value[]; ///< Value +} TcpOption; + +/** + * TCP segment flags + */ +typedef enum { + TCP_FLAG_FIN = 0x01, + TCP_FLAG_SYN = 0x02, + TCP_FLAG_RESET = 0x04, + TCP_FLAG_PUSH = 0x08, + TCP_FLAG_ACK = 0x10, + TCP_FLAG_URGENT = 0x20, + TCP_FLAG_ECNECHO = 0x40, + TCP_FLAG_CWR = 0x80, + TCP_FLAG_NONCE = 0x100 +} TcpFlag; + +/** + * TCP segment properties. + */ +typedef struct { + PcktPropsHeader + uint16_t SourcePort; ///< Source port + uint16_t DestinationPort; ///< Destination port + uint32_t SequenceNumber; ///< TCP sequence number + uint32_t AcknowledgementNumber; ///< TCP ack. number + uint8_t DataOffset; ///< Data offset in 32-bits (4 bit-long field) + uint16_t Flags; ///< TCP flags (9-bit, 8 + 4, but upper 3 is reserved) + uint16_t Window; ///< TCP window + uint16_t Checksum; ///< Checksum + uint16_t UrgentPtr; ///< Urgent pointer + TcpOption * options; ///< Linked list of TCP options +} TcpProps; + +struct EthInterface_; + +/** + * Parse raw TCP segments. + * @param hdr pointer to the TCP packet header + * @param size total packet size + * @param pcktHdrLe pointer to property storage + * @return 0 on success or -1 on failure + */ +int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); + +/** + * Insert TCP header. + * @param hdr space where the header is to be inserted + * @param headers linked list of header, top is always relevant + */ +void insert_tcp_header(uint8_t * hdr, const PcktHeaderElement * headers); + +#endif //ETHERLIB_TEST_TCP_SEGMENT_H diff --git a/prefab/packet_parsers/tcp_udp_common.c b/prefab/packet_parsers/tcp_udp_common.c new file mode 100644 index 0000000..bd239ad --- /dev/null +++ b/prefab/packet_parsers/tcp_udp_common.c @@ -0,0 +1,12 @@ +#include + +#include "tcp_udp_common.h" +#include "../../utils.h" + +uint16_t tcp_udp_checksum(const IPv4PseudoHeader *pseudoHeader, const uint8_t * hdr, uint32_t size) { + uint32_t sum = chksum((const uint8_t *) pseudoHeader, sizeof(IPv4PseudoHeader), true) + chksum(hdr, size, true); + while (sum >> 16) { + sum = (sum & 0xFFFF) + (sum >> 16); + } + return htonl(sum); +} \ No newline at end of file diff --git a/prefab/packet_parsers/tcp_udp_common.h b/prefab/packet_parsers/tcp_udp_common.h new file mode 100644 index 0000000..b8d609a --- /dev/null +++ b/prefab/packet_parsers/tcp_udp_common.h @@ -0,0 +1,23 @@ +#ifndef ETHERLIB_TEST_TCP_UDP_COMMON_H +#define ETHERLIB_TEST_TCP_UDP_COMMON_H + +#include + +typedef struct { + uint32_t sourceIpAddr; + uint32_t destIpAddr; + uint8_t zero; + uint8_t protocol; + uint16_t udpLength; +} IPv4PseudoHeader; + +/** + * Calculate TCP or UDP checksum. + * @param pseudoHeader pointer to IPv4 pseudo-header + * @param hdr pointer to data + * @param size size of data + * @return checksum + */ +uint16_t tcp_udp_checksum(const IPv4PseudoHeader *pseudoHeader, const uint8_t * hdr, uint32_t size); + +#endif //ETHERLIB_TEST_TCP_UDP_COMMON_H diff --git a/prefab/packet_parsers/udp_packet.c b/prefab/packet_parsers/udp_packet.c index d95b164..287a421 100644 --- a/prefab/packet_parsers/udp_packet.c +++ b/prefab/packet_parsers/udp_packet.c @@ -4,25 +4,21 @@ #include "ipv4_packet.h" #include "ethernet_frame.h" +#include "tcp_udp_common.h" + #define ETH_UDP_HEADER_SIZE (8) -typedef struct { - uint32_t sourceIpAddr; - uint32_t destIpAddr; - uint8_t zero; - uint8_t protocol; - uint16_t udpLength; -} UdpPseudoHeader; - -static uint16_t udp_checksum(const UdpPseudoHeader *pseudoHeader, const uint8_t * hdr, uint32_t size) { - uint32_t sum = chksum((const uint8_t *)pseudoHeader, sizeof(UdpPseudoHeader)) + chksum(hdr, size); - while (sum >> 16) { - sum = (sum & 0xFFFF) + (sum >> 16); - } - return sum; +static bool check_udp_validity(const uint8_t * hdr, const PcktHeaderElement *pcktHdrLe) { + const UdpProps *udpProps = HEADER_FETCH_PROPS(UdpProps, pcktHdrLe); + const IPv4Props *ipProps = (IPv4Props *) &pcktHdrLe->prev->props; + IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, htons(udpProps->Length)}; + uint16_t chkSum = tcp_udp_checksum(&ph, hdr, udpProps->Length); + bool valid = chkSum == 0; + return valid; } int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + const uint8_t * hdrBegin = hdr; UdpProps *udpProps = HEADER_FETCH_PROPS(UdpProps, pcktHdrLe); FETCH_WORD_H2N_ADVANCE(&udpProps->SourcePort, hdr); FETCH_WORD_H2N_ADVANCE(&udpProps->DestinationPort, hdr); @@ -31,7 +27,7 @@ int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s // common fields... udpProps->headerSize = ETH_UDP_HEADER_SIZE; - udpProps->validityOK = (size == udpProps->Length); // TODO UDP checksum validation! + udpProps->validityOK = check_udp_validity(hdrBegin, pcktHdrLe); udpProps->containedPacketClass = 0; return udpProps->validityOK ? 0 : -1; @@ -49,8 +45,8 @@ void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers) { // calculate checksum const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props; - UdpPseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, htons(udpProps->Length)}; - udpProps->Checksum = udp_checksum(&ph, hdrBegin, udpProps->Length); + IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, htons(udpProps->Length)}; + udpProps->Checksum = tcp_udp_checksum(&ph, hdrBegin, udpProps->Length); memcpy(ChkSumPtr, &udpProps->Checksum, 2); } diff --git a/utils.c b/utils.c index e46f933..3a551e5 100644 --- a/utils.c +++ b/utils.c @@ -60,12 +60,12 @@ uint32_t crc32(const uint8_t * data, uint32_t size) { return checksum; } -uint16_t chksum(const uint8_t * data, uint32_t size) { +uint16_t chksum(const uint8_t *data, uint32_t size, int swap) { // sum fields uint32_t sum = 0; const uint16_t *pField = (const uint16_t *) data; - for (uint8_t i = 0; i < (size / sizeof(uint16_t)); i++) { - uint16_t field = pField[i]; + for (uint16_t i = 0; i < (size / sizeof(uint16_t)); i++) { + uint16_t field = swap ? htons(pField[i]) : pField[i]; sum += field; } diff --git a/utils.h b/utils.h index 7fd5bd1..9eafed4 100644 --- a/utils.h +++ b/utils.h @@ -44,6 +44,8 @@ #define ASSERT_NULL(p) if ((p) == NULL) ERROR("NULL in function '%s' in file '%s' on line %d!\n", __func__, __FILE__, __LINE__) #define ALIGN(p,t) (((size_t)(p) + (sizeof(t) - 1)) & ~(sizeof(t) - 1)) +#define FLOOR_TO_4(x) ((x) & ~0b11) +#define CEIL_TO_4(x) ((((x) >> 2) + (((x) & 0b11) ? 1 : 0)) << 2) #define FETCH_ADVANCE(dst,src,n) memcpy((dst), (src), n), (src) += n #define FILL_ADVANCE(dst,src,n) memcpy((dst), (src), n), (dst) += n @@ -81,6 +83,6 @@ uint32_t crc32(const uint8_t * data, uint32_t size); * @param size size of data block * @return checksum */ -uint16_t chksum(const uint8_t * data, uint32_t size); +uint16_t chksum(const uint8_t *data, uint32_t size, int swap); #endif //ETHERLIB_UTILS_H