Old rev code
git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7372 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -1,604 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
#include "platform_constants.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_mux_proto_extern.h"
|
||||
#include "rlc_am_segment_proto_extern.h"
|
||||
#include "rlc_am_receiver_proto_extern.h"
|
||||
#include "rlc_am_demux_proto_extern.h"
|
||||
#include "rlc_am_reset_proto_extern.h"
|
||||
#include "rlc_am_status_proto_extern.h"
|
||||
#include "rlc_am_errno.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
#include "rlc_am_discard_rx_proto_extern.h"
|
||||
#include "rlc_am_discard_tx_proto_extern.h"
|
||||
#include "rlc_am_discard_notif_proto_extern.h"
|
||||
#include "mac_primitives.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_control_primitives_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "list.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//#define DEBUG_RLC_AM_DATA_REQUEST
|
||||
//#define DEBUG_RLC_AM_TX
|
||||
//#define DEBUG_RLC_AM_RX
|
||||
//#define DEBUG_RLC_AM_BO
|
||||
//-----------------------------------------------------------------------------
|
||||
void display_protocol_vars_rlc_am (struct rlc_am_entity *rlcP);
|
||||
uint32_t rlc_am_get_buffer_occupancy_in_pdus_for_ch1 (struct rlc_am_entity *rlcP);
|
||||
uint32_t rlc_am_get_buffer_occupancy_in_pdus_for_ch2 (struct rlc_am_entity *rlcP);
|
||||
void *rlc_am_tx (void *argP);
|
||||
void rlc_am_rx (void *argP, struct mac_data_ind data_indP);
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t
|
||||
rlc_am_get_buffer_occupancy_in_bytes_ch1 (struct rlc_am_entity *rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t sum = 0;
|
||||
|
||||
if (rlcP->buffer_occupancy > 0) {
|
||||
sum += (rlcP->pdus_to_mac_layer_ch1.nb_elements * rlcP->pdu_size);
|
||||
sum += (rlcP->buffer_occupancy_retransmission_buffer * rlcP->pdu_size);
|
||||
sum += rlcP->control.nb_elements * rlcP->pdu_size; // TEST LG + HA 23/10/2008
|
||||
sum += rlcP->buffer_occupancy; // approximation because of headers of pdus
|
||||
} else {
|
||||
if ((rlcP->li_one_byte_short_to_add_in_next_pdu) ||
|
||||
(rlcP->li_exactly_filled_to_add_in_next_pdu)) {
|
||||
// WARNING LG WE ASSUME TRANSPORT BLOCKS ARE < 125 bytes
|
||||
sum = rlcP->pdu_size; // 4 bytes; // so this is the exact size of the next TB to be sent (SN + 2LIs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_RLC_AM_BO
|
||||
msg ("[RLC_AM][RB %d] DTCH BO: %d bytes \n", rlcP->rb_id,sum);
|
||||
#endif
|
||||
return sum;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t
|
||||
rlc_am_get_buffer_occupancy_in_bytes_ch2 (struct rlc_am_entity * rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef DEBUG_RLC_AM_BO
|
||||
msg ("[RLC_AM][RB %d] DCCH BO: CONTROL %d DCCH %d\n", rlcP->rb_id, rlcP->control.nb_elements * rlcP->pdu_size,
|
||||
rlcP->pdus_to_mac_layer_ch2.nb_elements * rlcP->pdu_size);
|
||||
#endif
|
||||
return rlcP->control.nb_elements * rlcP->pdu_size + rlcP->pdus_to_mac_layer_ch2.nb_elements * rlcP->pdu_size;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t
|
||||
rlc_am_get_buffer_occupancy_in_pdus_ch1 (struct rlc_am_entity * rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t sum = 0;
|
||||
|
||||
sum += rlcP->pdus_to_mac_layer_ch1.nb_elements;
|
||||
sum += rlcP->buffer_occupancy_retransmission_buffer;
|
||||
sum += rlcP->control.nb_elements; // TEST LG + HA 23/10/2008
|
||||
sum += (rlcP->buffer_occupancy / (rlcP->pdu_size - 2)); // minus 2 = size min for pdu header
|
||||
|
||||
#ifdef DEBUG_RLC_AM_BO
|
||||
msg ("[RLC_AM][RB %d] BO : CH1 %d blocks \n", rlcP->rb_id, rlcP->pdus_to_mac_layer_ch1.nb_elements);
|
||||
msg ("[RLC_AM][RB %d] BO : RETRANS BUFFER %d blocks \n", rlcP->rb_id, rlcP->buffer_occupancy_retransmission_buffer);
|
||||
msg ("[RLC_AM][RB %d] BO : BUFFER SDU %d blocks \n", rlcP->rb_id, rlcP->buffer_occupancy / (rlcP->pdu_size - 2));
|
||||
#endif
|
||||
return sum;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t
|
||||
rlc_am_get_buffer_occupancy_in_pdus_ch2 (struct rlc_am_entity * rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef DEBUG_RLC_AM_BO
|
||||
msg ("[RLC_AM][RB %d] BO : CH2 CONTROL %d DCCH %d\n", rlcP->rb_id, rlcP->control.nb_elements, rlcP->pdus_to_mac_layer_ch2.nb_elements);
|
||||
#endif
|
||||
return rlcP->control.nb_elements + rlcP->pdus_to_mac_layer_ch2.nb_elements;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_get_pdus (void *argP, uint8_t traffic_typeP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct rlc_am_entity *rlc = (struct rlc_am_entity *) argP;
|
||||
|
||||
switch (rlc->protocol_state) {
|
||||
|
||||
case RLC_NULL_STATE:
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the NULL state the RLC entity does not exist and therefore it is not possible to transfer any data through it.
|
||||
// Upon reception of a CRLC-CONFIG-Req from upper layer indicating establishment, the RLC entity:
|
||||
// - is created; and
|
||||
// - enters the DATA_TRANSFER_READY state.
|
||||
break;
|
||||
|
||||
case RLC_DATA_TRANSFER_READY_STATE:
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the DATA_TRANSFER_READY state, acknowledged mode data can be exchanged between the entities according to subclause 11.3.
|
||||
// Upon reception of a CRLC-CONFIG-Req from upper layer indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon detection of an initiating condition for the RLC reset procedure described in subclause 11.4.2, the RLC entity:
|
||||
// - initiates the RLC reset procedure (see subclause 11.4); and
|
||||
// - enters the RESET_PENDING state.
|
||||
// Upon reception of a RESET PDU, the RLC entity responds according to subclause 11.4.3.
|
||||
// Upon reception of a RESET ACK PDU, the RLC entity takes no action.
|
||||
// Upon reception of CRLC-SUSPEND-Req from upper layer, the RLC entity is suspended and enters the LOCAL_SUSPEND state.
|
||||
// SEND DATA TO MAC
|
||||
|
||||
umts_timer_check_time_out (&rlc->rlc_am_timer_list, *rlc->frame_tick_milliseconds);
|
||||
|
||||
if ((rlc->send_status_pdu_requested)) {
|
||||
// may be timer status prohibit
|
||||
if (rlc_am_send_status (rlc) > 0) {
|
||||
rlc->send_status_pdu_requested = 0;
|
||||
}
|
||||
} else if ((rlc->timer_status_periodic) && ((Mac_rlc_xface->frame % (rlc->timer_status_periodic / 10)) == 0)
|
||||
&& (rlc->last_tx_status_frame != Mac_rlc_xface->frame)) {
|
||||
// may be MAC can poll RLC more than once in a time frame
|
||||
//msg ("[RLC_AM][RB %d] SEND STATUS PERIODIC frame %d\n", rlc->rb_id, Mac_rlc_xface->frame);
|
||||
if (rlc_am_send_status (rlc) > 0) {
|
||||
rlc->send_status_pdu_requested = 0;
|
||||
}
|
||||
|
||||
rlc->last_tx_status_frame = Mac_rlc_xface->frame;
|
||||
}
|
||||
|
||||
#ifdef NODE_MT
|
||||
rlc_am_mux_ue (rlc, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS | RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
#else
|
||||
rlc_am_mux_rg (rlc, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS | RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case RLC_RESET_PENDING_STATE:
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the RESET_PENDING state the entity waits for a response from its peer entity and no data can be exchanged between the entities.
|
||||
// Upon reception of a CRLC-CONFIG-Req from upper layer indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon reception of a RESET ACK PDU with the same RSN value as in the corresponding RESET PDU, the RLC entity:
|
||||
// - acts according to subclause 11.4.4; and
|
||||
// - enters the DATA_TRANSFER_READY state.
|
||||
// Upon reception of a RESET ACK PDU with a different RSN value as in the corresponding RESET PDU, the RLC entity:
|
||||
// - discards the RESET ACK PDU (see subclause 11.4.4); and
|
||||
// - stays in the RESET_PENDING state.
|
||||
// Upon reception of a RESET PDU, the RLC entity:
|
||||
// - responds according to subclause 11.4.3; and
|
||||
// - stays in the RESET_PENDING state.
|
||||
// Upon reception of CRLC-SUSPEND-Req from upper layer, the RLC entity:
|
||||
// - enters the RESET_AND_SUSPEND state.
|
||||
umts_timer_check_time_out (&rlc->rlc_am_timer_list, *rlc->frame_tick_milliseconds);
|
||||
#ifdef NODE_MT
|
||||
rlc_am_mux_ue (rlc, RLC_AM_TRAFFIC_NOT_ALLOWED);
|
||||
#else
|
||||
rlc_am_mux_rg (rlc, RLC_AM_TRAFFIC_NOT_ALLOWED);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case RLC_RESET_AND_SUSPEND_STATE:
|
||||
// In the RESET_ AND_SUSPEND state, the entity waits for a response from its peer entity or a primitive (CRLC-RESUME-Req) from its upper layer and no data can be exchanged between the entities.
|
||||
// Upon reception of CRLC-CONFIG-Req from upper layer indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon reception of a RESET ACK PDU with the same RSN value as in the corresponding RESET PDU, the RLC entity:
|
||||
// - acts according to subclause 11.4.4; and
|
||||
// - enters the LOCAL_SUSPEND state.
|
||||
// Upon reception of CRLC-RESUME-Req from upper layer in this state, the RLC entity:
|
||||
// - is resumed, i.e. releases the suspend constraint; and
|
||||
// - enters the RESET_PENDING state.
|
||||
#ifdef NODE_MT
|
||||
rlc_am_mux_ue (rlc, RLC_AM_TRAFFIC_NOT_ALLOWED);
|
||||
#else
|
||||
rlc_am_mux_rg (rlc, RLC_AM_TRAFFIC_NOT_ALLOWED);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case RLC_LOCAL_SUSPEND_STATE:
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the LOCAL_SUSPEND state, the RLC entity is suspended, i.e. it does not send AMD PDUs with SN greater than or equal to certain specified value (see subclause 9.7.5).
|
||||
// Upon reception of CRLC-RESUME-Req from upper layers in this state, the RLC entity:
|
||||
// - resumes the data transmission; and
|
||||
// - enters the DATA_TRANSFER_READY state.
|
||||
// Upon reception of CRLC-CONFIG-Req from upper layers indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon detection of an initiating condition for RLC reset procedure described in subclause 11.4.2, the RLC entity:
|
||||
// - initiates the RLC reset procedure (see subclause 11.4); and
|
||||
// - enters the RESET_AND_SUSPEND state.
|
||||
|
||||
// TO DO TAKE CARE OF SN : THE IMPLEMENTATION OF THIS FUNCTIONNALITY IS NOT CRITICAL
|
||||
if ((rlc->send_status_pdu_requested)) {
|
||||
rlc_am_send_status (rlc);
|
||||
rlc->send_status_pdu_requested = 0;
|
||||
}
|
||||
|
||||
#ifdef NODE_MT
|
||||
rlc_am_mux_ue (rlc, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS);
|
||||
#else
|
||||
rlc_am_mux_rg (rlc, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d] MAC_DATA_REQ UNKNOWN PROTOCOL STATE 0x%02X\n", rlc->rb_id, rlc->protocol_state);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_rx (void *argP, struct mac_data_ind data_indP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct rlc_am_entity *rlc = (struct rlc_am_entity *) argP;
|
||||
|
||||
#ifdef DEBUG_RLC_AM_RX
|
||||
msg("[RLC][AM] In rlc_am_rx\n");
|
||||
#endif
|
||||
|
||||
switch (rlc->protocol_state) {
|
||||
|
||||
case RLC_NULL_STATE:
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the NULL state the RLC entity does not exist and therefore it is not possible to transfer any data through it.
|
||||
// Upon reception of a CRLC-CONFIG-Req from upper layer indicating establishment, the RLC entity:
|
||||
// - is created; and
|
||||
// - enters the DATA_TRANSFER_READY state.
|
||||
msg ("[RLC_AM %p] ERROR MAC_DATA_IND IN RLC_NULL_STATE\n", argP);
|
||||
list_free (&data_indP.data);
|
||||
break;
|
||||
|
||||
case RLC_DATA_TRANSFER_READY_STATE:
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the DATA_TRANSFER_READY state, acknowledged mode data can be exchanged between the entities according to subclause 11.3.
|
||||
// Upon reception of a CRLC-CONFIG-Req from upper layer indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon detection of an initiating condition for the RLC reset procedure described in subclause 11.4.2, the RLC entity:
|
||||
// - initiates the RLC reset procedure (see subclause 11.4); and
|
||||
// - enters the RESET_PENDING state.
|
||||
// Upon reception of a RESET PDU, the RLC entity responds according to subclause 11.4.3.
|
||||
// Upon reception of a RESET ACK PDU, the RLC entity takes no action.
|
||||
// Upon reception of CRLC-SUSPEND-Req from upper layer, the RLC entity is suspended and enters the LOCAL_SUSPEND state.
|
||||
if ((rlc->rlc_am_timer_list.head)) {
|
||||
umts_timer_check_time_out (&rlc->rlc_am_timer_list, *rlc->frame_tick_milliseconds);
|
||||
}
|
||||
|
||||
rlc_am_demux_routing (rlc, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS | RLC_AM_TRAFFIC_ALLOWED_FOR_DATA, data_indP);
|
||||
break;
|
||||
|
||||
case RLC_RESET_PENDING_STATE:
|
||||
case RLC_RESET_AND_SUSPEND_STATE:
|
||||
case RLC_LOCAL_SUSPEND_STATE:
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the RESET_PENDING state the entity waits for a response from its peer entity and no data can be exchanged between the entities.
|
||||
// Upon reception of a CRLC-CONFIG-Req from upper layer indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon reception of a RESET ACK PDU with the same RSN value as in the corresponding RESET PDU, the RLC entity:
|
||||
// - acts according to subclause 11.4.4; and
|
||||
// - enters the DATA_TRANSFER_READY state.
|
||||
// Upon reception of a RESET ACK PDU with a different RSN value as in the corresponding RESET PDU, the RLC entity:
|
||||
// - discards the RESET ACK PDU (see subclause 11.4.4); and
|
||||
// - stays in the RESET_PENDING state.
|
||||
// Upon reception of a RESET PDU, the RLC entity:
|
||||
// - responds according to subclause 11.4.3; and
|
||||
// - stays in the RESET_PENDING state.
|
||||
// Upon reception of CRLC-SUSPEND-Req from upper layer, the RLC entity:
|
||||
// - enters the RESET_AND_SUSPEND state.
|
||||
|
||||
// In the RESET_ AND_SUSPEND state, the entity waits for a response from its peer entity or a primitive (CRLC-RESUME-Req) from its upper layer and no data can be exchanged between the entities.
|
||||
// Upon reception of CRLC-CONFIG-Req from upper layer indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon reception of a RESET ACK PDU with the same RSN value as in the corresponding RESET PDU, the RLC entity:
|
||||
// - acts according to subclause 11.4.4; and
|
||||
// - enters the LOCAL_SUSPEND state.
|
||||
// Upon reception of CRLC-RESUME-Req from upper layer in this state, the RLC entity:
|
||||
// - is resumed, i.e. releases the suspend constraint; and
|
||||
// - enters the RESET_PENDING state.
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the LOCAL_SUSPEND state, the RLC entity is suspended, i.e. it does not send AMD PDUs with SN greater than or equal to certain specified value (see subclause 9.7.5).
|
||||
// Upon reception of CRLC-RESUME-Req from upper layers in this state, the RLC entity:
|
||||
// - resumes the data transmission; and
|
||||
// - enters the DATA_TRANSFER_READY state.
|
||||
// Upon reception of CRLC-CONFIG-Req from upper layers indicating release, the RLC entity:
|
||||
// - enters the NULL state; and
|
||||
// - is considered as being terminated.
|
||||
// Upon detection of an initiating condition for RLC reset procedure described in subclause 11.4.2, the RLC entity:
|
||||
// - initiates the RLC reset procedure (see subclause 11.4); and
|
||||
// - enters the RESET_AND_SUSPEND state.
|
||||
|
||||
if ((rlc->rlc_am_timer_list.head)) {
|
||||
umts_timer_check_time_out (&rlc->rlc_am_timer_list, *rlc->frame_tick_milliseconds);
|
||||
}
|
||||
|
||||
rlc_am_demux_routing (rlc, RLC_AM_TRAFFIC_NOT_ALLOWED, data_indP);
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM %p] TX UNKNOWN PROTOCOL STATE 0x%02X\n", rlc, rlc->protocol_state);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp
|
||||
rlc_am_mac_status_indication (void *rlcP, uint16_t no_tbP, uint16_t tb_sizeP, struct mac_status_ind tx_statusP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp status_resp;
|
||||
struct rlc_am_entity *rlc = (struct rlc_am_entity *) rlcP;
|
||||
|
||||
|
||||
rlc_am_discard_check_sdu_time_out (rlc);
|
||||
|
||||
// call only for knowing if control pdu to transmit
|
||||
// special case: no data at startup on this side, but peer entity tx full sspeed
|
||||
// peer entity wqit for acks
|
||||
rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS);
|
||||
|
||||
rlc->nb_pdu_requested_by_mac_on_ch1 = no_tbP;
|
||||
//((struct rlc_am_entity*)rlcP)->rlc_pdu_size = tb_sizeP; no modification of pdu_size for RLC AM
|
||||
|
||||
status_resp.buffer_occupancy_in_pdus = rlc_am_get_buffer_occupancy_in_pdus_ch1 (rlc);
|
||||
status_resp.buffer_occupancy_in_pdus += rlc_am_get_buffer_occupancy_in_pdus_ch2 (rlc);
|
||||
status_resp.buffer_occupancy_in_pdus += rlc->control.nb_elements;
|
||||
status_resp.buffer_occupancy_in_bytes = status_resp.buffer_occupancy_in_pdus * (rlc)->pdu_size;
|
||||
status_resp.rlc_info.rlc_protocol_state = (rlc)->protocol_state;
|
||||
#ifdef DEBUG_RLC_AM_TX
|
||||
msg ("[RLC_AM][RB %d] MAC_STATUS_INDICATION %d TBs -> MAC_STATUS_RESPONSE %d TBs FRAME %d\n", rlc->rb_id, no_tbP, status_resp.buffer_occupancy_in_pdus,
|
||||
Mac_rlc_xface->frame);
|
||||
#endif
|
||||
return status_resp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp
|
||||
rlc_am_mac_status_indication_on_first_channel (void *rlcP, uint16_t no_tbP, uint16_t tb_sizeP, struct mac_status_ind tx_statusP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp status_resp;
|
||||
|
||||
rlc_am_discard_check_sdu_time_out ((struct rlc_am_entity *) rlcP);
|
||||
((struct rlc_am_entity *) rlcP)->nb_pdu_requested_by_mac_on_ch1 = no_tbP;
|
||||
//((struct rlc_am_entity*)rlcP)->rlc_pdu_size = tb_sizeP; no modification of pdu_size for RLC AM
|
||||
|
||||
|
||||
status_resp.buffer_occupancy_in_pdus = rlc_am_get_buffer_occupancy_in_pdus_ch1 ((struct rlc_am_entity *) rlcP);
|
||||
status_resp.buffer_occupancy_in_bytes = status_resp.buffer_occupancy_in_pdus * ((struct rlc_am_entity *) rlcP)->pdu_size;
|
||||
status_resp.rlc_info.rlc_protocol_state = ((struct rlc_am_entity *) rlcP)->protocol_state;
|
||||
#ifdef DEBUG_RLC_AM_TX
|
||||
msg ("[RLC_AM][RB %d] CHANNEL 1 MAC_STATUS_INDICATION (DATA) %d TBs -> MAC_STATUS_RESPONSE %d TBs\n", ((struct rlc_am_entity*) rlcP)->rb_id, no_tbP,
|
||||
status_resp.buffer_occupancy_in_pdus);
|
||||
#endif
|
||||
return status_resp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp
|
||||
rlc_am_mac_status_indication_on_second_channel (void *rlcP, uint16_t no_tbP, uint16_t tb_sizeP, struct mac_status_ind tx_statusP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp status_resp;
|
||||
|
||||
rlc_am_discard_check_sdu_time_out ((struct rlc_am_entity *) rlcP);
|
||||
|
||||
((struct rlc_am_entity *) rlcP)->nb_pdu_requested_by_mac_on_ch2 = no_tbP;
|
||||
//((struct rlc_am_entity*)rlcP)->rlc_pdu_size = tb_sizeP; no modification of pdu_size for RLC AM
|
||||
|
||||
status_resp.buffer_occupancy_in_pdus = rlc_am_get_buffer_occupancy_in_pdus_ch2 ((struct rlc_am_entity *) rlcP);
|
||||
status_resp.buffer_occupancy_in_bytes = status_resp.buffer_occupancy_in_pdus * ((struct rlc_am_entity *) rlcP)->pdu_size;
|
||||
status_resp.rlc_info.rlc_protocol_state = ((struct rlc_am_entity *) rlcP)->protocol_state;
|
||||
#ifdef DEBUG_RLC_AM_TX
|
||||
msg ("[RLC_AM][RB %d] CHANNEL 2 MAC_STATUS_INDICATION (CONTROL) %d TBs -> MAC_STATUS_RESPONSE %d TBs\n", ((struct rlc_am_entity*) rlcP)->rb_id, no_tbP,
|
||||
status_resp.buffer_occupancy_in_pdus);
|
||||
#endif
|
||||
return status_resp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req
|
||||
rlc_am_mac_data_request (void *rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req data_req;
|
||||
mem_block_t *pdu;
|
||||
signed int nb_pdu_to_transmit = ((struct rlc_am_entity *) rlcP)->nb_pdu_requested_by_mac_on_ch1 ;
|
||||
//rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS | RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
|
||||
list_init (&data_req.data, NULL);
|
||||
|
||||
//list_add_list (&((struct rlc_am_entity *) rlcP)->pdus_to_mac_layer_ch1, &data_req.data);
|
||||
while (nb_pdu_to_transmit > 0 ) {
|
||||
pdu = list_remove_head (&((struct rlc_am_entity *) rlcP)->pdus_to_mac_layer_ch1);
|
||||
|
||||
if (pdu != null) {
|
||||
list_add_tail_eurecom (pdu, &data_req.data);
|
||||
} else {
|
||||
//msg ("[RLC_AM][RB %d] WARNING MAC_DATA_REQUEST CANNOT GIVE A PDU REQUESTED BY MAC\n", ((struct rlc_am_entity *) rlcP)->rb_id);
|
||||
}
|
||||
|
||||
nb_pdu_to_transmit = nb_pdu_to_transmit - 1;
|
||||
}
|
||||
|
||||
//list_add_list (&((struct rlc_am_entity *) rlcP)->pdus_to_mac_layer_ch2, &data_req.data);
|
||||
|
||||
#ifdef DEBUG_RLC_AM_TX
|
||||
msg ("[RLC_AM][RB %d] MAC_DATA_REQUEST %d TBs (REQUESTED %d) Frame %d\n", ((struct rlc_am_entity *) rlcP)->rb_id, data_req.data.nb_elements,
|
||||
((struct rlc_am_entity *) rlcP)->nb_pdu_requested_by_mac_on_ch1 , Mac_rlc_xface->frame);
|
||||
#endif
|
||||
data_req.buffer_occupancy_in_pdus = rlc_am_get_buffer_occupancy_in_pdus_ch1 ((struct rlc_am_entity *) rlcP);
|
||||
data_req.buffer_occupancy_in_pdus += rlc_am_get_buffer_occupancy_in_pdus_ch2 ((struct rlc_am_entity *) rlcP);
|
||||
data_req.buffer_occupancy_in_bytes = data_req.buffer_occupancy_in_pdus * ((struct rlc_am_entity *) rlcP)->pdu_size;
|
||||
data_req.rlc_info.rlc_protocol_state = ((struct rlc_am_entity *) rlcP)->protocol_state;
|
||||
return data_req;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req
|
||||
rlc_am_mac_data_request_on_first_channel (void *rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req data_req;
|
||||
// from TS25.322 V4.2.0 p13
|
||||
// In case two logical channels are configured in the uplink, AMD PDUs are transmitted
|
||||
// on the first logical channel, and control PDUs are transmitted on the second logical
|
||||
// channel. In case two logical channels are configured in the downlink, AMD and Control
|
||||
// PDUs can be transmitted on any of the two logical channels.
|
||||
#ifdef NODE_RG
|
||||
rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS | RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
#else
|
||||
rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
#endif
|
||||
list_init (&data_req.data, NULL);
|
||||
list_add_list (&((struct rlc_am_entity *) rlcP)->pdus_to_mac_layer_ch1, &data_req.data);
|
||||
|
||||
#ifdef DEBUG_RLC_AM_TX
|
||||
msg ("[RLC_AM][RB %d] MAC_DATA_REQUEST (DATA) %d TBs\n", ((struct rlc_am_entity *) rlcP)->rb_id, data_req.data.nb_elements);
|
||||
#endif
|
||||
data_req.buffer_occupancy_in_pdus = rlc_am_get_buffer_occupancy_in_pdus_ch1 ((struct rlc_am_entity *) rlcP);
|
||||
data_req.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes_ch1 ((struct rlc_am_entity *) rlcP);
|
||||
data_req.rlc_info.rlc_protocol_state = ((struct rlc_am_entity *) rlcP)->protocol_state;
|
||||
return data_req;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req
|
||||
rlc_am_mac_data_request_on_second_channel (void *rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req data_req;
|
||||
|
||||
// from TS25.322 V4.2.0 p13
|
||||
// In case two logical channels are configured in the uplink, AMD PDUs are transmitted
|
||||
// on the first logical channel, and control PDUs are transmitted on the second logical
|
||||
// channel. In case two logical channels are configured in the downlink, AMD and Control
|
||||
// PDUs can be transmitted on any of the two logical channels.
|
||||
#ifdef NODE_RG
|
||||
rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS | RLC_AM_TRAFFIC_ALLOWED_FOR_DATA);
|
||||
#else
|
||||
rlc_am_get_pdus (rlcP, RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS);
|
||||
#endif
|
||||
list_init (&data_req.data, NULL);
|
||||
list_add_list (&((struct rlc_am_entity *) rlcP)->pdus_to_mac_layer_ch2, &data_req.data);
|
||||
|
||||
#ifdef DEBUG_RLC_AM_TX
|
||||
msg ("[RLC_AM][RB %d] MAC_DATA_REQUEST (CONTROL) %d TBs\n", ((struct rlc_am_entity *) rlcP)->rb_id, data_req.data.nb_elements);
|
||||
#endif
|
||||
data_req.buffer_occupancy_in_pdus = rlc_am_get_buffer_occupancy_in_pdus_ch2 ((struct rlc_am_entity *) rlcP);
|
||||
data_req.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes_ch2 ((struct rlc_am_entity *) rlcP);
|
||||
data_req.rlc_info.rlc_protocol_state = ((struct rlc_am_entity *) rlcP)->protocol_state;
|
||||
return data_req;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_mac_data_indication (void *rlcP, struct mac_data_ind data_indP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
rlc_am_rx (rlcP, data_indP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_data_req (void *rlcP, mem_block_t * sduP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_entity *rlc = (struct rlc_am_entity *) rlcP;
|
||||
uint32_t mui;
|
||||
uint16_t data_offset;
|
||||
uint16_t data_size;
|
||||
uint8_t conf;
|
||||
|
||||
|
||||
if ((rlc->input_sdus[rlc->next_sdu_index] == NULL) && (((rlc->next_sdu_index + 1) % rlc->size_input_sdus_buffer) != rlc->current_sdu_index)) {
|
||||
|
||||
rlc->stat_tx_pdcp_sdu += 1;
|
||||
|
||||
rlc->input_sdus[rlc->next_sdu_index] = sduP;
|
||||
mui = ((struct rlc_am_data_req *) (sduP->data))->mui;
|
||||
data_offset = ((struct rlc_am_data_req *) (sduP->data))->data_offset;
|
||||
data_size = ((struct rlc_am_data_req *) (sduP->data))->data_size;
|
||||
conf = ((struct rlc_am_data_req *) (sduP->data))->conf;
|
||||
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->mui = mui;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->sdu_size = data_size;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->confirm = conf;
|
||||
|
||||
rlc->buffer_occupancy += ((struct rlc_am_tx_sdu_management *) (sduP->data))->sdu_size;
|
||||
rlc->nb_sdu += 1;
|
||||
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->first_byte = &sduP->data[data_offset];
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->sdu_remaining_size = ((struct rlc_am_tx_sdu_management *) (sduP->data))->sdu_size;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->sdu_segmented_size = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->sdu_creation_time = *rlc->frame_tick_milliseconds;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->nb_pdus = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->nb_pdus_ack = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->nb_pdus_time = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->nb_pdus_internal_use = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->segmented = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->discarded = 0;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->li_index_for_discard = -1;
|
||||
((struct rlc_am_tx_sdu_management *) (sduP->data))->no_new_sdu_segmented_in_last_pdu = 0;
|
||||
rlc->next_sdu_index = (rlc->next_sdu_index + 1) % rlc->size_input_sdus_buffer;
|
||||
#ifdef DEBUG_RLC_AM_DATA_REQUEST
|
||||
msg ("[RLC_AM][RB %d] RLC_AM_DATA_REQ size %d Bytes, NB SDU %d current_sdu_index=%d next_sdu_index=%d conf %d mui %d ",
|
||||
rlc->rb_id, data_size, rlc->nb_sdu, rlc->current_sdu_index, rlc->next_sdu_index, conf, mui);
|
||||
msg ("BO=%ld Bytes\n", rlc->buffer_occupancy);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_DATA_REQUEST
|
||||
msg ("[RLC_AM][RB %d] RLC_AM_DATA_REQ BUFFER FULL, NB SDU %d current_sdu_index=%d next_sdu_index=%d size_input_sdus_buffer=%d\n",
|
||||
rlc->rb_id, rlc->nb_sdu, rlc->current_sdu_index, rlc->next_sdu_index, rlc->size_input_sdus_buffer);
|
||||
#endif
|
||||
rlc->stat_tx_pdcp_sdu_discarded += 1;
|
||||
free_mem_block (sduP);
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_constant.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_CONSTANT_H__
|
||||
# define __RLC_AM_CONSTANT_H__
|
||||
|
||||
# define RLC_AM_LOCATION_UTRAN 0xBA
|
||||
# define RLC_AM_LOCATION_UE 0x01
|
||||
|
||||
//----------------------------------------------------------
|
||||
// AMD DATA, CONTROL PDU parameters
|
||||
//----------------------------------------------------------
|
||||
# define NB_MAX_SUFI 30
|
||||
# define SUFI_MAX_SIZE 40
|
||||
// SUFI field (4 bits)
|
||||
# define RLC_AM_SUFI_NO_MORE 0x0
|
||||
# define RLC_AM_SUFI_WINDOW 0x1
|
||||
# define RLC_AM_SUFI_ACK 0x2
|
||||
# define RLC_AM_SUFI_LIST 0x3
|
||||
# define RLC_AM_SUFI_BITMAP 0x4
|
||||
# define RLC_AM_SUFI_RLIST 0x5
|
||||
# define RLC_AM_SUFI_MRW 0x6
|
||||
# define RLC_AM_SUFI_MRW_ACK 0x7
|
||||
|
||||
# define RLC_AM_SUFI_NO_MORE_SIZE 4
|
||||
//in bits
|
||||
# define RLC_AM_SUFI_ACK_SIZE 16
|
||||
//in bits
|
||||
# define RLC_AM_SUFI_LIST_SIZE_MIN 24
|
||||
//in bits
|
||||
# define RLC_AM_SUFI_BITMAP_SIZE_MIN 28
|
||||
//in bits
|
||||
//----------------------------------------------------------
|
||||
// values for ack field of struct rlc_am_tx_pdu_management
|
||||
// this struct is mapped on the misc field of each pdu
|
||||
# define RLC_AM_PDU_ACK_NO_EVENT 0
|
||||
# define RLC_AM_PDU_ACK_EVENT 1
|
||||
# define RLC_AM_PDU_NACK_EVENT -1
|
||||
//----------------------------------------------------------
|
||||
# define RLC_AM_SEND_MRW_OFF 0x0F
|
||||
# define RLC_AM_SEND_MRW_ON 0xF0
|
||||
//----------------------------------------------------------
|
||||
// SN Field
|
||||
# define RLC_AM_SN_1ST_PART_MASK 0x7F
|
||||
# define RLC_AM_SN_2ND_PART_MASK 0xF8
|
||||
//----------------------------------------------------------
|
||||
// Polling bit (values shifted 2 bits left)
|
||||
# define RLC_AM_P_STATUS_REPORT_NOT_REQUESTED 0
|
||||
# define RLC_AM_P_STATUS_REPORT_REQUESTED 4
|
||||
# define RLC_AM_P_STATUS_REPORT_MASK 4
|
||||
//----------------------------------------------------------
|
||||
// li field (values shifted 1 bit left)
|
||||
# define RLC_AM_SEGMENT_NB_MAX_LI_PER_PDU 32
|
||||
//----------------------------------------------------------
|
||||
// shifted 3 bits left
|
||||
# define RLC_AM_RESET_SEQUENCE_NUMBER_MASK 0x08
|
||||
|
||||
# define RLC_AM_TIMER_POLL_TIME_OUT_EVENT 0x001
|
||||
# define RLC_AM_TIMER_POLL_PROHIBIT_TIME_OUT_EVENT 0x002
|
||||
# define RLC_AM_TIMER_EPC_TIME_OUT_EVENT 0x004
|
||||
# define RLC_AM_TIMER_DISCARD_TIME_OUT_EVENT 0x008
|
||||
# define RLC_AM_TIMER_POLL_PERIODIC_TIME_OUT_EVENT 0x010
|
||||
# define RLC_AM_TIMER_STATUS_PROHIBIT_TIME_OUT_EVENT 0x020
|
||||
# define RLC_AM_TIMER_STATUS_PERIODIC_TIME_OUT_EVENT 0x040
|
||||
# define RLC_AM_TIMER_RST_TIME_OUT_EVENT 0x080
|
||||
# define RLC_AM_TIMER_MRW_TIME_OUT_EVENT 0x100
|
||||
//----------------------------------------------------------
|
||||
# define RLC_AM_SDU_SEGMENTS_SUBMITTED_TO_LOWER_LAYER 0xFF
|
||||
// for sdu_header_copy
|
||||
# define RLC_AM_SN_INVALID 0xFFFF
|
||||
|
||||
// PDU transmission
|
||||
# define RLC_AM_PDU_COPY_LOCATION_RETRANSMISSION_BUFFER_TO_SEND 0x10
|
||||
# define RLC_AM_PDU_COPY_LOCATION_PDUS_TO_MAC_LAYER 0x20
|
||||
# define RLC_AM_PDU_COPY_LOCATION_MASK 0xF0
|
||||
//----------------------------------------------------------
|
||||
// Events defined for state model of the acknowledged mode entity
|
||||
# define RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_NULL_STATE_EVENT 0x00
|
||||
# define RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT 0x01
|
||||
# define RLC_AM_RECEIVE_CRLC_SUSPEND_REQ_EVENT 0x10
|
||||
# define RLC_AM_TRANSMIT_CRLC_SUSPEND_CNF_EVENT 0x11
|
||||
# define RLC_AM_RECEIVE_CRLC_RESUME_REQ_EVENT 0x12
|
||||
# define RLC_AM_RECEIVE_RESET_EVENT 0x20
|
||||
# define RLC_AM_TRANSMIT_RESET_EVENT 0x21
|
||||
# define RLC_AM_RECEIVE_RESET_ACK_EVENT 0x22
|
||||
# define RLC_AM_TRANSMIT_RESET_ACK_EVENT 0x23
|
||||
//----------------------------------------------------------
|
||||
# define RLC_AM_TRAFFIC_NOT_ALLOWED 0x00
|
||||
# define RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS 0xC0
|
||||
// mutual exclusion of set bits with next value
|
||||
# define RLC_AM_TRAFFIC_ALLOWED_FOR_DATA 0x0D
|
||||
// mutual exclusion of set bits with previous value
|
||||
|
||||
# define RLC_AM_DCCH_ID 0xC0
|
||||
// mutual exclusion of set bits with next value
|
||||
# define RLC_AM_DTCH_ID 0x0D
|
||||
// mutual exclusion of set bits with previous value
|
||||
//----------------------------------------------------------
|
||||
// for status report of transmission by MAC layer
|
||||
# define RLC_AM_STATUS_PDU_TYPE 0x0001
|
||||
# define RLC_AM_FIRST_STATUS_PDU_TYPE 0x0011
|
||||
# define RLC_AM_LAST_STATUS_PDU_TYPE 0x0021
|
||||
# define RLC_AM_MRW_STATUS_PDU_TYPE 0x0040
|
||||
# define RLC_AM_RESET_PDU_TYPE 0x0080
|
||||
# define RLC_AM_RESET_ACK_PDU_TYPE 0x0100
|
||||
# define RLC_AM_DATA_POLL_PDU_TYPE 0x1800
|
||||
# define RLC_AM_DATA_PDU_TYPE 0x1000
|
||||
//----------------------------------------------------------
|
||||
// TIMER EPC
|
||||
# define TIMER_EPC_STATE_IDLE 0x00
|
||||
# define TIMER_EPC_STATE_TIMER_ARMED 0x01
|
||||
# define TIMER_EPC_STATE_TIMED_OUT 0x02
|
||||
# define TIMER_EPC_STATE_VR_EP_COUNTING_DOWN 0x04
|
||||
# define TIMER_EPC_STATE_VR_EP_EQUAL_ZERO 0x08
|
||||
|
||||
# define TIMER_EPC_PDU_STATUS_SUBMITTED_LOWER_LAYER_EVENT 0x01
|
||||
# define TIMER_EPC_PDU_STATUS_TRANSMITED_EVENT 0x02
|
||||
# define TIMER_EPC_TIMER_TIMED_OUT_EVENT 0x04
|
||||
# define TIMER_EPC_VR_EP_EQUAL_ZERO_EVENT 0x08
|
||||
# endif
|
||||
@@ -1,482 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_control_primitives.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_reset_proto_extern.h"
|
||||
#include "rlc_am_errno.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_fsm_proto_extern.h"
|
||||
#include "rlc_am_segment_proto_extern.h"
|
||||
#include "rrm_config_structs.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
void config_req_rlc_am (struct rlc_am_entity* rlcP, module_id_t module_idP, rlc_am_info_t* config_amP, uint8_t rb_idP, rb_type_t rb_typeP);
|
||||
void send_rlc_am_control_primitive (struct rlc_am_entity* rlcP, module_id_t module_idP, mem_block_t* cprimitiveP);
|
||||
void init_rlc_am (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_reset_state_variables (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_alloc_buffers_after_establishment (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_discard_all_pdus (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_stop_all_timers (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_free_all_resources (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_set_configured_parameters (struct rlc_am_entity* rlcP, mem_block_t* cprimitiveP);
|
||||
//void rlc_am_probing_get_buffer_occupancy_measurements (struct rlc_am_entity *rlcP, probing_report_traffic_rb_parameters *reportP, int measurement_indexP);
|
||||
//-----------------------------------------------------------------------------
|
||||
/*void
|
||||
rlc_am_probing_get_buffer_occupancy_measurements (struct rlc_am_entity *rlcP, probing_report_traffic_rb_parameters *reportP, int measurement_indexP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
if (rlcP->protocol_state != RLC_NULL_STATE) {
|
||||
reportP->incoming_sdu[measurement_indexP] = rlcP->buffer_occupancy;
|
||||
reportP->retransmission[measurement_indexP] = rlcP->buffer_occupancy_retransmission_buffer * rlcP->pdu_size;
|
||||
reportP->ready_to_send[measurement_indexP] = (rlcP->pdus_to_mac_layer_ch1.nb_elements + rlcP->pdus_to_mac_layer_ch2.nb_elements) * rlcP->pdu_size;
|
||||
}
|
||||
}*/
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
config_req_rlc_am (struct rlc_am_entity* rlcP, module_id_t module_idP, rlc_am_info_t* config_amP, uint8_t rb_idP, rb_type_t rb_typeP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* mb;
|
||||
mb = get_free_mem_block (sizeof (struct crlc_primitive));
|
||||
((struct crlc_primitive*) mb->data)->type = CRLC_CONFIG_REQ;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.e_r = RLC_E_R_ESTABLISHMENT;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.stop = 0;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.cont = 1;
|
||||
// timers
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_poll = config_amP->timer_poll;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_poll_prohibit = config_amP->timer_poll_prohibit;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_discard = config_amP->timer_discard;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_poll_periodic = config_amP->timer_poll_periodic;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_status_prohibit = config_amP->timer_status_prohibit;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_status_periodic = config_amP->timer_status_periodic;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_rst = config_amP->timer_rst;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.max_rst = config_amP->max_rst;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.timer_mrw = config_amP->timer_mrw;
|
||||
// protocol_parameters
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.pdu_size = config_amP->pdu_size;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.max_dat = config_amP->max_dat;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.poll_pdu = config_amP->poll_pdu;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.poll_sdu = config_amP->poll_sdu;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.poll_window = config_amP->poll_window;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.configured_tx_window_size = config_amP->tx_window_size;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.configured_rx_window_size = config_amP->rx_window_size;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.max_mrw = config_amP->max_mrw;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.last_transmission_pdu_poll_trigger =
|
||||
config_amP->last_transmission_pdu_poll_trigger;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.last_retransmission_pdu_poll_trigger =
|
||||
config_amP->last_retransmission_pdu_poll_trigger;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.sdu_discard_mode = config_amP->sdu_discard_mode;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.send_mrw = config_amP->send_mrw;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.frame_tick_milliseconds = &mac_xface->frame;
|
||||
((struct crlc_primitive*) mb->data)->primitive.c_config_req.parameters.am_parameters.rb_id = rb_idP;
|
||||
send_rlc_am_control_primitive (rlcP, module_idP, mb);
|
||||
|
||||
if (rb_typeP != SIGNALLING_RADIO_BEARER) {
|
||||
rlcP->data_plane = 1;
|
||||
msg ("[RLC AM][RB %d] DATA PLANE\n", rlcP->rb_id);
|
||||
|
||||
} else {
|
||||
rlcP->data_plane = 0;
|
||||
msg ("[RLC AM][RB %d] CONTROL PLANE\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
send_rlc_am_control_primitive (struct rlc_am_entity* rlcP, module_id_t module_idP, mem_block_t* cprimitiveP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
rlcP->module_id = module_idP;
|
||||
|
||||
switch (((struct crlc_primitive*) cprimitiveP->data)->type) {
|
||||
case CRLC_CONFIG_REQ:
|
||||
switch (((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.e_r) {
|
||||
case RLC_E_R_ESTABLISHMENT:
|
||||
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT)) {
|
||||
rlc_am_set_configured_parameters (rlcP, cprimitiveP); // the order of the calling of procedures...
|
||||
rlc_am_reset_state_variables (rlcP); // ...must not ...
|
||||
rlc_am_alloc_buffers_after_establishment (rlcP); // ...be changed
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_E_R_RE_ESTABLISHMENT:
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0(2001-09)
|
||||
// The RLC re-establishment function is applicable for AM and UM and is used when upper layers request an RLC entity to be re-established.
|
||||
// When an RLC entity is re-established by upper layers, the RLC entity shall:
|
||||
// - reset the state variables to their initial value;
|
||||
// - set the configurable parameters to their configured value;
|
||||
// - set the hyper frame number (HFN) in UL and DL to the value configured by upper layers;
|
||||
// - if the RLC entity is operating in unacknowledged mode:
|
||||
// - if it is a receiving UM RLC entity:
|
||||
// - discard all UMD PDUs;
|
||||
// - if it is a transmitting UM RLC entity:
|
||||
// - discard the RLC SDUs for which one or more segments have been submitted to a lower layer;
|
||||
// - otherwise if the RLC entity is operating in acknowledged mode:
|
||||
// - discard all AMD PDUs in the Receiver and Sender.
|
||||
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT)) {
|
||||
rlc_am_free_all_resources (rlcP);
|
||||
rlc_am_set_configured_parameters (rlcP, cprimitiveP); // the order of the calling of procedures...
|
||||
rlc_am_reset_state_variables (rlcP); // ...must not ...
|
||||
rlc_am_alloc_buffers_after_establishment (rlcP); // ...be changed
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_E_R_MODIFICATION:
|
||||
msg ("[RLC_AM][RB %d] WARNING CRLC_CONFIG_REQ:RLC_AM_E_R_MODIFICATION NOT IMPLEMENTED AT ALL: MAY BE BUGGY IF CHANGING WINDOWS SIZE\n", rlcP->rb_id);
|
||||
rlc_am_set_configured_parameters (rlcP, cprimitiveP);
|
||||
break;
|
||||
|
||||
case RLC_E_R_RELEASE:
|
||||
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_NULL_STATE_EVENT)) {
|
||||
rlc_am_free_all_resources (rlcP);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][ERROR] control_rlc_am(CRLC_CONFIG_REQ) unknown parameter E_R\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CRLC_SUSPEND_REQ:
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0(2001-09)
|
||||
// When an RLC entity operating in acknowledged mode is suspended by upper layers with the parameter N, the RLC entity shall:
|
||||
// - acknowledge the suspend request with a confirmation containing the current value of VT(S);
|
||||
// - not send AMD PDUs with sequence number SNVT(S)+N.
|
||||
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_CRLC_SUSPEND_REQ_EVENT)) {
|
||||
if ((rlcP->protocol_state == RLC_LOCAL_SUSPEND_STATE) || (rlcP->protocol_state == RLC_LOCAL_SUSPEND_STATE)) {
|
||||
// TO DO IN FUTURE, BUT IT SEEMS THERE IS NO NEED TO IMPLEMENT THIS FUNCTION IN THE CURRENTLY DEFINED ARCHITECTURE
|
||||
// SO DISPLAY ERROR MESSAGE
|
||||
msg ("[RLC_AM[RB %d] ERROR RECEIVED CRLC_SUSPEND_REQ NOT IMPLEMENTED AT ALL, RLC_AM MAY NOT WORK AS EXPECTED IN THE 3GPP SPECIFICATION\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CRLC_RESUME_REQ:
|
||||
|
||||
// from 3GPP TS 25.322 V4.2.0(2001-09)
|
||||
// When an RLC entity operating in acknowledged mode is resumed by upper layers, the RLC entity shall:
|
||||
// - if the RLC entity is suspended and a RLC Reset procedure is not ongoing:
|
||||
// - resume data transfer procedure.
|
||||
// - otherwise, if the RLC entity is suspended and a RLC Reset procedure is ongoing:
|
||||
// - remove the suspend constraint;
|
||||
// - resume the RLC reset procedure according to subclause 11.4.
|
||||
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_CRLC_RESUME_REQ_EVENT)) {
|
||||
if ((rlcP->protocol_state == RLC_RESET_PENDING_STATE) || (rlcP->protocol_state == RLC_DATA_TRANSFER_READY_STATE)) {
|
||||
// TO DO IN FUTURE, BUT IT SEEMS THERE IS NO NEED TO IMPLEMENT THIS FUNCTION IN THE CURRENTLY DEFINED ARCHITECTURE
|
||||
// SO DISPLAY ERROR MESSAGE
|
||||
msg ("[RLC_AM][RB %d] ERROR RECEIVED CRLC_RESUME_REQ NOT IMPLEMENTED AT ALL, RLC_AM MAY NOT WORK AS EXPECTED IN THE 3GPP SPECIFICATION\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][ERROR] control_rlc_am(UNKNOWN CPRIMITIVE)\n", rlcP->rb_id);
|
||||
}
|
||||
|
||||
free_mem_block (cprimitiveP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
init_rlc_am (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
memset (rlcP, 0, sizeof (struct rlc_am_entity));
|
||||
list2_init (&rlcP->retransmission_buffer_to_send, NULL);
|
||||
list_init (&rlcP->pdus_to_mac_layer_ch1, NULL);
|
||||
list_init (&rlcP->pdus_to_mac_layer_ch2, NULL);
|
||||
list_init (&rlcP->pdus_from_mac_layer_ch1, NULL);
|
||||
list_init (&rlcP->pdus_from_mac_layer_ch2, NULL);
|
||||
list_init (&rlcP->control, NULL);
|
||||
list2_init (&rlcP->sdu_conf_segmented, NULL);
|
||||
list2_init (&rlcP->sdu_discard_segmented, NULL);
|
||||
list2_init (&rlcP->sdu_discarded, NULL);
|
||||
list2_init (&rlcP->rlc_am_timer_list, NULL);
|
||||
rlcP->protocol_state = RLC_NULL_STATE;
|
||||
rlcP->next_sdu_index = 0;
|
||||
rlcP->current_sdu_index = 0;
|
||||
rlcP->last_received_rsn = 0xFF;
|
||||
//--------------------------------------------------------------------------
|
||||
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0;
|
||||
rlcP->discard_reassembly_start_sn = RLC_AM_SN_INVALID; // =>not activated
|
||||
rlcP->stat_tx_pdcp_sdu = 0;
|
||||
rlcP->stat_tx_pdcp_sdu_discarded = 0;
|
||||
rlcP->stat_tx_retransmit_pdu_unblock = 0;
|
||||
rlcP->stat_tx_retransmit_pdu_by_status = 0;
|
||||
rlcP->stat_tx_data_pdu = 0;
|
||||
rlcP->stat_tx_control_pdu = 0;
|
||||
rlcP->stat_rx_sdu = 0;
|
||||
rlcP->stat_rx_error_pdu = 0;
|
||||
rlcP->stat_rx_data_pdu = 0;
|
||||
rlcP->stat_rx_data_pdu_out_of_window = 0;
|
||||
rlcP->stat_rx_control_pdu = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_alloc_buffers_after_establishment (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
rlcP->recomputed_configured_tx_window_size = 1;
|
||||
|
||||
while (rlcP->recomputed_configured_tx_window_size < rlcP->configured_tx_window_size) {
|
||||
rlcP->recomputed_configured_tx_window_size = rlcP->recomputed_configured_tx_window_size << 1;
|
||||
}
|
||||
|
||||
rlcP->retransmission_buffer_alloc = get_free_mem_block (rlcP->recomputed_configured_tx_window_size * sizeof (mem_block_t*));
|
||||
rlcP->retransmission_buffer = (mem_block_t**) (rlcP->retransmission_buffer_alloc->data);
|
||||
//memset (rlcP->retransmission_buffer, 0, rlcP->recomputed_configured_tx_window_size * sizeof (mem_block_t *));
|
||||
rlcP->recomputed_configured_rx_window_size = 1;
|
||||
|
||||
while (rlcP->recomputed_configured_rx_window_size < rlcP->configured_rx_window_size) {
|
||||
rlcP->recomputed_configured_rx_window_size = rlcP->recomputed_configured_rx_window_size << 1;
|
||||
}
|
||||
|
||||
rlcP->receiver_buffer_alloc = get_free_mem_block (rlcP->recomputed_configured_rx_window_size * sizeof (mem_block_t*));
|
||||
rlcP->receiver_buffer = (mem_block_t**) (rlcP->receiver_buffer_alloc->data);
|
||||
msg("[RLC AM][RB %d] Window size %d\n",rlcP->rb_id,rlcP->recomputed_configured_rx_window_size);
|
||||
//memset (rlcP->receiver_buffer, 0, rlcP->recomputed_configured_rx_window_size * sizeof (mem_block_t *));
|
||||
rlcP->holes_alloc = get_free_mem_block ((rlcP->recomputed_configured_rx_window_size * sizeof (struct rlc_am_hole)) >> 1);
|
||||
rlcP->holes = (struct rlc_am_hole*) (rlcP->holes_alloc->data);
|
||||
//memset (rlcP->holes_alloc->data, 0, (rlcP->recomputed_configured_rx_window_size * sizeof (mem_block_t *)) >> 1);
|
||||
rlcP->size_input_sdus_buffer = rlcP->recomputed_configured_tx_window_size * 4;
|
||||
|
||||
if ((rlcP->input_sdus_alloc == NULL)) {
|
||||
rlcP->input_sdus_alloc = get_free_mem_block (rlcP->size_input_sdus_buffer * sizeof (void*));
|
||||
rlcP->input_sdus = (mem_block_t**) (rlcP->input_sdus_alloc->data);
|
||||
//memset (rlcP->input_sdus, 0, rlcP->size_input_sdus_buffer * sizeof (void *));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_reset_state_variables (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
rlcP->vt_s = 0;
|
||||
rlcP->vt_a = 0;
|
||||
rlcP->vt_pdu = 0;
|
||||
//................................................................
|
||||
rlcP->vt_sdu = 0;
|
||||
rlcP->vt_mrw = 0;
|
||||
rlcP->vt_ms = rlcP->configured_tx_window_size - 1;
|
||||
//................................................................
|
||||
rlcP->vt_ws = rlcP->configured_tx_window_size;
|
||||
rlcP->vr_r = 0;
|
||||
rlcP->vr_h = 0;
|
||||
//................................................................
|
||||
rlcP->vr_mr = rlcP->configured_rx_window_size - 1;
|
||||
rlcP->vt_rst = 0;
|
||||
//................................................................
|
||||
rlcP->send_status_pdu_requested = 0;
|
||||
rlcP->first_li_in_next_pdu = RLC_LI_UNDEFINED;
|
||||
rlcP->last_reassemblied_sn = SN_12BITS_MASK;
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 0;
|
||||
rlcP->li_one_byte_short_to_add_in_next_pdu = 0;
|
||||
//................................................................
|
||||
rlcP->sufi_to_insert_index = 0;
|
||||
rlcP->ack.vr_r_modified = 0;
|
||||
rlcP->ack.ack_other_vr_r = 0;
|
||||
//................................................................
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0;
|
||||
rlcP->discard_reassembly_start_sn = RLC_AM_SN_INVALID; // =>not activated
|
||||
//................................................................
|
||||
rlcP->timer_mrw = NULL;
|
||||
//................................................................
|
||||
rlcP->buffer_occupancy = 0;
|
||||
rlcP->nb_sdu = 0;
|
||||
rlcP->buffer_occupancy_retransmission_buffer = 0;
|
||||
rlcP->next_sdu_index = 0;
|
||||
rlcP->current_sdu_index = 0;
|
||||
rlcP->nb_pdu_requested_by_mac_on_ch1 = 0;
|
||||
rlcP->nb_pdu_requested_by_mac_on_ch2 = 0;
|
||||
rlcP->running_timer_status_prohibit = rlcP->timer_status_prohibit/10;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_stop_all_timers (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
list2_free (&rlcP->rlc_am_timer_list);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_discard_all_pdus (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t index;
|
||||
index = 0;
|
||||
|
||||
while (index < rlcP->recomputed_configured_rx_window_size) {
|
||||
if (rlcP->receiver_buffer[index] != NULL) {
|
||||
free_mem_block (rlcP->receiver_buffer[index]);
|
||||
rlcP->receiver_buffer[index] = NULL;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
while (index < rlcP->recomputed_configured_tx_window_size) {
|
||||
if (rlcP->retransmission_buffer[index] != NULL) {
|
||||
free_mem_block (rlcP->retransmission_buffer[index]);
|
||||
rlcP->retransmission_buffer[index] = NULL;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
list2_free (&rlcP->retransmission_buffer_to_send);
|
||||
list_free (&rlcP->pdus_to_mac_layer_ch1);
|
||||
list_free (&rlcP->pdus_to_mac_layer_ch2);
|
||||
list_free (&rlcP->control);
|
||||
|
||||
if ((rlcP->output_sdu_in_construction)) {
|
||||
free_mem_block (rlcP->output_sdu_in_construction);
|
||||
rlcP->output_sdu_in_construction = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_free_all_resources (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
int index;
|
||||
|
||||
for (index = 0; index < rlcP->size_input_sdus_buffer; index++) {
|
||||
if (rlcP->input_sdus[index]) {
|
||||
free_mem_block (rlcP->input_sdus[index]);
|
||||
rlcP->input_sdus[index] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rlc_am_discard_all_pdus (rlcP);
|
||||
|
||||
if (rlcP->retransmission_buffer_alloc) {
|
||||
free_mem_block (rlcP->retransmission_buffer_alloc);
|
||||
}
|
||||
|
||||
if (rlcP->receiver_buffer_alloc) {
|
||||
free_mem_block (rlcP->receiver_buffer_alloc);
|
||||
}
|
||||
|
||||
if (rlcP->input_sdus_alloc) {
|
||||
free_mem_block (rlcP->input_sdus_alloc);
|
||||
}
|
||||
|
||||
if (rlcP->holes_alloc) {
|
||||
free_mem_block (rlcP->holes_alloc);
|
||||
}
|
||||
|
||||
rlcP->holes_alloc = NULL;
|
||||
rlcP->input_sdus_alloc = NULL;
|
||||
rlcP->receiver_buffer_alloc = NULL;
|
||||
rlcP->retransmission_buffer_alloc = NULL;
|
||||
rlc_am_stop_all_timers (rlcP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_set_configured_parameters (struct rlc_am_entity* rlcP, mem_block_t* cprimitiveP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// timers
|
||||
//rlcP->timer_poll_trigger = ((struct crlc_primitive *)cprimitiveP->data)->cprimitive.c_config_req.parameters.am_parameters.timer_poll;
|
||||
//rlcP-> = ((struct crlc_primitive *)cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_poll_prohibit;
|
||||
rlcP->timer_discard_init = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_discard;
|
||||
rlcP->timer_poll_periodic_init = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_poll_periodic;
|
||||
rlcP-> timer_status_prohibit = ((struct crlc_primitive*)cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_status_prohibit;
|
||||
rlcP->timer_status_periodic = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_status_periodic;
|
||||
rlcP->timer_rst_init = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_rst;
|
||||
rlcP->max_rst = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.max_rst;
|
||||
rlcP->timer_mrw_init = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.timer_mrw;
|
||||
// protocol_parameters
|
||||
rlcP->pdu_size = (((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.pdu_size + 7) >> 3;
|
||||
rlcP->max_dat = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.max_dat;
|
||||
rlcP->missing_pdu_indicator = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.missing_pdu_indicator;
|
||||
rlcP->poll_pdu_trigger = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.poll_pdu;
|
||||
rlcP->poll_sdu_trigger = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.poll_sdu;
|
||||
rlcP->last_transmission_pdu_poll_trigger = ((struct crlc_primitive*)
|
||||
cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.last_transmission_pdu_poll_trigger;
|
||||
rlcP->last_retransmission_pdu_poll_trigger = ((struct crlc_primitive*)
|
||||
cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.last_retransmission_pdu_poll_trigger;
|
||||
rlcP->poll_window_trigger = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.poll_window;
|
||||
rlcP->configured_tx_window_size = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.configured_tx_window_size;
|
||||
rlcP->configured_rx_window_size = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.configured_rx_window_size;
|
||||
rlcP->max_mrw = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.max_mrw;
|
||||
rlcP->sdu_discard_mode = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.sdu_discard_mode;
|
||||
rlcP->send_mrw = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.send_mrw;
|
||||
// SPARE : not 3GPP
|
||||
rlcP->rb_id = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.rb_id;
|
||||
rlcP->frame_tick_milliseconds = ((struct crlc_primitive*) cprimitiveP->data)->primitive.c_config_req.parameters.am_parameters.frame_tick_milliseconds;
|
||||
rlcP->nb_logical_channels_per_rlc =1;
|
||||
|
||||
if (rlcP->pdu_size > 126) {
|
||||
rlcP->rlc_segment = rlc_am_segment_15;
|
||||
|
||||
} else {
|
||||
rlcP->rlc_segment = rlc_am_segment_7;
|
||||
}
|
||||
|
||||
if (rlcP->sdu_discard_mode == SDU_DISCARD_MODE_RESET) {
|
||||
msg ("[RLC AM][RB %d] SDU DISCARD RESET CONFIGURED\n", rlcP->rb_id);
|
||||
|
||||
} else if (rlcP->sdu_discard_mode == SDU_DISCARD_MODE_TIMER_BASED_EXPLICIT) {
|
||||
msg ("[RLC AM][RB %d] SDU DISCARD TIMER BASED EXPLICIT SIGNALING CONFIGURED\n", rlcP->rb_id);
|
||||
|
||||
} else if (rlcP->sdu_discard_mode == SDU_DISCARD_MODE_MAX_DAT_RETRANSMISSION) {
|
||||
msg ("[RLC AM][RB %d] SDU DISCARD MAX RETRANSMISSION CONFIGURED\n", rlcP->rb_id);
|
||||
|
||||
} else if (rlcP->sdu_discard_mode == SDU_DISCARD_MODE_NOT_CONFIGURED) {
|
||||
msg ("[RLC AM][RB %d] SDU DISCARD NOT CONFIGURED\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_control_primitives_proto_extern.h -
|
||||
-------------------
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_CONTROL_PRIMITIVES_H__
|
||||
# define __RLC_AM_CONTROL_PRIMITIVES_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "mem_block.h"
|
||||
# include "rrm_config_structs.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void config_req_rlc_am (struct rlc_am_entity *rlcP, module_id_t module_idP, rlc_am_info_t * config_amP, uint8_t rb_idP, rb_type_t rb_typeP);
|
||||
extern void send_rlc_am_control_primitive (struct rlc_am_entity *rlcP, module_id_t module_idP, mem_block_t * cprimitiveP);
|
||||
extern void init_rlc_am (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_reset_state_variables (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_alloc_buffers_after_establishment (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_discard_all_pdus (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_stop_all_timers (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_free_all_resources (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_set_configured_parameters (struct rlc_am_entity *rlcP, mem_block_t * cprimitiveP);
|
||||
//extern void rlc_am_probing_get_buffer_occupancy_measurements (struct rlc_am_entity *rlcP, probing_report_traffic_rb_parameters *reportP, int measurement_indexP);
|
||||
# endif
|
||||
@@ -1,223 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_demux.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
//#include "mac_log_interface_struct.h"
|
||||
#include "LAYER2/RLC/rlc.h"
|
||||
|
||||
#include "mac_primitives.h"
|
||||
#include "list.h"
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_am_receiver_proto_extern.h"
|
||||
#include "rlc_am_reset_proto_extern.h"
|
||||
#include "rlc_am_status_proto_extern.h"
|
||||
#include "rlc_am_timers_proto_extern.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
|
||||
|
||||
|
||||
#define DEBUG_DEMUX_RESET
|
||||
#define DEBUG_DEMUX
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_demux_routing (struct rlc_am_entity *rlcP, unsigned int traffic_typeP, struct mac_data_ind data_indP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct rlc_am_pdu_header *data;
|
||||
struct rlc_am_reset_header *control;
|
||||
mem_block_t *tb;
|
||||
uint8_t *first_byte;
|
||||
uint16_t tb_size_in_bytes;
|
||||
uint8_t first_bit;
|
||||
uint8_t bits_to_shift;
|
||||
uint8_t bits_to_shift_last_loop;
|
||||
|
||||
uint8_t data_received;
|
||||
int index;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// D A T A P D U
|
||||
//-------------------------------------------------------
|
||||
data_received = 0;
|
||||
|
||||
while ((tb = list_remove_head (&data_indP.data))) {
|
||||
if (!(((struct mac_tb_ind *) (tb->data))->error_indication)) {
|
||||
|
||||
first_byte = ((struct mac_tb_ind *) (tb->data))->data_ptr;
|
||||
|
||||
tb_size_in_bytes = data_indP.tb_size >> 3;
|
||||
first_bit = ((struct mac_tb_ind *) (tb->data))->first_bit;
|
||||
|
||||
if (first_bit > 0) {
|
||||
// shift data of transport_block TO CHECK
|
||||
bits_to_shift_last_loop = 0;
|
||||
|
||||
while ((tb_size_in_bytes)) {
|
||||
bits_to_shift = first_byte[tb_size_in_bytes] >> (8 - first_bit);
|
||||
first_byte[tb_size_in_bytes] = (first_byte[tb_size_in_bytes] << first_bit) | (bits_to_shift_last_loop);
|
||||
tb_size_in_bytes -= 1;
|
||||
bits_to_shift_last_loop = bits_to_shift;
|
||||
}
|
||||
|
||||
first_byte[0] = (first_byte[0] << first_bit) | (bits_to_shift_last_loop);
|
||||
}
|
||||
|
||||
((struct rlc_am_rx_pdu_management *) (tb->data))->first_byte = first_byte;
|
||||
data = (struct rlc_am_pdu_header *) (first_byte);
|
||||
|
||||
if ((data->byte1 & RLC_DC_MASK) == RLC_DC_DATA_PDU) {
|
||||
#ifdef DEBUG_DEMUX
|
||||
msg ("[RLC_AM][RB %d][DEMUX] RX AMD PDU Frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
|
||||
for (index=0; index < rlcP->pdu_size ; index++) {
|
||||
msg("%02X.",first_byte[index]);
|
||||
}
|
||||
|
||||
msg("\n");
|
||||
#endif
|
||||
|
||||
rlcP->stat_rx_data_pdu += 1;
|
||||
|
||||
if (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_DATA) {
|
||||
((struct rlc_am_rx_pdu_management *) (tb->data))->piggybacked_processed = 0;
|
||||
receiver_retransmission_management (rlcP, tb, data);
|
||||
// pdu is data;
|
||||
data_received = 1;
|
||||
} else {
|
||||
#ifdef DEBUG_DEMUX
|
||||
msg ("[RLC_AM][RB %d][DEMUX] DROP DATA TB NOT ALLOWED IN PROTOCOL STATE 0x%02X\n", rlcP->rb_id, rlcP->protocol_state);
|
||||
#endif
|
||||
free_mem_block (tb);
|
||||
}
|
||||
|
||||
} else {
|
||||
rlcP->stat_rx_control_pdu += 1;
|
||||
control = (struct rlc_am_reset_header *) first_byte;
|
||||
|
||||
if ((control->byte1 & RLC_PDU_TYPE_MASK) == RLC_PDU_TYPE_STATUS) {
|
||||
if (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_DATA) {
|
||||
#ifdef DEBUG_DEMUX
|
||||
msg ("[RLC_AM][RB %d][DEMUX] RX STATUS PDU ON DTCH Frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlc_am_process_status_info (rlcP, &(control->byte1));
|
||||
}
|
||||
} else if ((control->byte1 & RLC_PDU_TYPE_MASK) == RLC_PDU_TYPE_RESET) {
|
||||
#ifdef DEBUG_DEMUX_RESET
|
||||
msg ("[RLC_AM][RB %d][DEMUX] RX RESET PDU Frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
process_reset (tb, control, rlcP);
|
||||
} else if ((control->byte1 & RLC_PDU_TYPE_MASK) == RLC_PDU_TYPE_RESET_ACK) {
|
||||
#ifdef DEBUG_DEMUX_RESET
|
||||
msg ("[RLC_AM][RB %d][DEMUX] RX RESET ACK PDU Frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
process_reset_ack (tb, control, rlcP);
|
||||
#ifndef USER_MODE
|
||||
rlc_info_t Rlc_info_am_config1;
|
||||
|
||||
Rlc_info_am_config1.rlc_mode=RLC_AM;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.sdu_discard_mode = SDU_DISCARD_MODE_RESET;//SDU_DISCARD_MODE_MAX_DAT_RETRANSMISSION;//
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_poll = 0;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_poll_prohibit = 0;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_discard = 500;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_poll_periodic = 0;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_status_prohibit = 250;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_status_periodic = 500;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_rst = 250;//250
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.max_rst = 500;//500
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.timer_mrw = 0;
|
||||
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.pdu_size = 32; //416; // in bits
|
||||
//Rlc_info_am.rlc.rlc_am_info.in_sequence_delivery = 1;//boolean
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.max_dat = 32;//127;
|
||||
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.poll_pdu = 0;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.poll_sdu = 0;//256;/
|
||||
|
||||
|
||||
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.poll_window = 80;//128
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.tx_window_size = 512;
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.rx_window_size = 512;
|
||||
|
||||
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.max_mrw = 8;
|
||||
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.last_transmission_pdu_poll_trigger = 1;//boolean
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.last_retransmission_pdu_poll_trigger = 1;//boolean
|
||||
Rlc_info_am_config1.rlc.rlc_am_info.send_mrw = 1;//boolean*
|
||||
Mac_rlc_xface->rrc_rlc_config_req(0,CONFIG_ACTION_REMOVE,rlcP->rb_id,RADIO_ACCESS_BEARER,Rlc_info_am_config1);
|
||||
Mac_rlc_xface->rrc_rlc_config_req(0,CONFIG_ACTION_ADD,rlcP->rb_id,RADIO_ACCESS_BEARER,Rlc_info_am_config1);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
free_mem_block (tb);
|
||||
}
|
||||
} else {
|
||||
#ifdef BENCH_QOS_L2
|
||||
fprintf (bench_l2, "[PDU RX ERROR] FRAME %d RLC-AM %p\n", Mac_rlc_xface->frame, rlcP);
|
||||
#endif
|
||||
#ifdef DEBUG_DEMUX
|
||||
msg ("[RLC_AM][RB %d][DEMUX] RX PDU WITH ERROR INDICATION\n", rlcP->rb_id);
|
||||
#endif
|
||||
rlcP->stat_rx_error_pdu += 1;
|
||||
free_mem_block (tb);
|
||||
}
|
||||
}
|
||||
|
||||
if ((data_received)) { //avoid call
|
||||
if (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_DATA) {
|
||||
if (rlcP->pdu_size <= 126) {
|
||||
#ifdef DEBUG_DEMUX
|
||||
msg("[RLC_AM][RB %d] Calling process_receiver_buffer_7\n",rlcP->rb_id);
|
||||
#endif
|
||||
process_receiver_buffer_7 (rlcP);
|
||||
} else {
|
||||
#ifdef DEBUG_DEMUX
|
||||
msg("[RLC_AM][RB %d] Calling process_receiver_buffer_15\n",rlcP->rb_id);
|
||||
#endif
|
||||
process_receiver_buffer_15 (rlcP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_demux_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_DEMUX_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_DEMUX_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "mac_primitives.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_demux_routing (struct rlc_am_entity *rlcP, unsigned int traffic_typeP, struct mac_data_ind data_indP);
|
||||
# endif
|
||||
@@ -1,405 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_notif.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
***************************************************************************/
|
||||
#define RLC_AM_C
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_status_proto_extern.h"
|
||||
#include "umts_timer_struct.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
#include "rlc_am_discard_tx_proto_extern.h"
|
||||
#include "rlc_am_reset_proto_extern.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
void rlc_am_discard_notify_mrw_ack_time_out (struct rlc_am_entity* rlcP, mem_block_t* discard_procedureP);
|
||||
void rlc_am_discard_notify_sdu_time_out (struct rlc_am_entity* rlcP, mem_block_t* sduP);
|
||||
void rlc_am_discard_notify_max_dat_pdu (struct rlc_am_entity* rlcP, mem_block_t* mbP);
|
||||
//-----------------------------------------------------------------------------
|
||||
// handler for timer
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_discard_notify_mrw_ack_time_out (struct rlc_am_entity* rlcP, mem_block_t* discard_procedureP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
/* from 3GPP TS 25.322 V5.5.0
|
||||
If Timer_MRW expires before the discard procedure is terminated, the Sender shall:
|
||||
- if VT(MRW)<MaxMRW-1:
|
||||
- set the MRW SUFI as previously transmitted (even if additional SDUs were discarded in the mean-time);
|
||||
- include the MRW SUFI in a new status report (if other SUFIs are included, their contents shall be updated);
|
||||
- transmit the status report by either including it in a STATUS PDU or piggybacked in an AMD PDU;
|
||||
- increment VT(MRW) by one;
|
||||
- restart Timer_MRW for this discard procedure.
|
||||
|
||||
If the number of retransmission of an MRW SUFI (i.e. VT(MRW)) equals MaxMRW, the Sender shall:
|
||||
- terminate the SDU discard with explicit signalling procedure;
|
||||
- stop the timer Timer_MRW;
|
||||
- deliver an error indication to upper layers;
|
||||
- initiate the RLC RESET procedure */
|
||||
rlcP->timer_mrw = NULL;
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d][DISCARD] NOTIF MRW_ACK TIME OUT VT(MRW) %d PROCEDURE %p\n", rlcP->rb_id, rlcP->vt_mrw, discard_procedureP);
|
||||
#endif
|
||||
|
||||
if ((rlcP->protocol_state & (RLC_RESET_PENDING_STATE | RLC_RESET_AND_SUSPEND_STATE)) == 0) {
|
||||
// check the number of retransmission of the status pdu
|
||||
if (rlcP->vt_mrw < (rlcP->max_mrw - 1)) {
|
||||
rlc_am_schedule_procedure (rlcP);
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM %p][DISCARD] NOTIF MRW_ACK TIME OUT REARM TIMER\n", rlcP);
|
||||
#endif
|
||||
rlcP->vt_mrw += 1;
|
||||
|
||||
} else {
|
||||
// TO DO : "deliver an error indication to upper layers"
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n[RLC_AM][RB %d][DISCARD] NOTIF MRW_ACK TIME OUT MAX_MRW REACHED -> RESET\n", rlcP->rb_id);
|
||||
#endif
|
||||
send_reset_pdu (rlcP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handler for timer
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_discard_check_sdu_time_out (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* sdu;
|
||||
mem_block_t* pdu;
|
||||
int discard_go_on;
|
||||
int last_removed_pdu_sn;
|
||||
int sn;
|
||||
|
||||
// TIMER BASED DISCARD
|
||||
if ((rlcP->sdu_discard_mode & RLC_SDU_DISCARD_TIMER_BASED_EXPLICIT)
|
||||
&& ((rlcP->protocol_state & (RLC_RESET_PENDING_STATE | RLC_RESET_AND_SUSPEND_STATE)) == 0)) {
|
||||
/* from 3GPP TS 25.322 V5.0.0 p68
|
||||
- if "Timer based SDU discard with explicit signalling" is configured:
|
||||
- discard all SDUs up to and including the SDU for which the timer Timer_Discard expired.
|
||||
- discard all AMD PDUs including segments of the discarded SDUs, unless they also carry a segment of a SDU
|
||||
whose timer has not expired;
|
||||
- if more than 15 discarded SDUs are to be informed to the Receiver:
|
||||
- if "Send MRW" is not configured:
|
||||
- assemble an MRW SUFI with the discard information of the SDUs.
|
||||
- otherwise ("Send MRW" is configured):
|
||||
- assemble an MRW SUFI with the discard information of the first 15 SDUs; and
|
||||
- include the discard information of the rest SDUs in another MRW SUFI which shall be sent by the next
|
||||
SDU discard with explicit signalling procedure (after the current SDU discard with explicit signalling
|
||||
procedure is terminated).
|
||||
- otherwise (less than or equal to 15 discarded SDUs are to be informed to the Receiver):
|
||||
- assemble an MRW SUFI with the discard information of the SDUs.
|
||||
- schedule and submit to lower layer a STATUS PDU/piggybacked STATUS PDU containing the MRW SUFI;
|
||||
- if SN_MRWLENGTH in the MRW SUFI >VT(S):
|
||||
- update VT(S) to SN_MRWLENGTH.
|
||||
- start a timer Timer_MRW
|
||||
If a new SDU discard with explicit signalling procedure is triggered when the timer Timer_MRW is active, no new
|
||||
MRW SUFIs shall be sent before the current SDU discard with explicit signalling procedure is terminated by one of the
|
||||
termination criteria.
|
||||
*/
|
||||
discard_go_on = 1;
|
||||
last_removed_pdu_sn = -1;
|
||||
|
||||
while ((sdu = rlcP->input_sdus[rlcP->current_sdu_index]) && discard_go_on) {
|
||||
if ((*rlcP->frame_tick_milliseconds - ((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_creation_time) >= rlcP->timer_discard_init) {
|
||||
// buffer occupancy is not updated at each generation of pdu, it is only updated for a sdu when the
|
||||
// segmentation of this one is finished.
|
||||
rlcP->buffer_occupancy -= ((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_remaining_size;
|
||||
rlcP->nb_sdu -= 1;
|
||||
|
||||
if ((rlcP->send_mrw & RLC_AM_SEND_MRW_ON) ||
|
||||
// the condition says if the sdu has generated one or more pdus
|
||||
(((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_size != ((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_remaining_size)) {
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->last_pdu_sn = rlcP->vt_s;
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->no_new_sdu_segmented_in_last_pdu = 1;
|
||||
rlcP->vt_s = (rlcP->vt_s + 1) & SN_12BITS_MASK;
|
||||
list2_add_tail (sdu, &rlcP->sdu_discarded);
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] SDU DISCARDED SIGNALLING YES, TIMED OUT %ld ms frame %d ", rlcP->rb_id,
|
||||
(*rlcP->frame_tick_milliseconds - ((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_creation_time), Mac_rlc_xface->frame);
|
||||
msg ("BO %d, NB SDU %d\n", rlcP->buffer_occupancy, rlcP->nb_sdu);
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
#endif
|
||||
|
||||
if (((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_size != ((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_remaining_size) {
|
||||
// some pdu have to be removed if a sdu discarded generated almost one pdu
|
||||
if (last_removed_pdu_sn == -1) {
|
||||
sn = rlcP->vt_a;
|
||||
|
||||
} else {
|
||||
sn = last_removed_pdu_sn;
|
||||
}
|
||||
|
||||
while (sn != rlcP->vt_s) {
|
||||
pdu = rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size];
|
||||
|
||||
if ((pdu)) {
|
||||
// now check if a copy of the pdu is not present in the retransmission_buffer_to_send
|
||||
if ((((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy)) {
|
||||
list2_remove_element (((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy, &rlcP->retransmission_buffer_to_send);
|
||||
free_mem_block (((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy);
|
||||
}
|
||||
|
||||
// if this pdu has been retransmitted, remove its size from buffer occupancy
|
||||
if (((struct rlc_am_tx_data_pdu_management*) (pdu->data))->vt_dat > 0) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer -= 1;
|
||||
}
|
||||
|
||||
free_mem_block (rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size]);
|
||||
rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size] = NULL;
|
||||
}
|
||||
|
||||
sn = (sn + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
last_removed_pdu_sn = sn;
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] SDU DISCARDED SIGNALLING NO, TIMED OUT %ld ms ", rlcP->rb_id,
|
||||
(*rlcP->frame_tick_milliseconds - ((struct rlc_am_tx_sdu_management*) (sdu->data))->sdu_creation_time));
|
||||
msg ("BO %d, NB SDU %d\n", rlcP->buffer_occupancy, rlcP->nb_sdu);
|
||||
#endif
|
||||
free_mem_block (sdu);
|
||||
}
|
||||
|
||||
if (!(rlcP->data_plane)) {
|
||||
#ifdef DEBUG_RLC_AM_SEND_CONFIRM
|
||||
msg ("[RLC_AM][RB %d][CONFIRM] SDU MUI %d LOST IN DISCARD\n", rlcP->rb_id,
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[rlcP->current_sdu_index]->data))->mui);
|
||||
#endif
|
||||
rlc_data_conf (0, rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[rlcP->current_sdu_index]->data))->mui, RLC_TX_CONFIRM_FAILURE,
|
||||
rlcP->data_plane);
|
||||
}
|
||||
|
||||
rlcP->input_sdus[rlcP->current_sdu_index] = NULL;
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
// reset variables for segmentation
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 0;
|
||||
rlcP->li_one_byte_short_to_add_in_next_pdu = 0;
|
||||
|
||||
} else {
|
||||
discard_go_on = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_discard_notify_max_dat_pdu (struct rlc_am_entity* rlcP, mem_block_t* pduP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
struct rlc_am_tx_sdu_management* sdu_mngt;
|
||||
mem_block_t* pdu;
|
||||
mem_block_t* pdu2;
|
||||
mem_block_t* sdu;
|
||||
int sdu_index;
|
||||
int sdu_index2;
|
||||
int pdu_index;
|
||||
int last_sdu_index;
|
||||
int sn;
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) pduP->data;
|
||||
// should never occur
|
||||
//if (pdu_mngt->nb_sdu == 0) return;
|
||||
// discard previous SDUS
|
||||
#ifdef DEBUG_RLC_AM_DISCARD_MAX_DAT
|
||||
msg ("[RLC_AM][RB %d] DISCARD MAX DAT PDU FRAME %d SN 0x%03X CONTAINS SDU INDEX ", rlcP->rb_id, Mac_rlc_xface->frame, pdu_mngt->sn);
|
||||
sdu_index = 0;
|
||||
|
||||
while (sdu_index < pdu_mngt->nb_sdu) {
|
||||
msg ("%d ", pdu_mngt->sdu[sdu_index]);
|
||||
sdu_index += 1;
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
#endif
|
||||
// From 3GPP TS25.322 V5.0.0 (2002-03) page 68
|
||||
// - if "SDU discard after MaxDAT number of retransmissions" is configured:
|
||||
// - discard all SDUs that have segments in AMD PDUs with SN inside the interval
|
||||
// VT(A) <= SN <= X, where X is the value of the SN of the AMD PDU with VT(DAT) >= MaxDAT;
|
||||
// - if requested
|
||||
// - inform the upper layers of the discarded SDUs.
|
||||
//---------------------------------------------------------------
|
||||
// here delete all SDUs before the last sdu that have segments in the pdu discarded
|
||||
sdu_index = rlcP->next_sdu_index;
|
||||
last_sdu_index = pdu_mngt->sdu[pdu_mngt->nb_sdu - 1];
|
||||
|
||||
while (sdu_index != last_sdu_index) {
|
||||
if ((sdu = rlcP->input_sdus[sdu_index])) {
|
||||
list2_add_tail (sdu, &rlcP->sdu_discarded);
|
||||
|
||||
if (!(rlcP->data_plane)) {
|
||||
#ifdef DEBUG_RLC_AM_SEND_CONFIRM
|
||||
msg ("[RLC_AM][RB %d][CONFIRM] SDU MUI %d LOST IN DISCARD\n", rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[sdu_index]->data))->mui);
|
||||
#endif
|
||||
rlc_data_conf (0, rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[sdu_index]->data))->mui, RLC_TX_CONFIRM_FAILURE, rlcP->data_plane);
|
||||
}
|
||||
|
||||
rlcP->input_sdus[sdu_index] = NULL;
|
||||
rlcP->nb_sdu -= 1;
|
||||
#ifdef DEBUG_RLC_AM_FREE_SDU
|
||||
msg ("[RLC_AM][RB %d] DISCARD MAX DAT FREE_SDU INDEX %d\n", rlcP->rb_id, sdu_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
sdu_index = (sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// here delete all PDUs up to and except the last of the last sdu discarded
|
||||
sdu = rlcP->input_sdus[sdu_index];
|
||||
sdu_mngt = (struct rlc_am_tx_sdu_management*) (sdu->data);
|
||||
sn = rlcP->vt_a;
|
||||
|
||||
while (sn != sdu_mngt->last_pdu_sn) {
|
||||
if ((pdu2 = rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size])) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD FREE PDU SN 0x%03X\n", rlcP->rb_id, sn);
|
||||
#endif
|
||||
|
||||
// check if a copy of the pdu is not present in the retransmission_buffer_to_send
|
||||
if ((((struct rlc_am_tx_data_pdu_management*) (pdu2->data))->copy)) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] FREE PDU COPY ALSO\n", rlcP->rb_id);
|
||||
#endif
|
||||
list2_remove_element (((struct rlc_am_tx_data_pdu_management*) (pdu2->data))->copy, &rlcP->retransmission_buffer_to_send);
|
||||
free_mem_block (((struct rlc_am_tx_data_pdu_management*) (pdu2->data))->copy);
|
||||
}
|
||||
|
||||
// if this pdu has been retransmitted, remove its size from buffer occupancy
|
||||
if (((struct rlc_am_tx_data_pdu_management*) (pdu2->data))->vt_dat > 0) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer -= 1;
|
||||
}
|
||||
|
||||
free_mem_block (pdu2);
|
||||
rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size] = NULL;
|
||||
}
|
||||
|
||||
sn = (sn + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
// Now for the last pdu of the last sdu discarded, check if it contains other segments of
|
||||
// sdu newer than the discarded
|
||||
// if the pdu cannot be found : it is OK, nothing to do
|
||||
pdu = rlcP->retransmission_buffer[sdu_mngt->last_pdu_sn % rlcP->recomputed_configured_tx_window_size];
|
||||
|
||||
if ((pdu)) {
|
||||
// search the index of the sdu passed in parameter
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) pdu->data;
|
||||
|
||||
if (pdu_mngt->sdu[pdu_mngt->nb_sdu - 1] == sdu_index) {
|
||||
//----------------------------------------------
|
||||
// now check if a copy of the pdu is not present in the retransmission_buffer_to_send
|
||||
if ((pdu_mngt->copy)) {
|
||||
list2_remove_element (pdu_mngt->copy, &rlcP->retransmission_buffer_to_send);
|
||||
free_mem_block (pdu_mngt->copy);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD LAST PDU SN 0x%03X\n", rlcP->rb_id, sn);
|
||||
rlc_am_display_data_pdu7 (pdu);
|
||||
#endif
|
||||
|
||||
//----------------
|
||||
// discard the pdu
|
||||
// if this pdu has been retransmitted, remove its size from buffer occupancy
|
||||
if (((struct rlc_am_tx_data_pdu_management*) (pdu->data))->vt_dat > 0) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer -= 1;
|
||||
}
|
||||
|
||||
pdu_index = pdu_mngt->sn % rlcP->recomputed_configured_tx_window_size;
|
||||
free_mem_block (rlcP->retransmission_buffer[pdu_index]);
|
||||
rlcP->retransmission_buffer[pdu_index] = NULL;
|
||||
|
||||
} else {
|
||||
// if this pdu is not discarded, mark the sdu discarded by writing "-1" for their index : used in retransmission
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD LAST PDU SN 0x%03X, CONTAINS OTHER SDUS (LAST SDU INDEX=%d): NOT CLEARED\n", rlcP->rb_id, sdu_mngt->last_pdu_sn,
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu - 1]);
|
||||
#endif
|
||||
sdu_index2 = 0;
|
||||
|
||||
while (pdu_mngt->sdu[sdu_index2] != sdu_index) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD LAST PDU SN 0x%03X, MARK SDU index % AS DISCARDED\n", rlcP->rb_id, pdu_mngt->sn, pdu_mngt->sdu[sdu_index2]);
|
||||
#endif
|
||||
pdu_mngt->sdu[sdu_index2] = -1;
|
||||
sdu_index2 += 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD LAST PDU SN 0x%03X, MARK SDU index %d AS DISCARDED\n", rlcP->rb_id, pdu_mngt->sn, pdu_mngt->sdu[sdu_index2]);
|
||||
#endif
|
||||
pdu_mngt->sdu[sdu_index2] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
|
||||
else {
|
||||
msg ("[RLC_AM][RB %d] DISCARD LAST PDU SN 0x%03X, ALREADY CLEARED\n", rlcP->rb_id, sdu_mngt->last_pdu_sn);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------
|
||||
// discard the sdu
|
||||
if ((rlcP->input_sdus[sdu_index])) { // may be removed by "free_retransmission_buffer_no_confirmation"
|
||||
if (sdu_index == rlcP->current_sdu_index) {
|
||||
// sdu under segmentation
|
||||
rlcP->buffer_occupancy -= ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[sdu_index]->data))->sdu_remaining_size;
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[sdu_index]->data))->no_new_sdu_segmented_in_last_pdu = 1;
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 0;
|
||||
rlcP->li_one_byte_short_to_add_in_next_pdu = 0;
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD THE SDU DISCARDED WAS UNDER SEGMENTATION (index %d)\n", rlcP->rb_id, sdu_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
list2_add_tail (rlcP->input_sdus[sdu_index], &rlcP->sdu_discarded);
|
||||
#ifdef DEBUG_RLC_AM_FREE_SDU
|
||||
msg ("[RLC_AM][RB %d] DISCARD MAX DAT FREE_SDU INDEX %d\n", rlcP - rb_id, sdu_index);
|
||||
#endif
|
||||
rlcP->input_sdus[sdu_index] = NULL;
|
||||
rlcP->nb_sdu -= 1;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_notif_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_DISCARD_NOTIF_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_DISCARD_NOTIF_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "rlc_am_constants.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_discard_notify_mrw_ack_time_out (struct rlc_am_entity *rlcP, mem_block_t * discard_procedureP);
|
||||
extern void rlc_am_discard_check_sdu_time_out (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_discard_notify_max_dat_pdu (struct rlc_am_entity *rlcP, mem_block_t * pduP);
|
||||
# endif
|
||||
@@ -1,614 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_rx.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_receiver_proto_extern.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_status_proto_extern.h"
|
||||
#include "rlc_am_receiver_proto_extern.h"
|
||||
#include "rlc_am_discard_tx_proto_extern.h"
|
||||
#include "rlc_am_discard_notif_proto_extern.h"
|
||||
#include "rlc_am_retrans_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "rlc_am_proto_extern.h"
|
||||
#include "umts_timer_struct.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
#include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
void rlc_am_received_sufi_ack_check_discard_procedures (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_free_discard_procedure (mem_block_t* mb_current_procedureP);
|
||||
inline void rlc_am_discard_free_receiver_buffer (struct rlc_am_entity* rlcP, uint16_t sn_mrw_iP, uint8_t nlengthP);
|
||||
uint8_t* retransmission_buffer_management_mrw (struct rlc_am_entity* rlcP, uint8_t* byte1P, uint8_t* byte_alignedP);
|
||||
uint8_t* retransmission_buffer_management_mrw_ack (struct rlc_am_entity* rlcP, uint8_t* byte1P, uint8_t* byte_alignedP);
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_received_sufi_ack_check_discard_procedures (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* mb_proc;
|
||||
mem_block_t* tmp_proc;
|
||||
struct rlc_am_discard_procedure* procedure;
|
||||
/* From 3GPP 25.322 V5.0.0 (2002-03)
|
||||
The Sender shall terminate the SDU discard with explicit signalling procedure if one of the
|
||||
following criteria is fulfilled:
|
||||
|
||||
- a STATUS PDU/piggybacked STATUS PDU containing an MRW_ACK SUFI is received, and the SN_ACK : DONE in retransmission_buffer_management_mrw_ack(..)
|
||||
field in the received MRW_ACK SUFI > the SN_MRWLENGTH field in the transmitted MRW_SUFI,
|
||||
and the N field in the received MRW_ACK SUFI is set equal to "0000";
|
||||
|
||||
- a STATUS PDU/piggybacked STATUS PDU containing an MRW_ACK SUFI is received, and the SN_ACK : DONE in retransmission_buffer_management_mrw_ack(..)
|
||||
field in the received MRW_ACK SUFI = the SN_MRWLENGTH field in the transmitted MRW_SUFI,
|
||||
and the N field in the received MRW_ACK SUFI is set equal to the NLENGTH field in the
|
||||
transmitted MRW SUFI;
|
||||
|
||||
- a STATUS PDU/piggybacked STATUS PDU containing an ACK SUFI is received, and the LSN field : DONE HERE
|
||||
in the received ACK SUFI > the SN_MRWLENGTH field in the transmitted MRW SUFI.
|
||||
|
||||
Upon termination of the SDU discard with explicit signalling procedure, the Sender shall:
|
||||
- stop the timer Timer_MRW;
|
||||
- update VT(A) and VT(MS) according to the received STATUS PDU/piggybacked STATUS PDU;
|
||||
The Sender shall not confirm to upper layers the SDUs that are requested to be discarded.
|
||||
*/
|
||||
mb_proc = rlcP->discard_procedures.head;
|
||||
|
||||
while ((mb_proc)) {
|
||||
procedure = (struct rlc_am_discard_procedure*) (mb_proc->data);
|
||||
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, rlcP->vt_a, procedure->last_pdu_sn) > 0) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT NEW VT(A) 0x%04X REMOVE PROCEDURE SN_MRWlength 0x%04X\n", rlcP->rb_id, rlcP->vt_a, procedure->last_pdu_sn);
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ACK\n", rlcP->rb_id);
|
||||
#endif
|
||||
tmp_proc = mb_proc->next;
|
||||
list2_remove_element (mb_proc, &rlcP->discard_procedures);
|
||||
|
||||
// if procedure is running, free timer resources
|
||||
if ((procedure->running) && (rlcP->timer_mrw)) {
|
||||
if (rlcP->timer_mrw == list2_remove_element (rlcP->timer_mrw, &rlcP->rlc_am_timer_list)) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ACK->TERMINATE PROCEDURE: REMOVE TIMER mrw id %p\n", rlcP->rb_id,
|
||||
((struct timer_unit*) (rlcP->timer_mrw->data))->timer_id);
|
||||
#endif
|
||||
free_mem_block (rlcP->timer_mrw);
|
||||
rlcP->timer_mrw = NULL;
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT REMOVE TIMER FAILED\n", rlcP->rb_id);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
rlc_am_free_discard_procedure (mb_proc);
|
||||
mb_proc = tmp_proc;
|
||||
rlcP->vt_mrw = 0;
|
||||
|
||||
} else {
|
||||
mb_proc = mb_proc->next;
|
||||
}
|
||||
}
|
||||
|
||||
// may be other discard procedures to run
|
||||
rlc_am_schedule_procedure (rlcP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_free_discard_procedure (mem_block_t* mb_current_procedureP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// be carefull : the timer is not free here, it should be done before
|
||||
struct rlc_am_discard_procedure* procedure;
|
||||
|
||||
if (mb_current_procedureP) {
|
||||
procedure = (struct rlc_am_discard_procedure*) (mb_current_procedureP->data);
|
||||
list_free (&procedure->sdu_list);
|
||||
|
||||
if (procedure->control_pdu) {
|
||||
free_mem_block (procedure->control_pdu);
|
||||
}
|
||||
|
||||
free_mem_block (mb_current_procedureP);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
rlc_am_discard_free_receiver_buffer (struct rlc_am_entity* rlcP, uint16_t sn_mrw_iP, uint8_t nlengthP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t working_sn;
|
||||
uint16_t working_sn_index; // index in buffer
|
||||
// should start reassembly with sn working_sn
|
||||
working_sn = rlcP->last_reassemblied_sn;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
display_receiver_buffer (rlcP);
|
||||
#endif
|
||||
|
||||
while (working_sn != sn_mrw_iP) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER FREE RECEIVER BUFFER pdu sn 0x%04X VR(R) 0x%04X\n", rlcP->rb_id, working_sn, rlcP->vr_r);
|
||||
#endif
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
}
|
||||
|
||||
// From 3GPP TS 25.322 V5.0.0 (2002-03) page 35
|
||||
// NLENGTH is used together with SN_MRWLENGTH to indicate the end of the last SDU to be discarded in the receiver.
|
||||
// NLENGTH indicates which LI in the PDU with sequence number SN_MRWLENGTH corresponds to the last SDU to be discarded in the receiver.
|
||||
// NLENGTH = 0 indicates that the last SDU ended in the PDU with sequence number SN_MRWLENGTH -1 and that the first data octet
|
||||
// in the PDU with sequence number SN_MRWLENGTH is the first data octet to be reassembled next.
|
||||
// erase previous sdu in construction
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
|
||||
if ((nlengthP)) {
|
||||
rlcP->discard_reassembly_after_li = nlengthP; // will be used by process_receiver_buffer
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER rlc_am_discard_free_receiver_buffer pdu sn 0x%04X (nlength=0)\n", rlcP->rb_id, working_sn);
|
||||
#endif
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0;
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t*
|
||||
retransmission_buffer_management_mrw (struct rlc_am_entity* rlcP, uint8_t* byte1P, uint8_t* byte_alignedP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* mb;
|
||||
uint8_t* p8;
|
||||
uint16_t sn_mrw_i[15];
|
||||
uint16_t new_vr_r;
|
||||
uint16_t working_sn;
|
||||
uint16_t working_sn_index; // index in buffer
|
||||
uint8_t sn_mrw_i_index;
|
||||
uint8_t mrw_length;
|
||||
uint8_t nlength;
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
uint8_t i;
|
||||
#endif
|
||||
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
Upon reception of the STATUS PDU/piggybacked STATUS PDU containing an MRW SUFI, the Receiver shall:
|
||||
- if the LENGTH field in the received MRW SUFI is "0000":
|
||||
- consider SN_MRW1 to be above or equal to VR(R).
|
||||
- otherwise:
|
||||
- consider SN_MRW1 to be less than VR(MR);
|
||||
- consider all the SN_MRWis other than SN_MRW1 to be in sequential order within the list and
|
||||
sequentially above or equal to SN_MRWi-1.
|
||||
- discard AMD PDUs up to and including the PDU with sequence number SN_MRWLENGTH-1;
|
||||
- if the NLENGTH field in the received MRW SUFI is "0000":
|
||||
- reassemble from the first data octet of the AMD PDU with sequence number SN_MRWLENGTH
|
||||
after the discard.
|
||||
- otherwise:
|
||||
- discard further the data octets in the AMD PDU with sequence number SN_MRWLENGTH up to and
|
||||
including the octet indicated by the NLENGTH:th LI field of the PDU with sequence number
|
||||
SN_MRWLENGTH;
|
||||
- reassemble from the succeeding data octet in the AMD PDU with sequence number SN_MRWLENGTH
|
||||
after the discard;
|
||||
- if "Send MRW" is configured:
|
||||
- inform upper layers about all of the discarded SDUs that were not previously delivered to
|
||||
upper layer or discarded by other MRW SUFIs;
|
||||
- update the state variables VR(R), VR(H) and VR(MR) according to the received
|
||||
STATUS PDU/piggybacked STATUS PDU;
|
||||
- assemble a MRW_ACK SUFI
|
||||
- schedule and submit to lower layer a STATUS PDU/piggybacked STATUS PDU containing the MRW_ACK
|
||||
SUFI.
|
||||
|
||||
The Receiver shall:
|
||||
- set the SN_ACK field in the MRW_ACK SUFI to the new value of VR(R), updated after reception
|
||||
of the MRW SUFI;
|
||||
- if the SN_ACK field in the MRW_ACK SUFI is set equal to the SN_MRWLENGTH field in the
|
||||
received MRW SUFI:
|
||||
- set the N field in the MRW_ACK SUFI to the NLENGTH field in the received MRW SUFI.
|
||||
- otherwise:
|
||||
- set the N field in the MRW_ACK SUFI to "0000";
|
||||
- include the MRW_ACK SUFI in the next STATUS PDU/piggybacked STATUS PDU to be transmitted,
|
||||
according to subclause 11.5.2.
|
||||
*/
|
||||
p8 = byte1P;
|
||||
sn_mrw_i_index = 0;
|
||||
|
||||
if (*byte_alignedP) {
|
||||
mrw_length = *p8++ & 0X0F; // number of SN_MRWi
|
||||
|
||||
} else {
|
||||
p8 = p8 + 1;
|
||||
mrw_length = (*p8 & 0XF0) >> 4; // number of SN_MRWi
|
||||
}
|
||||
|
||||
if (!(mrw_length)) {
|
||||
if (*byte_alignedP) {
|
||||
// sn_mrw_i is SN_MRW length
|
||||
sn_mrw_i[0] = (*p8++) << 4;
|
||||
sn_mrw_i[0] += (*p8) >> 4;
|
||||
*byte_alignedP = 0;
|
||||
|
||||
} else {
|
||||
// sn_mrw_i is SN_MRW length
|
||||
sn_mrw_i[0] = (*p8++) << 8;
|
||||
sn_mrw_i[0] += *p8++;
|
||||
nlength = (*p8 & 0xF0) >> 4;
|
||||
*byte_alignedP = 1;
|
||||
}
|
||||
|
||||
sn_mrw_i_index += 1;
|
||||
|
||||
} else {
|
||||
// get all sn_mrw_i
|
||||
while (mrw_length != sn_mrw_i_index) {
|
||||
if (*byte_alignedP) {
|
||||
sn_mrw_i[sn_mrw_i_index] = (*p8++) << 4;
|
||||
sn_mrw_i[sn_mrw_i_index] += (*p8) >> 4;
|
||||
*byte_alignedP = 0;
|
||||
|
||||
} else {
|
||||
sn_mrw_i[sn_mrw_i_index] = ((*p8++) & 0x0F) << 8;
|
||||
sn_mrw_i[sn_mrw_i_index] += (*p8++);
|
||||
*byte_alignedP = 1;
|
||||
}
|
||||
|
||||
sn_mrw_i_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// get nlength
|
||||
if (*byte_alignedP) {
|
||||
nlength = (*p8 & 0xF0) >> 4;
|
||||
*byte_alignedP = 0;
|
||||
|
||||
} else {
|
||||
nlength = *p8++ & 0x0F;
|
||||
*byte_alignedP = 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER RECEIVED MRW LENGTH %d ", rlcP->rb_id, mrw_length);
|
||||
|
||||
for (i = 0; i < sn_mrw_i_index; i++) {
|
||||
msg ("sn_mrw%d 0x%04X ", i + 1, sn_mrw_i[i]);
|
||||
}
|
||||
|
||||
msg ("Nlength %d\n", nlength);
|
||||
#endif
|
||||
|
||||
/********************************************************************
|
||||
* M R W D I S C A R D E D *
|
||||
********************************************************************/
|
||||
/* From 3GPP TS 25.322 V5.0.0
|
||||
Reception of obsolete/corrupted MRW SUFI by the Receiver
|
||||
If the received MRW SUFI contains outdated information about the receiving window
|
||||
(receiving window already moved further than MRW SUFI is indicating), the Receiver shall:
|
||||
- discard the MRW SUFI;
|
||||
- set the SN_ACK field in the MRW_ACK SUFI to the current value of VR(R);
|
||||
- set the N field in the MRW_ACK SUFI to "0000";
|
||||
- include the MRW_ACK SUFI in the next STATUS PDU/piggybacked STATUS PDU to be transmitted.
|
||||
*/
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, sn_mrw_i[sn_mrw_i_index - 1], rlcP->vr_r) < 0) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER ERROR received OBSOLETE/CORRUPTED MRW command VR(R) 0x%04X VR(H) 0x%04X VR(MR) 0x%04X SN_MRWlength 0x%04X\n",
|
||||
rlcP->rb_id, rlcP->vr_r, rlcP->vr_h, rlcP->vr_mr, sn_mrw_i[sn_mrw_i_index - 1]);
|
||||
#endif
|
||||
|
||||
// send status pdu mrw_ack
|
||||
if ((mb = rlc_am_create_status_pdu_mrw_ack (rlcP, 0, rlcP->vr_r))) {
|
||||
list_add_tail_eurecom (mb, &rlcP->control);
|
||||
}
|
||||
|
||||
return p8;
|
||||
|
||||
} else {
|
||||
/********************************************************************
|
||||
* M R W N O T D I S C A R D E D *
|
||||
********************************************************************/
|
||||
new_vr_r = sn_mrw_i[sn_mrw_i_index - 1];
|
||||
/***********************************
|
||||
* DISCARD PDUS IN THE RECEIVER *
|
||||
***********************************/
|
||||
// should start discard with sn working_sn
|
||||
working_sn = rlcP->last_reassemblied_sn;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
// discard all pdus except the last one
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
display_receiver_buffer (rlcP);
|
||||
#endif
|
||||
|
||||
while (working_sn != new_vr_r) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER FREE RECEIVER BUFFER pdu sn 0x%04X VR(R) 0x%04X\n", rlcP->rb_id, working_sn, rlcP->vr_r);
|
||||
#endif
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
}
|
||||
|
||||
// From 3GPP TS 25.322 V5.0.0 (2002-03) page 35
|
||||
// NLENGTH is used together with SN_MRWLENGTH to indicate the end of the last SDU to be discarded in the receiver.
|
||||
// NLENGTH indicates which LI in the PDU with sequence number SN_MRWLENGTH corresponds to the last SDU to be discarded in the receiver.
|
||||
// NLENGTH = 0 indicates that the last SDU ended in the PDU with sequence number SN_MRWLENGTH -1 and that the first data octet
|
||||
// in the PDU with sequence number SN_MRWLENGTH is the first data octet to be reassembled next.
|
||||
// erase previous sdu in construction
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
rlcP->discard_reassembly_start_sn = new_vr_r;
|
||||
rlcP->discard_reassembly_after_li = nlength; // will be used by process_receiver_buffer
|
||||
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, new_vr_r, rlcP->vr_r) > 0) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER... VR(R) : 0x%04X -> 0x%04X (VR(H)=0x%04X)\n", rlcP->rb_id, rlcP->vr_r, new_vr_r, rlcP->vr_h);
|
||||
#endif
|
||||
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, new_vr_r, rlcP->vr_h) > 0) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD RECEIVER... VR(H) : 0x%04X -> 0x%04X\n", rlcP->rb_id, rlcP->vr_h, new_vr_r);
|
||||
#endif
|
||||
rlcP->vr_h = new_vr_r;
|
||||
}
|
||||
|
||||
rlcP->vr_r = new_vr_r;
|
||||
rlcP->ack.vr_r_modified = 1; // for status generation
|
||||
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
if ((rlcP->send_mrw & RLC_AM_SEND_MRW_ON)) {
|
||||
//send tu upper layers discarded sdus infos !!
|
||||
// TO DO !!!!!!!!
|
||||
}
|
||||
|
||||
if (rlcP->pdu_size <= 126) {
|
||||
process_receiver_buffer_7 (rlcP);
|
||||
|
||||
} else {
|
||||
process_receiver_buffer_15 (rlcP);
|
||||
}
|
||||
|
||||
/* From 3GPP 25.322 V5.0.0 (2002-03)
|
||||
The Receiver shall:
|
||||
- set the SN_ACK field in the MRW_ACK SUFI to the new value of VR(R), updated after reception
|
||||
of the MRW SUFI;
|
||||
- if the SN_ACK field in the MRW_ACK SUFI is set equal to the SN_MRWLENGTH field in the
|
||||
received MRW SUFI:
|
||||
- set the N field in the MRW_ACK SUFI to the NLENGTH field in the received MRW SUFI.
|
||||
- otherwise:
|
||||
- set the N field in the MRW_ACK SUFI to "0000";
|
||||
- include the MRW_ACK SUFI in the next STATUS PDU/piggybacked STATUS PDU to be transmitted,
|
||||
according to subclause 11.5.2. */
|
||||
if (sn_mrw_i[sn_mrw_i_index - 1] == rlcP->vr_r) {
|
||||
mb = rlc_am_create_status_pdu_mrw_ack (rlcP, nlength, rlcP->vr_r);
|
||||
|
||||
} else {
|
||||
mb = rlc_am_create_status_pdu_mrw_ack (rlcP, 0, rlcP->vr_r);
|
||||
}
|
||||
|
||||
/* SEND STATUS PDU MRW ACK */
|
||||
if (mb) {
|
||||
list_add_tail_eurecom (mb, &rlcP->control);
|
||||
}
|
||||
|
||||
return p8;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t*
|
||||
retransmission_buffer_management_mrw_ack (struct rlc_am_entity* rlcP, uint8_t* byte1P, uint8_t* byte_alignedP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* mb;
|
||||
mem_block_t* mb_current_procedure;
|
||||
struct rlc_am_tx_data_pdu_management* rlc_header;
|
||||
struct rlc_am_discard_procedure* procedure;
|
||||
uint8_t* p8;
|
||||
uint16_t sn_ack;
|
||||
uint16_t index;
|
||||
uint8_t n; // field of mrw_ack sufi
|
||||
//-------------------------------------
|
||||
// DECODE SUFI MRW_ACK
|
||||
//-------------------------------------
|
||||
p8 = byte1P;
|
||||
|
||||
if (*byte_alignedP) {
|
||||
n = *p8++ & 0X0F;
|
||||
// sn_mrw_i is SN_MRW length
|
||||
sn_ack = (*p8++) << 4;
|
||||
sn_ack += (*p8) >> 4;
|
||||
*byte_alignedP = 0;
|
||||
|
||||
} else {
|
||||
p8 = p8 + 1;
|
||||
n = (*p8 & 0XF0) >> 4;
|
||||
// sn_mrw_i is SN_MRW length
|
||||
sn_ack = ((*p8++) & 0x0F) << 8;
|
||||
sn_ack += *p8++;
|
||||
*byte_alignedP = 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("\n[RLC_AM][RB %d] DISCARD TRANSMIT RX MRW_ACK N %d SN_ACK 0x%04X VT(A) 0x%04X VT(S) 0x%04X\n", rlcP->rb_id, n, sn_ack, rlcP->vt_a, rlcP->vt_s);
|
||||
//display_retransmission_buffer(rlcP);
|
||||
#endif
|
||||
|
||||
// compare to current running procedure
|
||||
if ((mb_current_procedure = rlcP->discard_procedures.head)) {
|
||||
procedure = (struct rlc_am_discard_procedure*) (mb_current_procedure->data);
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ... procedure->last_pdu_sn 0x%04X procedure->nlength 0x%04X \n", rlcP->rb_id, procedure->last_pdu_sn,
|
||||
procedure->nlength);
|
||||
#endif
|
||||
|
||||
/* From 3GPP TS 25.322 V5.0.0
|
||||
The Sender shall discard the received MRW_ACK SUFI if one of the following cases occurs:
|
||||
|
||||
- the timer Timer_MRW is not active;
|
||||
or
|
||||
- the SN_ACK field in the received MRW_ACK SUFI < the SN_MRWLENGTH field in the transmitted MRW SUFI;
|
||||
or
|
||||
- the SN_ACK field in the received MRW_ACK SUFI = the SN_MRWLENGTH field in the transmitted MRW SUFI,
|
||||
and the N field in the received MRW_ACK SUFI is not equal to the NLENGTH field in the transmitted MRW SUFI;
|
||||
or
|
||||
- the SN_ACK field in the received MRW_ACK SUFI > the SN_MRWLENGTH field in the transmitted MRW SUFI,
|
||||
and the N field in the received MRW_ACK SUFI is not equal to "0000".
|
||||
*/
|
||||
if ((rlcP->timer_mrw == NULL) || // if timer_MRW is not active
|
||||
(rlc_am_comp_sn (rlcP, rlcP->vt_a, procedure->last_pdu_sn, sn_ack) > 0) ||
|
||||
((rlc_am_comp_sn (rlcP, rlcP->vt_a, procedure->last_pdu_sn, sn_ack) == 0) && (n != procedure->nlength)) ||
|
||||
((rlc_am_comp_sn (rlcP, rlcP->vt_a, procedure->last_pdu_sn, sn_ack) < 0) && (n != 0))) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ERROR RX OBSOLETE MRW_ACK VT(A) 0x%04X VT(S) 0x%04X SN_MRWlength 0x%04X N %d SN_ACK 0x%04X\n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, procedure->last_pdu_sn, n, sn_ack);
|
||||
#endif
|
||||
|
||||
} else if (
|
||||
/* From 3GPP 25.322 V5.0.0 (2002-03)
|
||||
The Sender shall terminate the SDU discard with explicit signalling procedure if one of the
|
||||
following criteria is fulfilled:
|
||||
|
||||
- a STATUS PDU/piggybacked STATUS PDU containing an MRW_ACK SUFI is received, and the SN_ACK : DONE HERE
|
||||
field in the received MRW_ACK SUFI > the SN_MRWLENGTH field in the transmitted MRW_SUFI,
|
||||
and the N field in the received MRW_ACK SUFI is set equal to "0000";
|
||||
|
||||
- a STATUS PDU/piggybacked STATUS PDU containing an MRW_ACK SUFI is received, and the SN_ACK : DONE HERE
|
||||
field in the received MRW_ACK SUFI = the SN_MRWLENGTH field in the transmitted MRW_SUFI,
|
||||
and the N field in the received MRW_ACK SUFI is set equal to the NLENGTH field in the
|
||||
transmitted MRW SUFI;
|
||||
|
||||
- a STATUS PDU/piggybacked STATUS PDU containing an ACK SUFI is received, and the LSN field : DONE in rlc_am_received_sufi_ack_check_discard_procedures(...)
|
||||
in the received ACK SUFI > the SN_MRWLENGTH field in the transmitted MRW SUFI.
|
||||
|
||||
Upon termination of the SDU discard with explicit signalling procedure, the Sender shall:
|
||||
- stop the timer Timer_MRW;
|
||||
- update VT(A) and VT(MS) according to the received STATUS PDU/piggybacked STATUS PDU;
|
||||
The Sender shall not confirm to upper layers the SDUs that are requested to be discarded.
|
||||
*/
|
||||
(rlc_am_comp_sn (rlcP, rlcP->vt_a, sn_ack, procedure->last_pdu_sn) > 0) || ((sn_ack == procedure->last_pdu_sn) && (n == procedure->nlength))
|
||||
) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD PROCEDURE %p TERMINATED\n", rlcP->rb_id, mb_current_procedure);
|
||||
#endif
|
||||
rlcP->vt_mrw = 0;
|
||||
|
||||
// remove timer
|
||||
if ((rlcP->timer_mrw)) {
|
||||
if (rlcP->timer_mrw == list2_remove_element (rlcP->timer_mrw, &rlcP->rlc_am_timer_list)) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT TERMINATE PROCEDURE: REMOVE TIMER mrw id %p\n", rlcP->rb_id, ((struct timer_unit*) (rlcP->timer_mrw->data))->timer_id);
|
||||
#endif
|
||||
free_mem_block (rlcP->timer_mrw);
|
||||
rlcP->timer_mrw = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
|
||||
else {
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ERROR TERMINATION PROCEDURE : TIMER MRW IS WRONG\n",
|
||||
rlcP->rb_id); // in fact : no, the lists are not protected against an element that is not inside the list
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
|
||||
else {
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ERROR TERMINATION PROCEDURE : NO TIMER MRW WAS FOUND\n", rlcP->rb_id);
|
||||
}
|
||||
|
||||
#endif
|
||||
mb_current_procedure = list2_remove_head (&rlcP->discard_procedures);
|
||||
|
||||
//update VT(A)
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, sn_ack, rlcP->vt_a) > 0) {
|
||||
// free resources that may be in retransmission buffer
|
||||
while (rlcP->vt_a != sn_ack) {
|
||||
index = rlcP->vt_a % rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
if ((mb = rlcP->retransmission_buffer[index])) {
|
||||
rlc_header = (struct rlc_am_tx_data_pdu_management*) (mb->data);
|
||||
|
||||
if (rlc_header->nb_sdu > 0) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT CASE 1 MRW_ACK\n", rlcP->rb_id);
|
||||
#endif
|
||||
// the sender of MRW_ACK changed sn_mrw_length to vr_r, so it is normal to free
|
||||
// pdus that are linked with sdus
|
||||
free_retransmission_buffer_no_confirmation (rlcP, index);
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT CASE 2 MRW_ACK FREE REMAINING RETRANS PDU 0x%04X\n", rlcP->rb_id, rlcP->vt_a);
|
||||
#endif
|
||||
|
||||
// if this pdu has been retransmitted, remove its size from buffer occupancy
|
||||
if (rlc_header->vt_dat > 0) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer -= 1;
|
||||
}
|
||||
|
||||
free_mem_block (mb);
|
||||
rlcP->retransmission_buffer[index] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rlcP->vt_a = (rlcP->vt_a + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT MRW_ACK VT(A) UPDATED 0x%04X VT(S) 0x%04X\n", rlcP->rb_id, rlcP->vt_a, rlcP->vt_s);
|
||||
#endif
|
||||
}
|
||||
|
||||
rlc_am_free_discard_procedure (mb_current_procedure);
|
||||
rlc_am_schedule_procedure (rlcP);
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM][RB %d] DISCARD TRANSMIT ERROR RX MRW_ACK CASE NOT TAKEN IN ACCOUNT : NO ACTION !\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
//display_mem_load();
|
||||
//display_retransmission_buffer(rlcP);
|
||||
#endif
|
||||
return p8;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_rx_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_DISCARD_RX_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_DISCARD_RX_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_received_sufi_ack_check_discard_procedures (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_free_discard_procedure (mem_block_t * mb_current_procedureP);
|
||||
extern inline void rlc_am_discard_free_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t sn_mrw_iP, uint8_t nlengthP);
|
||||
extern uint8_t *retransmission_buffer_management_mrw (struct rlc_am_entity *rlcP, uint8_t * byte1P, uint8_t * byte_alignedP);
|
||||
extern uint8_t *retransmission_buffer_management_mrw_ack (struct rlc_am_entity *rlcP, uint8_t * byte1P, uint8_t * byte_alignedP);
|
||||
# endif
|
||||
@@ -1,386 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_tx.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_discard_notif_proto_extern.h"
|
||||
#include "rlc_am_discard_rx_proto_extern.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_status_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
void rlc_am_schedule_procedure (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_process_sdu_discarded (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_configured (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_not_configured (struct rlc_am_entity* rlcP);
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_schedule_procedure (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* pdu_status;
|
||||
struct rlc_am_discard_procedure* procedure;
|
||||
|
||||
// if a procedure is running do nothing
|
||||
if (!(rlcP->timer_mrw) && (rlcP->discard_procedures.head)) {
|
||||
// launch remaining procedures (only 1 procedure running)
|
||||
procedure = (struct rlc_am_discard_procedure*) ((rlcP->discard_procedures.head)->data);
|
||||
/* sn_mrw_length = procedure->last_pdu_sn;
|
||||
|
||||
if (rlc_am_comp_sn(rlcP, rlcP->vt_s, sn_mrw_length, rlcP->vt_s) > 0) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg("[RLC_AM %p][DISCARD] SCHEDULE PROCEDURE %p UPDATE VT(S) %04X -> %04X\n", rlcP, rlcP->discard_procedures.head, rlcP->vt_s, sn_mrw_length);
|
||||
#endif
|
||||
rlcP->vt_s = sn_mrw_length;
|
||||
}
|
||||
*/
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD SCHEDULE PROCEDURE %p vt_s 0x%04X vt_a 0x%04X\n", rlcP->rb_id, rlcP->discard_procedures.head, rlcP->vt_s, rlcP->vt_a);
|
||||
#endif
|
||||
procedure->running = 0xFF;
|
||||
pdu_status = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
memcpy (pdu_status->data, procedure->control_pdu->data, rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation));
|
||||
list_add_tail_eurecom (pdu_status, &rlcP->control);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_process_sdu_discarded (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// We assume that the list sdu_discarded contains sdu(s)
|
||||
/* From 3GPP TS 25.322 V4.3.0 (2001-12)
|
||||
The Sender shall initiate the SDU discard with explicit signalling procedure if one of the
|
||||
following triggers is detected:
|
||||
- "Timer based SDU discard with explicit signalling" is configured, Timer_Discard expires
|
||||
for an SDU, and one or more segments of the SDU have been submitted to a lower layer;
|
||||
- "Timer based SDU discard with explicit signalling" is configured, Timer_Discard expires
|
||||
for an SDU, and Send MRW is configured;
|
||||
- "SDU discard after MaxDAT number of transmissions" is configured, and MaxDAT number of
|
||||
transmissions is reached (i.e. VT(DAT) � MaxDAT) for an AMD PDU.
|
||||
*/
|
||||
// discard procedure
|
||||
if ((rlcP->send_mrw & RLC_AM_SEND_MRW_ON)) {
|
||||
rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_configured (rlcP);
|
||||
|
||||
} else { // RLC_AM_SEND_MRW_OFF
|
||||
rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_not_configured (rlcP);
|
||||
}
|
||||
|
||||
rlc_am_schedule_procedure (rlcP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_configured (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
The Sender shall:
|
||||
- if "Send MRW" is configured:
|
||||
- if the last discarded SDU ended in an AMD PDU, and its "Length Indicator" is present in the same AMD
|
||||
PDU, and no new SDU is present inside this AMD PDU:
|
||||
- set the last SN_MRWi field in the MRW SUFI to 1 + "Sequence Number" of the AMD PDU which
|
||||
contains the "Length Indicator" of the last discarded SDU;
|
||||
- set the NLENGTH field in the MRW SUFI to "0000".
|
||||
- otherwise:
|
||||
- set the last SN_MRWi field in the MRW SUFI to the "Sequence Number" of the AMD PDU which
|
||||
contains the "Length Indicator" of the last discarded SDU;
|
||||
- set the NLENGTH field in the MRW SUFI so that the last data octet to be discarded in the Receiver shall be
|
||||
the octet indicated by the NLENGTH:th "Length Indicator" field of the AMD PDU which contains the
|
||||
"Length Indicator" of the last discarded SDU;
|
||||
- set each of the other SN_MRWi fields in the MRW SUFI to the "Sequence Number" of the AMD PDU which
|
||||
contains the "Length Indicator" of the i:th discarded SDU.
|
||||
- if the MRW SUFI contains only one SN_MRWi field and the value of SN_MRWi field
|
||||
VT(A)+Configured_Tx_Window_Size:
|
||||
- set the LENGTH field in the MRW SUFI to "0000".
|
||||
- otherwise:
|
||||
- set the LENGTH field in the MRW SUFI to the number of SN_MRWi fields in the same MRW SUFI. In this
|
||||
case, SN_MRW1 shall be in the interval VT(A) SN_MRW1 < VT(A)+Configured_Tx_Window_Size.
|
||||
*/
|
||||
mem_block_t* mb_discard_procedure = NULL;
|
||||
mem_block_t* sdu_discarded;
|
||||
struct rlc_am_tx_sdu_management* last_sdu_discarded_mngt;
|
||||
mem_block_t* le;
|
||||
struct rlc_am_status_header* pdu;
|
||||
uint8_t* p8;
|
||||
int last_sn_mrw_length;
|
||||
uint8_t count_sdu_discarded;
|
||||
uint8_t byte_aligned;
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
uint16_t sn_mrw_length;
|
||||
#endif
|
||||
|
||||
while (rlcP->sdu_discarded.head) {
|
||||
// alloc a discard procedure
|
||||
mb_discard_procedure = get_free_mem_block (sizeof (struct rlc_am_discard_procedure));
|
||||
memset (mb_discard_procedure->data, 0, sizeof (struct rlc_am_discard_procedure));
|
||||
list_init (&((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->sdu_list, NULL);
|
||||
count_sdu_discarded = 0;
|
||||
// assign sdu discarded to discard procedure
|
||||
// sdu headers are registered in discard procedure
|
||||
last_sn_mrw_length = -1;
|
||||
|
||||
while ((rlcP->sdu_discarded.head) && (count_sdu_discarded < 15)) { // max 15 sdu discarded per procedure
|
||||
sdu_discarded = list2_remove_head (&rlcP->sdu_discarded);
|
||||
|
||||
// this test is done to avoid signalling n times the same SN_MRW_length if a pdu contains n sdu
|
||||
// so it can save some discard procedures.
|
||||
if (last_sn_mrw_length != ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD IN PROCEDURE %p ADD SDU SN_MRWlength 0x%03X\n", rlcP->rb_id, mb_discard_procedure,
|
||||
((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn);
|
||||
#endif
|
||||
list_add_tail_eurecom (sdu_discarded, &((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->sdu_list);
|
||||
last_sn_mrw_length = ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn;
|
||||
count_sdu_discarded += 1;
|
||||
|
||||
} else {
|
||||
free_mem_block (sdu_discarded);
|
||||
}
|
||||
}
|
||||
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->length = count_sdu_discarded;
|
||||
//((struct rlc_am_discard_procedure*)(mb_discard_procedure->data))->nlength = ((struct rlc_am_sdu_discard_management*)((mem_block_t*)(sdu_header_copy_copy->data))->data)->li_index_for_discard;
|
||||
last_sdu_discarded_mngt = (struct rlc_am_tx_sdu_management*) (sdu_discarded->data);
|
||||
|
||||
if ((last_sdu_discarded_mngt->no_new_sdu_segmented_in_last_pdu)) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD NO NEW SDU SEGMENTED IN LAST PDU DISCARDED\n", rlcP->rb_id);
|
||||
#endif
|
||||
last_sdu_discarded_mngt->last_pdu_sn = (last_sdu_discarded_mngt->last_pdu_sn + 1) & SN_12BITS_MASK;
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength = 0;
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD OTHER SDU(s) SEGMENTED IN LAST PDU DISCARDED\n", rlcP->rb_id);
|
||||
#endif
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength = last_sdu_discarded_mngt->li_index_for_discard +
|
||||
1; // +1 since numerotation begins at 1
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD SET SN_MRW_LENGTH 0x%04X NLENGTH = %d \n", rlcP->rb_id, last_sdu_discarded_mngt->last_pdu_sn,
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength);
|
||||
sn_mrw_length = last_sdu_discarded_mngt->last_pdu_sn;
|
||||
#endif
|
||||
// make status pdu
|
||||
le = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (le == NULL) {
|
||||
// be carefull : lost resources in mb_discard : TO DO
|
||||
msg ("[RLC_AM][RB %d] FATAL ERROR : OUT OF MEMORY\n", rlcP->rb_id);
|
||||
return;
|
||||
|
||||
} else {
|
||||
((struct rlc_am_tx_control_pdu_management*) (le->data))->rlc_tb_type = RLC_AM_MRW_STATUS_PDU_TYPE;
|
||||
pdu = (struct rlc_am_status_header*) (&le->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
pdu->byte1 = RLC_PDU_TYPE_STATUS;
|
||||
p8 = &(pdu->byte1);
|
||||
*p8 = *p8 | RLC_AM_SUFI_MRW;
|
||||
p8 = p8 + 1;
|
||||
// fill field LENGTH
|
||||
*p8 = (count_sdu_discarded << 4);
|
||||
byte_aligned = 0;
|
||||
// fill fields SN_MRWi
|
||||
sdu_discarded = (((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->sdu_list.head); // reuse of var sdu_discarded
|
||||
|
||||
while ((count_sdu_discarded)) {
|
||||
count_sdu_discarded -= 1;
|
||||
|
||||
if (byte_aligned) {
|
||||
*p8 = ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn >> 4;
|
||||
p8 = p8 + 1;
|
||||
*p8 = ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn << 4;
|
||||
byte_aligned = 0;
|
||||
|
||||
} else {
|
||||
//*p8 = 0 << 4 | (temp_sn >> 8);
|
||||
*p8 |= (((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn >> 8);
|
||||
p8 = p8 + 1;
|
||||
*p8 = ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn;
|
||||
p8 = p8 + 1;
|
||||
byte_aligned = 1;
|
||||
}
|
||||
|
||||
sdu_discarded = sdu_discarded->next;
|
||||
}
|
||||
|
||||
// fill field Nlength
|
||||
if (byte_aligned) {
|
||||
*p8 = (((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength << 4) | RLC_AM_SUFI_NO_MORE;
|
||||
|
||||
} else {
|
||||
*p8 |= (((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength);
|
||||
p8 = p8 + 1;
|
||||
*p8 = (RLC_AM_SUFI_NO_MORE << 4);
|
||||
}
|
||||
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->control_pdu = le;
|
||||
list2_add_tail (mb_discard_procedure, &rlcP->discard_procedures);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD QUEUED NEW PROCEDURE SEND_MRW IS CONFIGURED SN_MRW_length = 0x%04X length %d nlength %d\n",
|
||||
rlcP->rb_id, sn_mrw_length, ((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->length,
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_not_configured (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
The Sender shall:
|
||||
- if "Send MRW" is NOT configured:
|
||||
- if the last SDU to be discarded in the Receiver ended in an AMD PDU, and its "Length Indicator" is present
|
||||
in the same AMD PDU, and no new SDU is present inside this AMD PDU:
|
||||
- set the last SN_MRWi field in the MRW SUFI to 1 + "Sequence Number" of the AMD PDU which
|
||||
contains the "Length Indicator" of the last SDU to be discarded in the Receiver;
|
||||
- set the NLENGTH field in the MRW SUFI to "0000".
|
||||
- otherwise:
|
||||
- set the last SN_MRWi field in the MRW SUFI to the "Sequence Number" of the AMD PDU which
|
||||
contains the "Length Indicator" of the last SDU to be discarded in the Receiver;
|
||||
- set the NLENGTH field in the MRW SUFI so that the last data octet to be discarded in the Receiver shall be
|
||||
the octet indicated by the NLENGTH:th "Length Indicator" field of the AMD PDU which contains the
|
||||
"Length Indicator" of the last SDU to be discarded in the Receiver;
|
||||
- optionally set each of the other SN_MRWi fields in the MRW SUFI to the "Sequence Number" of the AMD
|
||||
PDU which contains the "Length Indicator" of the i:th SDU to be discarded in the Receiver;
|
||||
- if the MRW SUFI contains only one SN_MRWi field and the value of SN_MRWi field
|
||||
VT(A)+Configured_Tx_Window_Size:
|
||||
- set the LENGTH field in the MRW SUFI to "0000".
|
||||
- otherwise:
|
||||
- set the LENGTH field in the MRW SUFI to the number of SN_MRWi fields in the same MRW SUFI. In this
|
||||
case, SN_MRW1 shall be in the interval VT(A) SN_MRW1 < VT(A)+Configured_Tx_Window_Size.
|
||||
*/
|
||||
mem_block_t* mb_discard_procedure = NULL;
|
||||
mem_block_t* sdu_discarded;
|
||||
struct rlc_am_tx_sdu_management* last_sdu_discarded_mngt;
|
||||
mem_block_t* le;
|
||||
struct rlc_am_status_header* pdu;
|
||||
int last_sn_mrw_length;
|
||||
uint8_t* p8;
|
||||
uint8_t count_sdu_discarded;
|
||||
uint8_t byte_aligned;
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
uint16_t sn_mrw_length;
|
||||
#endif
|
||||
|
||||
while (rlcP->sdu_discarded.head) {
|
||||
// alloc a discard procedure
|
||||
mb_discard_procedure = get_free_mem_block (sizeof (struct rlc_am_discard_procedure));
|
||||
memset (mb_discard_procedure->data, 0, sizeof (struct rlc_am_discard_procedure));
|
||||
list_init (&((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->sdu_list, NULL);
|
||||
count_sdu_discarded = 0;
|
||||
// assign sdu discarded to discard procedure
|
||||
// sdu headers are registered in discard procedure
|
||||
last_sn_mrw_length = -1;
|
||||
|
||||
while ((rlcP->sdu_discarded.head) && (count_sdu_discarded < 15)) { // max 15 sdu discarded per procedure
|
||||
sdu_discarded = list2_remove_head (&rlcP->sdu_discarded);
|
||||
|
||||
// this test is done to avoid signalling n times the same SN_MRW_length if a pdu contains n sdu
|
||||
// so it can save some discard procedures.
|
||||
if (last_sn_mrw_length != ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn) {
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
msg ("[RLC_AM][RB %d] DISCARD IN PROCEDURE %p ADD SDU SN_MRWlength %03X hex\n", rlcP->rb_id, mb_discard_procedure,
|
||||
((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn);
|
||||
#endif
|
||||
list_add_tail_eurecom (sdu_discarded, &((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->sdu_list);
|
||||
last_sn_mrw_length = ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn;
|
||||
count_sdu_discarded = 1;
|
||||
|
||||
} else {
|
||||
free_mem_block (sdu_discarded);
|
||||
}
|
||||
}
|
||||
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->length = count_sdu_discarded;
|
||||
//((struct rlc_am_discard_procedure*)(mb_discard_procedure->data))->nlength = ((struct rlc_am_sdu_discard_management*)((mem_block_t*)(sdu_header_copy_copy->data))->data)->li_index_for_discard;
|
||||
last_sdu_discarded_mngt = (struct rlc_am_tx_sdu_management*) (sdu_discarded->data);
|
||||
|
||||
if ((last_sdu_discarded_mngt->no_new_sdu_segmented_in_last_pdu)) {
|
||||
last_sdu_discarded_mngt->last_pdu_sn = (last_sdu_discarded_mngt->last_pdu_sn + 1) & SN_12BITS_MASK;
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength = 0;
|
||||
|
||||
} else {
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength = last_sdu_discarded_mngt->li_index_for_discard;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_DISCARD
|
||||
sn_mrw_length = last_sdu_discarded_mngt->last_pdu_sn;
|
||||
#endif
|
||||
|
||||
// make status pdu
|
||||
if ((le = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE))) {
|
||||
((struct rlc_am_tx_control_pdu_management*) (le->data))->rlc_tb_type = RLC_AM_MRW_STATUS_PDU_TYPE;
|
||||
pdu = (struct rlc_am_status_header*) (&le->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
pdu->byte1 = RLC_PDU_TYPE_STATUS;
|
||||
p8 = &(pdu->byte1);
|
||||
*p8 = *p8 | RLC_AM_SUFI_MRW;
|
||||
p8 = p8 + 1;
|
||||
// fill field LENGTH
|
||||
*p8 = (count_sdu_discarded << 4);
|
||||
byte_aligned = 0;
|
||||
// fill fields SN_MRWi
|
||||
sdu_discarded = (((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->sdu_list.head); // reuse of var sdu_discarded
|
||||
//*p8 = 0 << 4 | (temp_sn >> 8);
|
||||
*p8 |= (((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn >> 8);
|
||||
p8 = p8 + 1;
|
||||
*p8 = ((struct rlc_am_tx_sdu_management*) (sdu_discarded->data))->last_pdu_sn;
|
||||
p8 = p8 + 1;
|
||||
byte_aligned = 1;
|
||||
// fill field Nlength
|
||||
*p8 = (((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->nlength << 4) | RLC_AM_SUFI_NO_MORE;
|
||||
((struct rlc_am_discard_procedure*) (mb_discard_procedure->data))->control_pdu = le;
|
||||
list2_add_tail (mb_discard_procedure, &rlcP->discard_procedures);
|
||||
|
||||
} else {
|
||||
// out of memory
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_tx_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_DISCARD_TX_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_DISCARD_TX_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_schedule_procedure (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_process_sdu_discarded (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_configured (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_sdu_discard_with_explicit_signalling_procedure_send_mrw_not_configured (struct rlc_am_entity *rlcP);
|
||||
# endif
|
||||
@@ -1,326 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_entity.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_ENTITY_H__
|
||||
# define __RLC_AM_ENTITY_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "mem_block.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "rlc_def.h"
|
||||
# include "platform_types.h"
|
||||
# include "platform_constants.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_entity {
|
||||
module_id_t module_id;
|
||||
// for stats and trace purpose :
|
||||
uint16_t data_plane; // act as a boolean
|
||||
|
||||
uint16_t rb_id;
|
||||
//-----------------------------
|
||||
// polling info
|
||||
//-----------------------------
|
||||
uint16_t poll_pdu_trigger;
|
||||
uint16_t poll_sdu_trigger;
|
||||
uint16_t timer_poll_trigger;
|
||||
uint16_t timer_poll_prohibit_trigger;
|
||||
uint8_t last_transmission_pdu_poll_trigger;
|
||||
uint8_t last_retransmission_pdu_poll_trigger;
|
||||
uint8_t poll_window_trigger;
|
||||
//-----------------------------
|
||||
// timers
|
||||
//-----------------------------
|
||||
list2_t rlc_am_timer_list;
|
||||
//uint16_t timer_poll;
|
||||
//uint16_t timer_poll_prohibit;
|
||||
|
||||
uint16_t timer_poll_periodic;
|
||||
//uint16_t timer_status_prohibit;
|
||||
uint16_t timer_status_periodic;
|
||||
|
||||
signed int timer_status_prohibit;
|
||||
signed int running_timer_status_prohibit;
|
||||
|
||||
|
||||
mem_block_t *timer_rst;
|
||||
uint16_t time_out_events;
|
||||
mem_block_t *timer_mrw; // if NULL : no timer is running
|
||||
//uint8_t timer_mrw_is_running;
|
||||
|
||||
uint8_t max_mrw;
|
||||
//uint16_t timer_poll_init;
|
||||
//uint16_t timer_poll_prohibit_init;
|
||||
//uint16_t timer_epc_init;
|
||||
uint16_t timer_discard_init;
|
||||
uint16_t timer_poll_periodic_init;
|
||||
//uint16_t timer_status_prohibit_init;
|
||||
//uint16_t timer_status_periodic_init;
|
||||
uint16_t timer_rst_init;
|
||||
uint16_t timer_mrw_init;
|
||||
|
||||
uint32_t transmitted_pdu_types;
|
||||
int last_tx_status_frame;
|
||||
|
||||
uint32_t *frame_tick_milliseconds; // pointer on this tick variable handled by RRC : READ ONLY
|
||||
|
||||
uint8_t missing_pdu_indicator;
|
||||
//-----------------------------
|
||||
// tranmission
|
||||
//-----------------------------
|
||||
|
||||
//struct cnt_dbl_lk_list_up segmentation_buffer; // output of segmentation/concatenation function
|
||||
list2_t sdu_conf_segmented; // contain sdu_headers:sdu processed by the segmentation unit. (we keep them for confirm)
|
||||
list2_t sdu_discard_segmented; // contain sdu_headers:sdu processed by the segmentation unit. (we keep them for discard)
|
||||
list2_t sdu_discarded; // contain sdu_headers
|
||||
|
||||
list2_t discard_procedures; // contain procedures (struct rlc_am_discard_procedure)
|
||||
|
||||
//struct cnt_dbl_lk_list_up transmission_buffer; // output of mux module
|
||||
|
||||
//uint16_t data_pdu_size;
|
||||
//uint16_t control_pdu_size;
|
||||
|
||||
|
||||
|
||||
//struct cnt_list_up dcch_pdus_to_mac_layer;
|
||||
//struct cnt_list_up dtch_pdus_to_mac_layer;
|
||||
|
||||
//struct list_up dcch_pdus_from_mac_layer;
|
||||
//struct list_up dtch_pdus_from_mac_layer;
|
||||
|
||||
// implementation specific: our transmiter buffer is an array whose size must be a power of 2
|
||||
# define RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0 0x00
|
||||
uint8_t discard_reassembly_after_li; // when received mrw sufi
|
||||
uint16_t discard_reassembly_start_sn;
|
||||
//-----------------------------
|
||||
// management of received PDU for piggybacked status PDU and status PDU
|
||||
//-----------------------------
|
||||
struct sufi_to_insert_in_status status_in_construction[NB_MAX_SUFI];
|
||||
struct sufi_ack ack;
|
||||
uint8_t sufi_to_insert_index;
|
||||
//-----------------------------
|
||||
// Reset
|
||||
//-----------------------------
|
||||
uint8_t send_status_pdu_requested;
|
||||
uint8_t reset_sequence_number;
|
||||
uint8_t last_received_rsn;
|
||||
uint8_t max_rst;
|
||||
//-----------------------------
|
||||
// Mapping info
|
||||
//-----------------------------
|
||||
uint8_t dcch_logical_channel_identity;
|
||||
uint8_t dtch_logical_channel_identity;
|
||||
uint8_t nb_logical_channels_per_rlc;
|
||||
//-----------------------------
|
||||
// buffer occupancy measurements sent to MAC
|
||||
//-----------------------------
|
||||
// note occupancy of other buffers is deducted from nb elements in lists
|
||||
uint32_t buffer_occupancy_retransmission_buffer; // nb of pdus
|
||||
|
||||
//**************************************************************
|
||||
// new members
|
||||
//**************************************************************
|
||||
uint8_t allocation;
|
||||
uint8_t location; // UTRAN/UE
|
||||
uint8_t protocol_state;
|
||||
//-----------------------------
|
||||
// protocol variables
|
||||
//-----------------------------
|
||||
uint16_t first_li_in_next_pdu; // indicates :
|
||||
// value = 000000000000000 that the previous PDU was exactly
|
||||
// with the last segment of an RLC SDU and there is no LI that
|
||||
// indicates the end of the SDU in the previous RLC PDU.
|
||||
// value = 111111111111011 The last segment of an RLC SDU was one octet
|
||||
// short of exactly filling the previous RLC PDU and there is no LI that
|
||||
// indicates the end of the SDU in the previous RLC PDU. The remaining one
|
||||
// octet in the previous RLC PDU is ignored.
|
||||
// value = 111111111111110 AMD PDU: The rest of the RLC PDU includes a
|
||||
// piggybacked STATUS PDU.
|
||||
// value = 111111111111111 The rest of the RLC PDU is padding. The padding
|
||||
// length can be zero.
|
||||
|
||||
uint16_t vt_s; // send state variable
|
||||
// The sequence number of the next PDU to be transmitted for the
|
||||
// first time(i.e. excluding retransmission). It is updated after
|
||||
// transmission of a PDU, which includes not earlier transmitted
|
||||
// PDUs and after transmission of a MRW SUFI which includes SN_MRW
|
||||
// length > VT(S).
|
||||
uint16_t vt_a; // Acknowledged state variable
|
||||
// The sequence number of the next in sequence PDU expected to be
|
||||
// acknowledged, which forms the lower edge of the window of acceptable
|
||||
// acknowledgments. VT(A) is updated based on a receipt of a STATUS
|
||||
// PDU including an ACK and/or MRW_ACK super field.
|
||||
uint16_t max_dat; // This state variable counts the number of times a PDU has been transmited
|
||||
// There is one vt(dat) for each PDU and it is incremented each time the pdu
|
||||
// is transmited. The initial value of this variable is 0;
|
||||
uint16_t vt_ms; // Maximun send state variable
|
||||
// The sequence number of the first PDU not allowed by the receiver
|
||||
// [the receiver will allow up to VT(MS)-1], VT(MS) = VT(A)+VT(WS).
|
||||
// This value represents the upper edge of the transmit window. The
|
||||
// transmitter shall not transmit a PDU with SN>=VT(MS). VT(MS) is
|
||||
// updated when either VT(A) or VT(WS) is updated. The PDU with SN
|
||||
// VT(S)-1 can be transmitted also when VT(S) >= VT(MS).
|
||||
uint16_t vt_pdu; // not used
|
||||
uint16_t vt_sdu; // this state variable is used when the poll every Poll_SDU SDU
|
||||
// function is used. It is incremented with 1 each SDU is
|
||||
// transmitted. When it reaches Poll_SDU a new poll is transmitted
|
||||
// the state variable is set to 0. The poll bit should be set in the
|
||||
// PDU that contains the last segment of the SDU.
|
||||
uint16_t vt_rst; // Reset state variable
|
||||
// it is used to count the number of times a RESET PDU is transmitted.
|
||||
// vt(rst) is incremented with 1 each time a RESET PDU is transmitted. VT(rst) is
|
||||
// reset only upon the reception of a RESET ACK PDU, i.e. VT(RST) is not reset when
|
||||
// an RLC RESET occurs which was initiated from the peer RLC entity. The initial value
|
||||
// of this variable is 0.
|
||||
uint16_t vt_mrw; // MRW command send state variable
|
||||
// It is used to count the number of times a MRW command is transmitted.
|
||||
// VT(MRW) is reset when the discard procedure is terminated.
|
||||
uint16_t vt_ws; // transmitter window size state variable
|
||||
// The size that should be used for the transmitter window. VT(WS)
|
||||
//is set equal to the WSN field when the transmitter receives a
|
||||
// STATUS PDU including a WindowSize super-field.
|
||||
uint16_t vr_r; // Receive state variable
|
||||
// The sequence number of the next in sequence PDU expected to be
|
||||
// received. It is equal to SNmax+1 upon receipt of the next in
|
||||
// sequence PDU, where SNmax is the sequence number of the highest
|
||||
// received in sequence PDU. The initial value of this variable is 0
|
||||
uint16_t vr_h; // Highest expected state variable
|
||||
// The sequence number of the highest expected PDU. this state
|
||||
// variable is set equal to SN+1 only when a new PDU is received
|
||||
// with VR(MR)>SN>=VR(H). The initial value of this variable is 0.
|
||||
uint16_t vr_mr; // Maximum acceptable Receive state variable
|
||||
// The sequence number of the first PDU not allowed by the receiver.
|
||||
// It shall be set equal to SN+1 upon reception of a PDU. The
|
||||
// initial value of this variable is 0.
|
||||
int16_t vr_ep; // Estimated PDU counter state variable
|
||||
// The number of PDUs that should be received yet as a consequence
|
||||
// of the transmission of the latest status report. In acknowledged
|
||||
// mode, this state variable is updated at the end of each TTI. It
|
||||
// is decremented by the number of PDUs that should have been
|
||||
// received during the TTI. If VR(EP) is equal to 0, then check if
|
||||
// all PDUs requested for retransmission in the latest status report
|
||||
// have been received.
|
||||
|
||||
//-----------------------------
|
||||
// C-SAP
|
||||
//-----------------------------
|
||||
list_t c_sap;
|
||||
|
||||
//-----------------------------
|
||||
// discard
|
||||
//-----------------------------
|
||||
uint8_t sdu_discard_mode;
|
||||
uint8_t send_mrw;
|
||||
//-----------------------------
|
||||
// tranmission
|
||||
//-----------------------------
|
||||
mem_block_t **input_sdus; // should be accessed as an array
|
||||
mem_block_t *input_sdus_alloc; // allocation of the array
|
||||
uint16_t size_input_sdus_buffer;
|
||||
uint16_t nb_sdu;
|
||||
|
||||
uint16_t next_sdu_index; // next location of incoming sdu
|
||||
uint16_t current_sdu_index;
|
||||
uint32_t buffer_occupancy;
|
||||
// for segmentation procedures (optimization save space on stack)
|
||||
uint16_t li[RLC_AM_SEGMENT_NB_MAX_LI_PER_PDU];
|
||||
|
||||
|
||||
uint16_t configured_tx_window_size;
|
||||
// implementation specific: our transmiter buffer is an array whose size must be a power of 2
|
||||
uint16_t recomputed_configured_tx_window_size;
|
||||
|
||||
mem_block_t *(*rlc_segment) (struct rlc_am_entity * rlcP);
|
||||
|
||||
mem_block_t *retransmission_buffer_alloc;
|
||||
mem_block_t **retransmission_buffer;
|
||||
|
||||
list2_t retransmission_buffer_to_send; // contains PDUs that must be immediatly retransmitted
|
||||
list_t control; // contains control pdus
|
||||
|
||||
uint16_t nb_pdu_requested_by_mac_on_ch1;
|
||||
uint16_t nb_pdu_requested_by_mac_on_ch2;
|
||||
uint16_t pdu_size;
|
||||
|
||||
uint8_t li_one_byte_short_to_add_in_next_pdu;
|
||||
uint8_t li_exactly_filled_to_add_in_next_pdu;
|
||||
|
||||
list_t pdus_to_mac_layer_ch1;
|
||||
list_t pdus_to_mac_layer_ch2;
|
||||
|
||||
//-----------------------------
|
||||
// receiver
|
||||
//-----------------------------
|
||||
sdu_size_t output_sdu_size_to_write;
|
||||
mem_block_t *output_sdu_in_construction;
|
||||
|
||||
mem_block_t *receiver_buffer_alloc;
|
||||
mem_block_t **receiver_buffer;
|
||||
|
||||
uint16_t last_reassemblied_sn;
|
||||
uint16_t configured_rx_window_size;
|
||||
uint16_t recomputed_configured_rx_window_size;
|
||||
|
||||
list_t pdus_from_mac_layer_ch1;
|
||||
list_t pdus_from_mac_layer_ch2;
|
||||
|
||||
//-----------------------------
|
||||
// status generation
|
||||
//-----------------------------
|
||||
mem_block_t *holes_alloc;
|
||||
struct rlc_am_hole *holes;
|
||||
uint16_t nb_missing_pdus;
|
||||
uint16_t ack_sn;
|
||||
uint16_t nb_holes;
|
||||
# ifdef BYPASS_L1
|
||||
unsigned int pdu_counter;
|
||||
# endif
|
||||
|
||||
|
||||
unsigned int stat_tx_pdcp_sdu;
|
||||
unsigned int stat_tx_pdcp_sdu_discarded;
|
||||
unsigned int stat_tx_retransmit_pdu_unblock;
|
||||
unsigned int stat_tx_retransmit_pdu_by_status;
|
||||
unsigned int stat_tx_retransmit_pdu;
|
||||
unsigned int stat_tx_data_pdu;
|
||||
unsigned int stat_tx_control_pdu;
|
||||
|
||||
unsigned int stat_rx_sdu;
|
||||
unsigned int stat_rx_error_pdu;
|
||||
unsigned int stat_rx_data_pdu;
|
||||
unsigned int stat_rx_data_pdu_out_of_window;
|
||||
unsigned int stat_rx_control_pdu;
|
||||
};
|
||||
# endif
|
||||
@@ -1,36 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
# ifndef __RLC_AM_ERRNO_H__
|
||||
# define __RLC_AM_ERRNO_H__
|
||||
# endif
|
||||
|
||||
# define RLC_AM_OUT_OF_MEMORY_ERROR 1
|
||||
# define RLC_AM_VT_S_OVERFLOW_ERROR 2
|
||||
# define RLC_AM_RETRANS_REQ_PDU_NULL 3
|
||||
# define RLC_AM_RETRANS_REQ_PDU_DONE_BEFORE 4
|
||||
@@ -1,236 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_fsm.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_def.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
int
|
||||
rlc_am_fsm_notify_event (struct rlc_am_entity* rlcP, uint8_t eventP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
switch (rlcP->protocol_state) {
|
||||
//-------------------------------
|
||||
// RLC_NULL_STATE
|
||||
//-------------------------------
|
||||
case RLC_NULL_STATE:
|
||||
switch (eventP) {
|
||||
case RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_NULL_STATE -> RLC_DATA_TRANSFER_READY_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_DATA_TRANSFER_READY_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][FSM] WARNING PROTOCOL ERROR - EVENT %02X hex NOT EXPECTED FROM NULL_STATE frame %d\n", rlcP->rb_id, eventP, Mac_rlc_xface->frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//-------------------------------
|
||||
// RLC_DATA_TRANSFER_READY_STATE
|
||||
//-------------------------------
|
||||
case RLC_DATA_TRANSFER_READY_STATE:
|
||||
switch (eventP) {
|
||||
case RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_NULL_STATE_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_DATA_TRANSFER_READY_STATE -> RLC_NULL_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_NULL_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_RESET_EVENT:
|
||||
case RLC_AM_TRANSMIT_RESET_ACK_EVENT:
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_TRANSMIT_RESET_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_DATA_TRANSFER_READY_STATE -> RLC_RESET_PENDING_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_RESET_PENDING_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_CRLC_SUSPEND_REQ_EVENT:
|
||||
case RLC_AM_TRANSMIT_CRLC_SUSPEND_CNF_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_DATA_TRANSFER_READY_STATE -> RLC_LOCAL_SUSPEND_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_LOCAL_SUSPEND_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][FSM] WARNING PROTOCOL ERROR - EVENT 0x%02X NOT EXPECTED FROM DATA_TRANSFER_READY_STATE frame %d\n", rlcP->rb_id, eventP,
|
||||
Mac_rlc_xface->frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//-------------------------------
|
||||
// RLC_RESET_PENDING_STATE
|
||||
//-------------------------------
|
||||
case RLC_RESET_PENDING_STATE:
|
||||
switch (eventP) {
|
||||
case RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_NULL_STATE_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_RESET_PENDING_STATE -> RLC_NULL_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_NULL_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_RESET_EVENT:
|
||||
case RLC_AM_TRANSMIT_RESET_ACK_EVENT:
|
||||
case RLC_AM_TRANSMIT_RESET_EVENT: // WARNING: THIS EVENT IS NOT IN SPECS BUT MAY BE AN OMISSION ????
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_RESET_ACK_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_RESET_PENDING_STATE -> RLC_DATA_TRANSFER_READY_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_DATA_TRANSFER_READY_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_CRLC_SUSPEND_REQ_EVENT:
|
||||
case RLC_AM_TRANSMIT_CRLC_SUSPEND_CNF_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_RESET_PENDING_STATE -> RLC_RESET_AND_SUSPEND_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_RESET_AND_SUSPEND_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][FSM] WARNING PROTOCOL ERROR - EVENT 0x%02X NOT EXPECTED FROM RLC_RESET_PENDING_STATE frame %d\n", rlcP->rb_id, eventP,
|
||||
Mac_rlc_xface->frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//-------------------------------
|
||||
// RLC_RESET_AND_SUSPEND_STATE
|
||||
//-------------------------------
|
||||
case RLC_RESET_AND_SUSPEND_STATE:
|
||||
switch (eventP) {
|
||||
case RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_NULL_STATE_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_RESET_AND_SUSPEND_STATE -> RLC_NULL_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_NULL_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_RESET_ACK_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_RESET_AND_SUSPEND_STATE -> RLC_LOCAL_SUSPEND_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_LOCAL_SUSPEND_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_CRLC_RESUME_REQ_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_RESET_AND_SUSPEND_STATE -> RLC_RESET_PENDING_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_RESET_PENDING_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][FSM] WARNING PROTOCOL ERROR - EVENT 0x%02X NOT EXPECTED FROM RLC_RESET_AND_SUSPEND_STATE frame %d\n", rlcP->rb_id, eventP,
|
||||
Mac_rlc_xface->frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//-------------------------------
|
||||
// RLC_LOCAL_SUSPEND_STATE
|
||||
//-------------------------------
|
||||
case RLC_LOCAL_SUSPEND_STATE:
|
||||
switch (eventP) {
|
||||
case RLC_AM_RECEIVE_CRLC_CONFIG_REQ_ENTER_NULL_STATE_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_LOCAL_SUSPEND_STATE -> RLC_NULL_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_NULL_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_RECEIVE_CRLC_RESUME_REQ_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_LOCAL_SUSPEND_STATE -> RLC_DATA_TRANSFER_READY_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_DATA_TRANSFER_READY_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_TRANSMIT_RESET_EVENT:
|
||||
#ifdef DEBUG_RLC_AM_FSM
|
||||
msg ("[RLC_AM][RB %d][FSM] RLC_LOCAL_SUSPEND_STATE -> RLC_RESET_AND_SUSPEND_STATE frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlcP->protocol_state = RLC_RESET_AND_SUSPEND_STATE;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][FSM] WARNING PROTOCOL ERROR - EVENT 0x%02X NOT EXPECTED FROM RLC_LOCAL_SUSPEND_STATE frame %d\n", rlcP->rb_id, eventP,
|
||||
Mac_rlc_xface->frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM][RB %d][FSM] ERROR UNKNOWN STATE %d\n", rlcP->rb_id, rlcP->protocol_state);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_fsm_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_FSM_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_FSM_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "platform_types.h"
|
||||
# include "rlc_am_entity.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern int rlc_am_fsm_notify_event (struct rlc_am_entity *rlcP, uint8_t eventP);
|
||||
# endif
|
||||
@@ -1,103 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_mac_status.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_timers_proto_extern.h"
|
||||
#include "rlc_am_discard_notif_proto_extern.h"
|
||||
#include "rlc_am_reset_proto_extern.h"
|
||||
#include "rlc_am_fsm_proto_extern.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_status_report_from_mac (void* rlcP, uint16_t eventP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_entity* rlc = (struct rlc_am_entity*) rlcP;
|
||||
|
||||
//----------------------------------------
|
||||
// STATUS
|
||||
//----------------------------------------
|
||||
if ((eventP & RLC_AM_FIRST_STATUS_PDU_TYPE) == RLC_AM_FIRST_STATUS_PDU_TYPE) {
|
||||
#ifdef DEBUG_RLC_AM_MAC_STATUS
|
||||
msg ("[RLC_AM %p][MAC_STATUS] EVENT RLC_AM_FIRST_STATUS_PDU_TYPE\n", rlcP);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// DISCARD
|
||||
//----------------------------------------
|
||||
if ((eventP & RLC_AM_MRW_STATUS_PDU_TYPE)) {
|
||||
#ifdef DEBUG_RLC_AM_MAC_STATUS
|
||||
msg ("[RLC_AM %p][MAC_STATUS] EVENT RLC_AM_MRW_STATUS_PDU_TYPE\n", rlcP);
|
||||
#endif
|
||||
|
||||
// rearm the timer
|
||||
if (!(rlc->timer_mrw) && (rlc->discard_procedures.head)) {
|
||||
rlc->timer_mrw = umts_add_timer_list_up (&rlc->rlc_am_timer_list, rlc_am_discard_notify_mrw_ack_time_out, rlc,
|
||||
rlc->discard_procedures.head, (uint32_t) rlc->timer_mrw_init, *rlc->frame_tick_milliseconds);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// RESET
|
||||
//----------------------------------------
|
||||
if ((eventP & RLC_AM_RESET_PDU_TYPE)) {
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM %p][MAC_STATUS] EVENT RLC_AM_RESET_PDU_TYPE SENT ARMING RESET TIMER %d frames frame %d\n", rlcP, (uint32_t) rlc->timer_rst_init,
|
||||
*rlc->frame_tick_milliseconds);
|
||||
#endif
|
||||
rlc->timer_rst = umts_add_timer_list_up (&rlc->rlc_am_timer_list, rlc_am_reset_time_out, rlcP, NULL, (uint32_t) rlc->timer_rst_init,
|
||||
*rlc->frame_tick_milliseconds);
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// RESET ACK
|
||||
//----------------------------------------
|
||||
if ((eventP & RLC_AM_RESET_ACK_PDU_TYPE)) {
|
||||
#ifdef DEBUG_RLC_AM_MAC_STATUS
|
||||
msg ("[RLC_AM %p][MAC_STATUS] EVENT RLC_AM_RESET_ACK_PDU_TYPE\n", rlcP);
|
||||
#endif
|
||||
rlc_am_fsm_notify_event (rlc, RLC_AM_TRANSMIT_RESET_ACK_EVENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_mac_status_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_MAC_STATUS_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_MAC_STATUS_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_status_report_from_mac (void *rlcP, uint16_t eventP);
|
||||
# endif
|
||||
@@ -1,953 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_mux.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "list.h"
|
||||
#include "mem_block.h"
|
||||
#include "rlc_am_retrans_proto_extern.h"
|
||||
#include "rlc_am_mac_status_proto_extern.h"
|
||||
#include "rlc_am_discard_tx_proto_extern.h"
|
||||
#include "rlc_am_proto_extern.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//#define DEBUG_MUX
|
||||
//#define DEBUG_RLC_AM_POLL
|
||||
|
||||
#ifdef NODE_MT
|
||||
/*
|
||||
* mux PDUs from segmentation buffer and PDUs from retransmission buffer
|
||||
* onto transmission buffer
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_mux_ue (struct rlc_am_entity* rlcP, unsigned int traffic_typeP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* pdu;
|
||||
mem_block_t* sdu;
|
||||
mem_block_t* copy_pdu;
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
int pool_is_set;
|
||||
int index;
|
||||
int sdu_index;
|
||||
unsigned int j, segmentation_returned_pdu;
|
||||
unsigned int data_pdu_tx; // data pdu effectively transmitted
|
||||
unsigned int tx_pdu;
|
||||
int16_t nb_pdu_to_transmit_ch1;
|
||||
int16_t nb_pdu_to_transmit_ch2;
|
||||
# ifdef DEBUG_MUX
|
||||
uint16_t id;
|
||||
# endif
|
||||
data_pdu_tx = 0;
|
||||
nb_pdu_to_transmit_ch1 = rlcP->nb_pdu_requested_by_mac_on_ch1;
|
||||
nb_pdu_to_transmit_ch2 = rlcP->nb_pdu_requested_by_mac_on_ch2;
|
||||
|
||||
// discard
|
||||
if ((rlcP->sdu_discarded.head) && (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
rlc_am_process_sdu_discarded (rlcP);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* CONTROL PDU *
|
||||
******************************************/
|
||||
// from TS25.322 V4.2.0 p13
|
||||
// In case two logical channels are configured in the uplink, AMD PDUs are transmitted
|
||||
// on the first logical channel, and control PDUs are transmitted on the second logical
|
||||
// channel.
|
||||
if (rlcP->nb_logical_channels_per_rlc == 1) {
|
||||
while ((rlcP->control.head) && (nb_pdu_to_transmit_ch1)) {
|
||||
pdu = list_remove_head (&rlcP->control);
|
||||
|
||||
if ((traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
if (((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type & (RLC_AM_RESET_PDU_TYPE | RLC_AM_RESET_ACK_PDU_TYPE)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
tx_pdu = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tx_pdu)) {
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_tb_type = ((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (pdu->data))->data_ptr = &pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)];
|
||||
((struct mac_tb_req*) (pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d][MUX] TX CONTROL PDU CH1 VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
free_mem_block (pdu);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (rlcP->nb_logical_channels_per_rlc == 2) {
|
||||
while ((rlcP->control.head) && (nb_pdu_to_transmit_ch2)) {
|
||||
pdu = list_remove_head (&rlcP->control);
|
||||
|
||||
if ((traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
if (((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type & (RLC_AM_RESET_PDU_TYPE | RLC_AM_RESET_ACK_PDU_TYPE)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
tx_pdu = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tx_pdu)) {
|
||||
nb_pdu_to_transmit_ch2--;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_tb_type = ((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (pdu->data))->data_ptr = &pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)];
|
||||
((struct mac_tb_req*) (pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (pdu, &rlcP->pdus_to_mac_layer_ch2);
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d][MUX] TX CONTROL PDU CH2 VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X \n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
free_mem_block (pdu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_DATA) {
|
||||
/******************************************
|
||||
* RETRANSMITED DATA PDU *
|
||||
******************************************/
|
||||
// priority is then made at retransmitted PDUs
|
||||
while ((rlcP->retransmission_buffer_to_send.head) && (nb_pdu_to_transmit_ch1) && !(rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
// each retransmission may send RLC in RESET STATE if no discard is configured
|
||||
copy_pdu = list2_remove_head (&rlcP->retransmission_buffer_to_send);
|
||||
// unlink the pdu in retransmission buffer and its copy (mechanism avoiding multi-retransmission of the same
|
||||
// pdu in the same queue)
|
||||
pdu = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->copy;
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(copy_pdu);
|
||||
# endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy = NULL;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
data_pdu_tx++;
|
||||
|
||||
// for polling
|
||||
if (rlcP->poll_pdu_trigger) {
|
||||
rlcP->vt_pdu++;
|
||||
|
||||
if (rlcP->vt_pdu >= rlcP->poll_pdu_trigger) {
|
||||
// set poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_pdu = 0;
|
||||
|
||||
} else {
|
||||
// reset poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 =
|
||||
(((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2) & ~RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) |
|
||||
((((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] RETRANSMIT DATA PDU %04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* DATA PDU *
|
||||
******************************************/
|
||||
if (!(rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
segmentation_returned_pdu = 1;
|
||||
|
||||
while ((nb_pdu_to_transmit_ch1) && (rlcP->vt_s != rlcP->vt_ms) && (segmentation_returned_pdu) && !(rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
if ((pdu = rlcP->rlc_segment (rlcP))) {
|
||||
rlc_header = (struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]);
|
||||
// check polling
|
||||
pool_is_set = 0;
|
||||
|
||||
if (rlcP->poll_pdu_trigger) {
|
||||
rlcP->vt_pdu++;
|
||||
|
||||
// test every poll_PDU trigger
|
||||
if (rlcP->vt_pdu >= rlcP->poll_pdu_trigger) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
rlc_header->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_pdu = 0;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY poll_pdu trigger\n", rlcP);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
// test every poll_SDU trigger
|
||||
if ((rlcP->poll_sdu_trigger) && (((struct rlc_am_tx_data_pdu_management*) (pdu->data))->last_pdu_of_sdu)) {
|
||||
if (rlcP->vt_sdu >= rlcP->poll_sdu_trigger) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
rlc_header->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_sdu = 0;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY poll_sdu trigger\n", rlcP);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
rlcP->vt_sdu += ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->last_pdu_of_sdu;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pool_is_set) {
|
||||
// test last pdu in transmission buffer trigger == last sdu in input buffer in this implementation of RLC AM
|
||||
if ((rlcP->last_transmission_pdu_poll_trigger > 0) && (rlcP->nb_sdu == 0)) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
rlc_header->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY last pdu in tr buffer trigger\n", rlcP);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!pool_is_set) {
|
||||
// test last pdu in retransmission buffer trigger
|
||||
if ((rlcP->retransmission_buffer_to_send.head) && (rlcP->retransmission_buffer_to_send.head == rlcP->retransmission_buffer_to_send.tail)
|
||||
&& (rlcP->last_retransmission_pdu_poll_trigger)) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
rlc_header->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY last pdu in retrans buffer trigger\n", rlcP);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!pool_is_set) {
|
||||
// test window based trigger
|
||||
if (rlcP->poll_window_trigger) {
|
||||
j = (unsigned int) (((rlcP->vt_s + 4096) - rlcP->vt_a) % 4096) * 100 / rlcP->vt_ws;
|
||||
|
||||
if (j >= rlcP->poll_window_trigger) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
rlc_header->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p][POOL] POOL SET BY window based trigger j=%d\n", rlcP, j);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rlc_header->byte1 |= (rlcP->vt_s >> 5);
|
||||
rlc_header->byte2 |= ((uint8_t) rlcP->vt_s << 3);
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sn = rlcP->vt_s;
|
||||
insert_into_retransmission_buffer (rlcP, rlcP->vt_s % rlcP->recomputed_configured_tx_window_size, pdu);
|
||||
|
||||
// check if timer based discard configured
|
||||
if ((rlcP->sdu_discard_mode & RLC_SDU_DISCARD_TIMER_BASED_EXPLICIT)) {
|
||||
for (index = 0; index < ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->nb_sdu; index++) {
|
||||
sdu_index = ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index];
|
||||
sdu = rlcP->input_sdus[sdu_index];
|
||||
|
||||
// mark the sdu as invalid except if confirm requested
|
||||
if (!((struct rlc_am_tx_sdu_management*) (sdu->data))->confirm) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index] = -1; // tag sdu as non valid
|
||||
}
|
||||
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->nb_pdus_time += 1;
|
||||
|
||||
if ((((struct rlc_am_tx_sdu_management*) (sdu->data))->nb_pdus_time ==
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->nb_pdus) &&
|
||||
!(((struct rlc_am_tx_sdu_management*) (sdu->data))->confirm) && (((struct rlc_am_tx_sdu_management*) (sdu->data))->segmented)
|
||||
) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index] = -1; // tag sdu as non valid
|
||||
// we can remove the sdu if timer based discard and all pdus submitted to lower layers and no confirm running
|
||||
free_mem_block (sdu);
|
||||
rlcP->input_sdus[sdu_index] = NULL;
|
||||
# ifdef DEBUG_RLC_AM_FREE_SDU
|
||||
msg ("[RLC_AM][RB %d] MUX FREE_SDU INDEX %d\n", rlcP->rb_id, sdu_index);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->last_pdu_sn = rlcP->vt_s;
|
||||
}
|
||||
}
|
||||
|
||||
} else if ((rlcP->sdu_discard_mode & RLC_SDU_DISCARD_MAX_DAT_RETRANSMISSION)) {
|
||||
for (index = 0; index < ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->nb_sdu; index++) {
|
||||
// update the sn of the last transmitted pdu were this sdu was segmented
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index]]->data))->last_pdu_sn = rlcP->vt_s;
|
||||
// register the sn of the pdus where the sdu was segmented
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index]]->data))->
|
||||
pdus_index[((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[((struct rlc_am_tx_data_pdu_management*) (
|
||||
pdu->data))->sdu[index]]->data))->nb_pdus_internal_use++] = rlcP->vt_s;
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d] MUX SDU INDEX %d LINK PDU SN 0x%04X\n", rlcP->rb_id, ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index], rlcP->vt_s);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
rlcP->vt_s = (rlcP->vt_s + 1) & SN_12BITS_MASK;
|
||||
copy_pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (copy_pdu) {
|
||||
memcpy (copy_pdu->data, pdu->data, rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation));
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(pdu);
|
||||
# endif
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
data_pdu_tx++;
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (rlc_header->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) | ((rlc_header->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] TX DATA PDU 0x%04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
/* for (index = 0; index < 32 ; index++) {
|
||||
msg("%02X.", pdu->data[index]);
|
||||
}
|
||||
msg("\n");
|
||||
*/
|
||||
# endif
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM][RB %d][MUX] OUT OF MEMORY \n", rlcP->rb_id);
|
||||
}
|
||||
|
||||
} else { // segmentation returned no PDU
|
||||
segmentation_returned_pdu = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
// - if a poll has been triggered by either the poll triggers "Poll timer" or "Timer based" (see subclause 9.7.1);
|
||||
// AND
|
||||
// - if no AMD PDU is scheduled for transmission or retransmission:
|
||||
// - if the value of "Configured_Tx_Window_Size" is larger than or equal to "2048":
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1.
|
||||
// - otherwise if the "Configured_Tx_Window_Size" is less than "2048";
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1; or
|
||||
// - select an AMD PDU that has not yet been acknowledged by the peer entity;
|
||||
// - schedule the selected AMD PDU for retransmission (in order to transmit a poll).
|
||||
// The Sender may also schedule an AMD PDU for retransmission even if none of the criteria above is fulfilled. In this case, the Sender may:
|
||||
// - if the value of "Configured_Tx_Window_Size" is larger than or equal to "2048":
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1.
|
||||
// - otherwise if the "Configured_Tx_Window_Size" is less than "2048":
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1; or
|
||||
// - select an AMD PDU that has not yet been acknowledged by the peer entity;
|
||||
// - schedule the selected AMD PDU for retransmission.
|
||||
// TO DO : triggers "Poll timer" or "Timer based"
|
||||
if (!(data_pdu_tx)) {
|
||||
if (rlcP->configured_tx_window_size < 2048) {
|
||||
rlc_am_get_not_acknowledged_pdu_optimized (rlcP);
|
||||
|
||||
} else if (rlcP->vt_s != rlcP->vt_a) {
|
||||
rlc_am_get_not_acknowledged_pdu_optimized (rlcP);//rlc_am_get_not_acknowledged_pdu_vt_s_minus_1 (rlcP);
|
||||
}
|
||||
|
||||
// each retransmission may send RLC in RESET STATE if no discard is configured
|
||||
copy_pdu = list2_remove_head (&rlcP->retransmission_buffer_to_send);
|
||||
|
||||
if ((copy_pdu)) {
|
||||
// unlink the pdu in retransmission buffer and its copy (mechanism avoiding multi-retransmission of the same
|
||||
// pdu in the same queue)
|
||||
pdu = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->copy;
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(copy_pdu);
|
||||
# endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy = NULL;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
data_pdu_tx++;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
// set poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) |
|
||||
((((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] RETRANSMIT DATA PDU 0x%04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef NODE_RG
|
||||
//#define DEBUG_MUX
|
||||
/*
|
||||
* mux PDUs from segmentation buffer and PDUs from retransmission buffer
|
||||
* onto transmission buffer
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_mux_rg (struct rlc_am_entity* rlcP, unsigned int traffic_typeP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* pdu;
|
||||
mem_block_t* sdu;
|
||||
mem_block_t* copy_pdu = NULL;
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
int pool_is_set;
|
||||
int index;
|
||||
int sdu_index;
|
||||
unsigned int j, segmentation_returned_pdu;
|
||||
unsigned int data_pdu_tx; // data pdu effectively transmitted
|
||||
unsigned int tx_pdu;
|
||||
static unsigned int last_scheduled;
|
||||
int16_t nb_pdu_to_transmit_ch1;
|
||||
int16_t nb_pdu_to_transmit_ch2;
|
||||
# ifdef DEBUG_MUX
|
||||
uint16_t id;
|
||||
# endif
|
||||
data_pdu_tx = 0;
|
||||
nb_pdu_to_transmit_ch1 = rlcP->nb_pdu_requested_by_mac_on_ch1;
|
||||
nb_pdu_to_transmit_ch2 = rlcP->nb_pdu_requested_by_mac_on_ch2;
|
||||
|
||||
// discard
|
||||
if ((rlcP->sdu_discarded.head) && (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
rlc_am_process_sdu_discarded (rlcP);
|
||||
}
|
||||
|
||||
// from TS25.322 V4.2.0 p13
|
||||
// In case two logical channels are configured in the downlink, AMD and Control
|
||||
// PDUs can be transmitted on any of the two logical channels.
|
||||
/******************************************
|
||||
* CONTROL PDU *
|
||||
******************************************/
|
||||
if (rlcP->nb_logical_channels_per_rlc == 1) {
|
||||
while ((rlcP->control.head) && (nb_pdu_to_transmit_ch1)) {
|
||||
pdu = list_remove_head (&rlcP->control);
|
||||
|
||||
if ((traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
if (((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type & (RLC_AM_RESET_PDU_TYPE | RLC_AM_RESET_ACK_PDU_TYPE)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
tx_pdu = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tx_pdu)) {
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_tb_type = ((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (pdu->data))->data_ptr = &pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)];
|
||||
((struct mac_tb_req*) (pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
rlcP->stat_tx_control_pdu += 1;
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d][MUX] TX CONTROL PDU CH1 VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
free_mem_block (pdu);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (rlcP->nb_logical_channels_per_rlc == 2) {
|
||||
while ((rlcP->control.head) && (nb_pdu_to_transmit_ch2)) {
|
||||
pdu = list_remove_head (&rlcP->control);
|
||||
|
||||
if ((traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
if (((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type & (RLC_AM_RESET_PDU_TYPE | RLC_AM_RESET_ACK_PDU_TYPE)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
tx_pdu = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tx_pdu)) {
|
||||
nb_pdu_to_transmit_ch2--;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_tb_type = ((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (pdu->data))->data_ptr = &pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)];
|
||||
((struct mac_tb_req*) (pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (pdu, &rlcP->pdus_to_mac_layer_ch2);
|
||||
rlcP->stat_tx_control_pdu += 1;
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d][MUX] TX CONTROL PDU CH2 VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
free_mem_block (pdu);
|
||||
}
|
||||
}
|
||||
|
||||
while ((rlcP->control.head) && (nb_pdu_to_transmit_ch1)) {
|
||||
pdu = list_remove_head (&rlcP->control);
|
||||
|
||||
if ((traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_STATUS)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
if (((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type & (RLC_AM_RESET_PDU_TYPE | RLC_AM_RESET_ACK_PDU_TYPE)) {
|
||||
tx_pdu = 1;
|
||||
|
||||
} else {
|
||||
tx_pdu = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tx_pdu)) {
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_tb_type = ((struct rlc_am_tx_control_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (pdu->data))->data_ptr = &pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)];
|
||||
((struct mac_tb_req*) (pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
rlcP->stat_tx_control_pdu += 1;
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d][MUX] TX CONTROL PDU CH1 VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
free_mem_block (pdu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (traffic_typeP & RLC_AM_TRAFFIC_ALLOWED_FOR_DATA) {
|
||||
/******************************************
|
||||
* RETRANSMITED DATA PDU *
|
||||
******************************************/
|
||||
while ((rlcP->retransmission_buffer_to_send.head) && (nb_pdu_to_transmit_ch1) && !(rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
// each retransmission may send RLC in RESET STATE if no discard is configured
|
||||
copy_pdu = list2_remove_head (&rlcP->retransmission_buffer_to_send);
|
||||
// unlink the pdu in retransmission buffer and its copy (mechanism avoiding multi-retransmission of the same
|
||||
// pdu in the same queue)
|
||||
pdu = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->copy;
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(copy_pdu);
|
||||
# endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy = NULL;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
rlcP->stat_tx_retransmit_pdu += 1;
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
data_pdu_tx++;
|
||||
|
||||
// for polling
|
||||
if (rlcP->poll_pdu_trigger) {
|
||||
rlcP->vt_pdu++;
|
||||
|
||||
if (rlcP->vt_pdu >= rlcP->poll_pdu_trigger) {
|
||||
// set poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_pdu = 0;
|
||||
|
||||
} else {
|
||||
// reset poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 =
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & ~RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) |
|
||||
((((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] RETRANSMIT DATA PDU %04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
}
|
||||
|
||||
while ((rlcP->retransmission_buffer_to_send.head) && (nb_pdu_to_transmit_ch2) && !(rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
// each retransmission may send RLC in RESET STATE if no discard is configured
|
||||
copy_pdu = list2_remove_head (&rlcP->retransmission_buffer_to_send);
|
||||
// unlink the pdu in retransmission buffer and its copy (mechanism avoiding multi-retransmission of the same
|
||||
// pdu in the same queue)
|
||||
pdu = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->copy;
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(copy_pdu);
|
||||
# endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy = NULL;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch2);
|
||||
rlcP->stat_tx_retransmit_pdu += 1;
|
||||
nb_pdu_to_transmit_ch2--;
|
||||
data_pdu_tx++;
|
||||
|
||||
// for polling
|
||||
if (rlcP->poll_pdu_trigger) {
|
||||
rlcP->vt_pdu++;
|
||||
|
||||
if (rlcP->vt_pdu >= rlcP->poll_pdu_trigger) {
|
||||
// set poll bit
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY poll_pdu trigger RETRANS PDU\n", rlcP);
|
||||
# endif
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_pdu = 0;
|
||||
|
||||
} else {
|
||||
// reset poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 =
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & ~RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) |
|
||||
((((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] RETRANSMIT DATA PDU 0x%04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* DATA PDU *
|
||||
******************************************/
|
||||
if (!(rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
segmentation_returned_pdu = 1;
|
||||
|
||||
while (((nb_pdu_to_transmit_ch1) || (nb_pdu_to_transmit_ch2)) && (rlcP->vt_s != rlcP->vt_ms) && (segmentation_returned_pdu)) {
|
||||
if ((pdu = rlcP->rlc_segment (rlcP))) {
|
||||
rlc_header = (struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]);
|
||||
// check polling
|
||||
pool_is_set = 0;
|
||||
|
||||
if (rlcP->poll_pdu_trigger) {
|
||||
rlcP->vt_pdu++;
|
||||
|
||||
// test every poll_PDU trigger
|
||||
if (rlcP->vt_pdu >= rlcP->poll_pdu_trigger) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_pdu = 0;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY poll_pdu trigger\n", rlcP);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
// test every poll_SDU trigger
|
||||
if ((rlcP->poll_sdu_trigger) && (((struct rlc_am_tx_data_pdu_management*) (pdu->data))->last_pdu_of_sdu)) {
|
||||
if (rlcP->vt_sdu >= rlcP->poll_sdu_trigger) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
rlcP->vt_sdu = 0;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY poll_sdu trigger\n", rlcP);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
rlcP->vt_sdu += ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->last_pdu_of_sdu;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pool_is_set) {
|
||||
// test last pdu in transmission buffer trigger == last sdu in input buffer in this implementation of RLC AM
|
||||
if ((rlcP->last_transmission_pdu_poll_trigger > 0) && (rlcP->nb_sdu == 0)) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY last pdu in tr buffer trigger\n", rlcP);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!pool_is_set) {
|
||||
// test last pdu in retransmission buffer trigger
|
||||
if ((rlcP->retransmission_buffer_to_send.head) && (rlcP->retransmission_buffer_to_send.head == rlcP->retransmission_buffer_to_send.tail)
|
||||
&& (rlcP->last_retransmission_pdu_poll_trigger)) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY last pdu in retrans buffer trigger\n", rlcP);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (!pool_is_set) {
|
||||
// test window based trigger
|
||||
if (rlcP->poll_window_trigger) {
|
||||
j = (unsigned int) (((rlcP->vt_s + 4096) - rlcP->vt_a) % 4096) * 100 / rlcP->vt_ws;
|
||||
|
||||
if (j >= rlcP->poll_window_trigger) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_DATA_POLL_PDU_TYPE;
|
||||
((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
pool_is_set = 1;
|
||||
# ifdef DEBUG_RLC_AM_POLL
|
||||
msg ("[RLC_AM %p] POOL SET BY window based trigger J=%d\n", rlcP, j);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rlc_header->byte1 |= (rlcP->vt_s >> 5);
|
||||
rlc_header->byte2 |= ((uint8_t) rlcP->vt_s << 3);
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sn = rlcP->vt_s;
|
||||
insert_into_retransmission_buffer (rlcP, rlcP->vt_s % rlcP->recomputed_configured_tx_window_size, pdu);
|
||||
|
||||
// check if timer based discard configured
|
||||
if ((rlcP->sdu_discard_mode & RLC_SDU_DISCARD_TIMER_BASED_EXPLICIT)) {
|
||||
for (index = 0; index < ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->nb_sdu; index++) {
|
||||
sdu_index = ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index];
|
||||
sdu = rlcP->input_sdus[sdu_index];
|
||||
|
||||
// mark the sdu as invalid except if confirm requested
|
||||
if (!((struct rlc_am_tx_sdu_management*) (sdu->data))->confirm) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index] = -1; // tag sdu as non valid
|
||||
}
|
||||
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->nb_pdus_time += 1;
|
||||
|
||||
if ((((struct rlc_am_tx_sdu_management*) (sdu->data))->nb_pdus_time ==
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->nb_pdus) &&
|
||||
!(((struct rlc_am_tx_sdu_management*) (sdu->data))->confirm) && (((struct rlc_am_tx_sdu_management*) (sdu->data))->segmented)
|
||||
) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index] = -1; // tag sdu as non valid
|
||||
// we can remove the sdu if timer based discard and all pdus submitted to lower layers and no confirm running
|
||||
free_mem_block (sdu);
|
||||
rlcP->input_sdus[sdu_index] = NULL;
|
||||
# ifdef DEBUG_RLC_AM_FREE_SDU
|
||||
msg ("[RLC_AM][RB %d] MUX FREE_SDU INDEX %d\n", rlcP->rb_id, sdu_index);
|
||||
# endif
|
||||
|
||||
} else {
|
||||
((struct rlc_am_tx_sdu_management*) (sdu->data))->last_pdu_sn = rlcP->vt_s;
|
||||
}
|
||||
}
|
||||
|
||||
} else if ((rlcP->sdu_discard_mode & RLC_SDU_DISCARD_MAX_DAT_RETRANSMISSION)) {
|
||||
for (index = 0; index < ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->nb_sdu; index++) {
|
||||
// update the sn of the last transmitted pdu were this sdu was segmented
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index]]->data))->last_pdu_sn = rlcP->vt_s;
|
||||
// register the sn of the pdus where the sdu was segmented
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index]]->data))->
|
||||
pdus_index[((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[((struct rlc_am_tx_data_pdu_management*) (
|
||||
pdu->data))->sdu[index]]->data))->nb_pdus_internal_use++] = rlcP->vt_s;
|
||||
# ifdef DEBUG_MUX
|
||||
msg ("[RLC_AM][RB %d] MUX SDU INDEX %d LINK PDU SN 0x%04X\n", rlcP->rb_id, ((struct rlc_am_tx_data_pdu_management*) (pdu->data))->sdu[index], rlcP->vt_s);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
rlcP->vt_s = (rlcP->vt_s + 1) & SN_12BITS_MASK;
|
||||
copy_pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (copy_pdu) {
|
||||
memcpy (copy_pdu->data, pdu->data, rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation));
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(copy_pdu);
|
||||
# endif
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
|
||||
if ((nb_pdu_to_transmit_ch1)) {
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
rlcP->stat_tx_data_pdu += 1;
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
|
||||
} else if ((nb_pdu_to_transmit_ch2)) {
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch2);
|
||||
rlcP->stat_tx_data_pdu += 1;
|
||||
nb_pdu_to_transmit_ch2--;
|
||||
}
|
||||
|
||||
data_pdu_tx++;
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) |
|
||||
((((struct rlc_am_pdu_header*) (&pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] TX DATA PDU 0x%04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
/* for (index = 0; index < 32 ; index++) {
|
||||
msg("%02X.", pdu->data[index]);
|
||||
}
|
||||
msg("\n");
|
||||
*/
|
||||
# endif
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM][RB %d][MUX] OUT OF MEMORY \n", rlcP->rb_id);
|
||||
}
|
||||
|
||||
} else { // segmentation returned no PDU
|
||||
segmentation_returned_pdu = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From 3GPP TS 25.322 V5.0.0 (2001-09)
|
||||
// - if a poll has been triggered by either the poll triggers "Poll timer" or "Timer based" (see subclause 9.7.1);
|
||||
// AND
|
||||
// - if no AMD PDU is scheduled for transmission or retransmission:
|
||||
// - if the value of "Configured_Tx_Window_Size" is larger than or equal to "2048":
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1.
|
||||
// - otherwise if the "Configured_Tx_Window_Size" is less than "2048";
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1; or
|
||||
// - select an AMD PDU that has not yet been acknowledged by the peer entity;
|
||||
// - schedule the selected AMD PDU for retransmission (in order to transmit a poll).
|
||||
// The Sender may also schedule an AMD PDU for retransmission even if none of the criteria above is fulfilled. In this case, the Sender may:
|
||||
// - if the value of "Configured_Tx_Window_Size" is larger than or equal to "2048":
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1.
|
||||
// - otherwise if the "Configured_Tx_Window_Size" is less than "2048":
|
||||
// - select the AMD PDU with "Sequence Number" equal to VT(S)-1; or
|
||||
// - select an AMD PDU that has not yet been acknowledged by the peer entity;
|
||||
// - schedule the selected AMD PDU for retransmission.
|
||||
// TO DO : triggers "Poll timer" or "Timer based"
|
||||
if (!(data_pdu_tx)) {
|
||||
// this variable last_scheduled is used because a RLC may be scheduled
|
||||
// when several DSCH are configured in the RG
|
||||
if ((last_scheduled != (unsigned int) Mac_rlc_xface->frame) && (((unsigned int) Mac_rlc_xface->frame) % 48 == 0) ) {
|
||||
if (rlcP->configured_tx_window_size < 2048) {
|
||||
// rlc_am_get_not_acknowledged_pdu(rlcP);
|
||||
rlc_am_get_not_acknowledged_pdu_optimized (rlcP);
|
||||
//rlc_am_get_not_acknowledged_pdu_vt_s_minus_1 (rlcP); // LG JUST FOR TEST
|
||||
|
||||
} else if (rlcP->vt_s != rlcP->vt_a) {
|
||||
rlc_am_get_not_acknowledged_pdu_optimized (rlcP);//rlc_am_get_not_acknowledged_pdu_vt_s_minus_1 (rlcP);
|
||||
}
|
||||
}
|
||||
|
||||
last_scheduled = (unsigned int) Mac_rlc_xface->frame;
|
||||
// each retransmission may send RLC in RESET STATE if no discard is configured
|
||||
copy_pdu = list2_remove_head (&rlcP->retransmission_buffer_to_send);
|
||||
|
||||
if ((copy_pdu)) {
|
||||
// unlink the pdu in retransmission buffer and its copy (mechanism avoiding multi-retransmission of the same
|
||||
// pdu in the same queue)
|
||||
pdu = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->copy;
|
||||
# ifdef DEBUG_MUX
|
||||
rlc_am_display_data_pdu7(copy_pdu);
|
||||
# endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (pdu->data))->copy = NULL;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_tb_type = ((struct rlc_am_tx_data_pdu_management*) (copy_pdu->data))->rlc_tb_type;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc = rlcP;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->rlc_callback = rlc_am_status_report_from_mac;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->data_ptr = ©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
((struct mac_tb_req*) (copy_pdu->data))->first_bit = 0;
|
||||
((struct mac_tb_req*) (copy_pdu->data))->tb_size_in_bits = rlcP->pdu_size << 3;
|
||||
list_add_tail_eurecom (copy_pdu, &rlcP->pdus_to_mac_layer_ch1);
|
||||
rlcP->stat_tx_retransmit_pdu += 1;
|
||||
nb_pdu_to_transmit_ch1--;
|
||||
data_pdu_tx++;
|
||||
// for polling
|
||||
rlcP->vt_pdu++;
|
||||
// set poll bit
|
||||
((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 |= RLC_AM_P_STATUS_REPORT_REQUESTED;
|
||||
# ifdef DEBUG_MUX
|
||||
id = (((uint16_t) (((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) |
|
||||
((((struct rlc_am_pdu_header*) (©_pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)]))->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
msg ("[RLC_AM][RB %d][MUX] RETRANSMIT DATA PDU 0x%04X VT(A) 0x%03X VT(S) 0x%03X VT(MS) 0x%03X VR(R) 0x%03X VR(MR) 0x%03X\n",
|
||||
rlcP->rb_id, id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vr_r, rlcP->vr_mr);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,51 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_mux_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_MUX_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_MUX_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "rlc_am_constants.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
# ifdef NODE_MT
|
||||
extern void rlc_am_mux_ue (struct rlc_am_entity *rlcP, unsigned int traffic_typeP);
|
||||
# endif
|
||||
# ifdef NODE_RG
|
||||
extern void rlc_am_mux_rg (struct rlc_am_entity *rlcP, unsigned int traffic_typeP);
|
||||
# endif
|
||||
# endif
|
||||
@@ -1,64 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "platform_types.h"
|
||||
# include "platform_constants.h"
|
||||
# include "list.h"
|
||||
# include "rlc_am_entity.h"
|
||||
# include "mac_primitives.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void display_protocol_vars_rlc_am (struct rlc_am_entity *rlcP);
|
||||
extern uint32_t rlc_am_get_buffer_occupancy (struct rlc_am_entity *rlcP, uint8_t logical_channelsP);
|
||||
extern void init_rlc_am (struct rlc_am_entity *rlcP);
|
||||
extern void *rlc_am_tx (void *argP);
|
||||
extern void rlc_am_rx (void *argP, struct mac_data_ind data_indP);
|
||||
extern void *init_code_rlc_am (void *t);
|
||||
extern void send_rlc_am_control_primitive (struct rlc_am_entity *rlcP, module_id_t module_idP, mem_block_t * cprimitiveP);
|
||||
extern void rlc_am_send_mac_data_request (void *macP, uint8_t logical_channel_identityP, list_t * pduP);
|
||||
|
||||
extern struct mac_status_resp rlc_am_mac_status_indication (void *rlcP, uint16_t no_tbP, uint16_t tb_sizeP, struct mac_status_ind tx_statusP);
|
||||
extern struct mac_status_resp rlc_am_mac_status_indication_on_first_channel (void *rlcP, uint16_t no_tbP, uint16_t tb_sizeP, struct mac_status_ind tx_statusP);
|
||||
extern struct mac_status_resp rlc_am_mac_status_indication_on_second_channel (void *rlcP, uint16_t no_tbP, uint16_t tb_sizeP, struct mac_status_ind tx_statusP);
|
||||
extern struct mac_data_req rlc_am_mac_data_request (void *rlcP);
|
||||
extern struct mac_data_req rlc_am_mac_data_request_on_first_channel (void *rlcP);
|
||||
extern struct mac_data_req rlc_am_mac_data_request_on_second_channel (void *rlcP);
|
||||
extern void rlc_am_mac_data_indication (void *rlcP, struct mac_data_ind data_indP);
|
||||
extern void rlc_am_data_req (void *rlcP, mem_block_t * sduP);
|
||||
# endif
|
||||
@@ -1,134 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_reassembly.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#define RLC_AM_C
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc.h"
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "list.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
#define DEBUG_RLC_AM_SEND_SDU
|
||||
//#define DEBUG_REASSEMBLY
|
||||
//#define DEBUG_RLC_AM_DISPLAY_ASCII_DATA
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
reassembly (uint8_t* srcP, uint16_t lengthP, struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
int sdu_max_size_allowed;
|
||||
#ifdef DEBUG_RLC_AM_DISPLAY_ASCII_DATA
|
||||
int index;
|
||||
#endif
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] reassembly() %d bytes\n", rlcP->rb_id, lengthP);
|
||||
#endif
|
||||
|
||||
if ((rlcP->data_plane)) {
|
||||
sdu_max_size_allowed = RLC_SDU_MAX_SIZE_DATA_PLANE;
|
||||
|
||||
} else {
|
||||
sdu_max_size_allowed = RLC_SDU_MAX_SIZE_CONTROL_PLANE;
|
||||
}
|
||||
|
||||
if (rlcP->output_sdu_in_construction == NULL) {
|
||||
rlcP->output_sdu_in_construction = get_free_mem_block (sdu_max_size_allowed);
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] reassembly() %d bytes sdu_max_size allowed %d\n", rlcP->rb_id, lengthP, sdu_max_size_allowed);
|
||||
#endif
|
||||
|
||||
if ((rlcP->output_sdu_in_construction)) {
|
||||
#ifdef DEBUG_RLC_AM_DISPLAY_ASCII_DATA
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] DATA :", rlcP->rb_id);
|
||||
|
||||
for (index = 0; index < lengthP; index++) {
|
||||
//msg ("%c", srcP[index]);
|
||||
msg ("%02X.", srcP[index]);
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
#endif
|
||||
|
||||
// OOOPS
|
||||
if ((lengthP + rlcP->output_sdu_size_to_write) <= sdu_max_size_allowed) {
|
||||
memcpy (&rlcP->output_sdu_in_construction->data[rlcP->output_sdu_size_to_write], srcP, lengthP);
|
||||
rlcP->output_sdu_size_to_write += lengthP;
|
||||
|
||||
} else {
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM %p][REASSEMBLY] ERROR SDU IN CONSTRUCTION TOO BIG %d Bytes MAX SIZE ALLOWED %d\n", rlcP, lengthP + rlcP->output_sdu_size_to_write,
|
||||
sdu_max_size_allowed);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
|
||||
else {
|
||||
msg ("[RLC_AM %p][REASSEMBLY] ERROR OUTPUT SDU IS NULL\n", rlcP);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
send_sdu (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
if ((rlcP->output_sdu_in_construction) && (rlcP->output_sdu_size_to_write)) {
|
||||
#ifdef DEBUG_RLC_AM_SEND_SDU
|
||||
msg ("[RLC_AM][RB %d][SEND_SDU] send_SDU() %d bytes\n", rlcP->rb_id, rlcP->output_sdu_size_to_write);
|
||||
#endif
|
||||
#ifdef BENCH_QOS_L2
|
||||
fprintf (bench_l2, "[SDU DELIVERY] FRAME %d SIZE %d RB %d RLC-AM %p\n", Mac_rlc_xface->frame, rlcP->output_sdu_size_to_write, rlcP->rb_id, rlcP);
|
||||
#endif
|
||||
rlc_data_ind (rlcP->module_id, rlcP->rb_id, rlcP->output_sdu_size_to_write, rlcP->output_sdu_in_construction, rlcP->data_plane);
|
||||
rlcP->output_sdu_in_construction = NULL;
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
rlcP->stat_rx_sdu += 1;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_reassembly_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_REASSEMBLY_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_REASSEMBLY_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void reassembly (uint8_t * srcP, uint16_t lengthP, struct rlc_am_entity *rlcP);
|
||||
extern void send_sdu (struct rlc_am_entity *rlcP);
|
||||
# endif
|
||||
@@ -1,626 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_receiver.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_def.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_am_reassembly_proto_extern.h"
|
||||
#include "rlc_am_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "mem_block.h"
|
||||
|
||||
//#define DEBUG_RECEIVER_BUFFER
|
||||
//#define DEBUG_REASSEMBLY
|
||||
//#define DEBUG_STATUS
|
||||
//-----------------------------------------------------------------------------
|
||||
void receiver_retransmission_management (struct rlc_am_entity* rlcP, mem_block_t* pduP, struct rlc_am_pdu_header* rlc_headerP);
|
||||
void free_receiver_buffer (struct rlc_am_entity* rlcP, uint16_t indexP);
|
||||
void insert_into_receiver_buffer (struct rlc_am_entity* rlcP, uint16_t indexP, mem_block_t* pduP);
|
||||
void process_receiver_buffer_15 (struct rlc_am_entity* rlcP);
|
||||
void process_receiver_buffer_7 (struct rlc_am_entity* rlcP);
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
receiver_retransmission_management (struct rlc_am_entity* rlcP, mem_block_t* pduP, struct rlc_am_pdu_header* rlc_headerP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t id;
|
||||
uint16_t id_index;
|
||||
/* From TS25.3222 V5.0.0
|
||||
Upon reception of an AMD PDU, the Receiver shall:
|
||||
- update VR(R), VR(H) and VR(MR) state variables for each received AMD PDU (see clause 9.4);
|
||||
- if a received AMD PDU includes a "Polling bit" set to "1", or "Missing PDU Indicator" is configured and the
|
||||
Receiver detects that a PDU is missing:
|
||||
- initiate the STATUS PDU transfer procedure;
|
||||
- reassemble the received AMD PDUs into RLC SDUs;
|
||||
- if "In-Sequence Delivery" is configured:
|
||||
- deliver the RLC SDUs in-sequence (i.e. in the same order as the RLC SDUs were originally transmitted by
|
||||
the peer entity) to upper layers through the AM-SAP.
|
||||
- otherwise: (NOT IMPLEMENTED)
|
||||
- deliver the RLC SDUs in arbitrary order to upper layers through the AM-SAP. */
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg("[RLC_AM][DEBUG] receiver_retransmission_management() received PDU %p\n", pduP);
|
||||
display_protocol_vars_rlc_am(rlcP);
|
||||
#endif
|
||||
id = (((uint16_t) (rlc_headerP->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) | ((rlc_headerP->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
||||
// general case
|
||||
((struct rlc_am_rx_pdu_management*) (pduP->data))->sn = id;
|
||||
id_index = id % rlcP->recomputed_configured_rx_window_size;
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg("[RLC][RB %d][DEBUG] receiver_retransmission_management() received PDU %04X :\n", rlcP->rb_id, id);
|
||||
//display_protocol_vars_rlc_am(rlcP);
|
||||
#endif
|
||||
|
||||
// test poll bit for status pdu transmission;
|
||||
if ((rlc_headerP->byte2 & RLC_AM_P_STATUS_REPORT_MASK) == RLC_AM_P_STATUS_REPORT_REQUESTED) {
|
||||
rlcP->send_status_pdu_requested = 1;
|
||||
#ifdef DEBUG_STATUS
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] STATUS REQUESTED BY PEER\n", rlcP->rb_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (id == rlcP->vr_r) {
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p VR(R)=0x%04X id_index=0x%02X VR(H)=0x%04X\n", rlcP->rb_id, pduP, rlcP->vr_r, id_index, rlcP->vr_h);
|
||||
#endif
|
||||
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
||||
|
||||
// update vr_h;
|
||||
if (rlcP->vr_h == id) {
|
||||
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
adjust_vr_r_mr (rlcP);
|
||||
|
||||
} else {
|
||||
rlcP->send_status_pdu_requested = 1;
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn=0x%04X id_index=0x%02X VR(R)=0x%04X VR(H)=0x%04X WILL SEND STATUS\n", rlcP->rb_id, pduP, id, id_index,
|
||||
rlcP->vr_r, rlcP->vr_h);
|
||||
#endif
|
||||
|
||||
//------------------------------------;
|
||||
// CASE VR(R)<VR(H)<VR(MR);
|
||||
//------------------------------------;
|
||||
if ((rlcP->vr_r <= rlcP->vr_h) && (rlcP->vr_h <= rlcP->vr_mr) && (id < rlcP->vr_mr) && (id > rlcP->vr_r)) {
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN WINDOW\n", rlcP->rb_id, pduP, id);
|
||||
#endif
|
||||
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
||||
|
||||
// CASE VR(R)<VR(H)<id<VR(MR);
|
||||
if (id >= rlcP->vr_h) {
|
||||
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
//------------------------------------;
|
||||
// CASE id<VR(MR)<VR(R)<VR(H);
|
||||
//------------------------------------;
|
||||
// CASE VR(MR)<VR(R)<VR(H)<id;
|
||||
|
||||
} else if (((rlcP->vr_mr < rlcP->vr_r) && (rlcP->vr_h >= rlcP->vr_r) && (id < rlcP->vr_mr)) || ((rlcP->vr_mr < rlcP->vr_r) && (rlcP->vr_h >= rlcP->vr_r)
|
||||
&& (id > rlcP->vr_r))) {
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN REVERSED WINDOW\n", rlcP->rb_id, pduP, id);
|
||||
#endif
|
||||
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
||||
|
||||
if ((id >= rlcP->vr_h) || (id < rlcP->vr_mr)) {
|
||||
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
//------------------------------------;
|
||||
// CASE VR(H)<VR(MR)<VR(R);
|
||||
//------------------------------------;
|
||||
|
||||
} else if ((rlcP->vr_h <= rlcP->vr_mr) && (rlcP->vr_mr < rlcP->vr_r)) {
|
||||
if (id < rlcP->vr_mr) {
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN REVERSED WINDOW\n", rlcP->rb_id, pduP, id);
|
||||
#endif
|
||||
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
||||
|
||||
if (id >= rlcP->vr_h) {
|
||||
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
} else if (id > rlcP->vr_r) {
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN REVERSED WINDOW\n", rlcP->rb_id, pduP, id);
|
||||
#endif
|
||||
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
||||
|
||||
} else {
|
||||
// discard this PDU;
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X OUT OF WINDOW\n", rlcP->rb_id, pduP, id);
|
||||
#endif
|
||||
rlcP->stat_rx_data_pdu_out_of_window += 1;
|
||||
free_mem_block (pduP);
|
||||
}
|
||||
|
||||
//------------------------------------;
|
||||
// REJECT;
|
||||
//------------------------------------;
|
||||
|
||||
} else {
|
||||
// discard this PDU;
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X OUT OF WINDOW\n", rlcP->rb_id, pduP, id);
|
||||
#endif
|
||||
rlcP->stat_rx_data_pdu_out_of_window += 1;
|
||||
free_mem_block (pduP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
free_receiver_buffer (struct rlc_am_entity* rlcP, uint16_t indexP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
if (indexP < rlcP->recomputed_configured_rx_window_size) {
|
||||
if (rlcP->receiver_buffer[indexP]) {
|
||||
#ifdef DEBUG_FREE_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] FREE PDU %p index 0x%4X\n", rlcP->rb_id, rlcP->receiver_buffer[indexP], indexP);
|
||||
#endif
|
||||
free_mem_block (rlcP->receiver_buffer[indexP]);
|
||||
rlcP->receiver_buffer[indexP] = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR free_receiver_buffer() invalid index in array 0x%2X\n", rlcP->rb_id, indexP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
insert_into_receiver_buffer (struct rlc_am_entity* rlcP, uint16_t indexP, mem_block_t* pduP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
if (pduP) {
|
||||
if (indexP < rlcP->recomputed_configured_rx_window_size) {
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
|
||||
if (rlcP->receiver_buffer[indexP] != NULL) {
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR insert_into_receiver_buffer() location is not NULL, index in array = 0x%2X\n", rlcP->rb_id, indexP);
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// last received is good
|
||||
if (rlcP->receiver_buffer[indexP] != NULL) {
|
||||
free_mem_block (rlcP->receiver_buffer[indexP]);
|
||||
}
|
||||
|
||||
rlcP->receiver_buffer[indexP] = pduP;
|
||||
return;
|
||||
}
|
||||
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR insert_into_receiver_buffer() invalid index in array 0x%2X\n", rlcP->rb_id, indexP);
|
||||
return;
|
||||
}
|
||||
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR insert_into_receiver_buffer() pdu is NULL index 0x%2X\n", rlcP->rb_id, indexP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
process_receiver_buffer_15 (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
mem_block_t* pdu;
|
||||
uint16_t vr_r;
|
||||
uint16_t working_sn;
|
||||
uint16_t working_sn_index; // index in buffer
|
||||
uint8_t* data_pdu;
|
||||
uint16_t li[RLC_AM_SEGMENT_NB_MAX_LI_PER_PDU];
|
||||
uint16_t remaining_data_size;
|
||||
uint8_t nb_li;
|
||||
uint8_t li_index;
|
||||
uint8_t li_start_index;
|
||||
uint8_t reassembly_after_discard;
|
||||
// should start reassembly with sn working_sn
|
||||
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
vr_r = rlcP->vr_r;
|
||||
reassembly_after_discard = 0;
|
||||
|
||||
while (rlcP->receiver_buffer[working_sn_index]) {
|
||||
pdu = rlcP->receiver_buffer[working_sn_index];
|
||||
nb_li = 0;
|
||||
li_index = 0;
|
||||
rlc_header = (struct rlc_am_pdu_header*) (((struct rlc_am_rx_pdu_management*) (pdu->data))->first_byte);
|
||||
|
||||
if ((rlcP->discard_reassembly_start_sn == ((struct rlc_am_rx_pdu_management*) (pdu->data))->sn)) {
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
reassembly_after_discard = 1; // keep trace of entering in this block
|
||||
|
||||
if (!(rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
||||
while ((li[nb_li] = ((((uint16_t) rlc_header->li_data_7[nb_li << 1]) << 8) + rlc_header->li_data_7[(nb_li << 1) + 1])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
||||
li[nb_li] = li[nb_li] & (~(uint16_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
||||
nb_li++;
|
||||
}
|
||||
|
||||
nb_li++; // count the first li
|
||||
}
|
||||
|
||||
// this variable may be changed by the reception of a mrw sufi
|
||||
//li_start_index = rlcP->discard_reassembly_after_li + 1; // reassembly will start at this index
|
||||
li_start_index = rlcP->discard_reassembly_after_li; // reassembly will start at this index
|
||||
// after reception of sufi mrw the starting index for li will be 0
|
||||
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0; // =-1
|
||||
remaining_data_size = rlcP->pdu_size - 2 - (nb_li << 1);
|
||||
data_pdu = (uint8_t*) (&rlc_header->li_data_7[nb_li << 1]);
|
||||
|
||||
while (li_index < nb_li) {
|
||||
switch (li[li_index]) {
|
||||
case RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
||||
if (li_index >= li_start_index) {
|
||||
send_sdu (rlcP);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_LI_LAST_PDU_ONE_BYTE_SHORT:
|
||||
if (li_index >= li_start_index) {
|
||||
rlcP->output_sdu_size_to_write -= 1;
|
||||
send_sdu (rlcP);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
||||
case RLC_LI_PDU_PADDING:
|
||||
remaining_data_size = 0;
|
||||
break;
|
||||
|
||||
default: // li is length
|
||||
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
||||
|
||||
if (li_index >= li_start_index) {
|
||||
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
||||
send_sdu (rlcP);
|
||||
}
|
||||
|
||||
data_pdu = (uint8_t*) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
||||
}
|
||||
|
||||
li_index++;
|
||||
}
|
||||
|
||||
if ((remaining_data_size)) {
|
||||
reassembly (data_pdu, remaining_data_size, rlcP);
|
||||
remaining_data_size = 0;
|
||||
}
|
||||
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->discard_reassembly_start_sn = RLC_AM_SN_INVALID;
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
|
||||
// patch to make the protocol working
|
||||
// return 1 if sn1 > sn2
|
||||
// return 0 if sn1 = sn2
|
||||
// return -1 if sn1 < sn2
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
||||
rlcP->vr_r = working_sn;
|
||||
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
} else {
|
||||
// exploit HE field info
|
||||
if ((rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
||||
reassembly ((uint8_t*) (rlc_header->li_data_7), rlcP->pdu_size - 2, rlcP);
|
||||
|
||||
} else {
|
||||
while ((li[nb_li] = ((((uint16_t) rlc_header->li_data_7[nb_li << 1]) << 8) + rlc_header->li_data_7[(nb_li << 1) + 1])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
||||
//while ((li[nb_li] = (rlc_header->li.li_data_15[nb_li].optional)) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
||||
li[nb_li] = li[nb_li] & (~(uint16_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
||||
nb_li++;
|
||||
}
|
||||
|
||||
nb_li++;
|
||||
remaining_data_size = rlcP->pdu_size - 2 - (nb_li << 1);
|
||||
data_pdu = (uint8_t*) (&rlc_header->li_data_7[nb_li << 1]);
|
||||
|
||||
while (li_index < nb_li) {
|
||||
switch (li[li_index]) {
|
||||
case RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
||||
send_sdu (rlcP);
|
||||
break;
|
||||
|
||||
case RLC_LI_LAST_PDU_ONE_BYTE_SHORT:
|
||||
rlcP->output_sdu_size_to_write -= 1;
|
||||
send_sdu (rlcP);
|
||||
break;
|
||||
|
||||
case RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
||||
case RLC_LI_PDU_PADDING:
|
||||
remaining_data_size = 0;
|
||||
break;
|
||||
|
||||
default: // li is length
|
||||
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
||||
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
||||
data_pdu = (uint8_t*) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
||||
send_sdu (rlcP);
|
||||
}
|
||||
|
||||
li_index++;
|
||||
}
|
||||
|
||||
if ((remaining_data_size)) {
|
||||
reassembly (data_pdu, remaining_data_size, rlcP);
|
||||
remaining_data_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
|
||||
if ((reassembly_after_discard)) {
|
||||
// return 1 if vr_r > working_sn
|
||||
// return 0 if vr_r = working_sn
|
||||
// return -1 if vr_r < working_sn
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
||||
rlcP->vr_r = working_sn;
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU AFTER DISCARD ADJUST VR(R) 0x%04X\n", rlcP->rb_id, rlcP->vr_r);
|
||||
#endif
|
||||
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
process_receiver_buffer_7 (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
mem_block_t* pdu;
|
||||
uint16_t vr_r;
|
||||
uint16_t working_sn;
|
||||
uint16_t working_sn_index; // index in buffer
|
||||
uint8_t* data_pdu;
|
||||
uint8_t li[RLC_AM_SEGMENT_NB_MAX_LI_PER_PDU];
|
||||
uint16_t remaining_data_size;
|
||||
int8_t nb_li;
|
||||
int8_t li_index;
|
||||
int8_t li_start_index;
|
||||
uint8_t reassembly_after_discard;
|
||||
uint8_t sdu_sent=0;
|
||||
// should start reassembly with sn working_sn
|
||||
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
vr_r = rlcP->vr_r;
|
||||
reassembly_after_discard = 0;
|
||||
|
||||
while (rlcP->receiver_buffer[working_sn_index]) {
|
||||
pdu = rlcP->receiver_buffer[working_sn_index];
|
||||
nb_li = 0;
|
||||
li_index = 0;
|
||||
rlc_header = (struct rlc_am_pdu_header*) (((struct rlc_am_rx_pdu_management*) (pdu->data))->first_byte);
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU %p SN 0x%04X (sdu_sent %d)\n", rlcP->rb_id, pdu, working_sn,sdu_sent);
|
||||
#endif
|
||||
|
||||
if ((rlcP->discard_reassembly_start_sn == ((struct rlc_am_rx_pdu_management*) (pdu->data))->sn)) {
|
||||
rlcP->output_sdu_size_to_write = 0;
|
||||
reassembly_after_discard = 1; // keep trace of entering in this block
|
||||
|
||||
if (!(rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
||||
while ((li[nb_li] = (rlc_header->li_data_7[nb_li])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
||||
li[nb_li] = li[nb_li] & (~(uint8_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
||||
nb_li++;
|
||||
}
|
||||
|
||||
nb_li++; // count the first li
|
||||
}
|
||||
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU TO BE REASSEMBLIED AFTER DISCARD, START SN 0x%04X hex VR(R) 0x%04X\n", rlcP->rb_id,
|
||||
rlcP->discard_reassembly_start_sn, rlcP->vr_r);
|
||||
#endif
|
||||
// this variable may be changed by the reception of a mrw sufi
|
||||
//li_start_index = rlcP->discard_reassembly_after_li + 1; // reassembly will start at this index
|
||||
li_start_index = rlcP->discard_reassembly_after_li; // reassembly will start at this index
|
||||
// after reception of sufi mrw the starting index for li will be 0
|
||||
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0; // =-1
|
||||
remaining_data_size = rlcP->pdu_size - 2 - (nb_li);
|
||||
data_pdu = (uint8_t*) (&rlc_header->li_data_7[nb_li]);
|
||||
|
||||
while (li_index < nb_li) {
|
||||
switch (li[li_index]) {
|
||||
case (uint8_t) RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_LAST_PDU_EXACTLY_FILLED REMAINING DATA SIZE %d, li_index %d, li_start_index %d\n", rlcP->rb_id,
|
||||
working_sn, remaining_data_size, li_index, li_start_index);
|
||||
#endif
|
||||
|
||||
if (li_index >= li_start_index) {
|
||||
send_sdu (rlcP);
|
||||
sdu_sent=1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case (uint8_t) RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
||||
case (uint8_t) RLC_LI_PDU_PADDING:
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_PDU_PADDING\n", rlcP->rb_id, working_sn);
|
||||
#endif
|
||||
remaining_data_size = 0;
|
||||
break;
|
||||
|
||||
default: // li is length
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI SIZE %d\n", rlcP->rb_id, working_sn, li[li_index] >> 1);
|
||||
#endif
|
||||
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
||||
|
||||
if (li_index >= li_start_index) {
|
||||
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
||||
send_sdu (rlcP);
|
||||
sdu_sent=1;
|
||||
}
|
||||
|
||||
data_pdu = (uint8_t*) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
||||
}
|
||||
|
||||
li_index++;
|
||||
}
|
||||
|
||||
if ((remaining_data_size)) {
|
||||
reassembly (data_pdu, remaining_data_size, rlcP);
|
||||
remaining_data_size = 0;
|
||||
}
|
||||
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->discard_reassembly_start_sn = RLC_AM_SN_INVALID;
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
|
||||
// return 1 if vr_r > working_sn
|
||||
// return 0 if vr_r = working_sn
|
||||
// return -1 if vr_r < working_sn
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
||||
rlcP->vr_r = working_sn;
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU AFTER DISCARD ADJUST VR(R) 0x%04X hex\n", rlcP->rb_id, rlcP->vr_r);
|
||||
#endif
|
||||
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg("[RLC][AM] Reassembly, No discard. rlc_header->byte2 %d\n");
|
||||
#endif
|
||||
|
||||
// exploit HE field info
|
||||
if ((rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
||||
msg("WILL REASSEMBLY INDEX %04X\n", working_sn_index);
|
||||
reassembly ((uint8_t*) (rlc_header->li_data_7), rlcP->pdu_size - 2, rlcP);
|
||||
|
||||
} else {
|
||||
while ((li[nb_li] = (rlc_header->li_data_7[nb_li])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
||||
li[nb_li] = li[nb_li] & (~(uint8_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
||||
nb_li++;
|
||||
}
|
||||
|
||||
nb_li++;
|
||||
remaining_data_size = rlcP->pdu_size - 2 - nb_li;
|
||||
data_pdu = (uint8_t*) (&rlc_header->li_data_7[nb_li]);
|
||||
|
||||
while (li_index < nb_li) {
|
||||
switch (li[li_index]) {
|
||||
case (uint8_t) RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_LAST_PDU_EXACTLY_FILLED NUM LI %d\n", rlcP->rb_id, working_sn,nb_li);
|
||||
#endif
|
||||
send_sdu (rlcP);
|
||||
sdu_sent=1;
|
||||
break;
|
||||
|
||||
case (uint8_t) RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
||||
case (uint8_t) RLC_LI_PDU_PADDING:
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_PDU_PADDING\n", rlcP->rb_id, working_sn);
|
||||
#endif
|
||||
remaining_data_size = 0;
|
||||
break;
|
||||
|
||||
default: // li is length
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI SIZE %d Bytes\n", rlcP->rb_id, working_sn, li[li_index] >> 1);
|
||||
#endif
|
||||
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
||||
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
||||
data_pdu = (uint8_t*) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
||||
send_sdu (rlcP);
|
||||
sdu_sent=1;
|
||||
}
|
||||
|
||||
li_index++;
|
||||
}
|
||||
|
||||
if ((remaining_data_size)) {
|
||||
//msg("WILL REASSEMBLY INDEX %04X\n", working_sn_index);
|
||||
reassembly (data_pdu, remaining_data_size, rlcP);
|
||||
remaining_data_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free_receiver_buffer (rlcP, working_sn_index);
|
||||
rlcP->last_reassemblied_sn = working_sn;
|
||||
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
|
||||
if ((reassembly_after_discard)) {
|
||||
// return 1 if vr_r > working_sn
|
||||
// return 0 if vr_r = working_sn
|
||||
// return -1 if vr_r < working_sn
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
||||
rlcP->vr_r = working_sn;
|
||||
#ifdef DEBUG_REASSEMBLY
|
||||
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU AFTER DISCARD ADJUST VR(R) 0x%04X\n", rlcP->rb_id, rlcP->vr_r);
|
||||
#endif
|
||||
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg("receiver_buffer[%d] %p (sdu_sent %d)\n",working_sn_index,rlcP->receiver_buffer[working_sn_index],sdu_sent);
|
||||
}
|
||||
|
||||
// if (sdu_sent == 0) {
|
||||
// msg("[RLC_AM][RB %d][REASSEMBLY] Forcing send_sdu (sent_sdu == 0)\n",rlcP->rb_id);
|
||||
// send_sdu(rlcP);
|
||||
// }
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_receiver_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_RECEIVER_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_RECEIVER_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void receiver_retransmission_management (struct rlc_am_entity *rlcP, mem_block_t * pduP, struct rlc_am_pdu_header *rlc_headerP);
|
||||
extern void free_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t indexP);
|
||||
extern void insert_into_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t indexP, mem_block_t * pduP);
|
||||
extern void process_receiver_buffer_15 (struct rlc_am_entity *rlcP);
|
||||
extern void process_receiver_buffer_7 (struct rlc_am_entity *rlcP);
|
||||
# endif
|
||||
@@ -1,402 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_reset.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
The RLC reset procedure is used to reset two RLC peer entities, which are operating in acknowledged mode.
|
||||
During the reset procedure the hyper frame numbers (HFN) in UTRAN and UE are synchronised. Two HFNs
|
||||
used for ciphering needs to be synchronised, DL HFN in downlink and UL HFN in uplink.
|
||||
In the reset procedure, the highest UL HFN and DL HFN used by the RLC
|
||||
entity in the transmitting sides, i.e. the HFNs associated with AMD PDUs of "Sequence Number"=VT(S)-1 if at least
|
||||
one AMD PDU had been transmitted or of "Sequence Number"=0 if no AMD PDU had been transmitted, are
|
||||
exchanged between UE and UTRAN.
|
||||
The RESET PDUs and the RESET ACK PDUs have higher priority than AMD PDUs.
|
||||
*/
|
||||
#define RLC_AM_C
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc.h"
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_am_control_primitives_proto_extern.h"
|
||||
#include "rlc_am_fsm_proto_extern.h"
|
||||
#include "list.h"
|
||||
#include "mem_block.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
#define DEBUG_RESET
|
||||
//-----------------------------------------------------------------------------
|
||||
void send_reset_ack_pdu (uint8_t rsnP, struct rlc_am_entity* rlcP);
|
||||
void send_reset_pdu (struct rlc_am_entity* rlcP);
|
||||
void reset_rlc_am (struct rlc_am_entity* rlcP);
|
||||
void process_reset_ack (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP);
|
||||
void process_reset (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP);
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_reset_time_out (struct rlc_am_entity* rlcP, mem_block_t* not_usedP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
/* from 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
If Timer_RST expires before the reset procedure is terminated, the Sender shall:
|
||||
- if VT(RST)<MaxRST-1:
|
||||
- set the RESET PDU as previously transmitted (even if additional SDUs were discarded in the mean-time);
|
||||
- transmit RESET PDU;
|
||||
- increment VT(RST) by one;
|
||||
- restart Timer_RST.
|
||||
Unrecoverable error (VT(RST) MaxRST)
|
||||
The Sender shall:
|
||||
- if VT(RST) becomes larger than or equal to MaxRST:
|
||||
- indicate unrecoverable error to upper layer.
|
||||
*/
|
||||
rlcP->timer_rst = NULL;
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RESET TIME OUT VT(RST) = %d frame %d\n", rlcP->rb_id, rlcP->vt_rst, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
|
||||
if (rlcP->protocol_state & RLC_RESET_PENDING_STATE) {
|
||||
if (rlcP->vt_rst < rlcP->max_rst - 1) {
|
||||
send_reset_pdu (rlcP);
|
||||
rlcP->vt_rst += 1;
|
||||
|
||||
} else {
|
||||
//rrc_indication_unrecoverable_error_from_rlc_am(rlcP);
|
||||
// notification not raised to RRC, continue. (TO DO)
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RESET TIME OUT VT(RST) >= max_rst frame %d REPORT TO RRC\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
send_reset_pdu (rlcP);
|
||||
rlcP->vt_rst += 1;
|
||||
rlc_data_conf (0, rlcP->rb_id, 0,RLC_TX_CONFIRM_FAILURE, rlcP->data_plane); // mui, rb_ib, status
|
||||
#ifdef NODE_MT
|
||||
#warning rrc_ue_CPHY_Out_Synch_rx should be called
|
||||
//rrc_ue_CPHY_Out_Synch_rx (1); // Temporary hack to disconnect mobile upon RLC AM timeout
|
||||
#endif /* NODE_MT */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
send_reset_pdu (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* pdu;
|
||||
struct rlc_am_reset_header* header;
|
||||
|
||||
/* From TS 25.322 V5.0.0 (2002-03)
|
||||
RESET PDU contents to set
|
||||
The Sender shall:
|
||||
- set the HFNI field to the currently highest used HFN (DL HFN when the RESET PDU is sent by UTRAN or UL
|
||||
HFN when the RESET PDU is sent by the UE);
|
||||
- set the RSN field to the sequence number of the RESET PDU. The sequence number of the first RESET PDU
|
||||
after the AM entity is established or re-established shall be "0". This sequence number is incremented every time
|
||||
a new RESET PDU is transmitted, but not when a RESET PDU is retransmitted.
|
||||
*/
|
||||
if (!(rlcP->timer_rst)) {
|
||||
if (rlcP->vt_rst == 0) { // first transmission of reset PDU
|
||||
rlcP->reset_sequence_number ^= 1;
|
||||
}
|
||||
|
||||
rlcP->vt_rst += 1;
|
||||
pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if ((pdu)) {
|
||||
((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_RESET_PDU_TYPE;
|
||||
header = (struct rlc_am_reset_header*) (&pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
header->byte1 = RLC_PDU_TYPE_RESET | (rlcP->reset_sequence_number << 3);
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] TX RESET RSN %d VT(RST) %d frame %d\n", rlcP->rb_id, rlcP->reset_sequence_number, rlcP->vt_rst, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
// HFNI NOT IMPLEMENTED NOW needed only for cyphering
|
||||
/*header->hfni[0] = 0;
|
||||
header->hfni[1] = 0;
|
||||
header->hfni[2] = 0;
|
||||
*/
|
||||
list_add_head (pdu, &rlcP->control);
|
||||
rlc_am_fsm_notify_event (rlcP, RLC_AM_TRANSMIT_RESET_EVENT); // not yet submitted to lower layers
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM][RB %d] ERROR SEND RESET OUT OF MEMORY ERROR\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
send_reset_ack_pdu (uint8_t rsnP, struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* pdu;
|
||||
struct rlc_am_reset_header* header;
|
||||
|
||||
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
RESET ACK PDU contents to set
|
||||
The Receiver shall:
|
||||
- set the hyper frame number indicator field (HFNI) to the currently highest used HFN (DL HFN when the RESET
|
||||
ACK PDU is sent by UTRAN or UL HFN when the RESET ACK PDU is sent by the UE);
|
||||
- set the RSN field to the same value as in the corresponding received RESET PDU.
|
||||
*/
|
||||
if ((pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE))) {
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] TX RESET ACK RSN %d frame %d\n", rlcP->rb_id, rsnP, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_RESET_ACK_PDU_TYPE;
|
||||
header = (struct rlc_am_reset_header*) (&pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
header->byte1 = RLC_PDU_TYPE_RESET_ACK | (rsnP << 3);
|
||||
list_add_head (pdu, &rlcP->control);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RESET
|
||||
|
||||
else {
|
||||
msg ("[RLC_AM][RB %d] SEND RESET ACK OUT OF MEMORY ERROR\n", rlcP->rb_id);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
process_reset_ack (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
/* from 3GPP TS 25.322 V5.0.0 (2002-03)
|
||||
Upon reception of a RESET ACK PDU, the Sender shall:
|
||||
- if the Sender has already transmitted a RESET PDU which has not been yet acknowledged by a RESET ACK
|
||||
PDU:
|
||||
- if the received RSN value is the same as the one in the corresponding RESET PDU:
|
||||
- set the HFN value (DL HFN when the RESET ACK PDU is received in UE or UL HFN when the RESET
|
||||
ACK PDU is received in UTRAN) to the HFNI field of the received RESET ACK PDU;
|
||||
- reset the state variables described in subclause 9.4 to their initial values;
|
||||
- stop all the timers described in subclause 9.5;
|
||||
- reset configurable parameters to their configured values;
|
||||
- discard all RLC PDUs in the receiving side of the AM RLC entity;
|
||||
- discard all RLC SDUs that were transmitted before the reset in the transmitting side of the AM RLC
|
||||
entity;
|
||||
- increase with one the UL HFN and DL HFN, and the updated HFN values shall be used for the first
|
||||
transmitted and received AMD PDUs after the reset procedure;
|
||||
|
||||
- otherwise (if the received RSN value is not the same as the one in the corresponding RESET PDU):
|
||||
- discard the RESET ACK PDU;
|
||||
|
||||
- otherwise (if the Sender has not transmitted a RESET PDU which has not been yet acknowledged by a RESET
|
||||
ACK PDU):
|
||||
- discard the RESET ACK PDU.
|
||||
|
||||
NOTE: If the TFC selection exchange has been initiated by sending the RLC Entity Info parameter to MAC, the
|
||||
RLC entity may delay the RLC SDUs discard in the transmitting side until the end of the next TTI.
|
||||
*/
|
||||
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_RESET_ACK_EVENT)) {
|
||||
if (((controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3) == rlcP->reset_sequence_number) {
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RX RESET ACK RSN %d frame %d\n", rlcP->rb_id, ((controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3), Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
rlc_am_reset_state_variables (rlcP);
|
||||
reset_rlc_am (rlcP);
|
||||
umts_stop_all_timers (&rlcP->rlc_am_timer_list);
|
||||
rlcP->timer_rst = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RESET
|
||||
|
||||
else {
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RX RESET ACK WRONG RSN %d != %d frame %d\n", rlcP->rb_id, (controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3,
|
||||
rlcP->reset_sequence_number, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RESET
|
||||
|
||||
else {
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RX RESET ACK NOT EXPECTED frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
msg("RLC AM RESET EXIT\n");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
process_reset (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t rsn;
|
||||
uint8_t saved_vt_rst;
|
||||
/* From 25.322 V5.0.0 (2002-03)
|
||||
Reception of the RESET PDU by the Receiver
|
||||
Upon reception of a RESET PDU the Receiver shall:
|
||||
- if the RSN value in the RESET PDU is the same as the RSN value in the last received RESET PDU:
|
||||
- only submit a RESET ACK PDU to the lower layer with the contents set exactly as in the last transmitted
|
||||
RESET ACK PDU (i.e., in this case the RLC entity is not reset).
|
||||
|
||||
- if the RESET PDU is the first RESET PDU received since the entity was (re-)established or the RSN value is
|
||||
different from the RSN value in the last received RESET PDU:
|
||||
- submit a RESET ACK PDU to the lower layer with the content set as specified in subclause 11.4.3.1;
|
||||
- reset the state variables described in subclause 9.4 except VT(RST) to their initial values;
|
||||
- stop all the timers described in subclause 9.5 except Timer_RST;
|
||||
- reset configurable parameters to their configured values;
|
||||
- discard all RLC PDUs in the receiving side of the AM RLC entity;
|
||||
- discard all RLC SDUs that were transmitted before the reset in the transmitting side of the AM RLC entity;
|
||||
- set the HFN (DL HFN when the RESET PDU is received in UE or UL HFN when the RESET PDU is
|
||||
received in UTRAN) equal to the HFNI field in the received RESET PDU;
|
||||
- increase with one the UL HFN and DL HFN, and the updated HFN values shall be used for the first
|
||||
transmitted and received AMD PDUs after the reset procedure.
|
||||
NOTE: If the TFC selection exchange has been initiated by sending the RLC Entity Info parameter to MAC, the
|
||||
RLC entity may delay the RLC SDUs discard in the transmitting side of the AM RLC entity until the end
|
||||
of the next TTI.
|
||||
|
||||
Reception of the RESET PDU by the Sender
|
||||
Upon reception of a RESET PDU, the Sender shall:
|
||||
- submit a RESET ACK PDU to the lower layer with the content set as specified in subclause 11.4.3.1;
|
||||
- reset the state variables described in subclause 9.4 except VT(RST) to their initial values;
|
||||
- stop all the timers described in subclause 9.5 except Timer_RST;
|
||||
- reset configurable parameters to their configured values;
|
||||
- discard all RLC PDUs in the receiving side of the AM RLC entity;
|
||||
- discard all RLC SDUs that were transmitted before the reset in the transmitting side of the AM RLC entity;
|
||||
- set the HFN (DL HFN when the RESET PDU is received in UE or UL HFN when the RESET PDU is received
|
||||
in UTRAN) equal to the HFNI field in the received RESET PDU;
|
||||
- increase with one the UL HFN and DL HFN, and the updated HFN values shall be used for the first transmitted
|
||||
and received AMD PDUs after the reset procedure.
|
||||
NOTE: If the TFC selection exchange has been initiated by sending the RLC Entity Info parameter to MAC, the
|
||||
RLC entity may delay the RLC SDUs discard in the transmitting side until the end of the next TTI.
|
||||
|
||||
*/
|
||||
rsn = (controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3;
|
||||
|
||||
if ((rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RX RESET RSN %d frame %d\n", rlcP->rb_id, rsn, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_RESET_EVENT);
|
||||
// sender
|
||||
saved_vt_rst = rlcP->vt_rst;
|
||||
reset_rlc_am (rlcP);
|
||||
rlcP->vt_rst = saved_vt_rst;
|
||||
rlcP->last_received_rsn = rsn;
|
||||
send_reset_ack_pdu (rsn, rlcP);
|
||||
|
||||
// NOT IN SPECS, BUT IF SENDER RECEIVE A RESET, IT DISCARDS ALL CONTROL PDU IN ITS BUFFER
|
||||
// SO IF THE RESET PDU WAS STILL IN THE RLC BUFFERS...IT IS DROPPED AND THE RESET TIMER CAN NOT
|
||||
// BE STARTED (BY SUCCESSFULL TX ACK OF MAC LAYER), SO REARM THE TIMER AND SCHEDULE A NEW RESET
|
||||
// PDU FOR TRANSMISSION
|
||||
if (!(rlcP->timer_rst)) {
|
||||
umts_stop_all_timers (&rlcP->rlc_am_timer_list);
|
||||
rlc_am_reset_time_out (rlcP, NULL);
|
||||
|
||||
} else {
|
||||
umts_stop_all_timers_except (&rlcP->rlc_am_timer_list, rlc_am_reset_time_out);
|
||||
}
|
||||
|
||||
} else {
|
||||
// receiver
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RX RESET RSN %d frame %d\n", rlcP->rb_id, rsn, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
|
||||
if (rlcP->last_received_rsn == rsn) { //last_received_rsn initialized to -1 when RLC start
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("\n******************************************************************\n");
|
||||
msg ("[RLC_AM][RB %d] RX RESET RSN %d SAME RSN RECEIVED LAST RESET, SEND RESET ACK frame %d \n", rlcP->rb_id, rsn, Mac_rlc_xface->frame);
|
||||
msg ("\n******************************************************************\n");
|
||||
#endif
|
||||
send_reset_ack_pdu (rsn, rlcP); // rsn start to zero
|
||||
return;
|
||||
}
|
||||
|
||||
rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_RESET_EVENT);
|
||||
saved_vt_rst = rlcP->vt_rst;
|
||||
reset_rlc_am (rlcP);
|
||||
rlcP->vt_rst = saved_vt_rst;
|
||||
rlcP->last_received_rsn = rsn;
|
||||
send_reset_ack_pdu (rsn, rlcP);
|
||||
umts_stop_all_timers (&rlcP->rlc_am_timer_list);
|
||||
rlcP->timer_rst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
reset_rlc_am (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
int index;
|
||||
|
||||
for (index = 0; index < rlcP->size_input_sdus_buffer; index++) {
|
||||
if (rlcP->input_sdus[index]) {
|
||||
if (!(rlcP->data_plane)) {
|
||||
#ifdef DEBUG_RLC_AM_SEND_CONFIRM
|
||||
msg ("[RLC_AM][RB %d][CONFIRM] SDU MUI %d LOST IN RESET\n", rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[index]->data))->mui);
|
||||
#endif
|
||||
rlc_data_conf (0, rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[index]->data))->mui, RLC_TX_CONFIRM_FAILURE, rlcP->data_plane);
|
||||
}
|
||||
|
||||
free_mem_block (rlcP->input_sdus[index]);
|
||||
rlcP->input_sdus[index] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rlc_am_reset_state_variables (rlcP);
|
||||
rlc_am_discard_all_pdus (rlcP);
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d] RESETED\n", rlcP->rb_id);
|
||||
//display_mem_load();
|
||||
//msg("sdu_conf_segmented : %p\n" , rlcP->sdu_conf_segmented.head);
|
||||
//msg("sdu_discard_segmented : %p\n", rlcP->sdu_discard_segmented.head);
|
||||
//msg("sdu_discarded : %p\n" , rlcP->sdu_discarded.head);
|
||||
//msg("discard_procedures : %p\n" , rlcP->discard_procedures.head);
|
||||
//check_mem_area(mem);
|
||||
#endif
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_reset_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_RESET_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_RESET_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_reset_time_out (struct rlc_am_entity *rlcP, mem_block_t * not_usedP);
|
||||
extern void send_reset_ack_pdu (uint8_t rsnP, struct rlc_am_entity *rlcP);
|
||||
extern void send_reset_pdu (struct rlc_am_entity *rlcP);
|
||||
extern void reset_rlc_am (struct rlc_am_entity *rlcP);
|
||||
extern void process_reset_ack (mem_block_t * pduP, struct rlc_am_reset_header *controlP, struct rlc_am_entity *rlcP);
|
||||
extern void process_reset (mem_block_t * pduP, struct rlc_am_reset_header *controlP, struct rlc_am_entity *rlcP);
|
||||
# endif
|
||||
@@ -1,777 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_retrans.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
#define RLC_AM_C
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc.h"
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_errno.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_am_discard_notif_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "rlc_am_reset_proto_extern.h"
|
||||
#include "rlc_am_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "list.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//#define DEBUG_RETRANSMISSION
|
||||
//#define DEBUG_ACK
|
||||
//#define DEBUG_RESET
|
||||
//#define DEBUG_BITMAP
|
||||
//#define DEBUG_LIST
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int16_t retransmission_buffer_management_ack (struct rlc_am_entity* rlcP, uint8_t* sufiP, uint8_t byte_alignedP,
|
||||
int16_t* first_error_indicated_snP);
|
||||
inline uint8_t* retransmission_buffer_management_bitmap (struct rlc_am_entity* rlcP, uint8_t* bitmap_sufiP, uint8_t byte_alignedP,
|
||||
int16_t* first_error_indicated_snP);
|
||||
inline uint8_t* retransmission_buffer_management_list (struct rlc_am_entity* rlcP, uint8_t* bitmap_sufiP, uint8_t byte_alignedP,
|
||||
int16_t* first_error_indicated_snP);
|
||||
inline void free_retransmission_buffer (struct rlc_am_entity* rlcP, uint16_t indexP);
|
||||
inline void free_retransmission_buffer_no_confirmation (struct rlc_am_entity* rlcP, uint16_t indexP);
|
||||
inline void insert_into_retransmission_buffer (struct rlc_am_entity* rlcP, uint16_t indexP, mem_block_t* pduP);
|
||||
inline uint8_t retransmit_pdu (struct rlc_am_entity* rlcP, uint16_t snP);
|
||||
inline uint8_t add_to_transmission_buffer_unack_pdu (struct rlc_am_entity* rlcP, int16_t* nb_pdu_to_transmit);
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
* remove all mem_block_t(s) having sn <= snP
|
||||
*/
|
||||
int16_t
|
||||
retransmission_buffer_management_ack (struct rlc_am_entity* rlcP, uint8_t* sufiP, uint8_t byte_alignedP, int16_t* first_error_indicated_snP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t lsn; // sequence number acknowledged
|
||||
uint16_t current_sn;
|
||||
uint16_t upper_bound;
|
||||
int16_t current_index;
|
||||
uint8_t tmp;
|
||||
|
||||
// get LSN field;
|
||||
if (byte_alignedP) {
|
||||
// get next 12 bits;
|
||||
lsn = (*sufiP++ & 0x0F);
|
||||
lsn = lsn << 8;
|
||||
lsn += *sufiP;
|
||||
|
||||
} else {
|
||||
// get next 12 bits;
|
||||
sufiP++;
|
||||
lsn = *sufiP++;
|
||||
lsn = lsn << 4;
|
||||
tmp = *sufiP;
|
||||
lsn |= (tmp >> 4);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ACK
|
||||
msg ("[RLC_AM][RB %d][ACK] RX SUFI ACK 0x%04X VT(A) 0x%04X VT(S) 0x%04X VT(MS) 0x%04X\n", rlcP->rb_id, lsn, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms);
|
||||
#endif
|
||||
current_sn = rlcP->vt_a;
|
||||
|
||||
// From 3GPP TS 25.322 V4.3.0
|
||||
// LSN acknowledges the reception of all PDUs with "Sequence Number" < LSN (Last Sequence Number)
|
||||
// that are not indicated to be erroneous in earlier parts of the STATUS PDU.
|
||||
// This means that if the LSN is set to a value greater than VR(R), all erroneous PDUs shall
|
||||
// be included in the same STATUS PDU
|
||||
// and if the LSN is set to VR(R), the erroneous PDUs can be split into several STATUS PDUs.
|
||||
// At the transmitter, if the value of the LSN =< the value of the first error indicated
|
||||
// in the STATUS PDU, VT(A) will be updated according to the LSN,
|
||||
// otherwise VT(A) will be updated according to the first error indicated in the STATUS PDU.
|
||||
// VT(A) is only updated based on STATUS PDUs where ACK SUFI (or MRW_ACK SUFI) is included.
|
||||
// The LSN shall not be set to a value > VR(H) nor < VR(R).
|
||||
//-------------------------;
|
||||
// if ack lsn <= first error => vt_a = lsn;
|
||||
// else vt_a = first error indicated;
|
||||
// check lsn is valid
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, lsn, rlcP->vt_a) >= 0) {
|
||||
if (*first_error_indicated_snP >= 0) {
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, lsn, (uint16_t) * first_error_indicated_snP) <= 0) {
|
||||
#ifdef DEBUG_ACK
|
||||
msg ("[RLC_AM][RB %d][ACK] VT(A) 0x%04X -> 0x%04X VT(S) 0x%04X CASE LSN <= FIRST PDU IN ERROR IN STATUS PDU\n", rlcP->rb_id, rlcP->vt_a, lsn, rlcP->vt_s);
|
||||
#endif
|
||||
rlcP->vt_a = lsn;
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_ACK
|
||||
msg ("[RLC_AM][RB %d][ACK] VT(A) 0x%04X -> 0x%04X VT(S) 0x%04X CASE LSN > FIRST PDU IN ERROR IN STATUS PDU \n", rlcP->rb_id, rlcP->vt_a,
|
||||
(uint16_t) * first_error_indicated_snP, rlcP->vt_s);
|
||||
#endif
|
||||
rlcP->vt_a = (uint16_t) * first_error_indicated_snP;
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_ACK
|
||||
msg ("[RLC_AM][RB %d][ACK] VT(A) 0x%04X -> 0x%04X VT(S) 0x%04X CASE SUFI ACK ALONE IN CONTROL PDU\n", rlcP->rb_id, rlcP->vt_a, lsn, rlcP->vt_s);
|
||||
#endif
|
||||
rlcP->vt_a = lsn;
|
||||
}
|
||||
|
||||
rlcP->vt_ms = (rlcP->vt_a + rlcP->vt_ws - 1) & SN_12BITS_MASK;
|
||||
current_index = current_sn % (uint16_t) rlcP->recomputed_configured_tx_window_size;
|
||||
upper_bound = lsn % (uint16_t) rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
// remove all matching pdus from retransmission buffer;
|
||||
while (upper_bound != current_index) {
|
||||
// free all pdus that have not been stamped as missing;
|
||||
if (rlcP->retransmission_buffer[current_index] != NULL) {
|
||||
if (((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[current_index]->data))->ack != RLC_AM_PDU_NACK_EVENT) {
|
||||
#ifdef DEBUG_ACK
|
||||
msg ("[RLC_AM][RB %d][ACK] FREE PDU SN 0x%04X BECAUSE FIELD ACK=%d\n", rlcP->rb_id, current_sn,
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[current_index]->data))->ack);
|
||||
#endif
|
||||
free_retransmission_buffer (rlcP, (uint16_t) current_index);
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_ACK
|
||||
msg ("[RLC_AM][RB %d][ACK] CLEAR NACK EVENT (%d) PDU SN 0x%04X\n", rlcP->rb_id,
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[current_index]->data))->ack,
|
||||
current_sn);
|
||||
#endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[current_index]->data))->ack = RLC_AM_PDU_ACK_NO_EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
current_sn = (current_sn + 1) & SN_12BITS_MASK;
|
||||
current_index = current_sn % (uint16_t) rlcP->recomputed_configured_tx_window_size;
|
||||
}
|
||||
|
||||
/*if (rlcP->retransmission_buffer[current_index] != NULL) {
|
||||
if (((struct rlc_am_tx_data_pdu_management*)(&rlcP->retransmission_buffer[current_index]->data[sizeof(struct rlc_am_tx_data_pdu_allocation)]))->ack
|
||||
== RLC_AM_PDU_NACK_EVENT) {
|
||||
#ifdef DEBUG_ACK
|
||||
msg("[RLC_AM %p][ACK] CLEAR ACK EVENT PDU SN %04X\n",rlcP, current_sn);
|
||||
#endif
|
||||
((struct rlc_am_tx_data_pdu_management*)(&rlcP->retransmission_buffer[current_index]->data[sizeof(struct rlc_am_tx_data_pdu_allocation)]))->ack = RLC_AM_PDU_ACK_NO_EVENT;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return lsn;
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][ACK] ERROR SUFI ACK INVALID lsn 0x%02X vt(a) 0x%04X vt(s) 0x%04X -> RESET\n", rlcP->rb_id, lsn, rlcP->vt_a, rlcP->vt_s);
|
||||
//display_protocol_vars_rlc_am(rlcP);
|
||||
#endif
|
||||
send_reset_pdu (rlcP);
|
||||
return (int16_t) (-1);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
* remove all mem_block_t(s) correctly received
|
||||
* retransmit all mem_block_t(s) not correctly received
|
||||
* @param bitmap_sufiP pointer on byte containing field "sufi type"
|
||||
* @param byte_alignedP tells if sufi type quartet is on MSByte (1) or LSByte (0)
|
||||
*/
|
||||
inline uint8_t*
|
||||
retransmission_buffer_management_bitmap (struct rlc_am_entity* rlcP, uint8_t* bitmap_sufiP, uint8_t byte_alignedP, int16_t* first_error_indicated_snP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t id_index;
|
||||
uint16_t fsn;
|
||||
uint8_t length, tmp;
|
||||
uint8_t one_pdu_removed = 0; //optim: update vt_a only at the end of the proc
|
||||
uint8_t bit_mask;
|
||||
uint8_t end_bit;
|
||||
|
||||
if (byte_alignedP) {
|
||||
// get next 4 bits : length
|
||||
length = (*bitmap_sufiP++ & 0x0F) + 1;
|
||||
// get next 12 bits : FSN
|
||||
fsn = *bitmap_sufiP++;
|
||||
fsn = fsn << 4;
|
||||
tmp = *bitmap_sufiP;
|
||||
fsn += tmp >> 4;
|
||||
bit_mask = 8;
|
||||
|
||||
} else {
|
||||
bitmap_sufiP++;
|
||||
// get 4 bits length
|
||||
length = (*bitmap_sufiP >> 4) + 1;
|
||||
// get next 12 bits : FSN
|
||||
fsn = *bitmap_sufiP++ & 0x0F;
|
||||
fsn = fsn << 8;
|
||||
fsn = fsn + *bitmap_sufiP;
|
||||
bitmap_sufiP++;
|
||||
bit_mask = 128;
|
||||
}
|
||||
|
||||
end_bit = length << 3; // *8
|
||||
#ifdef DEBUG_BITMAP
|
||||
msg ("[RLC_AM][RB %d][BITMAP] SUFI BITMAP fsn 0x%04X length 0x%04X\n", rlcP->rb_id, fsn, length);
|
||||
#endif
|
||||
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, fsn, rlcP->vt_a) >= 0) {
|
||||
while (end_bit) {
|
||||
id_index = fsn % (uint16_t) (rlcP->recomputed_configured_tx_window_size);
|
||||
|
||||
// found a matching pdu
|
||||
if (*bitmap_sufiP & bit_mask) {
|
||||
// pdu correctly received
|
||||
// remove it from retransmission buffer
|
||||
free_retransmission_buffer (rlcP, id_index);
|
||||
one_pdu_removed = 1;
|
||||
#ifdef DEBUG_BITMAP
|
||||
msg ("[RLC_AM][RB %d][BITMAP] SUFI BITMAP ACK 0x%04x \n", rlcP->rb_id, fsn);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// pdu not correctly received;
|
||||
// retransmit it;
|
||||
#ifdef DEBUG_BITMAP
|
||||
msg ("[RLC_AM][RB %d][BITMAP] SUFI BITMAP NACK 0x%04x\n", rlcP->rb_id, fsn);
|
||||
#endif
|
||||
|
||||
if (rlcP->retransmission_buffer[id_index]) {
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[id_index]->data))->ack = RLC_AM_PDU_NACK_EVENT;
|
||||
retransmit_pdu (rlcP, fsn);
|
||||
rlcP->stat_tx_retransmit_pdu_by_status += 1;
|
||||
/*
|
||||
if (*first_error_indicated_snP == -1) {
|
||||
*first_error_indicated_snP = fsn;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (*first_error_indicated_snP == -1) {
|
||||
#ifdef DEBUG_BITMAP
|
||||
msg ("[RLC_AM][RB %d][BITMAP] FIRST ERROR INDICATED 0x%04x\n", rlcP->rb_id, fsn);
|
||||
#endif
|
||||
*first_error_indicated_snP = fsn;
|
||||
}
|
||||
}
|
||||
|
||||
// inc searched sequence number
|
||||
fsn++;
|
||||
fsn = fsn & SN_12BITS_MASK;
|
||||
bit_mask = bit_mask >> 1;
|
||||
// remaining nb bits to process
|
||||
end_bit--;
|
||||
|
||||
if (!bit_mask) {
|
||||
bit_mask = 128;
|
||||
bitmap_sufiP++;
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap_sufiP;
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][BITMAP] ERROR SUFI BITMAP INVALID sn 0x%02X vt(a) 0x%04X vt(s) 0x%04X send RESET requested\n", rlcP->rb_id, fsn, rlcP->vt_a, rlcP->vt_s);
|
||||
#endif
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
send_reset_pdu (rlcP);
|
||||
return bitmap_sufiP;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
* retransmit all mem_block_t(s) not correctly received
|
||||
* @param bitmap_sufiP pointer on byte containing field "sufi type"
|
||||
* @param byte_alignedP tells if sufi type quartet is on MSByte (1) or LSByte (0)
|
||||
*/
|
||||
inline uint8_t*
|
||||
retransmission_buffer_management_list (struct rlc_am_entity* rlcP, uint8_t* bitmap_sufiP, uint8_t byte_alignedP, int16_t* first_error_indicated_snP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t* p8;
|
||||
uint16_t start_marking_sn;
|
||||
uint8_t nb_missing_pdu;
|
||||
uint8_t nb_pairs;
|
||||
p8 = bitmap_sufiP;
|
||||
|
||||
if (byte_alignedP) {
|
||||
nb_pairs = *p8++ & 0X0F; // number of (SNi, Li) pairs in the sufi type LIST the value 0000
|
||||
|
||||
// is invalid and the list is discarded
|
||||
if (!nb_pairs) {
|
||||
p8 = p8 + 2;
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][LIST] ERROR SUFI LIST nb pairs is 0 send RESET requested\n", rlcP->rb_id);
|
||||
#endif
|
||||
send_reset_pdu (rlcP);
|
||||
#ifdef DEBUG_LIST
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
#endif
|
||||
return p8;
|
||||
return p8;
|
||||
|
||||
} else {
|
||||
while (nb_pairs) {
|
||||
start_marking_sn = ((uint16_t) (*p8++)) << 4;
|
||||
start_marking_sn = start_marking_sn | (*p8 >> 4);
|
||||
nb_missing_pdu = *p8++ & 0X0F;
|
||||
|
||||
if (*first_error_indicated_snP == -1) {
|
||||
*first_error_indicated_snP = start_marking_sn;
|
||||
#ifdef DEBUG_LIST
|
||||
msg ("[RLC_AM][RB %d][LIST] FIRST ERROR INDICATED 0x%04X VT(A) 0x%04X VT(S) 0x%04X\n", rlcP->rb_id, *first_error_indicated_snP, rlcP->vt_a, rlcP->vt_s);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LIST
|
||||
msg ("[RLC_AM][RB %d][LIST] SUFI LIST SN 0x%04X MISSING %d VT(A) 0x%04X VT(S) 0x%04X\n", rlcP->rb_id, start_marking_sn, nb_missing_pdu, rlcP->vt_a,
|
||||
rlcP->vt_s);
|
||||
#endif
|
||||
|
||||
while (nb_missing_pdu) {
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, start_marking_sn, rlcP->vt_a) >= 0) {
|
||||
if (rlcP->retransmission_buffer[start_marking_sn % rlcP->recomputed_configured_tx_window_size] != NULL) {
|
||||
#ifdef DEBUG_LIST
|
||||
msg ("[RLC_AM][RB %d][LIST] MARK SN 0x%04X INDEX 0x%04X TO RLC_AM_PDU_NACK_EVENT\n", rlcP->rb_id, start_marking_sn,
|
||||
start_marking_sn % rlcP->recomputed_configured_tx_window_size);
|
||||
#endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[start_marking_sn % rlcP->recomputed_configured_tx_window_size]->data))->ack =
|
||||
RLC_AM_PDU_NACK_EVENT;
|
||||
retransmit_pdu (rlcP, start_marking_sn);
|
||||
rlcP->stat_tx_retransmit_pdu_by_status += 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
send_reset_pdu (rlcP);
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][LIST] ERROR SUFI LIST INVALID SN 0x%02X VT(A) 0x%04X VT(S) 0x%04X send RESET requested \n", rlcP->rb_id, start_marking_sn, rlcP->vt_a,
|
||||
rlcP->vt_s);
|
||||
#endif
|
||||
#ifdef DEBUG_LIST
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
#endif
|
||||
return p8;
|
||||
}
|
||||
|
||||
start_marking_sn = (start_marking_sn + 1) & SN_12BITS_MASK;
|
||||
nb_missing_pdu--;
|
||||
}
|
||||
|
||||
nb_pairs--;
|
||||
}
|
||||
|
||||
return p8;
|
||||
}
|
||||
|
||||
} else {
|
||||
p8++;
|
||||
nb_pairs = *p8 >> 4; // number of (SNi, Li) pairs in the sufi type LIST the value 0000
|
||||
|
||||
// is invalid and the list is discarded
|
||||
if (!nb_pairs) {
|
||||
p8 = p8 + 2;
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][LIST] ERROR SUFI LIST nb pairs is 0 send RESET requested vt(a) 0x%04X vt(s) 0x%04X\n", rlcP->rb_id, rlcP->vt_a, rlcP->vt_s);
|
||||
#endif
|
||||
send_reset_pdu (rlcP);
|
||||
#ifdef DEBUG_LIST
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
#endif
|
||||
return p8;
|
||||
|
||||
} else {
|
||||
while (nb_pairs) {
|
||||
start_marking_sn = ((uint16_t) (*p8++) & 0x0F) << 8;
|
||||
start_marking_sn = start_marking_sn | *p8++;
|
||||
nb_missing_pdu = *p8 >> 4;
|
||||
|
||||
if (*first_error_indicated_snP == -1) {
|
||||
*first_error_indicated_snP = start_marking_sn;
|
||||
#ifdef DEBUG_LIST
|
||||
msg ("[RLC_AM][RB %d][LIST] FIRST ERROR INDICATED 0x%04X VT(A) 0x%04X VT(S) 0x%04X\n", rlcP->rb_id, *first_error_indicated_snP, rlcP->vt_a, rlcP->vt_s);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LIST
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] SUFI LIST SN 0x%04X MISSING %d VT(A) 0x%04X VT(S) 0x%04X\n", rlcP->rb_id, start_marking_sn, nb_missing_pdu, rlcP->vt_a,
|
||||
rlcP->vt_s);
|
||||
#endif
|
||||
|
||||
while (nb_missing_pdu) {
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->vt_a, start_marking_sn, rlcP->vt_a) >= 0) {
|
||||
if (rlcP->retransmission_buffer[start_marking_sn % rlcP->recomputed_configured_tx_window_size] != NULL) {
|
||||
#ifdef DEBUG_LIST
|
||||
msg ("[RLC_AM][RB %d][LIST] MARK SN 0x%04X INDEX 0x%04X TO RLC_AM_PDU_NACK_EVENT\n", rlcP->rb_id, start_marking_sn,
|
||||
start_marking_sn % rlcP->recomputed_configured_tx_window_size);
|
||||
#endif
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[start_marking_sn % rlcP->recomputed_configured_tx_window_size]->data))->ack =
|
||||
RLC_AM_PDU_NACK_EVENT;
|
||||
retransmit_pdu (rlcP, start_marking_sn);
|
||||
rlcP->stat_tx_retransmit_pdu_by_status += 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
send_reset_pdu (rlcP);
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][LIST] ERROR SUFI LIST invalid sn 0x%02X send RESET requested vt(a) 0x%04X vt(s) 0x%04X\n", rlcP->rb_id, start_marking_sn, rlcP->vt_a,
|
||||
rlcP->vt_s);
|
||||
#endif
|
||||
#ifdef DEBUG_LIST
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
#endif
|
||||
return p8;
|
||||
}
|
||||
|
||||
start_marking_sn = (start_marking_sn + 1) & SN_12BITS_MASK;
|
||||
nb_missing_pdu--;
|
||||
}
|
||||
|
||||
nb_pairs--;
|
||||
}
|
||||
|
||||
return p8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
free_retransmission_buffer (struct rlc_am_entity* rlcP, uint16_t indexP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* sdu_confirm;
|
||||
struct rlc_am_tx_data_pdu_management* pdu;
|
||||
mem_block_t* le = NULL;
|
||||
unsigned int index;
|
||||
unsigned int sdu_index;
|
||||
index = indexP;
|
||||
|
||||
if (index < (uint16_t) rlcP->recomputed_configured_tx_window_size) {
|
||||
le = rlcP->retransmission_buffer[index];
|
||||
|
||||
if (le != NULL) {
|
||||
// ???
|
||||
pdu = (struct rlc_am_tx_data_pdu_management*) (le->data);
|
||||
|
||||
// test if the sender of the sdu requested a confirmation of the reception of the sdu by the receiving RLC
|
||||
// or if mode discard is on
|
||||
for (sdu_index = 0; sdu_index < pdu->nb_sdu; sdu_index++) {
|
||||
if (pdu->sdu[sdu_index] != -1) { // may be discarded
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->nb_pdus_ack += 1;
|
||||
|
||||
if ((((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->nb_pdus_ack ==
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->nb_pdus) &&
|
||||
(((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->segmented)) {
|
||||
if (((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->confirm) {
|
||||
// send confirmation to upper layers
|
||||
#ifdef DEBUG_RLC_AM_SEND_CONFIRM
|
||||
msg ("[RLC_AM][RB %d][CONFIRM] SDU MUI %d ACK BY PEER\n", rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->mui);
|
||||
#endif
|
||||
rlc_data_conf (0, rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->mui, RLC_TX_CONFIRM_SUCCESSFULL,
|
||||
rlcP->data_plane);
|
||||
}
|
||||
|
||||
// FREE SDU : we can remove the sdu if timer based discard and all pdus submitted to lower layers and no confirm running
|
||||
#ifdef DEBUG_RLC_AM_FREE_SDU
|
||||
msg ("[RLC_AM][RB %d][RETRANS] FREE PDU INDEX 0x%04X FREE_SDU INDEX 0x%3X\n", rlcP->rb_id, indexP, pdu->sdu[sdu_index]);
|
||||
#endif
|
||||
free_mem_block (rlcP->input_sdus[pdu->sdu[sdu_index]]);
|
||||
rlcP->input_sdus[pdu->sdu[sdu_index]] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now check if a copy of the pdu is not present in the retransmission_buffer_to_send
|
||||
if ((pdu->copy)) {
|
||||
list2_remove_element (pdu->copy, &rlcP->retransmission_buffer_to_send);
|
||||
free_mem_block (pdu->copy);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] FREE PDU INDEX=0x%04X %p\n", rlcP->rb_id, index, le);
|
||||
#endif
|
||||
|
||||
// if this pdu has been retransmitted, remove its size from buffer occupancy
|
||||
if (pdu->vt_dat > 0) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer -= 1;
|
||||
}
|
||||
|
||||
free_mem_block (le);
|
||||
rlcP->retransmission_buffer[index] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
//msg("[RLC_AM %p][RETRANSMISSION] ERROR free_retransmission_buffer() pointer to free is NULL, index in array = %04X\n", rlcP,index);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] ERROR free_retransmission_buffer() invalid index in array decimal %d \n", rlcP->rb_id, index);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
free_retransmission_buffer_no_confirmation (struct rlc_am_entity* rlcP, uint16_t indexP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_tx_data_pdu_management* pdu;
|
||||
mem_block_t* le = NULL;
|
||||
unsigned int index;
|
||||
unsigned int sdu_index;
|
||||
index = indexP;
|
||||
|
||||
if (index < (uint16_t) rlcP->recomputed_configured_tx_window_size) {
|
||||
le = rlcP->retransmission_buffer[index];
|
||||
|
||||
if (le != NULL) {
|
||||
pdu = (struct rlc_am_tx_data_pdu_management*) (le->data);
|
||||
|
||||
// test if the sender of the sdu requested a confirmation of the reception of the sdu by the receiving RLC
|
||||
// or if mode discard is on
|
||||
for (sdu_index = 0; sdu_index < pdu->nb_sdu; sdu_index++) {
|
||||
if (pdu->sdu[sdu_index] != -1) { // may be discarded
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->nb_pdus_ack += 1;
|
||||
|
||||
if ((((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->nb_pdus_ack ==
|
||||
((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->nb_pdus) &&
|
||||
(((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[pdu->sdu[sdu_index]]->data))->segmented)) {
|
||||
// FREE SDU : we can remove the sdu if timer based discard and all pdus submitted to lower layers and no confirm running
|
||||
#ifdef DEBUG_RLC_AM_FREE_SDU
|
||||
msg ("[RLC_AM][RB %d][RETRANS] FREE PDU NO_CONF INDEX 0x%04X FREE_SDU INDEX %d\n", rlcP->rb_id, indexP, pdu->sdu[sdu_index]);
|
||||
#endif
|
||||
free_mem_block (rlcP->input_sdus[pdu->sdu[sdu_index]]);
|
||||
rlcP->input_sdus[pdu->sdu[sdu_index]] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now check if a copy of the pdu is not present in the retransmission_buffer_to_send
|
||||
if ((pdu->copy)) {
|
||||
list2_remove_element (pdu->copy, &rlcP->retransmission_buffer_to_send);
|
||||
free_mem_block (pdu->copy);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] FREE PDU NO_CONF INDEX=0x%04X %p\n", rlcP->rb_id, index, le);
|
||||
#endif
|
||||
|
||||
// if this pdu has been retransmitted, remove its size from buffer occupancy
|
||||
if (pdu->vt_dat > 0) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer -= 1;
|
||||
}
|
||||
|
||||
free_mem_block (le);
|
||||
rlcP->retransmission_buffer[index] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
//msg("[RLC_AM %p][RETRANSMISSION] ERROR free_retransmission_buffer() pointer to free is NULL, index in array = %04X\n", rlcP,index);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] ERROR free_retransmission_buffer() invalid index in array decimal %d \n", rlcP->rb_id, index);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
insert_into_retransmission_buffer (struct rlc_am_entity* rlcP, uint16_t indexP, mem_block_t* pduP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t index;
|
||||
index = indexP;
|
||||
|
||||
if (index < (uint16_t) (rlcP->recomputed_configured_tx_window_size)) {
|
||||
if (rlcP->retransmission_buffer[index]) {
|
||||
#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] INSERT PDU ERROR SLOT NOT EMPTY %d=0x%04X\n", rlcP->rb_id, index, index);
|
||||
display_retransmission_buffer (rlcP);
|
||||
#endif
|
||||
free_mem_block (rlcP->retransmission_buffer[index]);
|
||||
}
|
||||
|
||||
rlcP->retransmission_buffer[index] = pduP;
|
||||
#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] INSERT PDU INDEX=0x%04X %p\n", rlcP->rb_id, indexP, pduP);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
free_mem_block (pduP);
|
||||
//#ifdef DEBUG_BUFFER_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] ERROR INSERT RETRANS INVALID INDEX in array decimal %d\n", rlcP->rb_id, index);
|
||||
//#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline uint8_t
|
||||
retransmit_pdu (struct rlc_am_entity* rlcP, uint16_t snP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* pdu, *copy;
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
uint16_t index;
|
||||
|
||||
if ((rlcP->protocol_state & RLC_DATA_TRANSFER_READY_STATE)) {
|
||||
index = snP % rlcP->recomputed_configured_tx_window_size;
|
||||
pdu = rlcP->retransmission_buffer[index];
|
||||
|
||||
if (pdu) {
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) (pdu->data);
|
||||
pdu_mngt->vt_dat += 1;
|
||||
|
||||
// if first retransmission, add to buffer occupancy
|
||||
if (pdu_mngt->vt_dat == 1) {
|
||||
rlcP->buffer_occupancy_retransmission_buffer += 1;
|
||||
}
|
||||
|
||||
if ((pdu_mngt->vt_dat < rlcP->max_dat) || ((rlcP->sdu_discard_mode & SDU_DISCARD_MODE_TIMER_BASED_EXPLICIT))) {
|
||||
// now check if a copy of the pdu is not already present in the retransmission buffer
|
||||
if (pdu_mngt->copy == NULL) {
|
||||
copy = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (copy) {
|
||||
memcpy (copy->data, pdu->data, rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation));
|
||||
list2_add_tail (copy, &rlcP->retransmission_buffer_to_send);
|
||||
// make link between the original pdu and its copy
|
||||
pdu_mngt->copy = copy;
|
||||
((struct rlc_am_tx_data_pdu_management*) (copy->data))->copy = pdu;
|
||||
#ifdef BENCH_QOS_L2
|
||||
fprintf (bench_l2, "[PDU RETRANS] FRAME %d SN %d VT_DAT %d RLC-AM %p\n", Mac_rlc_xface->frame, snP, pdu_mngt->vt_dat, rlcP);
|
||||
#endif
|
||||
#ifdef DEBUG_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] PDU SN = 0x%04X hex VT(DAT) %d frame %d\n", rlcP->rb_id, snP, pdu_mngt->vt_dat, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] ERROR retransmit_pdu() retransmited copy of pdu is NULL index in array %04X\n", rlcP->rb_id, index);
|
||||
return RLC_AM_OUT_OF_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] PDU SN = 0x%04X hex VT(DAT) %d already in retransmission buffer to send\n", rlcP->rb_id, snP, pdu_mngt->vt_dat);
|
||||
#endif
|
||||
return RLC_AM_RETRANS_REQ_PDU_DONE_BEFORE;
|
||||
}
|
||||
|
||||
} else {
|
||||
if ((rlcP->sdu_discard_mode & SDU_DISCARD_MODE_TIMER_BASED_EXPLICIT)) {
|
||||
// DO NOTHING
|
||||
} else if ((rlcP->sdu_discard_mode & RLC_SDU_DISCARD_MAX_DAT_RETRANSMISSION)) {
|
||||
#ifdef DEBUG_RETRANSMISSION
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] VT(DAT) %d REACHED MAX_DAT, DISCARD PROCEDURE WILL BE STARTED frame %d\n", rlcP->rb_id, pdu_mngt->vt_dat,
|
||||
Mac_rlc_xface->frame);
|
||||
#endif
|
||||
rlc_am_discard_notify_max_dat_pdu (rlcP, pdu);
|
||||
|
||||
} else { // if No_discard after MaxDat number of retransmissions is used, the sender shall initiate the
|
||||
// RLC reset procedure when VT(DAT) >= MaxDAT (from 3GPP TS 25.322 V5.0.0 )
|
||||
// max transmission reached for this PDU, reset RLC entities
|
||||
#ifdef DEBUG_RESET
|
||||
msg ("[RLC_AM][RB %d][RETRANSMISSION] VT(DAT) %d REACHED MAX_DAT, RESET frame %d\n", rlcP->rb_id, pdu_mngt->vt_dat, Mac_rlc_xface->frame);
|
||||
#endif
|
||||
send_reset_pdu (rlcP);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
return RLC_AM_RETRANS_REQ_PDU_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_get_not_acknowledged_pdu_optimized (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t vt_dat_min = 255;
|
||||
uint16_t sn;
|
||||
uint16_t sn_min;
|
||||
mem_block_t* pdu;
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
sn = rlcP->vt_s;
|
||||
sn_min = sn;
|
||||
|
||||
while (sn != rlcP->vt_a) {
|
||||
sn = (sn - 1) & SN_12BITS_MASK;
|
||||
pdu = rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size];
|
||||
|
||||
if ((pdu)) {
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) (pdu->data);
|
||||
|
||||
if (pdu_mngt->vt_dat < vt_dat_min) {
|
||||
sn_min = sn;
|
||||
vt_dat_min = pdu_mngt->vt_dat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rlcP->retransmission_buffer[sn_min % rlcP->recomputed_configured_tx_window_size]) {
|
||||
retransmit_pdu (rlcP, sn_min);
|
||||
rlcP->stat_tx_retransmit_pdu_unblock += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_get_not_acknowledged_pdu (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t sn;
|
||||
sn = rlcP->vt_s;
|
||||
|
||||
while (sn != rlcP->vt_a) {
|
||||
sn = (sn - 1) & SN_12BITS_MASK;
|
||||
|
||||
if (rlcP->retransmission_buffer[sn % rlcP->recomputed_configured_tx_window_size]) {
|
||||
retransmit_pdu (rlcP, sn);
|
||||
rlcP->stat_tx_retransmit_pdu_unblock += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_get_not_acknowledged_pdu_vt_s_minus_1 (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
if (rlcP->retransmission_buffer[((rlcP->vt_s - 1) & SN_12BITS_MASK) % rlcP->recomputed_configured_tx_window_size]) {
|
||||
retransmit_pdu (rlcP, (rlcP->vt_s - 1) & SN_12BITS_MASK);
|
||||
rlcP->stat_tx_retransmit_pdu_unblock += 1;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_retrans_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_RETRANS_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_RETRANS_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "rlc_am_constants.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern int16_t retransmission_buffer_management_ack (struct rlc_am_entity *rlcP, uint8_t * sufiP, uint8_t byte_alignedP, int16_t * first_error_indicated_snP);
|
||||
extern uint8_t *retransmission_buffer_management_bitmap (struct rlc_am_entity *rlcP, uint8_t * bitmap_sufiP, uint8_t byte_alignedP, int16_t * first_error_indicated_snP);
|
||||
extern uint8_t *retransmission_buffer_management_list (struct rlc_am_entity *rlcP, uint8_t * bitmap_sufiP, uint8_t byte_alignedP, int16_t * first_error_indicated_snP);
|
||||
extern void free_retransmission_buffer (struct rlc_am_entity *rlcP, uint16_t indexP);
|
||||
extern void free_retransmission_buffer_no_confirmation (struct rlc_am_entity *rlcP, uint16_t indexP);
|
||||
extern void insert_into_retransmission_buffer (struct rlc_am_entity *rlcP, uint16_t indexP, mem_block_t * pduP);
|
||||
extern uint8_t retransmit_pdu (struct rlc_am_entity *rlcP, uint16_t snP);
|
||||
extern void rlc_am_get_not_acknowledged_pdu (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_get_not_acknowledged_pdu_vt_s_minus_1 (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_get_not_acknowledged_pdu_optimized (struct rlc_am_entity *rlcP);
|
||||
# endif
|
||||
@@ -1,616 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_segment.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "list.h"
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_primitives.h"
|
||||
#include "mem_block.h"
|
||||
|
||||
//#define DEBUG_RLC_AM_SEGMENT
|
||||
//#define DEBUG_RLC_AM_SEGMENT_FILL_DATA
|
||||
//#define DEBUG_MEM_MNGT
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* rlc_am_segment_15 (struct rlc_am_entity* rlcP);
|
||||
mem_block_t* rlc_am_segment_7 (struct rlc_am_entity* rlcP);
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
rlc_am_encode_pdu_15 (struct rlc_am_pdu_header* rlc_headerP, struct rlc_am_tx_data_pdu_management* pdu_mngtP, uint16_t* li_arrayP, uint8_t nb_liP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t li_index;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
int index;
|
||||
msg ("[RLC_AM] SEGMENT_15 PDU SET LIs: ");
|
||||
|
||||
for (index = 0; index < nb_liP; index++) {
|
||||
msg ("%04X ", li_arrayP[index]);
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
#endif
|
||||
rlc_headerP->byte1 = RLC_DC_DATA_PDU;
|
||||
rlc_headerP->byte2 = 0;
|
||||
nb_liP = nb_liP << 1;
|
||||
pdu_mngtP->payload = (uint8_t*) ((uint32_t) (&rlc_headerP->li_data_7[nb_liP]));
|
||||
|
||||
if (nb_liP) {
|
||||
rlc_headerP->byte2 |= RLC_E_NEXT_FIELD_IS_LI_E;
|
||||
li_index = 0;
|
||||
|
||||
// COPY LI
|
||||
while (li_index < nb_liP) {
|
||||
rlc_headerP->li_data_7[li_index] = li_arrayP[li_index >> 1] >> 8;
|
||||
li_index += 1;
|
||||
rlc_headerP->li_data_7[li_index] = li_arrayP[li_index >> 1] | RLC_E_NEXT_FIELD_IS_LI_E;
|
||||
li_index += 1;
|
||||
}
|
||||
|
||||
rlc_headerP->li_data_7[li_index - 1] = rlc_headerP->li_data_7[li_index - 1] ^ (uint8_t) RLC_E_NEXT_FIELD_IS_LI_E;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
rlc_am_encode_pdu_7 (struct rlc_am_pdu_header* rlc_headerP, struct rlc_am_tx_data_pdu_management* pdu_mngtP, uint16_t* li_arrayP, uint8_t nb_liP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t li_index;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
int index;
|
||||
msg ("[RLC_AM] SEGMENT_7 PDU %p SET LIs: ", pdu_mngtP);
|
||||
|
||||
for (index = 0; index < nb_liP; index++) {
|
||||
msg ("%04X ", li_arrayP[index]);
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
#endif
|
||||
rlc_headerP->byte1 = RLC_DC_DATA_PDU;
|
||||
rlc_headerP->byte2 = 0;
|
||||
pdu_mngtP->payload = (uint8_t*) ((uint32_t) (&rlc_headerP->li_data_7[nb_liP]));
|
||||
|
||||
if (nb_liP) {
|
||||
rlc_headerP->byte2 |= RLC_E_NEXT_FIELD_IS_LI_E;
|
||||
li_index = 0;
|
||||
|
||||
// COPY LI
|
||||
while (li_index < nb_liP) {
|
||||
rlc_headerP->li_data_7[li_index] = (uint8_t) (li_arrayP[li_index]) | RLC_E_NEXT_FIELD_IS_LI_E;
|
||||
li_index += 1;
|
||||
}
|
||||
|
||||
rlc_headerP->li_data_7[li_index - 1] = rlc_headerP->li_data_7[li_index - 1] ^ (uint8_t) RLC_E_NEXT_FIELD_IS_LI_E;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void
|
||||
rlc_am_fill_pdu (mem_block_t* pduP, list_t* segmented_sdusP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t* sdu;
|
||||
uint8_t* data_sdu;
|
||||
uint8_t* data_pdu;
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
struct rlc_am_tx_sdu_management* sdu_mngt;
|
||||
int continue_fill;
|
||||
uint16_t pdu_remaining_size;
|
||||
uint16_t sdu_available_size;
|
||||
sdu = NULL;
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) (pduP->data);
|
||||
rlc_header = (struct rlc_am_pdu_header*) (pdu_mngt->first_byte);
|
||||
pdu_remaining_size = pdu_mngt->data_size;
|
||||
data_pdu = (uint8_t*) pdu_mngt->payload;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT_FILL_DATA
|
||||
msg ("[RLC_AM] SEGMENT FILL GET PDU %p REMAINING SIZE=%d\n", pduP, pdu_remaining_size);
|
||||
#endif
|
||||
continue_fill = 1;
|
||||
|
||||
while ((continue_fill)) {
|
||||
// fill the pdu with data of sdu
|
||||
if (sdu == NULL) {
|
||||
sdu = list_remove_head (segmented_sdusP);
|
||||
|
||||
if (sdu == NULL) {
|
||||
return; // case pdu only 2 LIs : exactly_filled or one_byte_short + paddind
|
||||
}
|
||||
|
||||
sdu_mngt = (struct rlc_am_tx_sdu_management*) (sdu->data);
|
||||
data_sdu = &sdu->data[sizeof (struct rlc_am_tx_sdu_management) + sdu_mngt->sdu_segmented_size];
|
||||
sdu_available_size = sdu_mngt->sdu_size - sdu_mngt->sdu_remaining_size - sdu_mngt->sdu_segmented_size;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT_FILL_DATA
|
||||
msg ("[RLC_AM] SEGMENT FILL GET SDU %p AVAILABLE_SZ=%d (SZ %d REMAIN_SZ %d SEGMENT_SZ %d)\n",
|
||||
sdu, sdu_available_size, sdu_mngt->sdu_size, sdu_mngt->sdu_remaining_size, sdu_mngt->sdu_segmented_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
// copy the whole remaining data of the sdu in the remaining area of the pdu
|
||||
if (pdu_remaining_size >= sdu_available_size) {
|
||||
memcpy (data_pdu, data_sdu, sdu_available_size);
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT_FILL_DATA
|
||||
msg ("[RLC_AM] SEGMENT FILL PDU %p WITH SDU %p %p <- %p %d bytes (SZ %d REMAIN_SZ %d SEGMENT_SZ %d)\n",
|
||||
pduP, sdu, data_pdu, data_sdu, sdu_available_size, sdu_mngt->sdu_size, sdu_mngt->sdu_remaining_size, sdu_mngt->sdu_segmented_size);
|
||||
#endif
|
||||
pdu_remaining_size -= sdu_available_size;
|
||||
sdu_mngt->sdu_segmented_size += sdu_available_size;
|
||||
data_pdu = (uint8_t*) ((uint32_t) data_pdu + sdu_available_size);
|
||||
sdu_available_size = 0;
|
||||
// dispatch the sdu
|
||||
sdu = NULL;
|
||||
|
||||
// dispatch the pdu
|
||||
if (pdu_remaining_size == 0) {
|
||||
continue_fill = 0;
|
||||
|
||||
} else {
|
||||
}
|
||||
|
||||
// copy some data of the sdu in the whole remaining area of the pdu
|
||||
} else {
|
||||
memcpy (data_pdu, data_sdu, pdu_remaining_size);
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT_FILL_DATA
|
||||
msg ("[RLC_AM] SEGMENT FILL PDU %p WITH SDU %p %p <- %p %d bytes (SZ %d REMAIN_SZ %d SEGMENT_SZ %d)\n",
|
||||
pduP, sdu, data_pdu, data_sdu, pdu_remaining_size, sdu_mngt->sdu_size, sdu_mngt->sdu_remaining_size, sdu_mngt->sdu_segmented_size);
|
||||
#endif
|
||||
sdu_mngt->sdu_segmented_size += pdu_remaining_size;
|
||||
sdu_available_size -= pdu_remaining_size;
|
||||
data_sdu = (uint8_t*) ((uint32_t) data_sdu + (uint32_t) pdu_remaining_size);
|
||||
continue_fill = 0;
|
||||
pdu_remaining_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
list_free (segmented_sdusP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t*
|
||||
rlc_am_segment_15 (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
list_t segmented_sdus; // the copying of sdu data is done after identification of all LIs to put in pdu
|
||||
struct rlc_am_tx_sdu_management* sdu_mngt;
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
mem_block_t* pdu;
|
||||
int continue_segment = 1;
|
||||
int16_t pdu_remaining_size;
|
||||
uint8_t li_index = 0;
|
||||
pdu = NULL;
|
||||
list_init (&segmented_sdus, NULL); // param string identifying the list is NULL
|
||||
|
||||
while ((rlcP->input_sdus[rlcP->current_sdu_index]) && (continue_segment)) {
|
||||
sdu_mngt = ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[rlcP->current_sdu_index]->data));
|
||||
|
||||
if (!(sdu_mngt->segmented)) {
|
||||
// pdu management
|
||||
if (!(pdu)) {
|
||||
if (!(pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation) + GUARD_CRC_LIH_SIZE))) {
|
||||
#ifdef DEBUG_MEM_MNGT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT] ERROR COULD NOT GET NEW PDU, EXIT\n", rlcP->rb_id);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
li_index = 0;
|
||||
pdu_remaining_size = rlcP->pdu_size - 2; // 2= size of header, minimum
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) (pdu->data);
|
||||
memset (pdu->data, 0, sizeof (struct rlc_am_tx_data_pdu_allocation));
|
||||
pdu_mngt->rlc_tb_type = RLC_AM_DATA_PDU_TYPE;
|
||||
pdu_mngt->first_byte = &pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
rlc_header = (struct rlc_am_pdu_header*) (pdu_mngt->first_byte);
|
||||
}
|
||||
|
||||
if (sdu_mngt->sdu_remaining_size > 0) { // think RLC_LI_LAST_PDU_ONE_BYTE_SHORT, RLC_LI_LAST_PDU_EXACTLY_FILLED
|
||||
if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) < 0) {
|
||||
pdu_mngt->data_size += pdu_remaining_size;
|
||||
rlc_am_encode_pdu_15 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
sdu_mngt->sdu_remaining_size = sdu_mngt->sdu_remaining_size - pdu_remaining_size;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
|
||||
} else {
|
||||
// From 3GPP TS 25.322 V4.2.0 (2001-09) p28
|
||||
// If "SDU discard with explicit signalling" is configured:
|
||||
// - an AMD PDU can contain a maximum number of 15 "Length Indicators" indicating the end
|
||||
// of 15 corresponding SDUs; and
|
||||
// - the rest of the AMD PDU space shall be used as padding or as piggybacked STATUS PDU.
|
||||
// implementation limitation : we limit the number of li to 15 even if
|
||||
// no "SDU discard with explicit signalling" is configured.
|
||||
if (li_index >= 14) {
|
||||
rlcP->li[li_index++] = RLC_LI_PDU_PADDING;
|
||||
rlc_am_encode_pdu_15 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
sdu_mngt->no_new_sdu_segmented_in_last_pdu = 1;
|
||||
|
||||
} else { // nb li have not reached the limit
|
||||
if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) >= 2) {
|
||||
pdu_remaining_size = pdu_remaining_size - sdu_mngt->sdu_remaining_size - 2; // size of li length
|
||||
pdu_mngt->data_size += sdu_mngt->sdu_remaining_size;
|
||||
sdu_mngt->li_index_for_discard = li_index;
|
||||
rlcP->li[li_index++] = sdu_mngt->sdu_remaining_size << 1;
|
||||
sdu_mngt->sdu_remaining_size = 0;
|
||||
sdu_mngt->segmented = 1;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
pdu_mngt->last_pdu_of_sdu += 1;
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
rlcP->buffer_occupancy -= sdu_mngt->sdu_size;
|
||||
rlcP->nb_sdu -= 1;
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
//} else the while loop continue with the same pdu
|
||||
|
||||
} else if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) == 0) {
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
//In the case where the end of the last segment of an RLC SDU exactly ends at the end of
|
||||
// a PDU and there is no "Length Indicator" that indicates the end of the RLC SDU:
|
||||
// - if 7-bit "Length Indicator" is used:
|
||||
// - a "Length Indicator" with value "000 0000" shall be placed as the first "Length
|
||||
// Indicator" in the following PDU;
|
||||
// - if 15-bit "Length Indicator" is used:
|
||||
// - a "Length Indicator" with value "000 0000 0000 0000" shall be placed as the first
|
||||
// "Length Indicator" in the following PDU.
|
||||
pdu_mngt->data_size += pdu_remaining_size;
|
||||
rlc_am_encode_pdu_15 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
sdu_mngt->sdu_remaining_size = 0;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 1;
|
||||
|
||||
} else if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) == 1) { // one byte remaining
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
// In the case where a PDU contains a 15-bit "Length Indicator" indicating that an RLC SDU ends with
|
||||
// one octet left in the PDU, the last octet of this PDU shall:
|
||||
// - be padded by the Sender and ignored by the Receiver though there is no "Length Indicator"
|
||||
// indicating the existence of Padding; and
|
||||
// - not be filled with the first octet of the next RLC SDU data.
|
||||
// In the case where 15-bit "Length Indicators" are used for the previous PDU and
|
||||
// the last segment of an RLC SDU is one octet short of exactly filling the PDU:
|
||||
// - if a 15-bit "Length Indicator" is used for the following PDU:
|
||||
// - the "Length Indicator" with value "111 1111 1111 1011" shall be placed as
|
||||
// the first "Length Indicator" in the following PDU;
|
||||
// - the remaining one octet in the previous PDU shall be padded by the Sender
|
||||
// and ignored at the Receiver though there is no "Length Indicator" indicating
|
||||
// the existence of Padding;
|
||||
// - in case this SDU was the last one to be transmitted:
|
||||
// - a RLC PDU consisting of an RLC Header with "Length Indicator"
|
||||
// "111 1111 1111 1011" followed by a padding "Length Indicator" and padding
|
||||
// may be transmitted;
|
||||
pdu_mngt->data_size += pdu_remaining_size;
|
||||
rlc_am_encode_pdu_15 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
sdu_mngt->sdu_remaining_size = 0;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
rlcP->li_one_byte_short_to_add_in_next_pdu = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// management of previous pdu
|
||||
// In the case where 15-bit "Length Indicators" are used for the previous PDU and
|
||||
// the last segmentof an RLC SDU is one octet short of exactly filling the PDU:
|
||||
// - if a 15-bit "Length Indicator" is used for the following PDU:
|
||||
// - the "Length Indicator" with value "111 1111 1111 1011" shall be placed
|
||||
// as the first "Length Indicator" in the following PDU;
|
||||
// - the remaining one octet in the previous PDU shall be padded by the Sender
|
||||
// and ignored at the Receiver though there is no "Length Indicator" indicating
|
||||
// the existence of Padding;
|
||||
// - in case this SDU was the last one to be transmitted:
|
||||
// - a RLC PDU consisting of an RLC Header with "Length Indicator"
|
||||
// "111 1111 1111 1011" followed by a padding "Length Indicator" and padding
|
||||
// may be transmitted;
|
||||
|
||||
} else if ((rlcP->li_one_byte_short_to_add_in_next_pdu)) {
|
||||
sdu_mngt->li_index_for_discard = li_index;
|
||||
rlcP->li[li_index++] = RLC_LI_LAST_PDU_ONE_BYTE_SHORT;
|
||||
rlcP->li_one_byte_short_to_add_in_next_pdu = 0;
|
||||
sdu_mngt->segmented = 1;
|
||||
pdu_remaining_size -= 2;
|
||||
pdu_mngt->last_pdu_of_sdu += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
rlcP->buffer_occupancy -= sdu_mngt->sdu_size;
|
||||
rlcP->nb_sdu -= 1;
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
|
||||
} else if ((rlcP->li_exactly_filled_to_add_in_next_pdu)) {
|
||||
sdu_mngt->li_index_for_discard = li_index;
|
||||
rlcP->li[li_index++] = RLC_LI_LAST_PDU_EXACTLY_FILLED;
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 0;
|
||||
sdu_mngt->segmented = 1;
|
||||
pdu_remaining_size -= 2;
|
||||
pdu_mngt->last_pdu_of_sdu += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
rlcP->buffer_occupancy -= sdu_mngt->sdu_size;
|
||||
rlcP->nb_sdu -= 1;
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdu_mngt->sdu_remaining_size > 0) {
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
}
|
||||
}
|
||||
|
||||
if ((pdu)) {
|
||||
if ((continue_segment > 0)) { // means pdu not totaly filled
|
||||
if (pdu_remaining_size >= 2) {
|
||||
rlcP->li[li_index++] = RLC_LI_PDU_PADDING;
|
||||
sdu_mngt->no_new_sdu_segmented_in_last_pdu = 1;
|
||||
|
||||
} else if (pdu_remaining_size == 0) {
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 1;
|
||||
|
||||
} else if (pdu_remaining_size == 1) {
|
||||
rlcP->li_one_byte_short_to_add_in_next_pdu = 1;
|
||||
}
|
||||
|
||||
rlc_am_encode_pdu_15 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
}
|
||||
|
||||
rlc_am_fill_pdu (pdu, &segmented_sdus);
|
||||
|
||||
} else {
|
||||
// patch for max dat discard : avoid waiting sdu pointed by current_sdu_index <> NULL
|
||||
// (this sdu may have been segmented not at all then discarded)
|
||||
while ((rlcP->next_sdu_index != rlcP->current_sdu_index) && (rlcP->input_sdus[rlcP->current_sdu_index] == NULL)) {
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
rlcP->nb_sdu -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t*
|
||||
rlc_am_segment_7 (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
list_t segmented_sdus; // the copying of sdu data is done after identification of all LIs to put in pdu
|
||||
struct rlc_am_tx_sdu_management* sdu_mngt = NULL;
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
mem_block_t* pdu = NULL;
|
||||
int continue_segment = 1;
|
||||
int16_t pdu_remaining_size;
|
||||
uint8_t li_index = 0;
|
||||
list_init (&segmented_sdus, NULL); // param string identifying the list is NULL
|
||||
|
||||
while ((rlcP->input_sdus[rlcP->current_sdu_index]) && (continue_segment)) {
|
||||
sdu_mngt = ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[rlcP->current_sdu_index]->data));
|
||||
|
||||
if (!(sdu_mngt->segmented)) {
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d] SEGMENT GET NEW SDU %p INDEX %d AVAILABLE SIZE %d Bytes\n", rlcP->rb_id, sdu_mngt, rlcP->current_sdu_index, sdu_mngt->sdu_remaining_size);
|
||||
#endif
|
||||
|
||||
if (!(pdu)) {
|
||||
// pdu management
|
||||
if (!(pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_data_pdu_allocation) + GUARD_CRC_LIH_SIZE))) {
|
||||
#ifdef DEBUG_MEM_MNGT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] ERROR COULD NOT GET NEW PDU, EXIT\n", rlcP->rb_id);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
li_index = 0;
|
||||
pdu_remaining_size = rlcP->pdu_size - 2; // 2= size of header, minimum
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) (pdu->data);
|
||||
memset (pdu->data, 0, sizeof (struct rlc_am_tx_data_pdu_allocation));
|
||||
pdu_mngt->rlc_tb_type = RLC_AM_DATA_PDU_TYPE;
|
||||
pdu_mngt->first_byte = &pdu->data[sizeof (struct rlc_am_tx_data_pdu_allocation)];
|
||||
rlc_header = (struct rlc_am_pdu_header*) (pdu_mngt->first_byte);
|
||||
|
||||
if ((rlcP->li_exactly_filled_to_add_in_next_pdu)) {
|
||||
pdu_remaining_size -= 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] CONSTRUCT NEW PDU %p %p\n", rlcP->rb_id, pdu, pdu_mngt);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sdu_mngt->sdu_remaining_size > 0) {
|
||||
msg("sdu_mngt->sdu_remaining_size %d\n",sdu_mngt->sdu_remaining_size);
|
||||
|
||||
if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) < 0) {
|
||||
pdu_mngt->data_size += pdu_remaining_size;
|
||||
rlcP->buffer_occupancy -= pdu_remaining_size;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
rlc_am_encode_pdu_7 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
sdu_mngt->sdu_remaining_size = sdu_mngt->sdu_remaining_size - pdu_remaining_size;
|
||||
pdu_remaining_size = 0;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] PDU %p %p FILLED WITH SDU index %d SDU REMAINING %d\n", rlcP->rb_id, pdu, pdu_mngt, rlcP->current_sdu_index,
|
||||
sdu_mngt->sdu_remaining_size);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// From 3GPP TS 25.322 V4.2.0 (2001-09) p28
|
||||
// If "SDU discard with explicit signalling" is configured:
|
||||
// - an AMD PDU can contain a maximum number of 15 "Length Indicators" indicating the end
|
||||
// of 15 corresponding SDUs; and
|
||||
// - the rest of the AMD PDU space shall be used as padding or as piggybacked STATUS PDU.
|
||||
// implementation limitation : we limit the number of li to 15 even if
|
||||
// no "SDU discard with explicit signalling" is configured.
|
||||
if (li_index >= 14) {
|
||||
rlcP->li[li_index++] = RLC_LI_PDU_PADDING;
|
||||
rlc_am_encode_pdu_7 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
sdu_mngt->no_new_sdu_segmented_in_last_pdu = 1;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] NB MAX LI REACHED\n", rlcP->rb_id);
|
||||
#endif
|
||||
|
||||
} else { // nb li have not reached the limit
|
||||
if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) >= 1) {
|
||||
pdu_remaining_size = pdu_remaining_size - sdu_mngt->sdu_remaining_size - 1; // size of li length
|
||||
pdu_mngt->data_size += sdu_mngt->sdu_remaining_size;
|
||||
sdu_mngt->li_index_for_discard = li_index;
|
||||
rlcP->li[li_index++] = sdu_mngt->sdu_remaining_size << 1;
|
||||
rlcP->buffer_occupancy -= sdu_mngt->sdu_remaining_size;
|
||||
sdu_mngt->sdu_remaining_size = 0;
|
||||
sdu_mngt->segmented = 1;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
pdu_mngt->last_pdu_of_sdu += 1;
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
rlcP->nb_sdu -= 1;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] SDU index %d->%d ENDING IN PDU %p %p PDU REMAINING SIZE %d\n", rlcP->rb_id,
|
||||
rlcP->current_sdu_index, (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer, pdu, pdu_mngt, pdu_remaining_size);
|
||||
#endif
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
|
||||
// case where Li length exactly ends the pdu
|
||||
if (pdu_remaining_size == 0) {
|
||||
continue_segment = 0;
|
||||
rlc_am_encode_pdu_7 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
}
|
||||
|
||||
/*
|
||||
} else { // else:if (!last_sdu)
|
||||
} // the while loop continue with the same pdu */
|
||||
|
||||
} else if ((pdu_remaining_size - sdu_mngt->sdu_remaining_size) == 0) {
|
||||
// from 3GPP TS 25.322 V4.2.0
|
||||
//In the case where the end of the last segment of an RLC SDU exactly ends at the end of
|
||||
// a PDU and there is no "Length Indicator" that indicates the end of the RLC SDU:
|
||||
// - if 7-bit "Length Indicator" is used:
|
||||
// - a "Length Indicator" with value "000 0000" shall be placed as the first "Length
|
||||
// Indicator" in the following PDU;
|
||||
// - if 15-bit "Length Indicator" is used:
|
||||
// - a "Length Indicator" with value "000 0000 0000 0000" shall be placed as the first
|
||||
// "Length Indicator" in the following PDU.
|
||||
pdu_mngt->data_size += pdu_remaining_size;
|
||||
rlc_am_encode_pdu_7 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
continue_segment = 0;
|
||||
rlcP->buffer_occupancy -= sdu_mngt->sdu_remaining_size;
|
||||
sdu_mngt->sdu_remaining_size = 0;
|
||||
pdu_remaining_size = 0;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 1;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] SDU index %d EXACTLY ENDING IN PDU %p %p\n", rlcP->rb_id, rlcP->current_sdu_index, pdu, pdu_mngt);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// management of previous pdu
|
||||
// In the case where 15-bit "Length Indicators" are used for the previous PDU and the
|
||||
// last segment of an RLC SDU is one octet short of exactly filling the PDU:
|
||||
// - if a 15-bit "Length Indicator" is used for the following PDU:
|
||||
// - the "Length Indicator" with value "111 1111 1111 1011" shall be placed as
|
||||
// the first "Length Indicator" in the following PDU;
|
||||
// - the remaining one octet in the previous PDU shall be padded by the Sender and
|
||||
// ignored at the Receiver
|
||||
// though there is no "Length Indicator" indicating the existence of Padding;
|
||||
// - in case this SDU was the last one to be transmitted:
|
||||
// - a RLC PDU consisting of an RLC Header with "Length Indicator"
|
||||
// "111 1111 1111 1011" followed by a padding "Length Indicator" and padding
|
||||
// may be transmitted;
|
||||
// - if a 7-bit "Length Indicator" is used for the following PDU:
|
||||
// - if RLC is configured for UM mode:
|
||||
// - the "Length Indicator" with value "000 0000" shall be placed as the first
|
||||
// "Length indicator" in the following PDU and its SN shall be incremented by 2
|
||||
// before it is transmitted.
|
||||
|
||||
} else if ((rlcP->li_exactly_filled_to_add_in_next_pdu)) {
|
||||
sdu_mngt->li_index_for_discard = li_index;
|
||||
rlcP->li[li_index++] = RLC_LI_LAST_PDU_EXACTLY_FILLED;
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 0;
|
||||
sdu_mngt->segmented = 1;
|
||||
//pdu_remaining_size -= 1;
|
||||
pdu_mngt->last_pdu_of_sdu += 1;
|
||||
pdu_mngt->sdu[pdu_mngt->nb_sdu++] = rlcP->current_sdu_index;
|
||||
sdu_mngt->nb_pdus += 1;
|
||||
//rlcP->buffer_occupancy -= sdu_mngt->sdu_size;
|
||||
rlcP->nb_sdu -= 1;
|
||||
#ifdef DEBUG_RLC_AM_SEGMENT
|
||||
msg ("[RLC_AM][RB %d][SEGMENT7] RLC_LI_LAST_PDU_EXACTLY_FILLED -> PDU %p, %p, sdu index %d->%d \n", rlcP->rb_id, pdu, pdu_mngt,
|
||||
rlcP->current_sdu_index, (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer);
|
||||
#endif
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdu_mngt->sdu_remaining_size > 0) {
|
||||
list_add_tail_eurecom (rlcP->input_sdus[rlcP->current_sdu_index], &segmented_sdus);
|
||||
}
|
||||
}
|
||||
|
||||
if ((pdu)) {
|
||||
if ((continue_segment > 0)) { // means pdu not totaly filled
|
||||
if (pdu_remaining_size >= 1) {
|
||||
rlcP->li[li_index++] = RLC_LI_PDU_PADDING;
|
||||
sdu_mngt->no_new_sdu_segmented_in_last_pdu = 1;
|
||||
|
||||
} else {
|
||||
rlcP->li_exactly_filled_to_add_in_next_pdu = 1;
|
||||
}
|
||||
|
||||
rlc_am_encode_pdu_7 (rlc_header, pdu_mngt, rlcP->li, li_index);
|
||||
}
|
||||
|
||||
rlc_am_fill_pdu (pdu, &segmented_sdus);
|
||||
|
||||
} else {
|
||||
// patch for max dat discard : avoid waiting sdu pointed by current_sdu_index <> NULL
|
||||
// (this sdu may have been segmented not at all then discarded)
|
||||
while ((rlcP->next_sdu_index != rlcP->current_sdu_index) && (rlcP->input_sdus[rlcP->current_sdu_index] == NULL)) {
|
||||
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % rlcP->size_input_sdus_buffer;
|
||||
rlcP->nb_sdu -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_segment_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_SEGMENT_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_SEGMENT_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "rlc_am_constants.h"
|
||||
# include "list.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern inline uint16_t rlc_am_get_next_sn (struct rlc_am_entity *rlcP, uint16_t snP);
|
||||
extern inline int rlc_am_sn_in_tx_window (struct rlc_am_entity *rlcP, uint16_t snP);
|
||||
|
||||
extern inline void rlc_am_sdu_confirm_map_register_pdu (mem_block_t * pduP, struct rlc_am_pdu_header *rlc_headerP, mem_block_t * sdu_header_confirm_copyP);
|
||||
|
||||
extern inline void rlc_am_sdu_discard_map_register_pdu (mem_block_t * pduP, struct rlc_am_pdu_header *rlc_headerP, mem_block_t * sdu_header_discard_copyP);
|
||||
|
||||
extern mem_block_t *rlc_am_segment_15 (struct rlc_am_entity *rlcP);
|
||||
extern mem_block_t *rlc_am_segment_7 (struct rlc_am_entity *rlcP);
|
||||
# endif
|
||||
@@ -1,659 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_status.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_retrans_proto_extern.h"
|
||||
#include "rlc_am_status_proto_extern.h"
|
||||
#include "rlc_am_discard_rx_proto_extern.h"
|
||||
#include "rlc_am_proto_extern.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "LAYER2/MAC/extern.h"
|
||||
//#define DEBUG_CREATE_STATUS
|
||||
//#define DEBUG_CREATE_STATUS_SUFI
|
||||
//#define PROCESS_STATUS
|
||||
|
||||
void rlc_am_write_sufi_no_more_in_control_pdu (uint8_t * dataP, uint8_t byte_alignedP);
|
||||
void rlc_am_write_sufi_ack_in_control_pdu (uint8_t * dataP, uint16_t snP, uint8_t byte_alignedP);
|
||||
int rlc_am_send_status (struct rlc_am_entity *rlcP);
|
||||
int rlc_am_create_status_pdu (struct rlc_am_entity *rlcP, list_t* listP);
|
||||
void rlc_am_find_holes (struct rlc_am_entity *rlcP);
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_write_sufi_no_more_in_control_pdu (uint8_t * dataP, uint8_t byte_alignedP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef DEBUG_CREATE_STATUS_SUFI
|
||||
msg ("[RLC_AM][STATUS] GENERATE SUFI NO_MORE\n");
|
||||
#endif
|
||||
|
||||
if (!byte_alignedP) {
|
||||
*dataP = (*dataP & 0xF0) | RLC_AM_SUFI_NO_MORE;
|
||||
} else {
|
||||
*dataP = RLC_AM_SUFI_NO_MORE << 4;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_write_sufi_ack_in_control_pdu (uint8_t * dataP, uint16_t snP, uint8_t byte_alignedP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef DEBUG_CREATE_STATUS_SUFI
|
||||
msg ("[RLC_AM][STATUS] GENERATE SUFI ACK 0x%04X\n", snP);
|
||||
#endif
|
||||
|
||||
if (!byte_alignedP) {
|
||||
*dataP = (*dataP & 0xF0) | RLC_AM_SUFI_ACK;
|
||||
dataP++;
|
||||
*dataP++ = (uint8_t) (snP >> 4);
|
||||
*dataP = (uint8_t) (snP << 4);
|
||||
} else {
|
||||
*dataP = RLC_AM_SUFI_ACK << 4;
|
||||
*dataP = *dataP | (uint8_t) (snP >> 8);
|
||||
dataP++;
|
||||
*dataP = (uint8_t) (snP);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int
|
||||
rlc_am_send_status (struct rlc_am_entity *rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
display_receiver_buffer (rlcP);
|
||||
#endif
|
||||
|
||||
if (rlcP->timer_status_prohibit > 0) {
|
||||
if (rlcP->running_timer_status_prohibit > Mac_rlc_xface->frame) {
|
||||
//msg ("[RLC_AM][RB %d][STATUS] PREVENTED CREATE_STATUS_PDU %d %d\n", rlcP->rb_id, rlcP->running_timer_status_prohibit, Mac_rlc_xface->frame);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
//msg ("[RLC_AM][RB %d][STATUS] AUTHORIZE CREATE_STATUS_PDU frame %d timer %d timeout %d\n", rlcP->rb_id, Mac_rlc_xface->frame, rlcP->running_timer_status_prohibit, rlcP->timer_status_prohibit);
|
||||
rlcP->running_timer_status_prohibit = rlcP->timer_status_prohibit/10 + Mac_rlc_xface->frame;
|
||||
}
|
||||
}
|
||||
|
||||
// sufis are created in a array of sufi in rlc struct;
|
||||
rlc_am_find_holes (rlcP);
|
||||
|
||||
// create pdu with array of sufi previously generated;
|
||||
return rlc_am_create_status_pdu (rlcP, &rlcP->control);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int
|
||||
rlc_am_create_status_pdu (struct rlc_am_entity *rlcP, list_t * listP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t *mb = NULL;
|
||||
struct rlc_am_status_header *pdu;
|
||||
uint8_t *p8;
|
||||
uint8_t *tmp;
|
||||
int hole_index = 0;
|
||||
signed int pdu_remaining_size; // remaining size for SUFIs BITMAP, LIST, RLIST, WINDOW
|
||||
int current_sn;
|
||||
signed int remaining_sn;
|
||||
int pdu_status_count = 0;
|
||||
int length_sufi;
|
||||
int16_t last_hole_sn = -1;
|
||||
uint8_t byte_aligned;
|
||||
|
||||
|
||||
remaining_sn = rlcP->vr_h - rlcP->vr_r;
|
||||
|
||||
if (remaining_sn < 0) {
|
||||
remaining_sn = remaining_sn + SN_12BITS_MASK + 1;
|
||||
}
|
||||
|
||||
while ((rlcP->holes[hole_index].valid) && (remaining_sn)) {
|
||||
|
||||
|
||||
if (!(mb)) {
|
||||
mb = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (mb == NULL) {
|
||||
msg ("[MEM_MNGT] ERROR create_status_pdu() no free blocks\n");
|
||||
return 0;
|
||||
} else {
|
||||
pdu_status_count += 1;
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("[RLC_AM][RB %d][STATUS] CREATE_STATUS_PDU %d\n", rlcP->rb_id, pdu_status_count);
|
||||
#endif
|
||||
memset (mb->data, 0, rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation));
|
||||
|
||||
if (pdu_status_count == 1) {
|
||||
((struct rlc_am_tx_control_pdu_management *) (mb->data))->rlc_tb_type = RLC_AM_FIRST_STATUS_PDU_TYPE;
|
||||
} else {
|
||||
((struct rlc_am_tx_control_pdu_management *) (mb->data))->rlc_tb_type = RLC_AM_STATUS_PDU_TYPE;
|
||||
}
|
||||
|
||||
pdu = (struct rlc_am_status_header *) (&mb->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
pdu->byte1 = RLC_PDU_TYPE_STATUS;
|
||||
p8 = &(pdu->byte1);
|
||||
|
||||
// if first pdu of status include ack field
|
||||
if (pdu_status_count == 1) {
|
||||
pdu_remaining_size = (rlcP->pdu_size << 3) - 16; //-4(PDU_TYPE) -12(SUFI ACK)
|
||||
current_sn = rlcP->ack_sn;
|
||||
remaining_sn = rlcP->vr_h - rlcP->vr_r;
|
||||
|
||||
if (remaining_sn < 0) {
|
||||
remaining_sn = remaining_sn + SN_12BITS_MASK + 1;
|
||||
}
|
||||
} else {
|
||||
pdu_remaining_size = (rlcP->pdu_size << 3) - 8; //-4(PDU_TYPE) - 4(SUFI NO_MORE)
|
||||
}
|
||||
|
||||
byte_aligned = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// From 3GPP TS 25.322 V4.2.0 :
|
||||
// Which SUFI fields to use is implementation dependent,...
|
||||
// IMPLEMENTATION : KEEP GENERATION OF SUFI SIMPLE : GENERATE ONLY LIST
|
||||
if (pdu_remaining_size >= RLC_AM_SUFI_LIST_SIZE_MIN) {
|
||||
//----------------------------------
|
||||
// generate LIST
|
||||
//----------------------------------
|
||||
if (!byte_aligned) {
|
||||
*p8 = *p8 | RLC_AM_SUFI_LIST;
|
||||
p8 = p8 + 1;
|
||||
tmp = p8; //(*tmp = length_sufi << 4) when we will know length
|
||||
length_sufi = 0;
|
||||
pdu_remaining_size -= 8;
|
||||
|
||||
while ((length_sufi < 15) && (pdu_remaining_size >= 16) && (rlcP->holes[hole_index].valid) && (rlcP->nb_missing_pdus)) {
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("[RLC_AM][RB %d][STATUS] GENERATE SUFI LIST HOLE START 0x%04X ", rlcP->rb_id, rlcP->holes[hole_index].fsn);
|
||||
#endif
|
||||
*p8 = *p8 | (rlcP->holes[hole_index].fsn >> 8);
|
||||
p8 += 1;
|
||||
*p8 = rlcP->holes[hole_index].fsn;
|
||||
p8 += 1;
|
||||
|
||||
if (rlcP->holes[hole_index].length <= 15) {
|
||||
*p8 = rlcP->holes[hole_index].length << 4;
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("LENGTH %d\n", rlcP->holes[hole_index].length);
|
||||
#endif
|
||||
rlcP->nb_missing_pdus -= rlcP->holes[hole_index].length;
|
||||
current_sn = (rlcP->holes[hole_index].fsn + rlcP->holes[hole_index].length) & SN_12BITS_MASK;
|
||||
last_hole_sn = (rlcP->holes[hole_index].fsn + rlcP->holes[hole_index].length) & SN_12BITS_MASK;
|
||||
hole_index += 1;
|
||||
} else {
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("LENGTH 15\n");
|
||||
#endif
|
||||
*p8 = 0xF0;
|
||||
rlcP->nb_missing_pdus -= 15;
|
||||
rlcP->holes[hole_index].length -= 15;
|
||||
rlcP->holes[hole_index].fsn = (rlcP->holes[hole_index].fsn + 15) & SN_12BITS_MASK;
|
||||
current_sn = rlcP->holes[hole_index].fsn;
|
||||
}
|
||||
|
||||
length_sufi += 1;
|
||||
pdu_remaining_size -= 16;
|
||||
}
|
||||
|
||||
*tmp = *tmp | (length_sufi << 4);
|
||||
} else {
|
||||
*p8 = RLC_AM_SUFI_LIST << 4;
|
||||
tmp = p8; //(*tmp = length_sufi) when we will know length
|
||||
p8 = p8 + 1;
|
||||
length_sufi = 0;
|
||||
pdu_remaining_size -= 8;
|
||||
|
||||
while ((length_sufi < 15) && (pdu_remaining_size >= 16) && (rlcP->holes[hole_index].valid) && (rlcP->nb_missing_pdus)) {
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("[RLC_AM][RB %d][STATUS] GENERATE SUFI LIST HOLE START 0x%04X ", rlcP->rb_id, rlcP->holes[hole_index].fsn);
|
||||
#endif
|
||||
*p8 = rlcP->holes[hole_index].fsn >> 4;
|
||||
p8 += 1;
|
||||
*p8 = rlcP->holes[hole_index].fsn << 4;
|
||||
|
||||
if (rlcP->holes[hole_index].length <= 15) {
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("LENGTH %d\n", rlcP->holes[hole_index].length);
|
||||
#endif
|
||||
*p8 = *p8 | rlcP->holes[hole_index].length;
|
||||
p8 += 1;
|
||||
rlcP->nb_missing_pdus -= rlcP->holes[hole_index].length;
|
||||
current_sn = (rlcP->holes[hole_index].fsn + rlcP->holes[hole_index].length) & SN_12BITS_MASK;
|
||||
last_hole_sn = (rlcP->holes[hole_index].fsn + rlcP->holes[hole_index].length) & SN_12BITS_MASK;
|
||||
hole_index += 1;
|
||||
} else {
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("LENGTH 15\n");
|
||||
#endif
|
||||
*p8 = *p8 | 15;
|
||||
p8 += 1;
|
||||
rlcP->nb_missing_pdus -= 15;
|
||||
rlcP->holes[hole_index].length -= 15;
|
||||
rlcP->holes[hole_index].fsn = (rlcP->holes[hole_index].fsn + 15) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
length_sufi += 1;
|
||||
pdu_remaining_size -= 16;
|
||||
}
|
||||
|
||||
*tmp = *tmp | length_sufi;
|
||||
}
|
||||
} else {
|
||||
// it is not possible to write a sufi LIST in this control pdu, so close this pdu (write ACK or NO_MORE)
|
||||
if (pdu_status_count == 1) {
|
||||
//rlc_am_write_sufi_ack_in_control_pdu(p8, current_sn, byte_aligned);
|
||||
if (last_hole_sn > 0) {
|
||||
rlc_am_write_sufi_ack_in_control_pdu (p8, last_hole_sn, byte_aligned);
|
||||
} else {
|
||||
rlc_am_write_sufi_ack_in_control_pdu (p8, current_sn, byte_aligned);
|
||||
}
|
||||
} else {
|
||||
rlc_am_write_sufi_no_more_in_control_pdu (p8, byte_aligned);
|
||||
}
|
||||
|
||||
//hole_index += 1;
|
||||
list_add_tail_eurecom (mb, listP);
|
||||
mb = NULL;
|
||||
}
|
||||
|
||||
remaining_sn = rlcP->vr_h - current_sn;
|
||||
|
||||
if (remaining_sn < 0) {
|
||||
remaining_sn = remaining_sn + SN_12BITS_MASK + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mb == NULL) && !(pdu_status_count)) {
|
||||
mb = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (mb == NULL) {
|
||||
msg ("[MEM_MNGT] ERROR create_status_pdu() no free blocks\n");
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef DEBUG_CREATE_STATUS
|
||||
msg ("[RLC_AM][RB %d][STATUS] CREATE_STATUS_PDU %d\n", rlcP->rb_id, pdu_status_count + 1);
|
||||
#endif
|
||||
memset (mb->data, 0, rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation));
|
||||
((struct rlc_am_tx_control_pdu_management *) (mb->data))->rlc_tb_type = RLC_AM_FIRST_STATUS_PDU_TYPE | RLC_AM_LAST_STATUS_PDU_TYPE;
|
||||
|
||||
pdu = (struct rlc_am_status_header *) (&mb->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
pdu->byte1 = RLC_PDU_TYPE_STATUS;
|
||||
p8 = &(pdu->byte1);
|
||||
byte_aligned = 0;
|
||||
rlc_am_write_sufi_ack_in_control_pdu (p8, rlcP->ack_sn, byte_aligned);
|
||||
list_add_tail_eurecom (mb, listP);
|
||||
}
|
||||
} else if ((mb)) {
|
||||
// if first pdu insert ack field updated to last sn referenced by a sufi in this pdu
|
||||
// else insert no more field
|
||||
((struct rlc_am_tx_control_pdu_management *) (mb->data))->rlc_tb_type |= RLC_AM_LAST_STATUS_PDU_TYPE;
|
||||
|
||||
if (pdu_status_count == 1) {
|
||||
if (last_hole_sn > 0) {
|
||||
rlc_am_write_sufi_ack_in_control_pdu (p8, last_hole_sn, byte_aligned);
|
||||
} else {
|
||||
rlc_am_write_sufi_ack_in_control_pdu (p8, current_sn, byte_aligned);
|
||||
}
|
||||
} else {
|
||||
rlc_am_write_sufi_no_more_in_control_pdu (p8, byte_aligned);
|
||||
}
|
||||
|
||||
list_add_tail_eurecom (mb, listP);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_find_holes (struct rlc_am_entity *rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
uint16_t working_sn, working_sn_index;
|
||||
uint16_t end_sn;
|
||||
uint16_t distance;
|
||||
int hole_index;
|
||||
|
||||
//--------------------------------------------------
|
||||
// FIND HOLES
|
||||
//--------------------------------------------------
|
||||
hole_index = 0;
|
||||
// ACK
|
||||
rlcP->ack_sn = rlcP->vr_r;
|
||||
// HOLES
|
||||
rlcP->holes[0].valid = 0;
|
||||
rlcP->nb_missing_pdus = 0;
|
||||
|
||||
working_sn = rlcP->vr_r;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
end_sn = rlcP->vr_h;
|
||||
|
||||
while (working_sn != end_sn) {
|
||||
if ((rlcP->receiver_buffer[working_sn_index])) {
|
||||
// UPDATE ACK FIELD :
|
||||
if (rlcP->ack_sn == working_sn) {
|
||||
rlcP->ack_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
// STOP PREVIOUS HOLE IF ANY
|
||||
if (rlcP->holes[hole_index].valid) {
|
||||
hole_index += 1;
|
||||
rlcP->holes[hole_index].valid = 0;
|
||||
}
|
||||
} else {
|
||||
|
||||
// CONTINUE PREVIOUS HOLE IF ANY
|
||||
if (rlcP->holes[hole_index].valid) {
|
||||
rlcP->holes[hole_index].length += 1;
|
||||
rlcP->nb_missing_pdus += 1;
|
||||
|
||||
// START HOLE IF ANY
|
||||
} else {
|
||||
#ifdef DEBUG_RLC_AM_FIND_HOLE
|
||||
msg ("[RLC_AM %p] FOUND HOLE %d START 0x%04x(hex)\n", rlcP, hole_index, working_sn);
|
||||
#endif
|
||||
|
||||
if (hole_index > 0) {
|
||||
distance = working_sn - rlcP->holes[hole_index - 1].fsn;
|
||||
|
||||
if (distance & 0x8000) { // < 0
|
||||
rlcP->holes[hole_index - 1].dist_to_next = distance + SN_12BITS_MASK + 1;
|
||||
} else {
|
||||
rlcP->holes[hole_index - 1].dist_to_next = distance;
|
||||
}
|
||||
}
|
||||
|
||||
rlcP->holes[hole_index].valid = 1;
|
||||
rlcP->holes[hole_index + 1].valid = 0;
|
||||
rlcP->holes[hole_index].fsn = working_sn;
|
||||
rlcP->holes[hole_index].length = 1;
|
||||
rlcP->nb_missing_pdus += 1;
|
||||
}
|
||||
}
|
||||
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
}
|
||||
|
||||
// compute the number of holes
|
||||
if (rlcP->holes[hole_index].valid) {
|
||||
rlcP->nb_holes = hole_index;
|
||||
} else {
|
||||
if (hole_index > 0) {
|
||||
rlcP->nb_holes = hole_index - 1;
|
||||
} else {
|
||||
rlcP->nb_holes = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_process_status_info (struct rlc_am_entity *rlcP, uint8_t * statusP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
uint8_t *byte1;
|
||||
uint8_t byte_aligned; // 1: quartet starts on bit 7, 0: quartet starts on bit 3 (of a byte)
|
||||
uint8_t sufi_type;
|
||||
uint8_t end_process = 0;
|
||||
int16_t ack_sn = -1;
|
||||
int16_t first_error_indicated_sn = -1;
|
||||
int16_t sn_index;
|
||||
int16_t current_sn;
|
||||
int16_t current_index;
|
||||
|
||||
byte1 = statusP;
|
||||
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
display_retransmission_buffer (rlcP);
|
||||
#endif
|
||||
|
||||
if ((*byte1 & RLC_PIGGY_PDU_TYPE_MASK) == RLC_PIGGY_PDU_TYPE_STATUS) {
|
||||
sufi_type = *byte1 & 0x0F;
|
||||
byte_aligned = 0;
|
||||
|
||||
// process all bytes of the PDU
|
||||
while (!end_process) {
|
||||
// reset may have been triggered during processing of status, so exit
|
||||
//if (rlcP->protocol_state == RLC_DATA_TRANSFER_READY_STATE){
|
||||
switch (sufi_type) {
|
||||
|
||||
case RLC_AM_SUFI_NO_MORE:
|
||||
// end of pdu
|
||||
end_process = 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_WINDOW:
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS ERROR process_status_info() RLC_AM_SUFI_WINDOW not implemented\n", rlcP);
|
||||
end_process = 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_ACK:
|
||||
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS ACK\n", rlcP);
|
||||
#endif
|
||||
ack_sn = retransmission_buffer_management_ack (rlcP, byte1, byte_aligned, &first_error_indicated_sn);
|
||||
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS ACK WAS LSN %d(b10) %4X(b16)\n", rlcP, ack_sn, ack_sn);
|
||||
#endif
|
||||
// DISCARD : A discard procedure is terminated in the sender on the reception of a status pdu which contains
|
||||
// an ACK SUFI indicating VR(R) > SN_MRWlength
|
||||
rlc_am_received_sufi_ack_check_discard_procedures (rlcP);
|
||||
|
||||
// end of pdu, no NO_MORE sufi;
|
||||
end_process = 1;
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_LIST:
|
||||
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS LIST\n", rlcP);
|
||||
#endif
|
||||
byte1 = retransmission_buffer_management_list (rlcP, byte1, byte_aligned, &first_error_indicated_sn);
|
||||
|
||||
if (byte1 == NULL) {
|
||||
// error in processing;
|
||||
end_process = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// byte aligned is not changed for this sufi;
|
||||
if (!byte_aligned) {
|
||||
sufi_type = *byte1 & 0X0F;
|
||||
} else {
|
||||
sufi_type = (*byte1 & 0xF0) >> 4;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_BITMAP:
|
||||
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS BITMAP %p 0x%02X\n", rlcP, byte1, *byte1);
|
||||
#endif
|
||||
byte1 = retransmission_buffer_management_bitmap (rlcP, byte1, byte_aligned, &first_error_indicated_sn);
|
||||
|
||||
if (byte1 == NULL) {
|
||||
// error in processing;
|
||||
end_process = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// the length of this sufi is always n bytes + 4;
|
||||
// so invert byte_aligned;
|
||||
if (byte_aligned) {
|
||||
byte_aligned = 0;
|
||||
sufi_type = *byte1 & 0X0F;
|
||||
} else {
|
||||
byte_aligned = 1;
|
||||
sufi_type = (*byte1 & 0xF0) >> 4;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_RLIST:
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS ERROR SUFI RLIST NOT IMPLEMENTED\n", rlcP);
|
||||
end_process = 1;
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_MRW:
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS MRW %p 0x%02X\n", rlcP, byte1, *byte1);
|
||||
#endif
|
||||
byte1 = retransmission_buffer_management_mrw (rlcP, byte1, &byte_aligned);
|
||||
|
||||
if (byte1 == NULL) {
|
||||
// error in processing;
|
||||
end_process = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// the length of this sufi is always n bytes + 4;
|
||||
// so invert byte_aligned;
|
||||
if (byte_aligned) {
|
||||
sufi_type = (*byte1 & 0xF0) >> 4;
|
||||
} else {
|
||||
sufi_type = *byte1 & 0X0F;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RLC_AM_SUFI_MRW_ACK:
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS MRW_ACK %p 0x%02X\n", rlcP, byte1, *byte1);
|
||||
#endif
|
||||
byte1 = retransmission_buffer_management_mrw_ack (rlcP, byte1, &byte_aligned);
|
||||
|
||||
if (byte1 == NULL) {
|
||||
// error in processing;
|
||||
end_process = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// the length of this sufi is always n bytes + 4;
|
||||
// so invert byte_aligned;
|
||||
if (byte_aligned) {
|
||||
sufi_type = (*byte1 & 0xF0) >> 4;
|
||||
} else {
|
||||
sufi_type = *byte1 & 0X0F;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg ("[RLC_AM %p]PROCESS_STATUS ERROR SUFI UNKNOWN 0x%02X\n", rlcP, *byte1);
|
||||
end_process = 1;
|
||||
}
|
||||
|
||||
/*} else {
|
||||
return;
|
||||
} */
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// CLEAR ALL EVENTS RECEIVED;
|
||||
//-------------------------
|
||||
current_sn = rlcP->vt_a;
|
||||
current_index = rlcP->vt_a % rlcP->recomputed_configured_tx_window_size;
|
||||
sn_index = rlcP->vt_s % rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
while (sn_index != current_index) {
|
||||
if (rlcP->retransmission_buffer[current_index] != NULL) {
|
||||
|
||||
((struct rlc_am_tx_data_pdu_management *) (rlcP->retransmission_buffer[current_index]->data))->ack = RLC_AM_PDU_ACK_NO_EVENT;
|
||||
}
|
||||
|
||||
current_sn = (current_sn + 1) & SN_12BITS_MASK;
|
||||
current_index = current_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
}
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM %p][PROCESS_STATUS] ERROR process_piggybacked_status_info() PDU type field is not STATUS\n", rlcP);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PROCESS_STATUS
|
||||
display_retransmission_buffer (rlcP);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t *
|
||||
rlc_am_create_status_pdu_mrw_ack (struct rlc_am_entity *rlcP, uint8_t nP, uint16_t sn_ackP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
mem_block_t *le;
|
||||
struct rlc_am_status_header *pdu;
|
||||
uint8_t *p8;
|
||||
|
||||
#ifdef DEBUG_STATUS
|
||||
msg ("[RLC_AM %p][STATUS] rlc_am_mrw_send_ack(N=%d, sn_ack=0x%04X)\n", rlcP, nP, sn_ackP);
|
||||
#endif
|
||||
le = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
|
||||
|
||||
if (le == NULL) {
|
||||
msg ("[MEM_MNGT][ERROR] rlc_am_mrw_send_ack() no free blocks\n");
|
||||
return NULL;
|
||||
} else {
|
||||
((struct rlc_am_tx_control_pdu_management *) (le->data))->rlc_tb_type = RLC_AM_STATUS_PDU_TYPE;
|
||||
pdu = (struct rlc_am_status_header *) (&le->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
|
||||
pdu->byte1 = RLC_PDU_TYPE_STATUS;
|
||||
p8 = &(pdu->byte1);
|
||||
*p8 = *p8 | RLC_AM_SUFI_MRW_ACK;
|
||||
p8 = p8 + 1;
|
||||
*p8 = (nP << 4) | (sn_ackP >> 8);
|
||||
p8 = p8 + 1;
|
||||
*p8 = sn_ackP;
|
||||
p8 = p8 + 1;
|
||||
*p8 = RLC_AM_SUFI_NO_MORE << 4;
|
||||
return le;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_status_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_STATUS_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_STATUS_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "rlc_am_structs.h"
|
||||
# include "rlc_am_constants.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern int rlc_am_send_status (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_process_status_info (struct rlc_am_entity *rlcP, uint8_t * statusP);
|
||||
extern mem_block_t *rlc_am_create_status_pdu_mrw_ack (struct rlc_am_entity *rlcP, uint8_t nP, uint16_t sn_ackP);
|
||||
# endif
|
||||
@@ -1,222 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_structs.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_STRUCTS_H__
|
||||
# define __RLC_AM_STRUCTS_H__
|
||||
|
||||
# include "platform_types.h"
|
||||
# include "platform_constants.h"
|
||||
# include "list.h"
|
||||
# include "mem_block.h"
|
||||
# include "rlc_am_constants.h"
|
||||
//#ifdef USER_MODE
|
||||
# include "mac_rlc_primitives.h"
|
||||
//#endif //USER_MODE
|
||||
# include "mac_primitives.h"
|
||||
# include "rlc_primitives.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
// SDU MANAGEMENT
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_tx_sdu_management {
|
||||
uint8_t *first_byte; // payload
|
||||
int32_t sdu_creation_time;
|
||||
uint32_t mui; // mui may be used only by radio access bearers
|
||||
uint16_t sdu_remaining_size;
|
||||
uint16_t sdu_segmented_size;
|
||||
uint16_t sdu_size;
|
||||
int16_t pdus_index[42]; // sn of pdus (is an array)
|
||||
uint16_t last_pdu_sn;
|
||||
uint8_t nb_pdus; // number of pdus were this sdu was segmented
|
||||
uint8_t nb_pdus_internal_use; // count the number of pdus transmitted to lower layers (used in mux procedure)
|
||||
uint8_t nb_pdus_ack; // counter used for confirm and discard MaxDAT
|
||||
uint8_t nb_pdus_time; // counter used for timer based discard
|
||||
|
||||
uint8_t confirm; // confirm may be used only by signalling radio bearers
|
||||
|
||||
int8_t li_index_for_discard; // indicates the li index in the last pdu of the sdu, marking the end of the sdu
|
||||
uint8_t discarded;
|
||||
uint8_t segmented; // != 0 if segmentation running or achieved
|
||||
uint8_t no_new_sdu_segmented_in_last_pdu;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// SDU DISCARD
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_discard_procedure {
|
||||
// list of sdu discarded involved in this procedure
|
||||
list_t sdu_list; // index of sdu (index in rlc_am_entity.input_sdus[])
|
||||
uint8_t nb_sdu;
|
||||
mem_block_t *control_pdu;
|
||||
uint16_t last_pdu_sn; // for update of vt_s
|
||||
uint8_t length;
|
||||
uint8_t nlength;
|
||||
uint8_t running;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// DATA PDU
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_rx_pdu_management {
|
||||
uint8_t *first_byte;
|
||||
uint16_t sn;
|
||||
uint8_t piggybacked_processed; // the piggybacked info if any of the pdu has already been processed.
|
||||
};
|
||||
|
||||
struct rlc_am_tx_data_pdu_management {
|
||||
mem_block_t *copy; //pointer on pdu queued in retransmission_buffer_to_send in order
|
||||
// not to insert the same pdu to retransmit twice, also to avoid the transmission of the pdu if acknowledged
|
||||
// but previously was queued for retransmission in retransmission_buffer_to_send but not sent because of
|
||||
// limited number of pdu delivered by TTI.
|
||||
uint8_t *first_byte; // pointer on the pdu including header, LIs;
|
||||
uint8_t *payload; // pointer on the data field of the pdu;
|
||||
int16_t sdu[15]; // index of sdu having segments in this pdu (index in rlc_am_entity.input_sdus[])
|
||||
uint16_t padding_size; // size of padding area if any in a data pdu(for piggybacking)
|
||||
uint16_t data_size;
|
||||
uint16_t sn;
|
||||
|
||||
|
||||
uint8_t nb_sdu; // number of sdu having segments in this pdu
|
||||
uint8_t vt_dat; // This state variable counts the number of times a PDU has been transmitted;
|
||||
// there is one VT(DAT) for each PDU and it is incremented each time the PDU is transmitted;
|
||||
int8_t ack; // used when pdu is in retransmission buffer;
|
||||
// values are RLC_PDU_ACK_NO_EVENT, RLC_PDU_ACK_EVENT, RLC_PDU_NACK_EVENT
|
||||
uint8_t last_pdu_of_sdu; // nb of sdus ending in this pdu (for polling trigger)
|
||||
|
||||
uint16_t rlc_tb_type; // mac will return this value with the tx status
|
||||
uint8_t dummy[MAC_HEADER_MAX_SIZE]; // reserve area for mac header !!! always the last declaration in this struct !!!
|
||||
};
|
||||
|
||||
struct rlc_am_tx_control_pdu_management {
|
||||
uint16_t rlc_tb_type; // mac will return this value with the tx status
|
||||
uint8_t dummy[MAC_HEADER_MAX_SIZE]; // reserve area for mac header !!! always the last declaration in this struct !!!
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HEADERS
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_pdu_header {
|
||||
uint8_t byte1;
|
||||
uint8_t byte2;
|
||||
uint8_t li_data_7[1];
|
||||
};
|
||||
|
||||
struct rlc_am_reset_header {
|
||||
uint8_t byte1;
|
||||
uint8_t hfni[3]; // is coded on 20 most significant bits of 24 bits
|
||||
};
|
||||
|
||||
struct rlc_am_status_header {
|
||||
uint8_t byte1;
|
||||
uint8_t suffi[1]; // next suffi(s)
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// interlayers optimizations
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_tx_data_pdu_allocation {
|
||||
union {
|
||||
struct rlc_am_tx_data_pdu_management rlc_am_tx_pdu_mngmnt;
|
||||
struct mac_tb_req tb_req;
|
||||
struct mac_tx_tb_management tb_mngt;
|
||||
# ifdef BYPASS_L1
|
||||
struct rlc_am_rx_pdu_management dummy;
|
||||
struct mac_tb_ind dummy2;
|
||||
struct mac_rx_tb_management dummy3;
|
||||
struct rlc_indication dummy4;
|
||||
# endif
|
||||
} dummy;
|
||||
};
|
||||
|
||||
struct rlc_am_tx_control_pdu_allocation {
|
||||
union {
|
||||
struct mac_tb_req tb_req;
|
||||
struct mac_tx_tb_management tb_mngt;
|
||||
struct rlc_am_tx_control_pdu_management rlc_am_tx_pdu_mngmnt;
|
||||
# ifdef BYPASS_L1
|
||||
struct mac_tb_ind dummy2;
|
||||
struct mac_rx_tb_management dummy3;
|
||||
struct rlc_indication dummy4;
|
||||
# endif
|
||||
} dummy;
|
||||
};
|
||||
|
||||
struct rlc_am_data_req_alloc { // alloc enought bytes for sdu mngt also
|
||||
union {
|
||||
struct rlc_am_data_req dummy1;
|
||||
struct rlc_am_tx_sdu_management dummy2;
|
||||
} dummy;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// MISC
|
||||
//-----------------------------------------------------------------------------
|
||||
struct sufi_to_insert_in_status {
|
||||
uint16_t sn;
|
||||
uint8_t length; // in quartets, sufi invalid if length is zero
|
||||
uint8_t type; // ACK, BITMAP, LIST, etc
|
||||
uint8_t sufi[SUFI_MAX_SIZE];
|
||||
};
|
||||
|
||||
struct sufi_bitmap {
|
||||
uint16_t fsn;
|
||||
uint8_t valid;
|
||||
uint8_t length;
|
||||
uint8_t mask;
|
||||
uint8_t bitmap[16];
|
||||
};
|
||||
|
||||
struct pair {
|
||||
uint16_t sn;
|
||||
uint8_t valid;
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
struct sufi_list {
|
||||
struct pair pairs[15];
|
||||
uint8_t valid;
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
struct sufi_ack {
|
||||
uint16_t lsn;
|
||||
uint8_t vr_r_modified; // generate ack with vr_r value;
|
||||
uint8_t ack_other_vr_r; // generate ack with lsn value;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// STATUS GENERATION
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_hole {
|
||||
uint16_t valid;
|
||||
uint16_t fsn;
|
||||
uint16_t length;
|
||||
uint16_t dist_to_next; //count in sn
|
||||
};
|
||||
# endif
|
||||
@@ -1,199 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_timers.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_constants.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "rlc_am_util_proto_extern.h"
|
||||
#include "umts_timer_proto_extern.h"
|
||||
/*
|
||||
void rlc_am_timer_epc_notify_time_out (struct rlc_am_entity *rlcP, void *arg_not_usedP);
|
||||
void rlc_am_timer_epc_fsm (struct rlc_am_entity *rlcP, uint8_t eventP);
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_timer_epc_notify_time_out (struct rlc_am_entity *rlcP, void *arg_not_usedP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
rlc_am_timer_epc_fsm (rlcP, TIMER_EPC_TIMER_TIMED_OUT_EVENT);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_timer_epc_fsm (struct rlc_am_entity *rlcP, uint8_t eventP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// from 25.322 V4.3.0
|
||||
// The Estimated PDU Counter (EPC) is only applicable for RLC entities operating
|
||||
// in acknowledged mode. The EPC is a mechanism configured by upper layers used
|
||||
// for scheduling the retransmission of status reports in the Receiver. With this
|
||||
// mechanism, the Receiver will send a new status report in which it requests for
|
||||
// AMD PDUs not yet received. The time between two subsequent status report
|
||||
// retransmissions is not fixed, but it is controlled by both the timer Timer_EPC
|
||||
// and the state variable VR(EP), which adapt this time to the round trip delay
|
||||
// and the current bit rate, indicated in the TFI, in order to minimise the delay
|
||||
// of the status report retransmission.
|
||||
//
|
||||
// When a status report is triggered by some mechanisms and it is submitted to lower
|
||||
// layer (in UTRAN) or the successful or unsuccessful transmission of it is indicated
|
||||
// by lower layer (in UE) <<SEE CODE "Ref1">> to request for retransmitting one or more missing AMD PDUs,
|
||||
// the variable VR(EP) is set equal to the number of requested AMD PDUs. At least
|
||||
// one requested AMD PDU is needed to activate the EPC mechanism. The variable VR(EP)
|
||||
// is a counter, which is decremented every transmission time interval with the
|
||||
// estimated number of AMD PDUs that should have been received during that
|
||||
// transmission time interval on the corresponding logical channel.
|
||||
//
|
||||
// The timer Timer_EPC controls the maximum time that the variable VR(EP) needs to
|
||||
// wait before it will start counting down. This timer starts immediately after a
|
||||
// transmission of a retransmission request from the Receiver (when the first
|
||||
// STATUS PDU of the status report is submitted to lower layer (in UTRAN) or the
|
||||
// successful or unsuccessful transmission of it is indicated by lower layer(in UE)).
|
||||
// The initial value of the timer Timer_EPC is configured by upper layers. It typically
|
||||
// depends on the roundtrip delay, which consists of the propagation delay, processing
|
||||
// time in the transmitter and Receiver and the frame structure. This timer can also
|
||||
// be implemented as a counter, which counts the number of 10 ms radio frames that
|
||||
// could be expected to elapse before the first requested AMD PDU is received.
|
||||
//
|
||||
// If not all of these requested AMD PDUs have been received correctly when VR(EP)
|
||||
// is equal to zero, a new status report will be transmitted and the EPC mechanism
|
||||
// will be reset accordingly. The timer Timer_EPC will be started once more when the
|
||||
// first STATUS PDU of the status report is submitted to lower layer (in UTRAN) or the
|
||||
// successful or unsuccessful transmission of it is indicated by lower layer (in UE).
|
||||
// If all of the requested AMD PDUs have been received correctly, the EPC mechanism ends.
|
||||
|
||||
switch (rlcP->epc_state) {
|
||||
|
||||
//--------------------------------------------
|
||||
case TIMER_EPC_STATE_IDLE:
|
||||
//--------------------------------------------
|
||||
rlcP->epc_counting_down = 0;
|
||||
switch (eventP) {
|
||||
// Ref1
|
||||
case TIMER_EPC_PDU_STATUS_SUBMITTED_LOWER_LAYER_EVENT: // for RG
|
||||
case TIMER_EPC_PDU_STATUS_TRANSMITED_EVENT: // for UE
|
||||
rlcP->vr_ep = rlcP->epc_nb_missing_pdus;
|
||||
rlcP->epc_old_vr_h = rlcP->vr_h;
|
||||
rlcP->epc_old_vr_r = rlcP->vr_r;
|
||||
|
||||
rlcP->epc_state = TIMER_EPC_STATE_TIMER_ARMED;
|
||||
rlcP->timer_epc = umts_add_timer_list_up (&rlcP->rlc_am_timer_list, rlc_am_timer_epc_notify_time_out, rlcP, rlcP->discard_procedures.head, NULL, *rlcP->frame_tick_milliseconds);
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_IDLE -> TIMER_EPC_STATE_TIMER_ARMED\n", rlcP);
|
||||
#endif
|
||||
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_IDLE EVENT %02X hex NOT EXPECTED\n", rlcP, eventP);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
//--------------------------------------------
|
||||
case TIMER_EPC_STATE_TIMER_ARMED:
|
||||
//--------------------------------------------
|
||||
switch (eventP) {
|
||||
// Ref1
|
||||
case TIMER_EPC_PDU_STATUS_TRANSMITED_EVENT:
|
||||
return;
|
||||
break;
|
||||
|
||||
case TIMER_EPC_TIMER_TIMED_OUT_EVENT:
|
||||
rlcP->epc_counting_down = 1;
|
||||
rlcP->timer_epc = NULL;
|
||||
rlcP->epc_state = TIMER_EPC_STATE_TIMED_OUT;
|
||||
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_TIMER_ARMED -> TIMER_EPC_STATE_TIMED_OUT\n", rlcP);
|
||||
#endif
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_TIMER_ARMED EVENT %02X hex NOT EXPECTED\n", rlcP, eventP);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
//--------------------------------------------
|
||||
case TIMER_EPC_STATE_TIMED_OUT:
|
||||
//--------------------------------------------
|
||||
switch (eventP) {
|
||||
|
||||
case TIMER_EPC_VR_EP_EQUAL_ZERO_EVENT:
|
||||
rlcP->epc_counting_down = 0;
|
||||
rlcP->epc_state = TIMER_EPC_STATE_IDLE;
|
||||
|
||||
// return 1 if sn1 > sn2
|
||||
// return 0 if sn1 = sn2
|
||||
// return -1 if sn1 < sn2
|
||||
if (rlc_am_comp_sn (rlcP, rlcP->epc_old_vr_r, rlcP->epc_old_vr_h, rlcP->vr_r) > 0) {
|
||||
// not all missing pdus have been received
|
||||
// so generate a new status report
|
||||
rlcP->send_status_pdu_requested = 1;
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_TIMED_OUT -> TIMER_EPC_STATE_IDLE GENERATION OF STATUS REQUESTED\n", rlcP);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
else {
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_TIMED_OUT -> TIMER_EPC_STATE_IDLE\n", rlcP);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUG_RLC_AM_TIMER_EPC_FSM
|
||||
msg ("[RLC_AM %p][TIMER_EPC_FSM] TIMER_EPC_STATE_TIMED_OUT EVENT %02X hex NOT EXPECTED\n", rlcP, eventP);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,45 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_timers_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_TIMERS_H__
|
||||
# define __RLC_AM_RIMERS_H__
|
||||
# include "rlc_am_entity.h"
|
||||
# include "platform_types.h"
|
||||
|
||||
extern void rlc_am_timer_epc_notify_time_out (struct rlc_am_entity *rlcP, void *arg_not_usedP);
|
||||
extern void rlc_am_timer_epc_fsm (struct rlc_am_entity *rlcP, uint8_t eventP);
|
||||
# endif
|
||||
@@ -1,486 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_discard_rx.c -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
#include "rtos_header.h"
|
||||
#include "platform_types.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "rlc_primitives.h"
|
||||
#include "rlc_am_entity.h"
|
||||
#include "rlc_am_structs.h"
|
||||
#include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int rlc_am_comp_sn (struct rlc_am_entity* rlcP, uint16_t low_boundaryP, uint16_t sn1P, uint16_t sn2P);
|
||||
void adjust_vr_r_mr (struct rlc_am_entity* rlcP);
|
||||
void adjust_vt_a_ms (struct rlc_am_entity* rlcP);
|
||||
void display_protocol_vars_rlc_am (struct rlc_am_entity* rlcP);
|
||||
void display_retransmission_buffer (struct rlc_am_entity* rlcP);
|
||||
void display_receiver_buffer (struct rlc_am_entity* rlcP);
|
||||
void rlc_am_check_retransmission_buffer (struct rlc_am_entity* rlcP, uint8_t* messageP);
|
||||
void rlc_am_check_receiver_buffer (struct rlc_am_entity* rlcP, uint8_t* messageP);
|
||||
void rlc_am_display_data_pdu7 (mem_block_t* pduP);
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef DEBUG_RLC_AM_CONFIRM
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
debug_rlc_am_confirm (struct rlc_am_entity* rlcP, mem_block_t* confP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
msg ("[RLC_AM][RB %d] CONFIRM SDU MUI %d\n", rlcP->rb_id, ((struct rlc_output_primitive*) (confP->data))->primitive.conf.mui);
|
||||
free_mem_block_t (confP);
|
||||
}
|
||||
#endif /* DEBUG_RLC_AM_CONFIRM */
|
||||
|
||||
// return 1 if sn1 > sn2
|
||||
// return 0 if sn1 = sn2
|
||||
// return -1 if sn1 < sn2
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int
|
||||
rlc_am_comp_sn (struct rlc_am_entity* rlcP, uint16_t low_boundaryP, uint16_t sn1P, uint16_t sn2P)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// we require that sn are in tx window, if they are not we consider that they are always
|
||||
// before low_boundaryP (one loop over the max sn 0x0FFF), never above the boundary
|
||||
uint16_t bound = (low_boundaryP + rlcP->configured_tx_window_size - 1) & SN_12BITS_MASK;
|
||||
|
||||
if (sn1P == sn2P) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (low_boundaryP < bound) {
|
||||
if ((sn1P >= low_boundaryP) && (sn1P <= bound)) {
|
||||
if ((sn2P >= low_boundaryP) && (sn2P <= bound)) {
|
||||
if (sn1P > sn2P) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else { // not in tx window
|
||||
return 1;
|
||||
}
|
||||
|
||||
} else { // not in tx window
|
||||
if ((sn2P >= low_boundaryP) && (sn2P <= bound)) {
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
if ((sn1P > sn2P) && (sn1P <= low_boundaryP)) {
|
||||
return 1;
|
||||
|
||||
} else if ((sn2P > sn1P) && (sn2P <= low_boundaryP)) {
|
||||
return -1;
|
||||
|
||||
} else if ((sn1P > sn2P) && (sn1P > bound)) {
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (sn1P >= low_boundaryP) {
|
||||
if (sn2P <= bound) {
|
||||
return -1;
|
||||
|
||||
} else if ((sn2P >= low_boundaryP)) {
|
||||
if (sn1P > sn2P) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else { // not in tx window
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else if (sn1P <= bound) {
|
||||
if (sn2P > bound) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
if (sn1P > sn2P) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else { // bound < sn1< vt_a
|
||||
if (sn2P >= low_boundaryP) {
|
||||
return -1;
|
||||
|
||||
} else if (sn2P <= bound) {
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
if (sn1P > sn2P) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
adjust_vt_a_ms (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t vt_a_index, vt_s_index;
|
||||
vt_a_index = rlcP->vt_a % rlcP->recomputed_configured_tx_window_size;
|
||||
vt_s_index = rlcP->vt_s % rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
while ((rlcP->retransmission_buffer[vt_a_index] == NULL) && (vt_a_index != vt_s_index)) {
|
||||
rlcP->vt_a = (rlcP->vt_a + 1) & SN_12BITS_MASK;
|
||||
vt_a_index = rlcP->vt_a % rlcP->recomputed_configured_tx_window_size;
|
||||
}
|
||||
|
||||
rlcP->vt_ms = (rlcP->vt_a + rlcP->vt_ws - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
adjust_vr_r_mr (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t vr_r_index, vr_h_index;
|
||||
vr_r_index = rlcP->vr_r % rlcP->recomputed_configured_rx_window_size;
|
||||
vr_h_index = rlcP->vr_h % rlcP->recomputed_configured_rx_window_size;
|
||||
|
||||
while ((rlcP->receiver_buffer[vr_r_index] != NULL) && (vr_r_index != vr_h_index)) {
|
||||
rlcP->vr_r = (rlcP->vr_r + 1) & SN_12BITS_MASK;
|
||||
vr_r_index = rlcP->vr_r % rlcP->recomputed_configured_rx_window_size;
|
||||
}
|
||||
|
||||
rlcP->ack.vr_r_modified = 1;
|
||||
#ifdef DEBUG_RECEIVER_BUFFER
|
||||
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ADJUST VR(R)->0x%04X VR(H)=0x%04X\n", rlcP->rb_id, rlcP->vr_r, rlcP->vr_h);
|
||||
#endif
|
||||
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
display_protocol_vars_rlc_am (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
msg ("[RLC_AM][RB %d] VT(A) 0x%04X VT(S) 0x%04X VT(MS) 0x%04X VT(PDU) 0x%04X VT(SDU) 0x%04X VR(R) 0x%04X VR(H) 0x%04X VR(MR) 0x%04X\n",
|
||||
rlcP->rb_id, rlcP->vt_a, rlcP->vt_s, rlcP->vt_ms, rlcP->vt_pdu, rlcP->vt_sdu, rlcP->vr_r, rlcP->vr_h, rlcP->vr_mr);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
display_retransmission_buffer (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t working_sn, working_sn_index;
|
||||
uint16_t end_sn, end_sn_index;
|
||||
working_sn = rlcP->vt_a;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
end_sn = (rlcP->vt_a + rlcP->recomputed_configured_tx_window_size - 1) & SN_12BITS_MASK;
|
||||
end_sn_index = end_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
msg ("-------------------------------------------\nRetrans Buf rlc %p: VT(A) 0x%04X VT(S) 0x%04X XXX = sn based on index, (XXX) = sn read from pdu\n", rlcP,
|
||||
rlcP->vt_a, rlcP->vt_s);
|
||||
|
||||
while (working_sn_index != end_sn_index) {
|
||||
if (rlcP->retransmission_buffer[working_sn_index] != NULL) {
|
||||
msg ("%03X(%03X).", working_sn, ((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[working_sn_index]->data))->sn);
|
||||
|
||||
} else {
|
||||
msg ("_.");
|
||||
}
|
||||
|
||||
if ((working_sn_index % 32) == 0) {
|
||||
msg ("\n");
|
||||
}
|
||||
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
}
|
||||
|
||||
msg ("\n------------------------------------------\n");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
display_receiver_buffer (struct rlc_am_entity* rlcP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16_t working_sn, working_sn_index;
|
||||
uint16_t end_sn, end_sn_index;
|
||||
working_sn = rlcP->vr_r;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
end_sn = rlcP->vr_mr;
|
||||
end_sn_index = end_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
msg ("-------------------------------\nRec Buf rlc %p VR(R) 0x%04X: ", rlcP, rlcP->vr_r);
|
||||
|
||||
while (working_sn_index != end_sn_index) {
|
||||
if (rlcP->receiver_buffer[working_sn_index] != NULL) {
|
||||
msg ("%03X(%03X)", working_sn, ((struct rlc_am_rx_pdu_management*) (rlcP->receiver_buffer[working_sn_index]->data))->sn);
|
||||
|
||||
} else {
|
||||
msg ("_.");
|
||||
}
|
||||
|
||||
if ((working_sn_index % 32) == 0) {
|
||||
msg ("\n");
|
||||
}
|
||||
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
}
|
||||
|
||||
msg ("\n--------------------------------------\n");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_check_retransmission_buffer (struct rlc_am_entity* rlcP, uint8_t* messageP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
int error_found = 0;
|
||||
uint16_t working_sn, working_sn_index;
|
||||
uint16_t end_sn, end_sn_index;
|
||||
//---------------------------------------------
|
||||
// check if pdu remaining outside the window
|
||||
//---------------------------------------------
|
||||
working_sn = rlcP->vt_s;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
end_sn = rlcP->vt_a;
|
||||
end_sn_index = end_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
while (working_sn_index != end_sn_index) {
|
||||
if (rlcP->retransmission_buffer[working_sn_index] != NULL) {
|
||||
msg ("[RLC_AM][RB %d] CHECK RETRANSMISSION BUFFER ERROR %s : REMAINING PDU INDEX %d=0x%04X\n", rlcP->rb_id, messageP, working_sn_index, working_sn_index);
|
||||
rlc_am_display_data_pdu7 (rlcP->retransmission_buffer[working_sn_index]);
|
||||
error_found = 1;
|
||||
}
|
||||
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// check if pdu remaining inside the window have the correct value for ack field
|
||||
//---------------------------------------------
|
||||
end_sn = rlcP->vt_s;
|
||||
end_sn_index = end_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
working_sn = rlcP->vt_a;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
while (working_sn_index != end_sn_index) {
|
||||
if (rlcP->retransmission_buffer[working_sn_index] != NULL) {
|
||||
if (((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[working_sn_index]->data))->ack != RLC_AM_PDU_ACK_NO_EVENT) {
|
||||
msg ("[RLC_AM][RB %d] CHECK RETRANSMISSION BUFFER ERROR %s EVENT (%d) IN PDU SN 0x%04X\n", rlcP->rb_id, messageP,
|
||||
((struct rlc_am_tx_data_pdu_management*) (rlcP->retransmission_buffer[working_sn_index]->data))->ack, working_sn);
|
||||
rlc_am_display_data_pdu7 (rlcP->retransmission_buffer[working_sn_index]);
|
||||
error_found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
}
|
||||
|
||||
if ((error_found)) {
|
||||
display_protocol_vars_rlc_am (rlcP);
|
||||
|
||||
while (1);
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM][RB %d] CHECK RETRANSMISSION BUFFER OK\n", rlcP->rb_id);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_check_receiver_buffer (struct rlc_am_entity* rlcP, uint8_t* messageP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
int error_found = 0;
|
||||
uint16_t working_sn, working_sn_index;
|
||||
uint16_t end_sn, end_sn_index;
|
||||
working_sn = rlcP->vr_h;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
end_sn = rlcP->vr_r;
|
||||
end_sn_index = end_sn % rlcP->recomputed_configured_tx_window_size;
|
||||
|
||||
while (working_sn_index != end_sn_index) {
|
||||
if (rlcP->receiver_buffer[working_sn_index] != NULL) {
|
||||
msg ("[RLC_AM][RB %d] CHECK RECEIVER BUFFER ERROR %s : REMAINING PDU INDEX %d=0x%04X\n", rlcP->rb_id, messageP, working_sn_index, working_sn_index);
|
||||
error_found = 1;
|
||||
}
|
||||
|
||||
working_sn = (working_sn + 1) & SN_12BITS_MASK;
|
||||
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
||||
}
|
||||
|
||||
if ((error_found)) {
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_display_data_pdu7 (mem_block_t* pduP)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
struct rlc_am_tx_data_pdu_management* pdu_mngt;
|
||||
struct rlc_am_pdu_header* rlc_header;
|
||||
int index;
|
||||
int nb_li = 0;
|
||||
int li_index = 0;
|
||||
uint16_t li[32];
|
||||
|
||||
if ((pduP)) {
|
||||
pdu_mngt = (struct rlc_am_tx_data_pdu_management*) (pduP->data);
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU %p SN 0x%04X LAST_PDU_OF_SDU %d\n", pduP, pdu_mngt->sn, pdu_mngt->last_pdu_of_sdu);
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU HEADER ");
|
||||
|
||||
for (index = 0; index < 10; index++) {
|
||||
msg ("%02X.", pdu_mngt->first_byte[index]);
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
//--------------------------------------
|
||||
// LINKED SDUs
|
||||
//--------------------------------------
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU CONTAINS SDU(s) INDEX ");
|
||||
|
||||
for (index = 0; index < pdu_mngt->nb_sdu; index++) {
|
||||
msg ("%d", pdu_mngt->sdu[index]);
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
//--------------------------------------
|
||||
// LENGTH INDICATORS
|
||||
//--------------------------------------
|
||||
rlc_header = (struct rlc_am_pdu_header*) (pdu_mngt->first_byte);
|
||||
|
||||
if ((rlc_header->byte2 & RLC_HE_MASK) != RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU CONTAINS LI(s) ");
|
||||
nb_li = 0;
|
||||
|
||||
while ((li[nb_li] = (rlc_header->li_data_7[nb_li])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
||||
li[nb_li] = li[nb_li] & (~(uint8_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
||||
nb_li++;
|
||||
}
|
||||
|
||||
nb_li++;
|
||||
|
||||
while (li_index < nb_li) {
|
||||
switch (li[li_index]) {
|
||||
case RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
||||
msg ("LAST_PDU_EXACTLY_FILLED ");
|
||||
break;
|
||||
|
||||
case RLC_LI_LAST_PDU_ONE_BYTE_SHORT:
|
||||
msg ("LAST_PDU_ONE_BYTE_SHORT ");
|
||||
break;
|
||||
|
||||
case RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
||||
msg ("PDU_PIGGY_BACKED_STATUS ");
|
||||
break;
|
||||
|
||||
case RLC_LI_PDU_PADDING:
|
||||
msg ("PDU_PADDING ");
|
||||
break;
|
||||
|
||||
default: // li is length
|
||||
msg ("LENGTH %d ", li[li_index] >> 1);
|
||||
}
|
||||
|
||||
li_index++;
|
||||
}
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU CONTAINS NO LI(s) ");
|
||||
}
|
||||
|
||||
msg ("\n");
|
||||
//--------------------------------------
|
||||
// DATA
|
||||
//--------------------------------------
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU CONTENT <PDU>");
|
||||
|
||||
for (index = 0; index < pdu_mngt->data_size; index++) {
|
||||
msg ("%02X.", pdu_mngt->payload[index]);
|
||||
}
|
||||
|
||||
msg ("</PDU>\n");
|
||||
|
||||
} else {
|
||||
msg ("[RLC_AM] DISPLAY DATA PDU : IS NULL\n");
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_stat_req (struct rlc_am_entity* rlcP,
|
||||
unsigned int* tx_pdcp_sdu,
|
||||
unsigned int* tx_pdcp_sdu_discarded,
|
||||
unsigned int* tx_retransmit_pdu_unblock,
|
||||
unsigned int* tx_retransmit_pdu_by_status,
|
||||
unsigned int* tx_retransmit_pdu,
|
||||
unsigned int* tx_data_pdu,
|
||||
unsigned int* tx_control_pdu,
|
||||
unsigned int* rx_sdu,
|
||||
unsigned int* rx_error_pdu,
|
||||
unsigned int* rx_data_pdu,
|
||||
unsigned int* rx_data_pdu_out_of_window,
|
||||
unsigned int* rx_control_pdu)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
*tx_pdcp_sdu = rlcP->stat_tx_pdcp_sdu;
|
||||
*tx_pdcp_sdu_discarded = rlcP->stat_tx_pdcp_sdu_discarded;
|
||||
*tx_retransmit_pdu_unblock = rlcP->stat_tx_retransmit_pdu_unblock;
|
||||
*tx_retransmit_pdu_by_status = rlcP->stat_tx_retransmit_pdu_by_status;
|
||||
*tx_retransmit_pdu = rlcP->stat_tx_retransmit_pdu;
|
||||
*tx_data_pdu = rlcP->stat_tx_data_pdu;
|
||||
*tx_control_pdu = rlcP->stat_tx_control_pdu;
|
||||
*rx_sdu = rlcP->stat_rx_sdu;
|
||||
*rx_error_pdu = rlcP->stat_rx_error_pdu;
|
||||
*rx_data_pdu = rlcP->stat_rx_data_pdu;
|
||||
*rx_data_pdu_out_of_window = rlcP->stat_rx_data_pdu_out_of_window;
|
||||
*rx_control_pdu = rlcP->stat_rx_control_pdu;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
/***************************************************************************
|
||||
rlc_am_util_proto_extern.h -
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
|
||||
***************************************************************************/
|
||||
# ifndef __RLC_AM_UTIL_PROTO_EXTERN_H__
|
||||
# define __RLC_AM_UTIL_PROTO_EXTERN_H__
|
||||
//-----------------------------------------------------------------------------
|
||||
# include "rlc_am_entity.h"
|
||||
# include "mem_block.h"
|
||||
//-----------------------------------------------------------------------------
|
||||
extern void rlc_am_stat_req (struct rlc_am_entity *rlcP,
|
||||
unsigned int* tx_pdcp_sdu,
|
||||
unsigned int* tx_pdcp_sdu_discarded,
|
||||
unsigned int* tx_retransmit_pdu_unblock,
|
||||
unsigned int* tx_retransmit_pdu_by_status,
|
||||
unsigned int* tx_retransmit_pdu,
|
||||
unsigned int* tx_data_pdu,
|
||||
unsigned int* tx_control_pdu,
|
||||
unsigned int* rx_sdu,
|
||||
unsigned int* rx_error_pdu,
|
||||
unsigned int* rx_data_pdu,
|
||||
unsigned int* rx_data_pdu_out_of_window,
|
||||
unsigned int* rx_control_pdu);
|
||||
extern int rlc_am_comp_sn (struct rlc_am_entity *rlcP, uint16_t low_boundaryP, uint16_t sn1P, uint16_t sn2P);
|
||||
extern void adjust_vr_r_mr (struct rlc_am_entity *rlcP);
|
||||
extern void adjust_vt_a_ms (struct rlc_am_entity *rlcP);
|
||||
extern void display_protocol_vars_rlc_am (struct rlc_am_entity *rlcP);
|
||||
extern void display_retransmission_buffer (struct rlc_am_entity *rlcP);
|
||||
extern void display_receiver_buffer (struct rlc_am_entity *rlcP);
|
||||
extern void rlc_am_check_retransmission_buffer (struct rlc_am_entity *rlcP, uint8_t * messageP);
|
||||
extern void rlc_am_check_receiver_buffer (struct rlc_am_entity *rlcP, uint8_t * messageP);
|
||||
extern void rlc_am_display_data_pdu7 (mem_block_t * pduP);
|
||||
# ifdef DEBUG_RLC_AM_CONFIRM
|
||||
void debug_rlc_am_confirm (struct rlc_am_entity *rlcP, uint32_t muiP);
|
||||
# endif
|
||||
# endif
|
||||
Reference in New Issue
Block a user