From 6360152627c9a4e0a1f420a0868f7c7eff2917cb Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Fri, 22 Jan 2010 15:59:10 +0100
Subject: [PATCH] Add brcm_iscsi_uio

The bnx2i driver requires ARP and DHCP support from userspace.
This patch adds the required daemons for this.

Signed-off-by: Hannes Reinecke <hare@suse.de>

diff --git a/brcm_iscsi_uio/COPYING b/brcm_iscsi_uio/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/brcm_iscsi_uio/COPYING
@@ -0,0 +1,674 @@
+                    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>.
diff --git a/brcm_iscsi_uio/ChangeLog b/brcm_iscsi_uio/ChangeLog
new file mode 100644
index 0000000..7e94f1d
--- /dev/null
+++ b/brcm_iscsi_uio/ChangeLog
@@ -0,0 +1,7 @@
+Version 0.4.1 (July 20, 2009)
+  * Fix from Mike Christie to determine page size from getpagesize() 
+    rather then the constant PAGE_SIZE.  PAGE_SIZE is not defined om
+    ia64 and ppc.
+  * Update documentation to indicate IPv6 is not supported
+  * Fix code to catch the message from the CNIC that the network
+    interface is going down.
diff --git a/brcm_iscsi_uio/INSTALL b/brcm_iscsi_uio/INSTALL
new file mode 100644
index 0000000..8b82ade
--- /dev/null
+++ b/brcm_iscsi_uio/INSTALL
@@ -0,0 +1,291 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008 Free Software Foundation, Inc.
+
+   This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  6. Often, you can also type `make uninstall' to remove the installed
+     files again.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *Note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/brcm_iscsi_uio/Makefile.am b/brcm_iscsi_uio/Makefile.am
new file mode 100644
index 0000000..6be8eea
--- /dev/null
+++ b/brcm_iscsi_uio/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS= src
+
+EXTRA_DIST = build_date
+
+build_date:
+	echo 'char *build_date ="'`date`'";' > build_date.c
+	echo 'char *build_date; '> build_date.h
diff --git a/brcm_iscsi_uio/README b/brcm_iscsi_uio/README
new file mode 100644
index 0000000..bd13e29
--- /dev/null
+++ b/brcm_iscsi_uio/README
@@ -0,0 +1,100 @@
+Broadcom iSCSI Userspace Tools
+Version 0.5.2
+Dec 10, 2009
+------------------------------------------------------
+
+This tools is to be used in conjunction with the Broadcom NetXtreme II Linux
+driver (Kernel module name: 'bnx2' and 'bnx2x'), Broadcom CNIC driver,
+and the Broadcom iSCSI driver (Kernel module name: 'bnx2i'). 
+This user space driver is used  in conjunction with the following
+Broadcom Network Controllers:
+  bnx2:  BCM5708, BCM5709 devices
+  bnx2x: BCM57710, BCM57711, BCM57711E devices
+
+This utility will provide the ARP and DHCP functionality for the iSCSI offload.
+The communication to the driver is done via Userspace I/O (Kernel module name
+'uio').
+
+There are two components to this application:
+
+1.  'brcm_iscsiuio' - This is the daemon which aids in creating iSCSI offloaded
+                      connections.
+
+Dependencies:
+=======================================
+
+Linux Kernel Dependencies:
+1.  Broadcom CNIC driver (cnic)
+1.  Broadcom iSCSI offload driver (bnx2i)
+2.  Userspace I/O driver (uio)
+
+Directory Structure of this Package:
+=======================================
+
+<root>
+  |
+  +-doc (documentation directory: man pages)
+  |
+  +-src 
+     |
+     +- uip - the uIP stack
+     |
+     +- unix - brcm_iscsiuio source
+     
+
+
+Compiling / Installing
+=======================================
+
+1.  Please untar the tarball.
+2.  Run the configure script.  This will create the Makefiles and proper
+    header files needed for the build.
+3.  Run 'make'.  This will create 2 binaries, 'brcm_iscsiuio' and
+    'admin_client'
+4.  Run 'make install' to place the binaries in their installed location.
+
+iscsid IFACE Configuration File:
+=======================================
+The network interface configuration files are driven by the iscsid iface
+files.  The configuration data is parsed by iscsid and passed to the uIP
+stack when the connection is established.
+
+One can use the following iscsiadm commands to create/set the configuration
+using the iface files:
+
+To create the iface file:
+      iscsiadm -m iface -I <iface name> --op=new
+
+To update the iface file:
+
+  To use a static IPv4 address:
+      iscsiadm -m iface -I <iface name> --op=update --name=iface.ipaddress --value=<static IPv4 address ie: 192.168.0.1>
+
+  To use a DHCP address:
+      iscsiadm -m iface -I <iface name> --op=update --name=iface.ipaddress --value=0.0.0.0
+
+  The following values are required.
+
+  To specify the bnx2i as the transport:
+      iscsiadm -m iface -I <iface name> --op=update --name=iface.transport_name --value=bnx2i
+
+  To specify the network interface name:
+      iscsiadm -m iface -I <iface name> --op=update --name=iface.net_ifacename --value=<network interface name>
+
+  Now all the settings should be set so that one could connect to their
+  desired iSCSI target.
+      iscsiadm -m node -p <iSCSI target IP address> -T <target name> -I <iface name> --login
+
+Limitations:
+=======================================
+*  RX iSCSI ring:
+      *  default ring size is 3 entries
+      *  default buffer size is 0x400 bytes
+*  TX iSCSI ring:
+      *  default ring size of 1 entry
+      *  default buffer size is 0x400 bytes
+
+Any packets larger then the buffer size will not be sent/received by the
+hardware and will be dropped.
+
+There is no IPv6 support.
diff --git a/brcm_iscsi_uio/RELEASE.TXT b/brcm_iscsi_uio/RELEASE.TXT
new file mode 100644
index 0000000..38947af
--- /dev/null
+++ b/brcm_iscsi_uio/RELEASE.TXT
@@ -0,0 +1,3968 @@
+                              Release Notes
+                        Broadcom uIP Linux Driver
+                              Version 0.5.2
+                                12/10/2009
+
+                          Broadcom Corporation
+                         5300 California Avenue,
+                            Irvine, CA 92617
+
+               Copyright (c) 2004 - 2009 Broadcom Corporation
+                           All rights reserved
+
+uIP v0.5.2 (Dec 10, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: Switching between 10G and 1G iSCSI offloaded
+               devices caused login connectivity problems
+
+      Cause: The NIC devices within uIP were not cleanup
+             properly.
+
+      Change: The NIC structure is not re-initialized and the
+              NIC thread is destroyed when the host network
+              interface is brought down.
+
+      Impact: None.
+
+
+uIP v0.5.1 (Dec 9, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: 10G devices behind PCI bridges would not collect
+
+      Cause: PCI bus:slot.func string was parsed incorrectly
+             because the bridge string was used
+
+      Change: Parse the proper PCI bus:slot.func string.
+
+      Impact: None.
+
+
+uIP v0.5.0b (Nov 24, 2009)
+=======================================================
+   Initial release
+
+   Enhancements
+   ------------
+
+   1. Change: Add Broadcom 10G iSCSI offload support
+
+      Impact: Linux
+
+
+bnx2 v1.9.41b (Nov 19, 2009) cnic 1.9.11b (Nov 19, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: (CQ44617) Compile error on SLES10 and RHEL4 kernels.
+
+      Cause: bool not defined on older kernels.
+
+      Change: Added compatibility code.
+
+      Impact: None.
+
+   2. Problem: (CQ42096) iSCSI sessions do not recover after running
+               selftest/ifdown/etc with max sessions connected.
+
+      Cause: cnic_lock mutex has circular dependency, causing deadlock
+             when iscsid tries to cleanup connections.
+
+      Change: Merged in upstream cnic patches to avoid circular
+              dependency.
+
+      Impact: None.
+
+   Enhancements
+   ------------
+      Change: (CQ43088) Changed the firmware version string format.
+
+      Impact: None.
+
+bnx2 v1.9.40b (Nov 18, 2009) cnic 1.9.10b (Nov 12, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: (CQ44528) Kernel runs out of memory after load/unload bnx2.
+
+      Cause: RX SKB buffers were not freed.
+
+      Change: Fixed the regression introduced by VMWare development.
+
+      Impact: None.
+
+   2. Problem: (CQ44399) iLAB 5.10 connection establishment test failure.
+
+      Cause: Firmware SYN-ACK handling issue.
+
+      Change: Updated firmware to 5.0.0.j6 in bnx2_fw.h and 5.0.0.j9 in
+              bnx2_fw2.h. 
+
+      Impact: iSCSI.
+
+   Enhancements
+   ------------
+      Change: (CQ43088) Added VPD-R V0 firmware version string to ethtool -i.
+
+      Impact: None.
+
+bnx2 v1.9.39b (Nov 6, 2009) cnic 1.9.10b (Nov 12, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: (CQ44470) Kernel panics when bnx2/bnx2x is unloaded with
+               active iSCSI sessions.
+
+      Cause: NETDEV_UNREGISTER will cause bcm570x_* transport to be
+             destroyed while sessions may still be active.
+
+      Change: Use module referencing to prevent bnx2/bnx2x from unloading.
+              This is a simple interim solution to revert back to the
+              old behavior.  In T6.0, we will migrate to the upstream
+              driver architecture and network drivers will be able to be
+              unloaded again.
+
+      Impact: None.
+
+   Enhancements
+   ------------
+      Change: Added a short register dump during NETDEV_WATCHDOG.
+
+      Impact: None.
+
+bnx2 v1.9.38b (Nov 6, 2009) cnic 1.9.9b (Nov 6, 2009)
+=====================================================
+   Fixes
+   -----
+   1. Problem: (CQ44446) cnic panics during 10G iSCSI initialization.
+
+      Cause: Recent interface changes introduced this regression.
+             cnic_service_bnx2x() panics when accessing uninitialized
+             status block pointer.
+
+      Change: Added state checking in cnic_service_bnx2x().
+
+      Impact: None.
+
+   2. Problem: (CQ44439) bnx2 does not compile on older 2.6 kernels.
+
+      Cause: mutex not defined on older kernels.
+
+      Change: Use rtnl_lock() to protect bnx2_reset_task().
+
+      Impact: None.
+
+bnx2 v1.9.37b (Nov 4, 2009) cnic 1.9.8b (Nov 3, 2009)
+=====================================================
+   Enhancements
+   ------------
+
+   1. Change: Updated 5708/5706 firmware to 5.0.0.j5 for better small packet
+              performance.
+
+      Impact: 5706/5708.
+
+   Fixes
+   -----
+   1. Problem: (CQ43280) Cannot unload cnic after bnx2/bnx2x is loaded.
+
+      Cause: module referencing.
+
+      Change: Changed module referencing scheme.
+
+      Impact: None.
+
+bnx2 v1.9.36b (Oct 22, 2009)
+=======================================================
+   Enhancements
+   ------------
+
+   1. Change: Expand on NetQueue module parameters.
+
+      Impact: bnx2 VMware NetQ.
+
+bnx2 v1.9.35b (Oct 22, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: If only 1 queue is used on VMware ESX, iSCSI
+               offload would fail.
+
+      Cause: The inboxed VMware driver would only use
+             1 MSI-X vector.  Because of this the driver
+             would not setup MSI-X
+
+      Change: Always setup MSI-X reguardless of the
+              number of MSI-X vectors used.
+
+      Impact: 5709 iSCSI on VMware
+
+bnx2 v1.9.34b (Oct 20, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Change: Updated xinan firmware to 5.0.0.j8
+              Nop timeout tuning (VMware PR467194)
+              Added a new data fw heartbeat to work with
+              the new bootcode and also handle older
+              bootcode.
+
+      Impact: 5709.
+
+bnx2 v1.9.33b (Oct 8, 2009)
+=======================================================
+   Enhancements
+   ------------
+
+   1. Change: Make NetQueue module parameters more explict.
+
+      Impact: bnx2 VMware NetQ.
+
+bnx2 v1.9.32b (Oct 8, 2009) cnic v1.9.7c (Oct 8, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: CNIC unable to handle an unsolicited
+               RESET COMPLETE which would result in a hung
+               session.
+
+      Cause: The CNIC driver couldn't handle unexpected SYN.
+
+      Change: The CNIC driver will now handle an unsolicited
+              RESET COMPLETE and cleanup properly.
+
+      Impact: cnic
+
+   Enhancements
+   ------------
+
+   1. Change: Allow the default NetQueue options to be
+              controlled through the macro,
+              BNX2_ENABLE_NETQUEUE.
+
+      Impact: bnx2 VMware NetQ.
+
+bnx2 v1.9.31b (Oct 6, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: PSOD would occur when alloc()'ing NetQueue's
+
+      Cause: With the removal of the global 'disable_netq' 
+             parameters, the NetQueue CID's weren't being
+             mapped in some cases
+
+      Change: Always map the NetQueue CID's
+
+      Impact: bnx2 VMware ESX NetQueue
+
+bnx2 v1.9.30b (Oct 5, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: PSOD would occur because of TX timeouts
+
+      Cause: The VMware netdev watchdog timer was ran before
+             the reset task got a chance to run on a loaded
+             system. 
+
+      Change: Elongated the TX timeout value for VMware ESX
+              only to allow for the reset task to run.
+
+      Impact: bnx2 VMware ESX
+
+
+   Enhancements
+   ------------
+
+   1. Change: Updated vmkernel module parameter, 'force_netq',
+              to allow NetQueue setting to be adjusted per
+              function rather then globally for all functions.
+
+      Impact: bnx2 VMware ESX
+
+
+bnx2 v1.9.29b (Oct 1, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Change: Updated xinan firmware to 5.0.0.j7 and
+              teton firmware to 5.0.0.j4 which will fix
+              L2 hang due to iSCSI PDU's padding byte
+              extended to another TCP segment
+
+      Impact: 5706/5708/5709.
+
+
+bnx2 v1.9.28b (Sep 25, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Change: Updated firmware to 5.0.0.j6 which will add
+              the corresponding flow control trip point.
+
+      Impact: 5709.
+
+
+bnx2 v1.9.27b (Sep 24, 2009) cnic v1.9.7b (Sep 24, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: For the cnic users would see in the kernel logs:
+
+               "kcq abs(hw_prod(0) - sw_prod(65534)) >
+                MAX_KCQ_IDX(2047)"
+
+      Cause: The function was not taking into account the
+             wrapping of the software and hardware producer
+             indexes.
+
+      Change: Recaculate the difference between the index with
+              wrapping taken into account.
+
+      Impact: cnic
+
+
+   Enhancements
+   ------------
+
+   1. Change: Updated firmware to 5.0.0.j5 which increased the
+              rxpq depth from 32 to 256 to enhance the performance 
+              on systems without flow control.
+
+      Impact: 5709.
+
+
+bnx2 v1.9.26c (Sep 17, 2009)
+=======================================================
+   Enhancements
+   ------------
+   1. Change: Cleanup the VMware NetQueue code.  Eliminate unneeded
+              RX flush routine, fix the number of queues to be the
+              same on 1500 and 9000 MTU sized packets.
+
+      Impact: bnx2 VMware NetQ.
+
+bnx2 v1.9.26b (Sep 14, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: VMware PSOD on MTU change
+
+      Cause: MSI-X window was remapped to the beginning of the PCI
+             config space.  The driver would disable the bar space
+             because the MSI-X window was remapped incorrectly.  This
+             would eventually cause a PSOD.
+
+      Change: Before the chip reset, the driver would disable MSI-X,
+              after the chip reset, MSI-X is re-enabled.
+
+      Impact: VMware NetQueue
+
+
+bnx2 v1.9.25b (Aug 21, 2009) cnic v1.9.6 (Aug 21, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: (CQ 43182/43252) Compile error on RHEL4
+
+      Cause: struct mutex not defined on older kernels.
+
+      Change: Wrap cnic_lock mutex structure and code with #ifdef BCM_CNIC.
+
+      Impact: None.
+
+   2. Problem: Unloading cnic after ifdown may crash.
+
+      Cause: cnic unregisters with bnx2/bnx2x twice.
+
+      Change: Fixed logic to unregister only once.
+
+      Impact: None.
+
+bnx2 v1.9.24b (Aug 13, 2009) cnic v1.9.6 (Aug 13, 2009)
+=======================================================
+   Fixes
+   -----
+   1. Problem: (CQ 42778) Kernel occasionally panics when enabling jumbo
+               frames.
+
+      Cause: If the driver is unable to allocate memory for the buffers,
+             the device is not properly shutdown.
+
+      Change: Added logic to shutdown device if unable to allocate buffers
+              and complete the setup of the device.
+
+      Impact: bnx2, changing MTU and ring sizes.
+
+   Enhancements
+   ------------
+   1. Change: Updated firmware to 5.0.0.j3 for better small packet rx
+              performance.  Firmware also fixes header digest error during
+              I/O.
+
+      Impact: All bnx2 devices.
+
+bnx2 v1.9.23b (July 29, 2009) cnic v1.9.5 (July 29, 2009)
+==========================================================
+
+   Fixes
+   -----
+   1. Problem: (CQ 42723) KCQ not resetting to 0 problem
+
+      Cause:   RCU deadlock during shutdown
+
+      Change:  Move the bnx2_register_cnic() call out of the
+               above sequence. Instead, register and
+               unregister during NETDEV_UP/NETDEV_DOWN events.
+
+               Change all slow path RCU read locks to mutex.
+               In cnic, we also use reference counting to
+               protect some slow paths.
+
+      Impact: bnx2 iSCSI, bnx2x iSCSI
+
+
+bnx2 v1.9.22b (July 23, 2009) cnic v1.9.4 (July 23, 2009)
+==========================================================
+
+   Enhancements
+   ------------
+   1. Change: If a TX timeout occurs, there could be the possiblity that the
+              chip is hung. By printing chip state into the kernel ring buffer,
+              it will be easier to determine this.
+
+      Impact: bnx2 iSCSI.
+
+   2. Change: The bnx2 firmware should always be matched with the proper bnx2
+              driver. The bnx2 firmware version string are now printed.
+              It will be easier to identify the running firmware.
+
+      Impact: bnx2
+
+   3. Change: When a TX timeout occurs and the chip is reset, the ability to
+              debug the chip further is lost.  This is because the chip state
+              information is lost during the reset.  The users have a choice
+              to prevent the chip reset.
+
+      Impact: bnx2
+
+   4. Change: Add a check to see if there was a KCQ overflow was
+              in the bnx2x firmware.  Now this check has been moved to the
+              CNIC so that the driver could control the cleanup/recovery.
+              
+      Impact: bnx2 iSCSI.
+
+
+bnx2 v1.9.21b (July 16, 2009)
+==========================================================
+   Enhancements
+   ------------
+   1. Change: Updated firmware to 5.0.0.j2  to fix remote reset problem
+
+      Impact: bnx2 iSCSI.
+
+
+bnx2 v1.9.20b (July 09, 2009), cnic v1.9.3 (July 09, 2009)
+==========================================================
+   Fixes
+   -----
+   1. Problem: (CQ42534) cnic.c does not compile on older kernels.
+
+      Cause:   Some iscsi_proto constants not defined in <scsi/iscsi_proto.h>
+
+      Change:  Added the constant definitions if not already defined.
+
+      Impact: None.
+
+   Enhancements
+   ------------
+   1. Change: Updated firmware to 5.0.0.j to fix TMF releated iSCSI issues.
+
+      Impact: bnx2 iSCSI.
+
+bnx2 v1.9.19b (July 01, 2009), cnic v1.9.2 (July 01, 2009)
+==========================================================
+   Fixes
+   -----
+   1. Problem: (CQ42399) 10G iSCSI fails when initiator and target MTUs
+               don't match.
+
+      Cause: cnic driver sets the MSS without knowing the actual MSS
+             option and timestamp option during TCP connection.
+
+      Change: Changed driver to set MSS to 0xffff so that firmware can
+              calculate MSS on its own.
+
+      Impact: bnx2x iSCSI.
+
+   2. Problem: 1G iSCSI fails when initiator and target MTUs don't
+               match and timestamp is enabled.
+
+      Cause: Firmware was not adjusting for the 12-byte timestamp option
+             if MSS was reduced by MSS option.
+
+      Change Updated firmware to 5.0.0.i
+
+      Impact: bnx2 iSCSI.
+
+   3. Problem: (CQ42353) Unable to disable TCP timestamp on 10G iSCSI.
+
+      Cause: Timestamp was hardcoded to be enabled for 10G.
+
+      Change: Update global timestamp option during each TCP connection.
+
+      Impact: bnx2x iSCSI.
+
+   4. Problem: (CQ42329) bnx2x MC assert during IPv6 login/logout.
+
+      Cause: EQ filled with more than 128 L4 kcqes without MSI-X interrupt
+             for 2 seconds.  The driver can only buffer 128 L4 kcqes.
+
+      Change: Increased L4 kcqe buffer to 256 entries as a temporary solution.
+              Need to understand the delayed interrupt issue.
+
+      Impact: None.
+
+bnx2 v1.9.18b (June 25, 2009), cnic v1.9.1 (June 24, 2009)
+==========================================================
+   Enhancements
+   ------------
+   1. Change: Added FTQDiscard counter to the list of counters being
+              reported.  During small packet test, there may be FTQ
+              overflow and this counter is very useful.
+
+      Impact: None.
+
+   2. Change: Updated firmware to 5.0.0.h to improve small packet L2
+              performance and to enhance iSCSI TMF handling.
+
+      Impact: 5706/5708/5709.
+
+bnx2 v1.9.17b (June 24, 2009), cnic v1.9.1 (June 24, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: Leaking NetQueues if the firmware did not respond in time
+
+      Cause: System might be clogged and there is not enough time to 
+             process the KCQ
+
+      Change: Updated driver/firmware to allow the calling of the free RX
+              queue request before a RX alloc request is issued
+
+      Impact: 5709
+
+   2. Problem: An offloaded iSCSI connection would get stuck
+
+      Cause: Issing an offload request might fail, and this was not handled
+             properly.
+
+      Change: Updated driver/firmware to return the proper return code and
+              handle offload connection failures.
+
+      Impact: 5706/5708/5709
+
+   3. Problem: tasklet_init() is being called on a task that is scheduled
+
+      Cause: When the CNIC calls register_device(), that task might already
+             be schedled.
+
+      Change: tasklet_disable() is insufficient because the tasklet remains
+              scheduled and stays on the tasklet list, instead tasklet_kill() 
+              is now used.
+
+      Impact: 5706/5708/5709
+
+
+
+bnx2 v1.9.16b (June 10, 2009), cnic v1.9.0 (June 10, 2009)
+==========================================================
+   Enhancements
+   ------------
+   1. Change: (CQ38228) Use symbol_get() for ipv6 symbols so that the
+              cnic driver will load without necessarily loading ipv6
+              modules.
+
+      Impact: iSCSI over IPv6.
+
+   2. Change: Updated 5706/08/09 MIPS firmware to 5.0.0.g.
+
+      Impact: 5706/08/09.
+
+   3. Change: Backported some dma_mapping_error() checking.
+
+      Impact: None.
+
+bnx2 v1.9.15b (June 1, 2009), cnic v1.8.6 (June 1, 2009)
+========================================================
+   Enhancements
+   ------------
+   1. Change: Upstream bnx2 tx path optimizations.  Please see ChangeLog.
+
+      Impact: bnx2 tx path.
+
+   2. Change: In the cnic driver, save the last allocated TCP port during
+              unregistration so that previously used TCP ports will not
+              be immediately re-used.
+
+      Impact: iSCSI.
+
+   3. Change: VMWare TCP port allocation changes.
+
+      Impact: VMWare iSCSI.
+
+bnx2 v1.9.14b (May 21, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: NOPOUT timeouts on 570x iSCSI connections.
+
+      Cause: Bugs in TCP timestamp implementation.
+
+      Change: Updated MIPS firmware to 5.0.0.f.
+
+      Impact: 5706/5708/5709.
+
+bnx2 v1.9.13b (May 18, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: Potentially exceeding the NetQueue limit recommendations
+               by VMware which could stress system resources
+
+      Cause:  When system resources are strained.
+
+      Change: There are now limits on the number of NetQueues which the
+              driver will request:
+              When the MTU is 1500 the max number of queues per port is 8
+              When the MTU is 9000 the max number of queues per port is 4
+
+      Impact: NetQueue enabled version of VMware ESX
+
+   2. Problem: Getting conflicting NetQueue and iSCSI completions
+
+      Cause:  When MSI-X is not used on a 5709, NetQueue is still enabled
+
+      Change: NetQueue is not disabled is MSI-X is not used.
+
+      Impact: NetQueue enabled version of VMware ESX
+
+
+bnx2 v1.9.12b (May 13, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: Potentially returning a negative number of NetQueues
+
+      Cause: When calculating the number of rings, we use the calculation from
+             the number of msi-x vectors returned,  The number of NetQueues
+             returned could potentially be negitive if only 1 vector was
+             returned.  This is because the driver was subtracting 2
+             instead of subtracting 1 (for the default queue) from the total
+             number of rings.
+
+      Change: Return the proper number of queues not including the default
+              queue.
+
+      Impact: NetQueue enabled version of VMware ESX
+
+bnx2 v1.9.11b (May 12, 2009), cnic v1.8.5 (May 13, 2009)
+========================================================
+   Fixes
+   -----
+   1. Problem: TCP Delay ACK not working on bnx2x iSCSI
+
+      Cause: Disabled in cnic driver.
+
+      Change: Fixed csk->tcp_flags definitions and enabled the proper storm
+              bit for delay ACK.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.9.11b (May 12, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: iSCSI timestamp TCP option not working.
+
+      Cause: Disabled in firmware.
+
+      Change: Updated to 5.0.0e MIPS firmware.
+
+      Impact: 5709.
+
+bnx2 v1.9.10b, cnic v1.8.4 (May 11, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: NetQ and iSCSI do not work in Vmware environment.
+
+      Cause: 1. cnic driver is overwriting CP and COM mailbox bit values newly
+                defined to support multiple kcqs.
+
+             2. Firmware is completing some iSCSI kcqes on the NetQ's kcq.
+
+      Change: Fixed cnic driver to only set and clear bit 0 of the CP
+              and COM mailbox.
+
+              Firmware has been updated to 5.0.0d. This firmware also
+              supports TCP timestamp option for iSCSI connections.
+
+      Impact: 5706/5708/5709 iSCSI, NetQ.
+
+bnx2 v1.9.9b (May 1, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: There is link, but can't pass traffic on ESXi
+
+      Cause: Bits in the RX context are being trampled during the
+             renegotiation of the link.
+
+      Change:  RX context offset 0x6 should only be initialized once
+               during init and not be updated during run-time.  Offset
+               4 contains the BIDX that's mapped to the mailbox.
+
+      Impact: VMware with NetQueue
+
+bnx2 v1.9.8b, cnic v1.8.2 (April 27, 2009)
+==========================================
+   Enhancements
+   ------------
+   1. Change: Updated cnic driver to support 1.50.x HSI as well as the older
+              1.48.107 HSI.  A compile flag will be used to select one or the
+              other.
+
+      Impact: iSCSI on bnx2x.
+
+   2. Change: Spec file and Makefile changes detect the proper module
+              install directory.
+
+      Impact: installation.
+
+bnx2 v1.9.7b, cnic v1.8.1 (April 22, 2009)
+==========================================
+   Fixes
+   -----
+   1. Problem: Compile error with redfinition of struct kwqe.
+
+      Cause: Both the CNIC and bnx2 defined this structure.
+
+      Change: Because the bnx2 definition is L2 specific, it was renamed to
+              struct l2_kwqe.
+
+      Impact: None.
+
+   2. Problem: Add context memory DMA alignment for 57710.
+
+      Cause: For the 57710 context memory needs to be 16k aligned.
+             Without this alignment you will see errors when trying to
+             establish more then 5 iSCSI connections on VMware ESX 4.0 U1.
+
+      Change: Properly aligned the context memory by allocating a bigger 
+              chunk of memory and then finding the proper alignment.
+              This reduces the number of possible connections in half
+              but now we can properly establish more then 5 connections
+              on VMware.
+
+      Impact: iSCSI.
+
+
+bnx2 v1.9.6b (April 17, 2009)
+=============================
+   Enhancements
+   ------------
+   1. Change: Added NetQueue support for VMware.
+
+      Impact: 5709.
+
+bnx2 v1.9.5b (April 17, 2009)
+=============================
+   Enhancements
+   ------------
+   1. Change: Updated to 5.0.0.a firmware with NetQ support and iSCSI max
+              connection license information. RV2P firmware unchanged:
+              4.6.16 for 5706, 4.6.15 for 5709.
+
+      Impact: All chips.
+
+   2. Change: Set USE_INT_PARAM on 5709.  This will switch the chip in
+              use "interrupt mode" coalescing after MSI/MSI-X.
+
+      Impact: 5709.
+
+   3. Change: Included 5706 when doing statistics block DMA workaround.
+
+      Impact: 5706.
+
+bnx2 v1.8.8b (March 12, 2009)
+=============================
+   Enhancements
+   ------------
+   1. Change: Updated to latest 4.6.17 CP firmware for 5709.
+
+      Impact: iSCSI licensing on 5709.
+
+bnx2 v1.8.7b, cnic v1.7.8 (March 10, 2009)
+==========================================
+   Enhancements
+   ------------
+   1. Change: Reverted 5706/5708 firmware to 4.6.16.  Low latency interrupt
+              mode does not work on 5706/5708.
+
+      Impact: None.
+
+   2. Change: VMWare changes to expose max. number of iSCSI connections in
+              the cnic_device structure.
+
+      Impact: VMware iSCSI.
+
+   Fixes
+   -----
+   1. Problem: (CQ39867) Compile error on RHEL5.3 Xen kernel.
+
+      Cause: msi related symbols undefined because CONFIG_PCI_MSI is not
+             enabled on Xen kernels.
+
+      Change: Added CONFIG_PCI_MSI around the msi related code.
+
+      Impact: None.
+
+   2. Problem: (CQ39818) iSCSI targets do not reconnect after running self test.
+
+      Cause: Interrupt is disabled by bnx2 before notifying CNIC to clean up
+             and stop.  As a result, bnx2i will not receive interrupts when
+             closing the connections if sharing INTA/MSI with network.
+
+      Change: Disable interrupt after notifying CNIC to stop.
+
+      Impact: iSCSI.
+
+bnx2 v1.8.6b, cnic v1.7.7 (March 2, 2009)
+=========================================
+   Enhancements
+   ------------
+   1. Change: Updated to new 5706 firmware (4.6.17) and 5709 firmware (4.6.16).
+              New interrupt coalescing mode for improved latency and iSCSI
+              cache line fix on 5709.
+
+      Impact: All bnx2 chips.
+
+   2. Change: CNIC iSCSI changes for VMWare.
+
+      Impact: VMWare only.
+
+bnx2 v1.8.5b, cnic v1.7.6 (Feb 9, 2009)
+=======================================
+   Fixes
+   -----
+   1. Problem: (CQ39380) bnx2x iSCSI license not read correctly.
+
+      Cause: Using wrong variable to check the license.
+
+      Change: Fixed the logic.
+
+      Impact: bnx2x iSCSI.
+
+   2. Problem: Driver accesing MMIO registers during VLAN operations when
+               the device is in D3hot state in older kernels.
+
+      Cause: VLAN registration functions do not check for device state.
+
+      Change: Added if_running check before MMIO access in VLAN registration
+              functions.
+
+      Impact: VLAN operations on all bnx2 chips.
+
+   Enhancements
+   -----------
+   1. Problem: Updated 5706/5708 firmware to 4.6.16.
+
+      Impact: 5706/5708.
+
+bnx2 v1.8.4b, cnic v1.7.5 (Jan 30, 2009)
+========================================
+   Fixes
+   -----
+   1. Problem: (CQ39281) Management firmware stops passing traffic when
+               bnx2 driver is loaded with jumbo frames enabled.
+
+      Cause: Firmware bug.
+
+      Change: Updated to 4.6.15 firmware.
+
+      Impact: 5706/5708/5709.
+
+   2. Problem: iSCSI does not work on 57711 in single function mode.
+
+      Cause: Driver only allows iSCSI on 57711 if iSCSI is enabled.
+
+      Change: iSCSI config. not required in single function mode.
+
+      Impact: bnx2x iSCSI.
+
+   Enhancements
+   ------------
+   1. Change: (CQ38576) Add 5709 to bnx2.4 man page.
+
+      Impact: None.
+
+bnx2 v1.8.3b, cnic v1.7.4 (Jan 23, 2009)
+========================================
+   Fixes
+   -----
+   1. Problem: (CQ38610, CQ39000, CQ39015, CQ39071, CQ39133) Various Jumbo
+               frames related data corruption issues.
+
+      Cause: Bug in RV2P firmware causing jumbo frames to be DMA'ed without
+             the frame header control structure occasionally.
+
+      Change: New firmware.
+
+      Impact: 5706/5708/5709.
+
+bnx2 v1.8.2c, cnic v1.7.4 (Dec 30, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: (CQ38955) Xen kernel panic when unloading bnx2 with jumbo MTU.
+
+      Cause: Bug in bnx2_free_rx_mem().  The jumbo page ring memory was
+             freed incorrectly using the wrong local variable as array
+             index.
+
+      Change: Fixed bug by using the correct variable as array index.
+
+      Impact: Jumbo frames.
+
+   2. Problem: (CQ38965) iSCSI connection timeout on bnx2x.
+
+      Cause: During CFC Delete RAMROD completion handling, the wrong (older)
+             iSCSI connection ID can sometimes be retrieved using the
+             harware CID.  The CID in the mapping table was not cleared
+             after the CID was freed. 
+
+      Fix: Adding clearing of the CID in the data structure after a CID
+           is freed.
+
+      Impact: bnx2x iSCSI.
+
+   Enhancements
+   ------------
+   1. Change: (CQ38744) Reduced R2TQ memory usage to match new firmware
+              interface (firmware 4.8.9). This reduces the amount of
+              kernel memory substantially for each iSCSI connection on
+              bnx2x.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.8.2b, cnic v1.7.3 (Dec 17, 2008)
+========================================
+   Enhancements
+   ------------
+   1. Change: Added iSCSI configuration check on 57711E devices before
+              allowing iSCSI connections.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.8.2b, cnic v1.7.2 (Nov 25, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: bnx2x iSCSI does not work on functions 2 or above.
+
+      Cause: This was caused by multiple problems:
+             a) Status block ID specified by bnx2x was wrong.
+             b) MSI-X vector assigned to CNIC was wrong.
+             c) New method to ack. status block using HC register was not
+                implemented.
+             d) Status block ID in CSTORM status block is always 0, and
+                as a result, the status block ID used to ack. the status
+                block was wrong.
+
+             All these problems only affect functions 2 and above.
+
+     Change: All problems fixed in bnx2x and cnic.
+
+     Impact: bnx2x iSCSI.
+
+bnx2 v1.8.2b, cnic v1.7.1 (Nov 15, 2008)
+========================================
+   Enhancements
+   ------------
+   1. Change: Added CNIC support for Multi function bnx2x iSCSI.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.8.2b, cnic v1.6.2 (Nov 12, 2008)
+========================================
+   Enhancements
+   ------------
+   1. Change: Updated to latest 4.6.13 5709 firmware to fix context corruption
+              with flow control enabled.
+
+      Impact: 5709.
+
+   2. Change: Added support for 5716S PCI ID.
+
+      Impact: None.
+
+   Fixes
+   -----
+   1. Problem: (CQ35904) Netdump does not work.
+
+      Cause: Problem introduced by MSI-X multiqueue.  IRQ handlers were
+             changed to take bnx2_napi parameter instead of netdev parameter.
+
+      Change: Fixed by passing proper parameter to IRQ handler from netpoll.
+              All IRQ handlers are called when using multiple MSI-X vectors.
+
+      Impact: 5709 netpoll.
+
+bnx2 v1.8.1f, cnic v1.6.1 (Nov 5, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: All TSO packets corrupted on 5706/5708.
+
+      Cause: Firmware bug zeroing the wrong field in IP header.
+
+      Change: Updated to latest 4.6.11 5706/5708 firmware and 4.6.12 5709
+              Firmware.
+
+      Impact: 5706/5708/5709.
+
+   2. Problem: bnx2x chip asserts when trying to make iSCSI connection
+               to an unknown IP address.
+
+      Cause: When connection fails, the driver sends a command to an
+             unitialized CID.
+
+      Change: Added logic to only send deletion commands to initialized
+              CIDs.
+
+      Impact: bnx2x iSCSI.
+
+   Enhancements
+   ------------
+   1. Change: Added support for one single VLAN to a bnx2x iSCSI interface.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.8.1e, cnic v1.6.0 (Oct 27, 2008)
+========================================
+   1. Change: Updated to latest 5709 firmware to fix iSCSI data integrity
+              problem.
+
+      Impact: 5709.
+
+bnx2 v1.8.1d, cnic v1.6.0 (Oct 23, 2008)
+========================================
+   Enhancements
+   ------------
+   1. Change: Updated to latest bnx2 firmware to fix iSCSI data integrity
+              problem.
+
+      Impact: 5706/5708/5709.
+
+   2. Change: Updated to the latest bnx2x HSI files.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.8.1c, cnic v1.5.9 (Oct 13, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: (CQ37905) Unable to compile on SLES10 SP2.
+
+      Cause: DIV_ROUND_UP macro not defined in this kernel.
+
+      Change: Added it for compatibility.
+
+      Impact: None.
+
+   Enhancements
+   ------------
+   1. Change: Updated to latest 5709 firmware that fixes an NCSI problem.
+
+      Impact: 5709.
+
+   2. Change: Handle TCP reset in the middle of TCP close more appropriately.
+
+      Impact: iSCSI.
+
+   3. Change: Handle iSCSI license checking in the same way as 5708/5709.
+
+      Impact: iSCSI on bnx2x.
+
+bnx2 v1.8.1b, cnic v1.5.8 (Oct 13, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: bnx2x iSCSI CIDs may be allocated outside the range of allocated
+               host memory.
+
+      Cause: CID range bigger than the amount of allocated host context
+             memory.
+
+      Change: Changed to match the CID range with memory range.
+
+      Impact: bnx2x iSCSI.
+
+   Enhancements
+   ------------
+   1. Change: Sync'ed with the latest upstream driver bnx2 1.8.1.
+
+      Impact: None.
+
+   2. Change: Implemented iSCSI connection license enforcement for bnx2x
+              devices.
+
+      Impact: bnx2x iSCSI.
+
+bnx2 v1.8.0j, cnic v1.5.7 (Oct 6, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: (CQ37610) Chip hangs when changing MTU with active iSCSI
+               connections.
+
+      Cause: Both cnic and bnx2 drivers setting up the chip at the same
+             time.
+
+      Change: Added check so that the register_cnic function will fail
+              if the bnx2 driver is in reset.
+
+      Impact: iSCSI.
+
+   2. Problem: (CQ37762) Able to unload bnx2/bnx2x drivers while there are
+               active iSCSI connections.
+
+      Cause: CNIC driver does not have a reference count on the BNX2/BNX2X
+             drivers.
+
+      Change: This became a problem after the register_cnic function was
+              no longer exported.  To solve the problem, the CNIC driver
+              will now get an explicit reference during register_cnic.
+
+      Impact: iSCSI.
+
+   3. Problem: (CQ37429) MMIO access while the chip is in D3hot state.
+
+      Cause: The driver does not check if_running state consistently during
+             ethtool operations.
+
+      Change: Added proper checks to all ethtool and multicast change
+              functions.
+
+      Impact: ethtool operations and multicast operations.
+
+   Enhancements
+   ------------
+   1. Change: Simplified ipv4 TSO logic in the driver.  This was made
+              possible with newer 5708 firmware.
+
+      Impact: 5708 TSO and other traffic.
+
+   2. Change: ethtool -p now blinks forever.  This is the standard behavior
+              in most other net drivers.
+
+      Impact: ethtool -p.
+
+bnx2 v1.8.0i, cnic v1.5.5 (Sep 30, 2008)
+========================================
+   Fixes
+   -----
+   1. Problem: (CQ36787) iSCSI login/logout commands fail on 5709 after a
+               while.
+
+      Cause: Not handling the KWQ completion properly on 5709 in INTA/MSI
+             mode.
+
+      Change: Changed to handle KWQ completions by checking the
+              cmd_consumer_index instead of the rx_quick_index15.
+
+      Impact: 5709 ISCSI in INTA/MSI mode.
+
+   2. Problem: (CQ37497) CNIC driver does not compile on powerpc.
+
+      Cause: csum_ipv6_magic() not defined.
+
+      Change: Added #include <net/ip6_checksum.h>
+
+      Impact: None.
+
+v1.8.0g (Sep 24, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: (CQ37511) System locks up when loading cnic driver on 2.6.16
+               kernel.
+
+      Cause: symbol_put_addr() in 2.6.16 tries to acquire the same lock twice.
+
+      Change: Workaround by using __symbol_put() which does not have the same
+              problem.
+
+      Impact: None.
+
+v1.8.0f (Sep 23, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: (CQ37405) Kernel panic when performing ifup/ifdown with iSCSI
+               connections on bnx2x devices.
+
+      Cause: Sending searcher delete to bnx2x devices when connection was
+             not established (due to Spanning Tree or other reasons).
+
+      Change: Check PG offload state before sending searcher delete.
+
+      Impact: iSCSI on bnx2x.
+
+v1.8.0e (Sep 22, 2008)
+========================
+   Enhancement
+   -----------
+   1. Change: Updated to latest driver firmware 4.6.6 for 5709.
+
+      Impact: 5709.
+
+   2. Change: Updated cnic so that it will not crash even if using older
+              bnx2/bnx2x drivers without CNIC support.  The net driver
+              can also be loaded after cnic and it will still work without
+              crashing.
+
+      Impact: iSCSI.
+
+   3. Change: (CQ 37381) Updated driver to check Vaux PRESET before allowing
+              WoL.  This is needed to support 5709 quad-port boards.
+
+      Impact: WoL on all devices.
+
+v1.8.0d (Sep 15, 2008)
+========================
+   Enhancements
+   ------------
+   1. Change: Updated CNIC iSCSI setup for bnx2x devices.
+
+      Impact: iSCSI on bnx2x devices.
+
+v1.8.0c (Aug 25, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: Does not compile on older kernels.
+
+      Cause: "__maybe_unused" undefined on older kernels.  "num_online_cpus()"
+              undefined on 2.4 kernels.
+
+      Change: Added compatibility code to workaround.
+
+      Impact: None.
+
+v1.8.0b (Aug 25, 2008)
+========================
+   Enhancement
+   -----------
+   1. Change: Updated to latest driver firmware 4.6.2 for 5709.
+
+      Impact: 5709.
+
+v1.7.9c (Aug 5, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: bnx2 does not compile on older kernels.
+
+      Cause: <linux/log2.h> is missing on 2.6.19 and older kernels.
+
+      Change: Added compatibility code to check for kernel version before
+              including the file.
+
+      Impact: none.
+
+v1.7.9b (Aug 5, 2008)
+========================
+   Enhancements
+   ------------
+   1. Change: Added multi-tx ring for 5709.  This fetaure is available on
+              2.6.27 kernel when using MSI-X.
+
+      Impact: 5709
+
+   2. Change: Added support for 57710 iSCSI in the CNIC driver.
+
+      Impact: iSCSI.
+
+v1.7.7c (July 14, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: Source RPM fails to build.
+
+      Cause: New file missing in tarball.
+
+      Change: Added missing file.
+
+      Impact: None.
+
+v1.7.7b (July 9, 2008)
+========================
+   Enhancements
+   ------------
+   1. Change:  Added probe function so that the CNIC driver can get the
+               pci_device pointer earlier before registration.
+
+      Impact:  iSCSI.
+
+   2. Change:  Added support for 5716.
+
+      Impact:  None.
+
+v1.7.6c (June 6, 2008)
+========================
+   Enhancements
+   ------------
+   1. Change:  Added multi-ring RX support on 5709 using MSI-X.  This feature
+               is only available on 2.6.24 and newer kernels running on SMP
+               machines.
+
+      Impact:  5709.
+
+   2. Change:  Added secondary unicast address support.  We now support up
+               to 5 unicast addresses.  This feature is only available on
+               2.6.23 and newer kernels.
+
+      Impact:  All chips.
+
+v1.7.6b.1 (Aug 14, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: (CQ36808) VLAN tagged packets received by host stack without
+               the VLAN tag.
+
+      Cause: If no VLANs are set up using vconfig, and if the driver
+             configures the chip to strip the VLAN tag, the problem can
+             happen.  With IPMI or UMP enabled, the driver is likely to
+             configure the chip to strip the VLAN tag.
+
+      Change: Modified the driver to re-insert the VLAN tag when necessary.
+              I.e. when IPMI/UMP is enabled and vconfig has not setup any
+              VLANs.
+
+      Impact: All chips receiving VLAN traffic.
+
+v1.7.6b (May 29, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: IPv4 TSO generates bad packet when the TSO packet size
+               is 1-MSS.
+
+      Cause: Probably firmware does not expect this boundary condition.
+
+      Change: Detect this 1-MSS condition in driver and skip the TSO logic.
+              1-MSS TSO packet will be treated like a regular TX checksum
+              offload packet.
+
+      Impact: TSO on all chips.
+
+   2. Problem: Cannot disable VLAN stripping even when management firmware
+               is disabled.
+
+      Cause: The new logic to check firmware VLAN stripping capability
+             was buggy.
+
+      Change: Fixed the code so that VLAN stripping can always be disabled
+              if management firmware is disabled.
+
+      Impact: VLAN/management firmware.
+
+v1.7.5d (May 13, 2008)
+========================
+   Enhancements
+   ------------
+   1. Change: Incorporated latest firmware 4.4.18. Bug fix is in
+              RV2P.
+
+      Impact: All chips.
+
+v1.7.5c (May 7, 2008)
+========================
+   Enhancements
+   ------------
+   1. Change: Incorporated latest firmware 4.4.17. Bug fix is in
+              RV2P.
+
+      Impact: All chips.
+
+v1.7.5b (May 5, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: (CQ35080) Hard lock when running ethtool -s on the device
+               that is in the down state.
+
+      Cause: I/O to the device to set link speed in D3-hot state can cause
+             lockup because the chip does not respond to I/O.
+
+      Change: ethtool -s will just store the new settings without configuring
+              the new speed.  When the device is later brought up, the new
+              speed will be set as part of chip init.
+
+      Impact: All chips.
+
+   2. Problem: (CQ35075 CQ35042) Various compile errors on SuSE SLES 9 and SLES
+               10 distro kernels.
+
+      Cause: ip_hdr() and __le32/__le32 backported to the distro kernels.
+
+      Change: Adjusted compatibility defines.
+
+      Impact: None.
+
+   Enhancements
+   ------------
+   1. Change: Incorporated latest 5709 firmware 4.4.16.  Timer context
+              scanning is reduced with this firmware to 500us.  With this,
+              the temporary enhancement in 1.7.4c #2 has been removed.
+
+      Impact: 5709 iSCSI.
+
+v1.7.4e (April 26, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: (CQ34841) 5709 does not link up on some remote PHY systems.
+
+      Cause: No initial link interrupt.
+
+      Change: Added code to poll for link when remote PHY is present.
+
+      Impact: Remote PHY systems.
+
+   2. Problem: (CQ34767) Kernel panic on 5709 when using jumbo frames
+               with NCSI traffic.
+
+      Cause: RV2P bug causing RX packets to overwrite kernel memory.
+
+      Change: Updated to latest RV2P code for 5709 and 5708.
+
+      Impact: 5706/5708/5709.
+               
+v1.7.4d (April 17, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: IPv6 iSCSI does not work.
+
+      Cause: Added code in the last version 1.7.3c to check for CONFIG_IPV6
+             before enabling the IPv6 CNIC support.  This failed to check
+             for CONFIG_IPV6_MODULE if IPv6 is configured as module in the
+             kernel configuration.
+
+      Change: Changed the checking to CONFIG_IPV6 or CONFIG_IPV6_MODULE.
+
+      Impact: None.
+
+v1.7.4c (April 16, 2008)
+========================
+   Fixes
+   -----
+   1. Problem: (CQ34814, CQ33984) Driver does not compile on 2.4 kernels.
+
+      Cause: __le32 and __be32 not defined in 2.4 kernels.
+
+      Change: Defined these as u32 on 2.4 kernels.
+
+      Impact: 2.4 kernels.
+
+   Enhancements
+   ------------
+   1. Change:  Incorporated latest 5709 4.4.12 firmware to fix various iSCSI
+               problems.
+
+      Impact:  5709.
+
+   2. Change:  Slowed down the timer block reload time.  It was noticed that
+               after the CNIC driver was unloaded, the timer context memory
+               was reloaded in a tight loop by the chip.  This issue needs
+               to be properly addressed in the firmware at a future date.
+
+      Impact:  iSCSI.
+
+v1.7.4b (April 11, 2008)
+=======================
+   Enhancements
+   ------------
+   1. Change:  Incorporated latest 5709 4.4.11 firmware to fix various iSCSI
+               problems.
+
+      Impact:  5709.
+
+v1.7.3k (April 9, 2008)
+=======================
+   Enhancements
+   ------------
+   1. Change:  Incorporated latest 5709 4.4.10 firmware to fix various iSCSI
+               problems.  CID ranges are now read directly from shared memory.
+
+      Impact:  5709.
+
+v1.7.3j (April 7, 2008)
+=======================
+   Fixes
+   -----
+   1. Problem: (CQ33967) Ethtool register test fails.
+
+      Cause: Register 0x1004 context status register should not be tested.
+
+      Change: Removed 0x1004 from register test.
+
+      Impact: None.
+ 
+   Enhancements
+   ------------
+   1. Change:  Incorporated latest 5709 4.4.9 firmware to fix various iSCSI
+               problems.
+
+      Impact:  5709.
+
+v1.7.3i (April 4, 2008)
+=======================
+   Fixes
+   -----
+   1. Problem: (CQ33948) iSCSI over IPv6 does not work on SLES10.
+
+      Cause: The CNIC driver does not handle IPv6 on older kernels without
+             NETEVENTS support.
+
+      Change: Modified the logic to support older kernels.
+
+      Impact: All iSCSI connections using IPv4 or IPv6.
+
+   2. Problem: (CQ34315) Scanning iSCSI disks during max sessions test causes
+               connection problems.
+
+      Cause: 5709 context memeory allocated by CNIC driver does not match
+             the iSCSI and PG CID range used by the firmware.
+
+      Change: Changed to the matching CID range.
+
+      Impact: 5709 iSCSI.
+
+v1.7.3h (March 28, 2008)
+=======================
+   Fixes
+   -----
+   1. Problem: (CQ33984, CQ34210, CQ34310, CQ34597) Various compiler warnings
+               and errors on RHEL, SuSE, and 2.4 kernels.
+
+      Cause: New features not compatible with older kernels, or older
+             vendor kernels backported with newer features.
+
+      Change: Fine-tuned compatibility compiler directives.
+
+      Impact: All kernels.
+
+v1.7.3g (March 10, 2008)
+=======================
+   Enhancements
+   ------------
+   1. Change: Updated to latest 5709 firmware version 4.4.7.
+
+      Impact: 5709.
+
+v1.7.3f (March 10, 2008)
+=======================
+   Fixes
+   -----
+   1. Problem: CNIC takes a long time to resolve ARP, causing iSCSI to fail.
+
+      Cause: NETEVENT_NEIGH_UPDATE event notifier sometimes takes a long time
+             to be called.
+
+      Change: This is under investigation.  For now, the workaround is to
+              use the existing neighbour entry if it is in NUD_VALID state.
+              Previously, we would only use it if it was in NUD_CONNECTED
+              state.
+
+      Impact: iSCSI neighbour resolution.
+
+   2. Problem: iSCSI sometimes fails to initialize.
+
+      Cause: The KWQ is in full condition and prevents any KWQE to be sent
+             to the firmware.  This is caused by the KWQ consumer index in
+             the status block not initializing to 0.
+
+      Change: Added workaround to skip the KWQ full condition check when
+              sending the first KWQE.  This should be properly fixed in
+              firmware.
+
+      Impact: None.
+
+v1.7.3d (February 15, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: System hangs with iSCSI traffic.
+
+      Cause: Infinite loop in NAPI poll.
+
+      Change: Fixed the problem of not comparing the CNIC tag properly when
+              determining whether there is more work in NAPI poll.
+
+      Impact: None.
+
+   2. Problem: iSCSI does not work on 5709
+
+      Cause: Not initializing 5709 properly for iSCSI.  The chip_id field was
+             not propagated to the CNIC driver.
+
+      Change: Fixed the chip_id field.
+
+      Impact: None.
+
+v1.7.3c (February 09, 2008)
+============================
+   Enhancements
+   ------------
+   1. Change: Updated 5708 and 5709 firmware to version 4.4.2.
+
+      Impact: All devices.
+
+   2. Change: Updated RV2P firmware to the latest.  This may fix the jumbo
+              frame issue.
+
+      Impact: All devices, especially jumbo frames on 5709 Bx.
+
+   3. Change: Modified CNIC interface in preparation for 57710 devices.
+
+      Impact: iSCSI.
+
+v1.7.2f (February 04, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: Temporary workaround for one prototype 5709S mezz. card not
+               working.
+
+      Cause: The driver was looking at the wrong shared memory location to
+             identify the card.
+
+      Change: Fixed the code to check the correct BNX2_SHARED_HW_CFG_CONFIG
+              location.
+
+      Impact: 5709S.
+
+v1.7.2e (January 31, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: (CQ33704) CNIC driver fails MSI-X mode on 5709.
+
+      Cause: When implementing the fix, the wrong constant was used
+             for the CNIC MSI-X vector.
+
+      Change: Corrected to use the correct constant BNX2_CNIC_VEC.
+
+      Impact: None.
+
+   2. Problem: iSCSI outgoing packets over IPv6 are bigger than 1518 bytes.
+
+      Cause: MSS calculation was based on IPv4 and did not accout for the
+             IPv6 header size.
+
+      Change: Adjusted MSS calculation for IPv6.
+
+      Impact: None.
+
+v1.7.2c (January 30, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: CNIC driver does not work in MSI-X mode on 5709.
+
+      Cause:  This is a regression caused by moving the CNIC MSI-X
+              vector from 8 to 2.  The context memory did not get
+              updated with the new vector.
+
+      Change: Changed the definition.  All bits that depend on the
+              MSI-X vector will now have the proper definitions automatically.
+
+      Impact: None.
+
+v1.7.2b (January 30, 2008)
+============================
+   Enhancements
+   ------------
+   1. Change: Updated 5709 firmware to 4.4.1.
+
+      Impact: 5709.
+
+   2. Change: Added temporary workaround for one prototype 5709S mezz. card.
+              The workaround will be removed once newer cards are available.
+
+      Impact: 5709S.
+
+v1.7.1e (January 14, 2008)
+============================
+   Enhancements
+   ------------
+   1. Change: Updated 5709 firmware to 4.1.1 for IPv6 iSCSI support.
+
+      Impact: 5709.
+
+   2. Change: Updated 5708 RXP firmware to 4.1.1.
+
+      Impact: 5706/5708.
+
+   3. Change: Updated RV2P firmware for 5709.
+
+      Impact: 5709.
+
+   4. Change: Added IPv6 support to CNIC driver.
+
+      Impact: New BNX2I driver must be used with this new CNIC driver.
+
+v1.7.1d.3 (February 7, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: 5706S continues to not link down occasionally on some blade
+               systems.
+
+      Cause:  In some cases, even turning off the tx current does not
+              cause the link to go down.
+
+      Change: Link transition can be triggered based on the SYNC_FAILED bit
+              in the AN_DEBUG register when all else fails.
+
+      Impact: 5706S.
+
+v1.7.1d.1 (February 1, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: 5706S still not linking down occasionally on some blade
+               systems when the switch blade is disconnected.
+
+      Cause:  Occasionally, all the bits that we check will falsely
+              indicate link up and trigger the parallel detect logic on
+              this blade platform. Once in parallel detect mode with
+              autoneg disabled, the driver will never detect link down.
+
+      Change: Disabled parallel detect on this platform by checking
+              PCI sub IDs to identify the device.
+
+      Impact: Parallel detect not supported on this vendor device.
+
+v1.7.1d (January 25, 2008)
+============================
+   Fixes
+   -----
+   1. Problem: 5706S still not linking down on some blade systems when the
+               switch blade is disconnected.
+
+      Cause:  This is the same problem that was fixed in 1.7.0b.  After
+              switch module is removed, the SYNC_FAILED bit sometimes
+              toggles low, and this causes the parallel detect logic in the
+              driver to trigger and disable autoneg.  Disabling autoneg
+              causes false link to come up immediately.
+
+      Change: It seems that the RUDI_INVALID bit can be used to prevent the
+              above from happening.  Modified parallel detect code to
+              additionally check the RUDI_INVALID bit and trigger only when
+              the bit is cleared.
+
+      Impact: Parallel detect logic in 5706S.
+
+v1.7.1c (December 27, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: Driver crashes when adding VLAN and bonding.
+
+      Cause: Bonding calls driver's VLAN function in interrupt context with lock
+             held.  We recently added a VLAN feature in 1.6.8b which requires
+             chip reset when VLANs are added or removed.  The reset will call
+             vmalloc/vfree which must not be called in interrupt context.
+
+      Change: Reverted the VLAN feature for now.  Will workaround it in the
+              future.
+
+      Impact: 5709 only. This new VLAN feature is no longer available.
+
+v1.7.1b (December 24, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: Driver crashes when using jumbo frames on 5709 A1.
+
+      Cause: RV2P firmware problem.
+
+      Change: Disabled jumbo page ring on 5709 Ax chips.
+
+      Impact: Jumbo receive page rings not supported on 5709 Ax.
+
+   2. Problem: CNIC driver prints "Failed waiting for ref count to go to zero"
+               when unloading the driver. This is a minor cosmetic issue.
+
+      Cause: Minor bug in driver comparing ref_count to 1 instead of zero
+             during exit.
+
+      Change: Fixed the code to check for ref_count == 0.
+
+      Impact: None.
+
+v1.7.0b (December 12, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: (CQ33032) CPU utilization increases dramatically when TSO
+               is enabled.
+
+      Cause: Driver is spending a lot of unnecessary time in TX handling
+             code when TSO is enabled.  This regression was introduced when
+             the TX handling code was changed to match the RX handling code.
+             The RX handling code was changed to fix a packet rot problem.
+             When TSO is enabled, the tx index can stop at non-packet
+             boundaries and the code will keep waiting until it gets to the
+             next packet boundary.
+
+      Change: Fixed it to handle this condition properly.
+
+      Impact: None.
+
+   2. Problem:  5706S does not link down in some blade systems.
+
+      Cause: Hardware problem.
+
+      Change: Added workaround logic to check periodically and force a
+              link down when the PHY reports SYNC status failed.  This
+              only works when autoneg is enabled.
+
+      Impact: 5706S.
+
+v1.6.8e (December 10, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: When using jumbo MTU with large RX ring sizes, system will
+               crash or the driver won't load.
+
+      Cause: Bug in driver where the page descriptor array was declared
+             too small.
+
+      Change: Fixed the array size.
+
+      Impact: None.
+
+   2. Problem: CNIC driver won't compile on kernels without CONFIG_PCI_MSI.
+
+      Cause: Some code needs to be conditionally compiled only when
+             CONFIG_PCI_MSI is set.
+
+      Change: Added #ifdef CONFIG_PCI_MSI where necessary.
+
+      Impact: None.
+
+   3. Change: Disabled iSCSI on 5709 until next release.
+
+      Impact: None.
+
+v1.6.8d (December 07, 2007)
+============================
+   Change: Reverted the 5706S workaround made in 1.6.8c because it was
+           unreliable.
+
+   Impact: None.
+
+v1.6.8c (December 07, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: (CQ32794) Kernel panic (skb_over_panic) with jumbo frames.
+
+      Cause: RV2P firmware incorrectly placed jumbo data into SKB.
+
+      Change: New RV2P firmware.
+
+      Impact: Jumbo frames on all hardware.
+
+   2. Problem: (CQ32817) ethtool loopback test fails.
+   3. Problem: (CQ32842) Chariot test fails.
+
+      Cause: RX buffer size too small to contain MTU-sized frame.
+             This was introduced by the new Jumbo RX logic.
+
+      Change: Fixed RX buffer size logic.
+
+      Impact: Traffic on all hardware.
+
+   4. Problem: (CQ32862) Fails to compile on RH9u9.
+
+      Cause: Kernel API skb_fill_page_desc() backported to RH kernel
+             causing duplicate definition.
+
+      Change: Adjusted compatibility code.
+
+      Impact: None.
+
+   5. Problem: (CQ32866) ISCSI driver fails to compile with 1.6.8b.
+
+      Cause: print_mac() multiply defined when bnx2.h is included
+             in the bnx2i driver.
+
+      Change: Changed print_mac() to static inline.
+
+      Impact: None.
+
+   6. Problem:  5706S does not link down in some blade systems.
+
+      Cause: Hardware problem.
+
+      Change: Added workaround logic to check periodically.
+
+      Impact: 5706S.
+
+   Enhancements
+   ------------
+   1. Change: Added flow control logic on 5709.
+
+      Impact: 5709.
+
+   2. Change: Updated all firmware to 4.0.5.
+
+      Impact: All hardware.
+
+v1.6.8b (November 28, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change:  Added MSIX support for 5709 B0.
+
+      Impact: 5709 B0.
+
+   2. Change:  Added multi-page buffer support for Receive Jumbo frames.
+
+      Impact: All chips.  This feature is experimental at this point.
+
+   3. Change:  Allow VLAN tags in receive packets when management firmware
+               is enabled.
+
+      Impact: 5709 only. This feature is experimental and requires new
+              boot code and UMP/IPMI code.
+
+   4. Change: Updated firmware to 4.0.3.
+
+      Impact:  All chips.
+
+v1.6.7b (October 16, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: (CQ31861) Remote copper PHY does not link up if WoL is enabled.
+
+      Cause: bnx2_set_power_state() assumes that only copper devices support
+             WoL and proceeds to configure the copper PHY to 10/100 Mbps.
+             This assumption is no longer valid after Serdes WoL support
+             was added in 1.6.3c.
+
+      Change: Fixed the code to take check for Serdes and copper when setting
+              up the PHY for WoL.
+
+      Impact: WoL.
+
+v1.6.6b (October 10, 2007)
+============================
+   1. Change: Update 5708 firmware to 3.7.19.
+
+v1.6.5k (October 10, 2007)
+============================
+   1. Problem: Will not compile on 2.6.23 kernel.
+
+      Cause: get_perm_addr no longer defined in struct ethtool_ops
+
+      Change: Adjusted kernel compatibility #ifdef.
+
+      Impact: None.
+
+v1.6.5j (October 10, 2007)
+============================
+   No change to bnx2.  Updated cnic driver to 1.1.24.
+
+v1.6.5i (October 8, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Update 5708 firmware to 3.7.18.
+
+v1.6.5h (October 4, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Update 5708 firmware to 3.7.17.
+
+v1.6.5g (October 1, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Update 5708 firmware to 3.7.16.
+
+v1.6.5f (September 30, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Update 5708 firmware to newer 3.7.15.
+
+v1.6.5e (September 29, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Update 5708 firmware to 3.7.15.
+
+v1.6.5d (September 28, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Combined RPM package and tar file with CNIC driver.
+
+v1.6.5c (September 26, 2007)
+============================
+   Enhancements
+   ------------
+   1. Change: Update 5708 firmware to 3.7.14.
+
+v1.6.5b (September 25, 2007)
+============================
+   Fixes
+   -----
+   1. Problem: (CQ30086) 5709 A1 does not link up when connected to
+               some Broadcom devices.
+
+      Cause: Early DAC wakeup workaround needed for 5709 A1.
+
+      Change: Added workaround.
+
+      Impact: None.
+
+   Enhancements
+   ------------
+   1. Change: Added CNIC support for iSCSI.
+
+      Impact: Only enabled on 2.6.16 and newer kernels.
+
+v1.6.3c (July 23, 2007)
+=======================
+   Fixes
+   -----
+   1. Problem: (CQ30591) ethtool -t fails on remote PHY systems.
+
+      Cause: Link test and loopback test were not modified to support
+             remote PHY.
+
+      Change: Added remote PHY support to link test and changed the code
+              to skip PHY loopback on remote PHY since it's not supported.
+
+      Impact: None.
+
+   2. Problem: (CQ30625) ethtool speed settings are lost after ifdown.
+
+      Cause: The remote PHY settings stored in firmware is not the same
+             as the driver's last setting.
+
+      Change: Modified the code to keep the driver's setting unless there's
+              is change in the remote PHY media.
+
+      Impact: ethtool -s on remote PHY systems.
+
+   Enhancements
+   ------------
+   1. Change: Change ethtool's wol setting to NVRAM's default and
+              add support for Serdes WoL if NVRAM supports it.
+
+      Impact: ethtool wol's default setting.
+
+v1.6.3b (July 13, 2007)
+=======================
+   1. Problem: Problems reading and writing flash on 5709.
+
+      Cause: Hardware changes in 5709.
+
+      Change: Rearranged current flash code to properly support 5709.
+
+      Impact: Changes will impact flash operations on 5706/5708/5709 devices.
+
+   2. Problem: (CQ30516) Management firmware version string disappears
+               on 2nd modprobe of the driver.
+
+      Cause:  The 2nd modprobe will program the device back to D0 from D3hot.
+              This causes a reset and it will take some time before the
+              management firmware information will be available.
+
+      Change: Added a proper wait loop to wait for the firmware information
+              to be deposited in shared memory.
+
+      Impact: None.
+
+v1.6.2f (July 3, 2007)
+=======================
+   1. Problem: The fix for CQ29488 in the previous version is problematic
+               and needs to be reverted.
+
+      Cause: Adding the netif_carrier_off() call before register_netdev()
+             in bnx2_init_one() can cause problems if register_netdev()
+             fails.  netif_carrier_off() can queue a link watch event
+             that can run later.  If register_netdev() fails, the netdev
+             structure will be freed and the link watch event may panic
+             when it is scheduled to run.
+
+      Change: Moving the netif_carrier_off() to after register_netdev()
+              also will not work as it can cause race conditions with
+              the interrupt handler.  So the best thing to do is to
+              revert the earlier fix and not address the CQ29488 issue.
+
+      Impact: CQ29488 is not fixed.
+
+v1.6.2e (July 3, 2007)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ29528) Link does not come up using remote PHY (continued).
+
+      Cause: ifup script may be using mii-tool to obtain link status,
+             and interfering with remote PHY firmware.
+
+      Change: Block mii-tool ioctl access when remote PHY firmware is present.
+
+      Impact: None.
+
+   2. Problem: (CQ29488) Driver reports link up in ethtool before the interface
+               is brought up.
+
+      Cause: The netdevice structure's initial link setting is up and that
+             gets reported directly by ethtool.
+
+      Change: Added netif_carrier_off() call in bnx2_init_one().
+
+      Impact: None.
+
+v1.6.2d (June 22, 2007)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ29528) Link does not come up using remote PHY.
+
+      Cause: The fix in 1.6.2b still has a problem.  The copper or Serdes
+             default link setting does not follow the correct port when
+             the port is changed during chip reset.
+
+      Change: Fix the code to always refresh the port and link setting
+              during chip reset.
+
+      Impact: None.
+
+   2. Problem: (CQ30181) Cannot compile on 2.4 kernels.
+
+      Cause: USEC_TO_SEC constant is not defined on older kernels.
+
+      Change: Added conditional #define for this constant on older kernels.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Update 5709 firmware to 3.7.1.
+
+      Impact: 5709 devices.
+
+v1.6.2b (June 21, 2007)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added management firmware version to ethtool -i.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQ29528) Link does not come up using remote PHY.
+
+      Cause: The driver is using the wrong port when setting up the remote
+             PHY link.
+
+      Change: Fixed bug to always use the correct requested port or
+              default port when setting remote PHY link.
+
+      Impact: None.
+
+   2. Problem: (CQ30028) Advertised Autoneg not set in ethtool.
+
+      Cause: Remote PHY code is not setting the flag which is for
+             information only.
+
+      Change: Added code the set the flag for consistency.
+
+      Impact: None.
+
+v1.6.1c (May 22, 2007)
+=====================
+   Enhancements:
+   -------------
+   1. Change: (CQ28907) Added support for setting copper and fibre speeds.
+
+      Impact: Only available on Remote PHY systems.
+
+v1.6.1b (May 7, 2007)
+=====================
+   Fixes:
+   ------
+   1. Problem: (CQ29301) Setting invalid speed setting causes driver to
+               crash.
+
+      Cause: Lock taken without unlock when exiting iwith error the
+             procedure to set speed.
+
+      Change: Fixed the code with proper unlock.
+
+      Impact: None.
+
+v1.6.0b (April 30, 2007)
+========================
+   Enhancements:
+   -------------
+   1. Change: Improved handshake with remote PHY firmware.
+
+      Impact: None.
+
+v1.5.10c (May 4 , 2007)
+=======================
+   Fixes:
+   ------
+   1. Problem: Extremely low TSO performance when destination has a
+               smaller MSS than the source.
+
+      Cause: Packets smaller than MTU are not processed as TSO packets.
+
+      Change: Removed the SKB length check when doing TSO.
+
+      Impact: None.
+
+v1.5.10b (May 1, 2007)
+=========================
+   Enhancements:
+   -------------
+   1. Change: Removed Remote PHY until next release.
+
+      Impact: No Remote PHY support.
+
+   2. Change: Added check for 2.5G capability before enabling 2.5G on
+              5709S.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQ28438) NETDEV WATCHDOG after OS boot.
+
+      Cause:  The mailbox queue is halted after the OS reads config.
+              register 0x94.
+
+      Change: Set MQ_CONFIG_HALT_DIS in register MQ_CONFIG on 5709 A0 and
+              A1.
+
+      Impact: None.
+
+v1.5.9b (April 20, 2007)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Enhanced remote PHY support for 5708S.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQ29056) Driver does not compile on SLES 10 SP1 kernel.
+
+      Cause:   Backported netif_tx_lock() causes compatibility problem.
+
+      Change:  Adjuested compatibility #ifdef.
+
+      Impact:  None.
+
+   2. Problem: (CQ28880) Driver fails register test after running traffic.
+
+      Cause:   A reserved register 0x500c was mistakenly included in the test.
+
+      Change:  Removed this register from the test.
+
+      Impact: None.
+
+v1.5.8b (March 13, 2007)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added remote PHY support for 5708S.
+
+      Impact: None.
+
+v1.5.7b (March 2, 2007)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added IPV6 TSO for 5709.
+
+      Impact: None.
+
+   2. Change: Added 2.5G parallel detection for 5709s.
+
+      Impact: None.
+
+v1.5.6b (February 28, 2007)
+===========================
+   Enhancements:
+   -------------
+   1. Change: Added Serdes support for 5709.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQ28433) Driver does not compile on some early 2.6 and
+               2.4 kernels.
+
+      Cause: Kernel compatibility issue.
+
+      Change: Added some missing #ifdef CONFIG_PCI_MSI.
+
+      Impact: None.
+
+   2. Problem: (CQ28527) System hangs when running bonding scripts on 5709.
+
+      Cause: Bonding driver reads MDIO registers after the device is in
+             D3hot state.
+
+      Change: Added check to disallow MDIO access after the device is down.
+
+      Impact: None.
+
+v1.5.5b (January 31, 2007)
+===========================
+   Fixes:
+   ------
+   1. Problem: (CQ28252) Driver reports the same MAC address for both
+               ports of 5709.
+
+      Cause: The driver was obtaining the MAC address from the same
+             shared memory area for both ports.
+
+      Change: Updated driver to read from the deicated shared memory
+              area for each port.
+
+      Impact: None.
+
+   2. Problem: (CQ28226) 5709C does not link up when connected to Dell
+               5324 and some other switches.
+
+      Cause:  PHY's Early DAC Wakeup Enable bit's strapped value is set.
+
+      Change: Disable Early DAC Wakeup enable on 5709 A0 after PHY reset.
+
+      Impact: None.
+
+v1.5.4b (January 8, 2006)
+===========================
+   Fixes:
+   ------
+   1. Problem: 5709 copper device detected as serdes.
+
+      Cause:  Media detection code not complete.
+
+      Change: Added complete media detection code.
+
+      Impact: None.
+
+   Enhancement:
+   ------------
+   1. Change: Add IPv6 checksum support.
+
+      Impact: None.
+
+v1.5.2b (December 22, 2006)
+===========================
+   Merged in all latest changes.
+
+v1.5.1c (November 30, 2006)
+===========================
+   Enhancement:
+   ------------
+   1. Change: Remove 5709 FPGA code.
+
+      Impact: None.
+
+v1.5.1b (November 15, 2006)
+===========================
+   Enhancement:
+   ------------
+   1. Change: Added support for 5709.
+
+      Impact: None.
+
+v1.4.52c (March 07, 2007)
+=========================
+   Enhancement:
+   ------------
+   1. Change: Increase maximum receive ring size to 4080.
+              The default is kept the same at 255.
+
+      Impact: None.
+
+v1.4.51b (December 21, 2006)
+============================
+   Fixes:
+   ------
+   1. Problem: (CQ27802) Cannot enable flow control in some cases.
+
+      Cause:  In some cases when flow control is forced to on, the
+              driver detects no changes in advertisement, and as a
+              result, will not re-autoneg.  Without the link change,
+              flow control settings will not change.
+
+      Change:  Added some code to setup flow control when no other
+               PHY settings are made.  This will ensure that flow
+               control changes will take effect immediately.
+
+      Impact: None.
+
+v1.4.50b (December 15, 2006)
+============================
+   Fixes:
+   ------
+   1. Problem: (CQ27424) Panic when writing to nvram.
+
+      Cause:  Bug in driver when an alignment buffer is used
+
+      Change: Fixed the bug so that the alignment buffer is freed with the
+              correct pointer.
+
+      Impact: None.
+
+v1.4.49b (December 13, 2006)
+============================
+   Fixes:
+   ------
+   1. Problem: (CQ27459) Driver reports link down when link is up.
+
+      Cause:  Hotplug scripts can cause bnx2_open() to be called immediately
+              after bnx2_init_one() calls register_netdev().  The initial
+              link state set after register_netdev() may overwrite the actual
+              link state set by the link handler on SMP systems.
+
+      Change:  Move all initial state setup code to before calling
+               register_netdev().
+
+      Impact : None.
+
+v1.4.48b (December 08, 2006)
+============================
+   Fixes:
+   ------
+   1. Problem: (RHBZ 212055)  Panic in bnx2_poll().
+
+      Cause: Bug in determining tx ring space when the tx ring is
+             completely full.
+
+      Change: Fixed the flawed logic in bnx2_tx_avail().
+
+      Impact: None.
+
+   2. Problem: (CQ27424) Buffer overflow when writing to nvram.
+
+      Cause:  Bug in driver when the beginning NVRAM offset is
+              not 4-byte aligned.
+
+      Change: Fixed the bug to allocate enough buffer space.
+
+      Impact: None.
+
+   3. Problem: (CQ27543) Loopback failed if MAC address is changed.
+
+      Cause: Driver uses permanent MAC address for loopback which may
+             be different from a locally administered address.
+
+      Change: Fixed by alwaysing using the current MAC address in the
+              netdevice structure.
+
+      Impact: None.
+
+v1.4.47b (November 02, 2006)
+===========================
+   Fixes:
+   ------
+   1. Problem: (CQ25922) 5708S does not pass PHY loopback test on
+               some blade servers.
+
+      Cause:  It takes longer (about 100msec) to link up in some
+              backplane environments when the Serdes is set to PHY
+              loopback mode.
+
+      Change: Increase delay loop to up to 1 sec when waiting for
+              link up after PHY loopback.  Previous wait time was
+              100usec.
+
+      Impact: None.
+
+v1.4.46b (October 30, 2006)
+===========================
+   Fixes:
+   ------
+   1. Problem: (CQ25916) Device does not receive packets when configured
+               by the Xen bridge script and when IPMI is enabled.
+
+      Cause: Firmware does not forward packets to the host when the
+             device is in promiscuous mode in some cases.
+
+      Change: Firmware change and driver change to enable the
+              BNX2_RPM_SORT_USER0_PROM_VLAN bit when going into
+              promiscuous mode.
+
+      Impact: None.
+             
+v1.4.45b (October 19, 2006)
+===========================
+   Enhancement:
+   ------------
+   1. Change: Added software parallel detection on 5708S to link at
+              1000Mbps or 2500Mbps automatically if the link partner is
+              forced at 2500Mbps.
+
+      Impact: None.
+
+   2. Change: Added 2500Mbps forced speed setting.  Setting it requires
+              a future version of ethtool or custom apps.
+
+      Impact: None.
+
+   3. Change: Port driver to compile on 2.6.19 kernel.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: Driver does not complile on 2.4 kernels.
+
+      Cause: TSO symbols not defined in 2.4 kernels.
+
+      Change: Added #ifdef for compatibility.
+
+      Impact: None.
+
+   2. Problem: MSI doesn't work on 5706 when the host bridge is AMD8132.
+
+      Cause: Compatibility issue.
+
+      Change: Added code to disable MSI when 5706 is on a systems with
+              AMD8132.
+
+      Impact: 5706 cannot use MSI on such systems.
+
+v1.4.44b (August 10, 2006)
+==========================
+   Fixes:
+   ------
+   1. Problem: A rare tx race window exists in the tx path.
+
+      Cause: CPU re-ordering can cause the tx queue to be stopped
+             forever when the tx ring is full in a very rare
+             condition.  See ChangeLog for more details.
+
+      Change: Fixed the race condition with memory barriers.
+              See ChangeLog for more details.
+
+      Impact: None.
+
+   Enhancement:
+   ------------
+   1. Change: Increase default rx ring size to 255 to prevent
+              packet drops under heavy load.
+
+      Impact: Higher memory usage.
+
+   2. Change: Port driver to run on 2.6.18 kernel.
+
+      Impact: None.
+
+
+v1.4.43b (June 26, 2006)
+=======================
+   Enhancement:
+   ------------
+   1. Change: (CQ25508) Use DRV_MSG_CODE_UNLOAD_LNK_DN message on
+              5708 B1 and older chips so that the link will turn
+              off after ifdown.
+
+      Impact: None.
+
+v1.4.42b (June 2, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ22585) WoL cannot be enabled on 5708 B2.
+
+      Cause: Hardware limitation in previous 5708 versions required
+             driver to always disable driver WoL on 5708.
+
+      Change: With the issue fixed in B2, the driver was changed to
+              allow 5708 B2 and above to support driver WoL.
+
+      Impact: None.
+
+   2. Problem: (CQ21779) Driver does not report dropped receive packets.
+
+      Cause: Packets dropped by firmware are reported in a scratch pad
+             location in memory separate from other counters.
+
+      Change: Added code to report this firmware counter.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: (CQ24690) Allow driver to be compiled for non-running kernels.
+
+      Impact: None.
+
+v1.4.41b (May 17, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: Driver writes wrong data to non-buffered flash.
+
+      Cause: Bug in driver causing the unchanged portion of the page
+             to be corrupted.
+
+      Change: Fixed bug.
+
+      Impact: None.
+
+v1.4.40b (April 17, 2006)
+=========================
+   Enhancements:
+   -------------
+   1. Change: Combine 2 small memory allocations into 1.
+
+      Impact: None.
+
+   2. Change: Separate tx consumer and producer entries into separate
+              cache lines for better performance.
+
+      Impact: None.
+
+   3. Change: Compress firmware data to reduce driver size.
+
+      Impact: Driver now requires zib_inflate library which should be
+              available on most vendor kernels.
+
+v1.4.39b (Mar. 10, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ23181) Driver loses track of link changes in some cases.
+
+      Cause: In some cases, the status block gets a link change indication
+             that contradicts with the MII link status. This is due to
+             transient link signals during link changes.
+
+      Change: Add coalesce_now at the end of link change interrupt to flush
+              out the transient behavior.
+
+      Impact: None.
+
+   2. Problem: 5708 only supports 40-bit DMA addresses.
+
+      Cause: Limitation of the built-in PCIE-to-PCIX bridge.
+
+      Change: Add workaround code to make sure all DMA addresses are
+              less than 40 bits.
+
+      Impact: Some minor impact on performance on some 64-bits systems.
+              There should be practically no performance impact on i386 and
+              x86_64 systems.
+
+   3. Problem: "Copyright" deprecated in RPM spec file.
+
+      Change: Changed to "License".
+
+      Impact: Should be none on the distributions that we support.
+
+v1.4.38b (Feb. 10, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: Setting rx ring size to 255 causes memory allocation errors.
+
+      Cause: Multiple bugs that do not handle the full ring properly.
+
+      Change: Fixed all bugs related to full ring handling and changed
+              maximum ring size from 4080 to 1020 after discussion with
+              Dave Miller.
+
+      Impact: Maximum rx ring size is now smaller.
+
+   2. Problem: Compile warnings and panic on IA64.
+
+      Cause: <vmalloc.h> not included.
+
+      Change: Added include <vmalloc.h>.
+
+      Impact: None.
+
+v1.4.36b (Jan. 19, 2006)
+=======================
+   Version number update.
+
+v1.3.36 (Jan. 17, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ22827) bnx2 does not compile on 2.6.6 and earlier
+               kernels. 
+
+      Cause: Introduced bug while fixing CQ22666.
+
+      Change: Fix compatibility code.
+
+      Impact: None.
+
+   2. Problem: (CQ22823) bnx2 reports extra .5 at the end of firmware
+               version string.
+
+      Change: Skip the last digit in the firmware version string.
+
+      Impact: None.
+
+   3. Problem: (CQ22585) WoL still does not work on 5708.
+
+      Cause: New WoL mechanism introduced in 1.3.34 has a flaw.
+
+      Change: Removed the workaround code and disabled WoL support
+              on 5708. During shutdown and suspend, the driver will
+              shutdown the device and WoL will be setup by the
+              bootcode according to the nvram's out-of-box WoL
+              setting.
+
+      Impact: 5708 will not support driver-initiated (ethtool-intiated)
+              WoL.
+              
+v1.3.35 (Jan. 17, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ22666) bnx2 driver does not compile on RHEL3 U7.
+
+      Cause: if_mii() back-ported to RHEL3 U7.
+
+      Change: Adjusted the compatibility code.
+
+      Impact: None.
+
+   2. Problem: (CQ22718) UMP connection is lost after enabling WoL.
+
+      Cause: FORCE LINK was mistakenly set during WoL setup.
+
+      Change: Do not set FORCE LINK.
+
+      Impact: None.
+
+v1.3.34 (Jan. 13, 2006)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQ22585) WoL does not work on 5708.
+
+      Cause: Internal bridge not in proper PME state.
+
+      Change: Added new firmware message to allow bootcode to help set up
+              WoL.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Added compile option to include crc32 function for RH2.4
+              boot kernels.
+
+      Impact: None.
+
+   2. Change: Updated TSO firmware to handle ECN.
+
+      Impact: None.
+
+v1.3.33 (Dec. 12, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Increased firmware hand-shake timeout from 50 msec to
+              100 msec. Also changed the delay from busy-wait udelay
+              to non-busy-wait msleep.
+
+      Impact: None.
+
+   2. Change: Added code to read nvram size from shared memory if
+              available. Otherwise, the size will come from the
+              flash table which only gives the smallest size for
+              that type of flash.
+
+      Impact: None.
+
+   3. Change: Added workaround to issue 2 separate IOs for interrupt
+              acknowledgement. The workaround is only used for INTA
+              (non-MSI) interrupts.
+
+      Impact: Slightly higher overhead for INTA interrupts.
+
+v1.3.32 (Dec. 01, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added PHY loopback to the loopback selftest.
+
+      Impact: None.
+
+   2. Change: (CQ21810) Added ethtool -d register dump.
+
+      Impact: None.
+
+   3. Change: Reduce the number of registers tested in selftest to make
+              the driver smaller.
+
+      Impact: None.
+
+   4. Change: Increased maximum rx ring size to 4080.
+
+      Impact: None.
+
+   5. Change: Changed rx checksum logic for better reliability.
+
+      Impact: None.
+
+   6. Change: Added 5708 B1 workarounds.
+
+      Impact: None.
+
+v1.3.31 (Nov. 18, 2005)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQTO2080) Cannot pass traffic during 2nd ifup if IPMI
+               is enabled.
+
+      Cause: A flaw in driver/firmware handshake.
+
+      Change: Changed driver/firmware handshake by doing WAIT0 first before
+              writing the first signature.
+
+      Impact: None.
+
+   2. Problem: (CQTO2056) VLAN-tagged IPMI traffic fails after driver is
+               loaded.
+
+      Cause: Driver configures the NIC to keep the VLAN tag by default,
+             causing VLAN-tagged IPMI traffic to fail.
+
+      Change: Changed driver to always strip VLAN tags if IPMI is enabled.
+
+      Impact: VLAN will always be stripped when IPMI is enabled. This may
+              affect some applications that rely on raw VLAN packets.
+
+   Enhancements:
+   -------------
+   1. Change: Sync'ed up with latest upstream bnx2.
+
+v1.3.29 (Oct. 6, 2005)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQTO1929) Traffic stops when MTU is greater than 1500
+               with TSO enabled.
+
+      Cause: TSO firmware bug.
+
+      Change: Updated to latest firmware.
+
+      Impact: None.
+
+v1.3.28 (Sep. 29, 2005)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQTO1875) Traffic stops when running Nettack with TSO
+               turned on.
+
+      Cause: TSO firmware bug.
+
+      Change: Updated to latest firmware.
+
+      Impact: None.
+
+   2. Problem: (CQTO1575) ethtool -S shows non-zero rx_error_bytes.
+
+      Cause: Hardware errata.
+
+      Change: Ignore this counter and always report zero.
+
+      Impact: None.
+
+v1.3.27 (Sep. 21, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Enabled ethernet@wirespeed on copper devices.
+
+      Impact: None.
+
+   2. Change: Enabled customized pre-emphasis and other serdes control
+              settings on 5708S backplane devices. A special PHY
+              register will be programmed according to the NVRAM value.
+
+      Impact: None.
+
+   3. Change: Modified Makefile to check for the source symbolic link
+              in the kbuild environment.
+
+      Impact: None.
+
+   4. Change: Improved NAPI poll processing so that all events will be
+              processed before interrupts are re-enabled. This will
+              reduce the number of unnecessary interrupts.
+
+      Impact: None.
+
+   5. Change: Add support for ETHTOOL_GPERMADDR (from John Linville)
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: Bug in irq handler causing extra register read.
+
+      Cause: Bug in bnx2_interrupt() reading BNX2_PCICFG_MISC_STATUS
+             register when it is not necessary.
+
+      Change: Fixed the logic bug and added prefetch of status block in
+              msi handler.
+
+      Impact: None. 
+
+v1.3.25 (Aug. 22, 2005)
+=======================
+   Fixes:
+   ------
+   1. Problem: Ethtool register and memory tests fail on 5708.
+
+      Cause: Some code was not merged properly many versions ago.
+
+      Change: Merged in properly code.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Slow down flash clock speeds
+
+      Impact: None.
+
+   2. Change: Code re-sync'ed with upstream driver.
+
+      Impact: None.
+
+v1.3.24 (Aug. 16, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Changed all spin_lock_irqsave locks to spin_lock_bh for
+              better overall system performance. All code requiring
+              spin_lock runs in BH or user context.
+
+      Impact: None.
+
+   2. Change: Removed atomic operations in the transmit fast path.
+              Code should run a bit faster as atomic operations can be
+              quite slow.
+
+      Impact: None.
+
+v1.3.23 (Aug. 10, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added reporting of link speed to firmware.
+
+      Impact: None.
+
+   2. Change: Added shared memory base look-up.
+
+      Impact: None.
+
+   3. Change: Possible sparse fixes (from Peter Hagervall)
+              - use C99 struct initializers
+              - make a few arrays and structs static
+              - remove a few uses of literal 0 as NULL pointer
+              - use convenience function instead of cast+dereference in
+                bnx2_ioctl()
+              - remove superfluous casts to u8 * in calls to readl/writel
+
+      Impact: None.
+
+   4. Change: Updated documentation with the crc32 library requirement and
+              other minor updates.
+
+      Impact: None.
+
+v1.3.22 (July 25, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added check for default link speed setting in shared memory.
+              This allows some blade servers that don't support autoneg to
+              default to forced speed to speed up link-up time.
+
+      Impact: None.
+
+   2. Change: Changed timer code to speed up the timer after serdes autoneg.
+              This speeds up the time for parallel detection when the link
+              partner does not autoneg. After autoneg or parallel detction
+              completes, timer goes back to normal 1 HZ interval. With the
+              new scheme, link should be detected up using parallel detection
+              in less than 0.7 seconds. Autoneg normally completes in 120
+              msec exchanging base pages and 3 next pages. 
+
+      Impact: None.
+
+v1.3.21 (July 21, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Updated firmware to properly handle TSO packets with ECN
+              bits set.
+
+      Impact: None.
+
+   2. Change: Updated to latest rxp firmware.
+
+      Impact: None.
+
+   3. Change: Added check for the 2.5G capability in shared memory.
+
+      Impact: None.
+
+   4. Change: Expanded nvram support for 5708.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQTO1511) Downing a team of bnx2 adapters causes hang.
+
+      Cause: Deadlock when the second adapter's close routine calls
+             flush_scheduled_work() because the linkwatch_event
+             is scheduled on the work queue when the first adapter
+             is closed. The linkwatch_event will try to get the rtnl_lock
+             which is already held by the bnx2_close routine.
+
+      Change: Fixed by not calling flush_scheduled_work(). Instead,
+              use a flag to indicate work is pending and wait until
+              the flag is cleared.
+
+      Impact: None.
+
+   2. Problem: (CQTO1439) ethtool -S on 5708 causes oops.
+
+      Cause: A pointer is not initialized if the device is 5708.
+
+      Change: Added proper initialization.
+
+      Impact: None.
+
+   3. Problem: Some error counters are mis-reporting.
+
+      Cause: The workaround for the hw errata is not applied properly
+             on the chips with the errata.
+
+      Change: Added proper checks for the workaround.
+
+      Impact: None.
+
+   4. Problem: High BER on 5708 SerDes.
+
+      Cause: hardware errata.
+
+      Change: Added workaround for 5708 A0 and B0.
+
+      Impact: None.
+
+v1.3.19 (May 27, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Merged 5708 code with the latest 1.1.19.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQTO1260) 5708S does not link at 1000Mbps when forced. It
+               links at 2500Mbps when connected back-to-back with another
+               5708S.
+
+      Cause: 2.5G bit is still turned on.
+
+      Change: Fixed by turning off 2.5G when the speed is forced.
+
+      Impact: None.
+
+v1.1.19 (May 26, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Made significant changes to merge into the kernel. Among
+              them, consolidate all source files into bnx2.[ch] and
+              bnx2_fw.h, change structure style register definitions
+              to offset based.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: Excessive stack usage.
+
+      Cause: Use of local variable array.
+
+      Change: Fix excessive stack usage in bnx2_alloc_bad_rbuf() by
+              replacing local variable array with kmalloc array. Also
+              changed function to return error code, and changed some
+              of the callers to check for the return code.
+
+      Impact: None.
+
+   2. Problem: Bug in receive checksum.
+
+      Cause: Software bug.
+
+      Change: Fix bug in rx checksum by indicating CHECKSUM_UNNECESSARY
+              only when the hw calculated checksum is 0xffff.
+
+      Impact: None.
+
+   3. Problem: Excessive busy loop.
+
+      Cause: Software bug.
+
+      Change: Replaced one excessive udelay of 15msec with msleep since
+              the calling context is always process.
+
+      Impact: None.
+
+  4.  Problem: Need to call flush_scheduled_work() and bnx2_netif_stop().
+
+      Cause: Bug in bnx2_close().
+
+      Change: Fix bug in bnx2_close() by calling flush_scheduled_work()
+              since we are using a work queue in netdev watchdog. Also
+              added bnx2_netif_stop() call in bnx2_close().
+
+      Impact: None.
+
+   5. Problem: Some symbols do not have bnx2 prefix and are not static.
+
+      Change: Add bnx2_ prefix to some remaining names and mark some
+              remaining names static.
+
+      Impact: None.
+
+v1.1.17 (Apr. 7, 2005)
+=======================
+   Fixes:
+   ------
+   1. Problem: Driver does not compile on 2.6.12 kernel.
+
+      Cause: pci_dev->slot_name has been deprecated.
+
+      Change: replaced with pci_name.
+
+      Impact: None. All kernels supported by bnx2 including 2.4.21-*EL have
+              pci_name defined.
+
+v1.1.16 (Mar. 16, 2005)
+=======================
+   Fixes:
+   ------
+   1. Problem: (CQTO936 & 1004) Tx carrier and rx_byte_errors reported
+               during normal operations.
+
+      Cause: 5706 hardware errata on these 2 statistics counters.
+
+      Change: Modified driver to skip these 2 counters.
+
+      Impact: These 2 counters will always report 0 and not the true
+              statistics.
+
+v1.3.15 (Mar. 11, 2005)
+======================
+   Enhancements:
+   -------------
+   1. Change: Added SGMII 10/100/1000 Mbps and fiber mode 1000/2500 Mbps
+              support.
+
+      Impact: None.
+
+v1.1.15 (Mar. 09, 2005)
+=======================
+   Enhancements:
+   -------------
+   1. Change: Added code to program proper phy settings for jumbo
+              frames on copper and serdes devices.
+
+      Impact: None.
+
+   2. Change: Changed INTx ISR to handle a valid case where INTx
+              arrives before status block update.
+
+      Impact: None.
+
+   3. Change: Added a separate ISR for MSI to handle subtle differences
+              between INTx and MSI.
+
+      Impact: None.
+
+v1.1.14 (Mar. 03, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: netdump does not work on latest RH3EL errata kernel.
+
+      Cause: #define RED_HAT_LINUX_KERNEL removed from kernel
+             include files, causing netdump poll function to
+             be compiled wrong for RH kernels.
+
+      Change: Changed Makefile to workaround the problem.
+
+      Impact: None.
+
+v1.1.12 (Feb. 25, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO1062) Driver allows ethtool to set illegal speed/duplex
+               on fiber cards.
+
+      Cause: Missing checks for the case where autoneg is off.
+
+      Change: Added proper checks.
+
+      Impact: No.
+
+v1.1.11 (Feb. 18, 2005)
+======================
+   Enhancements:
+   -------------
+   1. Change: (CQTO901) Added bnx2(4) man page.
+
+      Impact: None.
+
+v1.1.10 (Feb. 16, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: Wrong device ID in pci_dev_id table.
+
+      Change: Fixed ID.
+
+      Impact: None.
+
+v1.1.9 (Feb. 10, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO771) Driver fails to compile on RHEL3 update 4.
+
+      Cause: The RH kernel has back-ported some netif functions
+             not found in the same vanilla kernel version. Duplicate
+             function names are defined.
+
+      Change: Added intelligence in Makefile to detect such conditions
+              and change the CFLAGS accordingly.
+
+      Impact: None.
+
+   2. Problem: (CQTO1017) Driver allows 1000 half duplex autoneg off.
+
+      Cause: Missing validity check.
+
+      Change: Added check.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: The code to handle tx queue full condition was redone
+              to properly handle all boundary and race conditions.
+
+      Impact: Minimum tx ring size is now MAX_SKB_FRAGS+1.
+
+   2. Change: Tx timeout code was changed to work queue context.
+              This allows netif to be shutdown gracefully before
+              chip reset.
+
+      Impact: None.
+
+   3. Change: Added memory barriers to ISR and NAPI poll for
+              correctness.
+
+      Impact: None.
+
+v1.1.8 (Feb. 01, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO969) No interupts on a system that does not
+               support MSI.
+
+      Cause: On this system, the MSI generated in the MSI test
+             terminates with Master Abort which is a fatal
+             condition for the chip.
+
+      Change: A chip reset is added when MSI test fails to bring
+              the chip back to normal operations again (in INTx mode).
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Removed register 0x84 from the ethtool register test.
+              This is an interrupt control register that should
+              not be touched to prevent unwanted interrupts.
+
+      Impact: None.
+
+v1.1.7 (Jan. 28, 2005)
+======================
+   Enhancements:
+   -------------
+   1. Change: Added interrupt test when MSI is enabled. If MSI test
+              fails, driver will fallback to INTx mode.
+
+      Impact: None.
+
+   2. Change: Added test for certain chipsets where MSI is known
+              to fail, and disable MSI unconditionally when
+              such chipsets are found.
+
+      Impact: None.
+
+   3. Change: Removed support for 1000 Mbps half duplex.
+
+      Impact: 1000 Mbps half duplex will no longer work.
+
+v1.1.6 (Jan. 26, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO940) MTU size not set properly when device is down.
+
+      Cause: bnx2_change_mtu only handled the "up" case.
+
+      Change: Simple fix to handle the "down" case as well.
+
+      Impact: None
+
+   2. Problem: (CQTO926) 5706S does not autoneg properly after the
+                tx cable is pulled.
+
+      Cause: If the link partner is autonegotiating, autoneg will
+             fail when the tx cable is pulled. The software will
+             turn off autoneg seeing that the rx cable is still
+             attached with SIGNAL_DETECT. When the tx cable is
+             re-attached, autoneg is still off and the link partner
+             will not establish link.
+
+      Change: Added code to poll another PHY register to check if
+              configs are received when autoneg is disabled.
+              
+      Impact: None
+              
+   Enhancements:
+   -------------
+   1. Change: Added OEM product name strings.
+
+      Impact: None.
+
+v1.1.5 (Jan. 25, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: PCI-X bus speed may not be detected correctly by the driver,
+               causing failure because certain register settings are done
+               based on bus speed.
+
+      Cause: hardware problem.
+ 
+      Change: Use a different register to detect PCI-X speed.
+
+      Impact: None.
+
+v1.1.4 (Jan. 17, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: 5706S does not reliably detect link up or down.
+
+      Cause: hardware problem.
+
+      Change: Enabled hardware workaround which is effective in
+              A2 and newer chips only.
+
+      Impact: None.
+
+v1.1.3 (Jan. 13, 2005)
+======================
+   Fixes:
+   ------
+   1. Problem: netdump does not work.
+
+      Cause: poll_controller routine does not work in NAPI mode.
+
+      Change: Fixed poll_controller routine for NAPI mode.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Added the new mmiowb macro which is used mainly in NUMA
+              machines to guarantee PCI ordering.
+
+      Impact: None.
+
+   2. Change: Added OEM product name strings.
+
+      Impact: None.
+
+   3. Change: Changed ONE_TDMA workaround on systems with P64H bridge to
+              PING_PONG_DMA on all systems using PCI.
+
+      Impact: Better performance and better compatibility on all PCI
+              systems.
+
+   4. Change: Added "disable_msi" parameter to allow disabling MSI.
+
+      Impact: None.
+
+   5. Change: Reduced default tx coalescing parameters for better
+              tx only performance such as ttcp.
+
+      Impact: None.
+
+   6. Change: Changed NIC detection console message to display more
+              information.
+
+      Impact: None.
+
+   7. Change: Cleaned up some Linux .h files that are not needed.
+
+      Impact: None.
+
+   8. Change: Cleaned up the nvram routines.
+
+      Impact: None.
+
+v1.1.2 (Nov. 11, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: Unable to load the driver on more than 2 or 3 devices.
+
+      Cause: Default register space is too big. System fails to map
+             the register space on the 3rd or 4th device.
+
+      Change: Changed driver to map a smaller register space as the higher
+              registers are not needed for standard operations.
+
+      Impact: None.
+
+v1.1.1 (Nov. 9, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO656) One remaining ethtool parameter can be set out of
+               range.
+
+      Cause: Wrong upper bounds in code.
+
+      Change: Fixed upper bound.
+
+      Impact: None.
+
+   1. Problem: 5706 A1 cannot be run on a PCI bus.
+
+      Cause: Hardware errata.
+
+      Change: Added workaround to detect 5706 A1 on PCI bus and abort.
+
+      Impact: Driver will not load 5706 A1 on PCI bus.
+
+v1.1.0 (Oct. 29, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO663) No link on fiber NIC set to autoneg when
+               the link partner is set to forced speed.
+
+      Cause: No code to handle this case.
+
+      Change: Added code to check SIGNAL DETECT when autoneg fails,
+              and turn off autoneg when appropriate. Also added code
+              to force a link down when speed settings are changed.
+
+      Impact: None.
+
+    2. Problem: (CQTO649) ifconfig up/down can cause system to
+                hang on 2.6 kernels using mmconfig.
+
+       Cause: Dummy read in the kernel's pci_mmcfg_write routine
+              may cause system to hang during D3hot -> D0
+              transition. The PLL may lose lock during the internal
+              D0 transition chip reset and cause the dummy read to
+              hang.
+
+       Change: The PLL problem will be fixed in A2. Meanwhile, the
+               driver is changed to go into D3hot only if wol is
+               enabled.
+
+       Impact: Minor impact in increased power consumption when
+               the driver is shutdown with wol disabled.
+              
+    3. Change: Changed to use pci_get_device as pci_find_device
+               will be deprecated soon.
+
+       Impact: None.
+
+    4. Problem: (CQTO656) Some ethtool parameters can be set out of range.
+
+       Cause: Wrong upper bounds in code or documentation.
+
+       Change: Fixed code and documentation.
+
+       Impact: None.
+
+v1.0.15 (Oct. 15, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO644) Data corruption when sending FTP traffic on
+               Dell Precision 530MT.
+
+      Cause: PCI bridge errata.
+
+      Change: Added code to enable ONE_TDMA workaround when P64H
+              PCI bridge is detected.
+
+      Impact: Slower tx performance on systems using P64H bridge.
+
+   2. Problem: (CQTO643) Driver allows MTU to be set up to 9004.
+
+      Cause: Driver used the wrong upper bound limit.
+
+      Change: Fixed the upper bound.
+
+      Impact: None.
+
+   3. Problem: Driver does not support forced speed on 5706S.
+
+      Cause: Missing software logic.
+
+      Change: Added code to support forced 1000 Full and Half duplex.
+
+      Impact: None.
+
+   4. Change: Added workaround to disable PERR generation on
+              5706 A1 when it is in PCI 64-bit slot.
+
+      Impact: None.
+
+v1.0.14 (Oct. 05, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: Driver load/unload hangs on some machines.
+
+      Cause: Transition delay required during D3hot -> D0 transition.
+
+      Change: Added necessary delay.
+
+      Impact: None.
+
+v1.0.12 (Oct. 04, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO609) New flow control parameter does not take
+               effect until ifdown/ifup or link down/up.
+
+      Cause: New flow control settings are only configured during
+             link up. The driver did not check flow control
+             advertisement changes and therefore no re-negotiation
+             and no link down.
+
+      Change: Fixed logic so that link will always go down whenever
+              there is a change a flow control advertisement.
+
+      Impact: None.
+
+   2. Problem: (CQTO612) VLAN packet reception not working.
+
+      Cause: VLAN #define not setup properly.
+
+      Change: Fixed #define for VLAN.
+
+      Impact: None.
+
+   3. Problem: (CQTO628) WoL not functioning correctly.
+
+      Cause: Multiple problems in the WoL code.
+
+      Change: Fixed by:
+                 1. using sort mode.
+                 2. setting up mac address correctly.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Added support for non-dword and non-aligned write access
+              to eeprom, allowing ethtool -E to work.
+
+      Impact: None.
+
+v1.0.11 (Sep. 24, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO600) Kernel panic when attempting to ftp on
+               Fedora kernel.
+
+      Cause: skbuffs are 4-byte aligned on Fedora, causing
+             the rx headers to be misaligned. skbuffs are
+             16-byte aligned on other standard kernels.
+
+      Change: Removed any assumptions about skbuff alignment
+              and added code to align all rx skbuffs to 8-byte
+              boundaries.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Added netif_carrier_off to Driver init code so that
+              the initial link state is off.
+
+      Impact: None.
+
+v1.0.10 (Sep. 23, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO599) Driver fails to compile on RH 3.0ES.
+
+      Cause: Bug in poll_bcm5706 where bp is referenced without
+             being defined.
+
+      Change: Fixed the minor bug.
+
+      Impact: None.
+
+v1.0.9 (Sep. 23, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: Jumbo frames not working reliably.
+
+      Cause: Bug in bcm5706_reuse_rx_skb.
+
+      Change: Fixed the bug so that the host address is properly
+              copied from one BD to the other.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Change the locking scheme for more reliable open/close/ioctl
+              operations where the spinlock is needed.
+
+      Impact: None.
+
+   2. Change: Added minimum MTU size check for MTU changes.
+
+      Impact: None.
+
+v1.0.8 (Sep. 20, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO561) Kernel panic on RH30EL after repeated
+               driver load/unload.
+
+      Cause: Occasionally, the system is unable to map device
+             registers, causing subsequent register access to fail.
+
+      Change: Added check for the return value from ioremap, and exit
+              gracefully if it fails.
+
+      Impact: None.
+
+   2. Problem: (CQTO574) NETDEV WATCHDOG when running 5706 A1 on
+               PCIX 133MHz slot.
+
+      Cause: Some hw register setup required for 133 Mhz.
+
+      Change: Added the register setup code.
+
+      Impact: None.
+
+   3. Problem: (CQTO468) Link does not go down after changing from
+               10Mbps full (forced) to 10Mbps half (forced) and vice versa
+               when the link partner is also using forced speed. 
+
+      Cause: Delay not long enough for the link to go down.
+
+      Change: Not practical to increase delay as a very long delay is
+              needed for the link to go down. Added code to record the
+              proper link speed and duplex when speed is forced so that
+              ethtool will return the proper speed without the link going
+              down. Note that the link will go down if the link partner
+              has autoneg turned on, ensuring that the link partner will
+              see the link change.
+
+      Impact: None.
+
+   Enhancements:
+   -------------
+   1. Change: Added power management and WOL during device close. This
+              will allow WOL to work after Linux shutdown.
+
+      Impact: None.
+
+   2. Change: Changed driver so that ethtool will report invalid
+              speed after ifdown.
+
+      Impact: None.
+
+   3. Change: Updated tpatfw.h
+
+      Impact: None.
+
+v1.0.7 (Sep. 14, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO523) 5706 A1 hangs after a thousand iterations of
+               load/ifup/ifdown/unload.
+
+      Cause: The driver may be servicing an interrupt
+             within 15 msec of chip reset, causing the chip to hang.
+             The problem was aggravated by the timer mode
+             coalescing which created an excessive number of
+             interrupts (hardware problem).
+
+             The Driver may also occasionally see
+             the wrong firmware signature that will cause it to abort.
+
+      Change: Added synchronization to make sure all pending interrupts
+              are serviced before resetting the chip. Also changed to
+              collect mode coalescing. The firmware signature problem
+              will be fixed in boot code.
+
+      Impact: The use of collect mode coalescing may affect performance.
+
+   2. Problem: (CQTO558) Unable to load driver on some early 2.6 kernels.
+
+      Cause: pci_dma_sync_single_for_* routines not defined on early
+             2.6 kernels.
+
+      Change: Added compatibility defines for earlier kernels.
+
+      Impact: None.
+
+v1.0.6 (Sep. 08, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO523) 5706 A1 hangs during repeated driver ifup/down. 
+
+      Cause: No delay after chip reset for A1.
+
+      Change: Added 15 msec delay after chip reset for A1.
+
+      Impact: None.
+
+   2. Problem: (CQTO468) Link does not go down after changing from
+               10Mbps full (forced) to 10Mbps half (forced) and vice versa. 
+
+      Cause: Not enough delay after forcing link down.
+
+      Change: Added proper delay for link to go down.
+
+      Impact: None.
+
+v1.0.5 (Sep. 02, 2004)
+======================
+   Enhancements:
+   -------------
+   1. Change: Added support for ethtool -c, ethtool -C, ethtool -p,
+              and firmware version for ethtool -i.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: 5706C not advertising 1000 half duplex.
+
+      Cause: 1000 full duplex overwrites 1000 half duplex.
+
+      Change: Fixed the bug so that the 2 bits are or'ed together.
+
+      Impact: None.
+
+    2. Problem: ethtool -A does not change the flow control settings
+                in all cases.
+
+       Cause: Flow control settings not zeroed out before setting new
+              values.
+
+       Change: Minor bug fix to zero out the value.
+
+       Impact: None.
+
+v1.0.4 (Sep. 02, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO504) Multiple NFS transfers will hang some
+               connections.
+
+      Cause: Driver discards some receive packets when the
+             error status is non-zero.
+
+      Change: Changed the driver to only discard receive packets
+              when the defined error bits in the error status are
+              non-zero.
+
+      Impact: None.
+
+v1.0.3 (Sep. 01, 2004)
+======================
+   Enhancements:
+   -------------
+   1. Problem: Driver does not support ethtool -t self test and
+               ethtool -S statistics.
+
+      Change: Added ethtool self test and statistics.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQTO478) Kernel still panics when transmitting certain
+               files using NFS after many iterations
+
+      Cause: Tx DMA stalls on certain UDP packets, causing NFS
+             client to stall.
+
+      Change: More fixes made in firmware.
+
+      Impact: None.
+
+v1.0.2 (Aug. 26, 2004)
+======================
+   Enhancements:
+   -------------
+   1. Problem: Driver does not work on big endian machines.
+
+      Change: Ported and tested on SPARC64 machine.
+
+      Impact: None.
+
+   Fixes:
+   ------
+   1. Problem: (CQTO478) Kernel panics when transmitting certain
+               files using NFS.
+
+      Cause: Tx DMA stalls on certain UDP packets, causing NFS
+             client to stall.
+
+      Change: Fixed in firmware.
+
+      Impact: None.
+
+   2. Problem: (CQTO469) Unable to modify flow control parameters
+
+      Cause: Did not call setup_phy after the parameters are changed.
+
+      Change: Added call to setup_phy after parameters are changed.
+
+      Impact: None.
+
+   3. Problem: (CQTO467) 5706 does not autonegotiate properly after
+               changing settings with ethtool.
+
+      Cause: This is an ethtool limitation as the proper advertising
+             parameters are not passed to the driver properly.
+
+      Change: Implemented a new scheme to work around the problem to
+              allow users to specify full autoneg, single speed autoneg,
+              and fixed speed.
+
+      Impact: None.
+
+   4. Problem: ethtool -e does not work.
+
+      Cause: Various bugs in the nvram routines.
+
+      Change: Fixed and tested nvram routines on little endian and big endian
+              machines.
+
+      Impact: None.
+
+v1.0.1 (Aug. 18, 2004)
+======================
+   Fixes:
+   ------
+   1. Problem: (CQTO459) 5706 NIC does not get link.
+
+      Cause: Boot code timing out in WAIT2 state before driver is ready.
+
+      Change: Moved the WAIT2 state ahead in the driver reset sequence
+              as a temporary workaround until it is fixed in boot code.
+
+      Impact: None.
+
+   2. Problem: (CQTO463) Kernel panics when loading the driver on
+               RH30EL (2.4.21-4.EL)
+
+      Cause: Older kernel used different API to allocate and register
+             netdev.
+
+      Change: Added older APIs to be used on older kernels.
+
+      Impact: None.
+
+v1.0.0 (Aug. 13, 2004)
+======================
+    Initial release
diff --git a/brcm_iscsi_uio/config.h.in b/brcm_iscsi_uio/config.h.in
new file mode 100644
index 0000000..10b4824
--- /dev/null
+++ b/brcm_iscsi_uio/config.h.in
@@ -0,0 +1,161 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if the system has the type `int16_t'. */
+#undef HAVE_INT16_T
+
+/* Define to 1 if the system has the type `int32_t'. */
+#undef HAVE_INT32_T
+
+/* Define to 1 if the system has the type `int64_t'. */
+#undef HAVE_INT64_T
+
+/* Define to 1 if the system has the type `int8_t'. */
+#undef HAVE_INT8_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#undef HAVE_UINT16_T
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#undef HAVE_UINT32_T
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#undef HAVE_UINT64_T
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#undef HAVE_UINT8_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/brcm_iscsi_uio/configure.ac b/brcm_iscsi_uio/configure.ac
new file mode 100644
index 0000000..d0ce7cb
--- /dev/null
+++ b/brcm_iscsi_uio/configure.ac
@@ -0,0 +1,73 @@
+dnl admin_sock.h: CNIC UIO uIP user space stack
+dnl
+dnl Copyright (c) 2004-2008 Broadcom Corporation
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation.
+dnl
+dnl Written by: Benjamin Li  (benli@broadcom.com)
+dnl
+
+PACKAGE=brcm_iscsiuio
+VERSION=0.5.2
+
+AC_INIT(brcm_iscsi, 0.5.2, benli@broadcom.com)
+
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+AC_CONFIG_HEADER(config.h)
+AC_PATH_PROGS(BASH, bash)
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_LEX
+AC_PROG_YACC
+
+AC_GNU_SOURCE
+AC_PROG_INSTALL
+AC_PROG_GCC_TRADITIONAL
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_CHECK_TYPES(int8_t)
+AC_CHECK_TYPES(uint8_t)
+AC_CHECK_TYPES(int16_t)
+AC_CHECK_TYPES(uint16_t)
+AC_CHECK_TYPES(int32_t)
+AC_CHECK_TYPES(uint32_t)
+AC_CHECK_TYPES(int64_t)
+AC_CHECK_TYPES(uint64_t)
+AC_CHECK_SIZEOF(short, 2)
+AC_CHECK_SIZEOF(int, 4)
+AC_CHECK_SIZEOF(long, 4)
+
+AC_C_BIGENDIAN(AC_SUBST([ENDIAN],[BIG]),AC_SUBST([ENDIAN],[LITTLE]))
+
+AC_LIBTOOL_DLOPEN
+
+# libtool stuff
+AC_PROG_LIBTOOL
+
+CFLAGS="-O2 -Wall"
+## check for --enable-debug first before checking CFLAGS before
+## so that we don't mix -O and -g
+AC_ARG_ENABLE(debug,
+[  --enable-debug          Turn on compiler debugging information (default=no)],
+    [if eval "test x$enable_debug = xyes"; then
+        CFLAGS="${CFLAGS} -g -O0"
+    fi])
+AM_CONDITIONAL([DEBUG], [test x$debug = xtrue])
+
+AC_CONFIG_COMMANDS([default],[[ echo 'char *build_date ="'`date`'";' > src/unix/build_date.c  && echo 'char *build_date; '> src/unix/build_date.h]],[[]])
+
+AC_OUTPUT([Makefile
+src/Makefile
+src/apps/Makefile
+src/apps/dhcpc/Makefile
+src/apps/brcm-iscsi/Makefile
+src/uip/Makefile
+src/unix/Makefile
+src/unix/libs/Makefile])
diff --git a/brcm_iscsi_uio/docs/brcm_iscsiuio.8 b/brcm_iscsi_uio/docs/brcm_iscsiuio.8
new file mode 100644
index 0000000..bfb381d
--- /dev/null
+++ b/brcm_iscsi_uio/docs/brcm_iscsiuio.8
@@ -0,0 +1,64 @@
+.\" Copyright (c) 200o Broadcom Corporation
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation.
+.\"
+.\" bnx2.4,v 0.5.0
+.\"
+.TH brcm_iscsiuio 8 "01/08/09" "Broadcom Corporation"
+.\"
+.\" NAME part
+.\"
+.SH NAME
+brcm_iscsiuio \- Broadcom iSCSI UserSpace I/O driver
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.B brcm_iscsiuio
+.RB [ --config --version --help ]
+.PP
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+brcm_iscsiuio is the UserSpace I/O driver for the Broadcom NetXtreme II
+BCM5706/5708/5709 series PCI/PCI-X Gigabit Ethernet Network Interface Card
+(NIC) and for the Broadcom NetXtreme II BCM57710/57711/570711E series
+PCI-E 10 Gigabit Ethernet Network Interface Card.
+The driver has been tested on 2.6.28 kernels and above.
+.PP
+Refer to the README.TXT from the driver package on how to
+compile and install the driver.
+.PP
+Refer to various Linux documentations
+on how to configure network protocol and address.
+.\"
+.\" DRIVER DEPENDENCIES part
+.\"
+.SH DRIVER DEPENDENCIES
+
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+There are very few parameters when running this application.
+.TP
+.BI -d
+This is to enable debug mode where debug messages will be sent to stdout
+.PP
+.TP
+.TP
+.BI -f
+This is to enable forground mode so that this application doesn't get sent
+into the background.
+.PP
+.TP
+.BI -v
+This is to print the version.
+
+.\"
+.\" AUTHOR part
+.\"
+.SH AUTHOR
+Benjamin Li \- benli@broadcom.com
diff --git a/brcm_iscsi_uio/include/config.h b/brcm_iscsi_uio/include/config.h
new file mode 100644
index 0000000..ffada25
--- /dev/null
+++ b/brcm_iscsi_uio/include/config.h
@@ -0,0 +1,237 @@
+/*
+ * iSCSI Configuration
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <netdb.h>
+//#include <net/if.h>
+//#include "types.h"
+//#include "auth.h"	/* for the username and password sizes */
+#include "list.h"
+
+/* ISIDs now have a typed naming authority in them.  We use an OUI */
+#define DRIVER_ISID_0  0x00
+#define DRIVER_ISID_1  0x02
+#define DRIVER_ISID_2  0x3D
+
+/* number of possible connections per session */
+#define ISCSI_CONN_MAX		1
+/* max len of interface */
+#define ISCSI_MAX_IFACE_LEN	65
+
+/* the following structures store the options set in the config file.
+ * a structure is defined for each logically-related group of options.
+ * if you are adding a new option, first check if it should belong
+ * to one of the existing groups.  If it does, add it.  If not, define
+ * a new structure.
+ */
+
+#if 0
+/* all authentication-related options should be added to this structure.
+ * this structure is per-session, and can be configured
+ * by TargetName but not Subnet.
+ */
+struct iscsi_auth_config {
+	unsigned int authmethod;
+	char username[AUTH_STR_MAX_LEN];
+	unsigned char password[AUTH_STR_MAX_LEN];
+	unsigned int password_length;
+	char username_in[AUTH_STR_MAX_LEN];
+	unsigned char password_in[AUTH_STR_MAX_LEN];
+	unsigned int password_in_length;
+};
+
+/* all per-connection timeouts go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_connection_timeout_config {
+	int login_timeout;
+	int logout_timeout;
+	int auth_timeout;
+	int active_timeout;
+	int noop_out_interval;
+	int noop_out_timeout;
+};
+
+/* all per-connection timeouts go in this structure.
+ * this structure is per-session, and can be configured
+ * by TargetName but not by Subnet.
+ */
+struct iscsi_session_timeout_config {
+	int replacement_timeout;
+};
+
+/* all error handling timeouts go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_error_timeout_config {
+	int abort_timeout;
+	int host_reset_timeout;
+	int lu_reset_timeout;
+};
+
+/* all TCP options go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_tcp_config {
+	int window_size;
+	int type_of_service;	/* try to set IP TOS bits */
+};
+
+struct iscsi_conn_operational_config {
+	int MaxRecvDataSegmentLength;
+	int MaxXmitDataSegmentLength;
+	int HeaderDigest;
+	int DataDigest;
+	int IFMarker;
+	int OFMarker;
+};
+
+/* all iSCSI operational params go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_session_operational_config {
+	int DataPDUInOrder;
+	int DataSequenceInOrder;
+	int protocol;
+	int InitialR2T;
+	int ImmediateData;
+	int FirstBurstLength;
+	int MaxBurstLength;
+	int DefaultTime2Wait;
+	int DefaultTime2Retain;
+	int MaxConnections;
+	int MaxOutstandingR2T;
+	int ERL;
+	int FastAbort;
+};
+
+#define CONFIG_DIGEST_NEVER  0
+#define CONFIG_DIGEST_ALWAYS 1
+#define CONFIG_DIGEST_PREFER_ON 2
+#define CONFIG_DIGEST_PREFER_OFF 3
+
+struct iscsi_sendtargets_config {
+	int reopen_max;
+	struct iscsi_auth_config auth;
+	struct iscsi_connection_timeout_config conn_timeo;
+	struct iscsi_conn_operational_config iscsi;
+};
+
+struct iscsi_slp_config {
+	char *scopes;
+	char *interfaces;	/* for multicast, list of interfaces names,
+				 * "all", or "none" */
+	int poll_interval;
+	struct iscsi_auth_config auth;
+};
+
+typedef enum iscsi_startup {
+	ISCSI_STARTUP_MANUAL,
+	ISCSI_STARTUP_AUTOMATIC,
+	ISCSI_STARTUP_ONBOOT,
+} iscsi_startup_e;
+
+typedef enum discovery_type {
+	DISCOVERY_TYPE_SENDTARGETS,
+	DISCOVERY_TYPE_OFFLOAD_SENDTARGETS,
+	DISCOVERY_TYPE_SLP,
+	DISCOVERY_TYPE_ISNS,
+	DISCOVERY_TYPE_STATIC,
+	DISCOVERY_TYPE_FW,
+} discovery_type_e;
+
+typedef struct conn_rec {
+	iscsi_startup_e				startup;
+	char					address[NI_MAXHOST];
+	int					port;
+	struct iscsi_tcp_config			tcp;
+	struct iscsi_connection_timeout_config	timeo;
+	struct iscsi_conn_operational_config	iscsi;
+} conn_rec_t;
+
+typedef struct session_rec {
+	int					initial_cmdsn;
+	int					reopen_max;
+	int					xmit_thread_priority;
+	int					cmds_max;
+	int					queue_depth;
+	int					initial_login_retry_max;
+	struct iscsi_auth_config		auth;
+	struct iscsi_session_timeout_config	timeo;
+	struct iscsi_error_timeout_config	err_timeo;
+	struct iscsi_session_operational_config	iscsi;
+} session_rec_t;
+#endif
+
+#define ISCSI_TRANSPORT_NAME_MAXLEN 16
+
+typedef struct iface_rec {
+	struct list_head	list;
+	/* iscsi iface record name */
+	char			name[ISCSI_MAX_IFACE_LEN];
+	/* network layer iface name (eth0) */
+	char			netdev[IFNAMSIZ];
+	char			ipaddress[NI_MAXHOST];
+	/*
+	 * TODO: we may have to make this bigger and interconnect
+	 * specific for infinniband 
+	 */
+	char			hwaddress[ISCSI_MAX_IFACE_LEN];
+	char			transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
+	/*
+	 * This is only used for boot now, but the iser guys
+	 * can use this for their virtualization idea.
+	 */
+	char			alias[TARGET_NAME_MAXLEN + 1];
+	char			iname[TARGET_NAME_MAXLEN + 1];
+} iface_rec_t;
+
+#if 0
+typedef struct node_rec {
+	struct list_head	list;
+	char			name[TARGET_NAME_MAXLEN];
+	int			tpgt;
+	iscsi_startup_e		startup;
+	session_rec_t		session;
+	conn_rec_t		conn[ISCSI_CONN_MAX];
+	iface_rec_t		iface;
+	discovery_type_e	disc_type;
+	char			disc_address[NI_MAXHOST];
+	int			disc_port;
+} node_rec_t;
+
+typedef struct discovery_rec {
+	iscsi_startup_e		startup;
+	discovery_type_e	type;
+	char			address[NI_MAXHOST];
+	int			port;
+	union {
+		struct iscsi_sendtargets_config	sendtargets;
+		struct iscsi_slp_config		slp;
+	} u;
+} discovery_rec_t;
+#endif
+
+#endif /* CONFIG_H */
diff --git a/brcm_iscsi_uio/include/fw_context.h b/brcm_iscsi_uio/include/fw_context.h
new file mode 100644
index 0000000..d3971c4
--- /dev/null
+++ b/brcm_iscsi_uio/include/fw_context.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.com>
+ *         "Prasanna Mumbai" <mumbai.prasanna@gmail.com>
+ *
+ */
+#ifndef FWPARAM_CONTEXT_H_
+#define FWPARAM_CONTEXT_H_
+
+#include <net/if.h>
+
+#include "iscsi_proto.h"
+#include "list.h"
+#include "auth.h"
+
+struct boot_context {
+	struct list_head list;
+
+	/* target settings */
+	int target_port;
+	char targetname[TARGET_NAME_MAXLEN + 1];
+	char target_ipaddr[32];
+	char chap_name[AUTH_STR_MAX_LEN];
+	char chap_password[AUTH_STR_MAX_LEN];
+	char chap_name_in[AUTH_STR_MAX_LEN];
+	char chap_password_in[AUTH_STR_MAX_LEN];
+
+	/* initiator settings */
+	char isid[10];
+	char initiatorname[TARGET_NAME_MAXLEN + 1];
+
+	/* network settings */
+	char dhcp[18];
+	char iface[IF_NAMESIZE];
+	char mac[18];
+	char ipaddr[18];
+	char gateway[18];
+	char primary_dns[18];
+	char secondary_dns[18];
+	char mask[18];
+	char lun[17];
+	char vlan[15];
+};
+
+extern int fw_get_entry(struct boot_context *context);
+extern void fw_print_entry(struct boot_context *context);
+extern int fw_get_targets(struct list_head *list);
+extern void fw_free_targets(struct list_head *list);
+
+#endif /* FWPARAM_CONTEXT_H_ */
diff --git a/brcm_iscsi_uio/include/iscsi_if.h b/brcm_iscsi_uio/include/iscsi_if.h
new file mode 100644
index 0000000..a9ac145
--- /dev/null
+++ b/brcm_iscsi_uio/include/iscsi_if.h
@@ -0,0 +1,473 @@
+/*
+ * iSCSI User/Kernel Shares (Defines, Constants, Protocol definitions, etc)
+ *
+ * Copyright (C) 2005 Dmitry Yusupov
+ * Copyright (C) 2005 Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#ifndef ISCSI_IF_H
+#define ISCSI_IF_H
+
+#include "iscsi_proto.h"
+#include <netinet/in.h>
+//#include <linux/in6.h>
+
+#define ISCSI_NL_GRP_ISCSID     1
+#define ISCSI_NL_GRP_UIP        2
+
+#define UEVENT_BASE			10
+#define KEVENT_BASE			100
+#define ISCSI_ERR_BASE			1000
+
+enum iscsi_uevent_e {
+	ISCSI_UEVENT_UNKNOWN		= 0,
+
+	/* down events */
+	ISCSI_UEVENT_CREATE_SESSION	= UEVENT_BASE + 1,
+	ISCSI_UEVENT_DESTROY_SESSION	= UEVENT_BASE + 2,
+	ISCSI_UEVENT_CREATE_CONN	= UEVENT_BASE + 3,
+	ISCSI_UEVENT_DESTROY_CONN	= UEVENT_BASE + 4,
+	ISCSI_UEVENT_BIND_CONN		= UEVENT_BASE + 5,
+	ISCSI_UEVENT_SET_PARAM		= UEVENT_BASE + 6,
+	ISCSI_UEVENT_START_CONN		= UEVENT_BASE + 7,
+	ISCSI_UEVENT_STOP_CONN		= UEVENT_BASE + 8,
+	ISCSI_UEVENT_SEND_PDU		= UEVENT_BASE + 9,
+	ISCSI_UEVENT_GET_STATS		= UEVENT_BASE + 10,
+	ISCSI_UEVENT_GET_PARAM		= UEVENT_BASE + 11,
+
+	ISCSI_UEVENT_TRANSPORT_EP_CONNECT	= UEVENT_BASE + 12,
+	ISCSI_UEVENT_TRANSPORT_EP_POLL		= UEVENT_BASE + 13,
+	ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT	= UEVENT_BASE + 14,
+
+	ISCSI_UEVENT_TGT_DSCVR		= UEVENT_BASE + 15,
+	ISCSI_UEVENT_SET_HOST_PARAM	= UEVENT_BASE + 16,
+	ISCSI_UEVENT_UNBIND_SESSION	= UEVENT_BASE + 17,
+	ISCSI_UEVENT_CREATE_BOUND_SESSION	= UEVENT_BASE + 18,
+	ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST  = UEVENT_BASE + 19,
+
+	ISCSI_UEVENT_PATH_UPDATE	= UEVENT_BASE + 20,
+
+	/* up events */
+	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
+	ISCSI_KEVENT_CONN_ERROR		= KEVENT_BASE + 2,
+	ISCSI_KEVENT_IF_ERROR		= KEVENT_BASE + 3,
+	ISCSI_KEVENT_DESTROY_SESSION	= KEVENT_BASE + 4,
+	ISCSI_KEVENT_UNBIND_SESSION	= KEVENT_BASE + 5,
+	ISCSI_KEVENT_CREATE_SESSION	= KEVENT_BASE + 6,
+
+	ISCSI_KEVENT_PATH_REQ           = KEVENT_BASE + 7,
+        ISCSI_KEVENT_IF_DOWN            = KEVENT_BASE + 8,
+};
+
+enum iscsi_tgt_dscvr {
+	ISCSI_TGT_DSCVR_SEND_TARGETS	= 1,
+	ISCSI_TGT_DSCVR_ISNS		= 2,
+	ISCSI_TGT_DSCVR_SLP		= 3,
+};
+
+struct iscsi_uevent {
+	uint32_t type; /* k/u events type */
+	uint32_t iferror; /* carries interface or resource errors */
+	uint64_t transport_handle;
+
+	union {
+		/* messages u -> k */
+		struct msg_create_session {
+			uint32_t	initial_cmdsn;
+			uint16_t	cmds_max;
+			uint16_t	queue_depth;
+		} c_session;
+		struct msg_create_bound_session {
+			uint64_t	ep_handle;
+			uint32_t	initial_cmdsn;
+			uint16_t	cmds_max;
+			uint16_t	queue_depth;
+		} c_bound_session;
+		struct msg_destroy_session {
+			uint32_t	sid;
+		} d_session;
+		struct msg_create_conn {
+			uint32_t	sid;
+			uint32_t	cid;
+		} c_conn;
+		struct msg_bind_conn {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint64_t	transport_eph;
+			uint32_t	is_leading;
+		} b_conn;
+		struct msg_destroy_conn {
+			uint32_t	sid;
+			uint32_t	cid;
+		} d_conn;
+		struct msg_send_pdu {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint32_t	hdr_size;
+			uint32_t	data_size;
+		} send_pdu;
+		struct msg_set_param {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint32_t	param; /* enum iscsi_param */
+			uint32_t	len;
+		} set_param;
+		struct msg_start_conn {
+			uint32_t	sid;
+			uint32_t	cid;
+		} start_conn;
+		struct msg_stop_conn {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint64_t	conn_handle;
+			uint32_t	flag;
+		} stop_conn;
+		struct msg_get_stats {
+			uint32_t	sid;
+			uint32_t	cid;
+		} get_stats;
+		struct msg_transport_connect {
+			uint32_t	non_blocking;
+		} ep_connect;
+		struct msg_transport_connect_through_host {
+			uint32_t	host_no;
+			uint32_t	non_blocking;
+		} ep_connect_through_host;
+		struct msg_transport_poll {
+			uint64_t	ep_handle;
+			uint32_t	timeout_ms;
+		} ep_poll;
+		struct msg_transport_disconnect {
+			uint64_t	ep_handle;
+		} ep_disconnect;
+		struct msg_tgt_dscvr {
+			enum iscsi_tgt_dscvr	type;
+			uint32_t	host_no;
+			/*
+ 			 * enable = 1 to establish a new connection
+			 * with the server. enable = 0 to disconnect
+			 * from the server. Used primarily to switch
+			 * from one iSNS server to another.
+			 */
+			uint32_t	enable;
+		} tgt_dscvr;
+		struct msg_set_host_param {
+			uint32_t	host_no;
+			uint32_t	param; /* enum iscsi_host_param */
+			uint32_t	len;
+		} set_host_param;
+		struct msg_set_path {
+			uint32_t        host_no;
+		} set_path;
+	} u;
+	union {
+		/* messages k -> u */
+		int			retcode;
+		struct msg_create_session_ret {
+			uint32_t	sid;
+			uint32_t	host_no;
+		} c_session_ret;
+		struct msg_create_conn_ret {
+			uint32_t	sid;
+			uint32_t	cid;
+		} c_conn_ret;
+		struct msg_unbind_session {
+			uint32_t	sid;
+			uint32_t	host_no;
+		} unbind_session;
+		struct msg_recv_req {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint64_t	recv_handle;
+		} recv_req;
+		struct msg_conn_error {
+			uint32_t	sid;
+			uint32_t	cid;
+			uint32_t	error; /* enum iscsi_err */
+		} connerror;
+		struct msg_session_destroyed {
+			uint32_t	host_no;
+			uint32_t	sid;
+		} d_session;
+		struct msg_transport_connect_ret {
+			uint64_t	handle;
+		} ep_connect_ret;
+                struct msg_req_path {
+			uint32_t        host_no;
+		} req_path;
+		struct msg_notify_if_down {
+			uint32_t        host_no;
+		} notify_if_down;
+	} r;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+/*
+ * To keep the struct iscsi_uevent size the same for userspace code
+ * compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and
+ * ISCSI_KEVENT_PATH_REQ is defined separately and comes after the
+ * struct iscsi_uevent in the NETLINK_ISCSI message.
+ */
+struct iscsi_path {
+	uint64_t        handle;
+	uint8_t         mac_addr[6];
+	uint8_t         mac_addr_old[6];
+	uint32_t        ip_addr_len;    /* 4 or 16 */
+	union {
+		struct in_addr  v4_addr;
+		struct in6_addr v6_addr;
+	} src;
+	union {
+		struct in_addr  v4_addr;
+		struct in6_addr v6_addr;
+	} dst;
+	uint16_t        vlan_id;
+	uint16_t        pmtu;
+}  __attribute__ ((aligned (sizeof(uint64_t))));
+
+
+/*
+ * Common error codes
+ */
+enum iscsi_err {
+	ISCSI_OK			= 0,
+
+	ISCSI_ERR_DATASN		= ISCSI_ERR_BASE + 1,
+	ISCSI_ERR_DATA_OFFSET		= ISCSI_ERR_BASE + 2,
+	ISCSI_ERR_MAX_CMDSN		= ISCSI_ERR_BASE + 3,
+	ISCSI_ERR_EXP_CMDSN		= ISCSI_ERR_BASE + 4,
+	ISCSI_ERR_BAD_OPCODE		= ISCSI_ERR_BASE + 5,
+	ISCSI_ERR_DATALEN		= ISCSI_ERR_BASE + 6,
+	ISCSI_ERR_AHSLEN		= ISCSI_ERR_BASE + 7,
+	ISCSI_ERR_PROTO			= ISCSI_ERR_BASE + 8,
+	ISCSI_ERR_LUN			= ISCSI_ERR_BASE + 9,
+	ISCSI_ERR_BAD_ITT		= ISCSI_ERR_BASE + 10,
+	ISCSI_ERR_CONN_FAILED		= ISCSI_ERR_BASE + 11,
+	ISCSI_ERR_R2TSN			= ISCSI_ERR_BASE + 12,
+	ISCSI_ERR_SESSION_FAILED	= ISCSI_ERR_BASE + 13,
+	ISCSI_ERR_HDR_DGST		= ISCSI_ERR_BASE + 14,
+	ISCSI_ERR_DATA_DGST		= ISCSI_ERR_BASE + 15,
+	ISCSI_ERR_PARAM_NOT_FOUND	= ISCSI_ERR_BASE + 16,
+	ISCSI_ERR_NO_SCSI_CMD		= ISCSI_ERR_BASE + 17,
+	ISCSI_ERR_INVALID_HOST		= ISCSI_ERR_BASE + 18,
+	ISCSI_ERR_XMIT_FAILED		= ISCSI_ERR_BASE + 19,
+};
+
+/*
+ * iSCSI Parameters (RFC3720)
+ */
+enum iscsi_param {
+	/* passed in using netlink set param */
+	ISCSI_PARAM_MAX_RECV_DLENGTH,
+	ISCSI_PARAM_MAX_XMIT_DLENGTH,
+	ISCSI_PARAM_HDRDGST_EN,
+	ISCSI_PARAM_DATADGST_EN,
+	ISCSI_PARAM_INITIAL_R2T_EN,
+	ISCSI_PARAM_MAX_R2T,
+	ISCSI_PARAM_IMM_DATA_EN,
+	ISCSI_PARAM_FIRST_BURST,
+	ISCSI_PARAM_MAX_BURST,
+	ISCSI_PARAM_PDU_INORDER_EN,
+	ISCSI_PARAM_DATASEQ_INORDER_EN,
+	ISCSI_PARAM_ERL,
+	ISCSI_PARAM_IFMARKER_EN,
+	ISCSI_PARAM_OFMARKER_EN,
+	ISCSI_PARAM_EXP_STATSN,
+	ISCSI_PARAM_TARGET_NAME,
+	ISCSI_PARAM_TPGT,
+	ISCSI_PARAM_PERSISTENT_ADDRESS,
+	ISCSI_PARAM_PERSISTENT_PORT,
+	ISCSI_PARAM_SESS_RECOVERY_TMO,
+
+	/* pased in through bind conn using transport_fd */
+	ISCSI_PARAM_CONN_PORT,
+	ISCSI_PARAM_CONN_ADDRESS,
+
+	ISCSI_PARAM_USERNAME,
+	ISCSI_PARAM_USERNAME_IN,
+	ISCSI_PARAM_PASSWORD,
+	ISCSI_PARAM_PASSWORD_IN,
+
+	ISCSI_PARAM_FAST_ABORT,
+	ISCSI_PARAM_ABORT_TMO,
+	ISCSI_PARAM_LU_RESET_TMO,
+	ISCSI_PARAM_HOST_RESET_TMO,
+
+	ISCSI_PARAM_PING_TMO,
+	ISCSI_PARAM_RECV_TMO,
+
+	ISCSI_PARAM_IFACE_NAME,
+	ISCSI_PARAM_ISID,
+	ISCSI_PARAM_INITIATOR_NAME,
+	/* must always be last */
+	ISCSI_PARAM_MAX,
+};
+
+#define ISCSI_MAX_RECV_DLENGTH		(1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH)
+#define ISCSI_MAX_XMIT_DLENGTH		(1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH)
+#define ISCSI_HDRDGST_EN		(1ULL << ISCSI_PARAM_HDRDGST_EN)
+#define ISCSI_DATADGST_EN		(1ULL << ISCSI_PARAM_DATADGST_EN)
+#define ISCSI_INITIAL_R2T_EN		(1ULL << ISCSI_PARAM_INITIAL_R2T_EN)
+#define ISCSI_MAX_R2T			(1ULL << ISCSI_PARAM_MAX_R2T)
+#define ISCSI_IMM_DATA_EN		(1ULL << ISCSI_PARAM_IMM_DATA_EN)
+#define ISCSI_FIRST_BURST		(1ULL << ISCSI_PARAM_FIRST_BURST)
+#define ISCSI_MAX_BURST			(1ULL << ISCSI_PARAM_MAX_BURST)
+#define ISCSI_PDU_INORDER_EN		(1ULL << ISCSI_PARAM_PDU_INORDER_EN)
+#define ISCSI_DATASEQ_INORDER_EN	(1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN)
+#define ISCSI_ERL			(1ULL << ISCSI_PARAM_ERL)
+#define ISCSI_IFMARKER_EN		(1ULL << ISCSI_PARAM_IFMARKER_EN)
+#define ISCSI_OFMARKER_EN		(1ULL << ISCSI_PARAM_OFMARKER_EN)
+#define ISCSI_EXP_STATSN		(1ULL << ISCSI_PARAM_EXP_STATSN)
+#define ISCSI_TARGET_NAME		(1ULL << ISCSI_PARAM_TARGET_NAME)
+#define ISCSI_TPGT			(1ULL << ISCSI_PARAM_TPGT)
+#define ISCSI_PERSISTENT_ADDRESS	(1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS)
+#define ISCSI_PERSISTENT_PORT		(1ULL << ISCSI_PARAM_PERSISTENT_PORT)
+#define ISCSI_SESS_RECOVERY_TMO		(1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO)
+#define ISCSI_CONN_PORT			(1ULL << ISCSI_PARAM_CONN_PORT)
+#define ISCSI_CONN_ADDRESS		(1ULL << ISCSI_PARAM_CONN_ADDRESS)
+#define ISCSI_USERNAME			(1ULL << ISCSI_PARAM_USERNAME)
+#define ISCSI_USERNAME_IN		(1ULL << ISCSI_PARAM_USERNAME_IN)
+#define ISCSI_PASSWORD			(1ULL << ISCSI_PARAM_PASSWORD)
+#define ISCSI_PASSWORD_IN		(1ULL << ISCSI_PARAM_PASSWORD_IN)
+#define ISCSI_FAST_ABORT		(1ULL << ISCSI_PARAM_FAST_ABORT)
+#define ISCSI_ABORT_TMO			(1ULL << ISCSI_PARAM_ABORT_TMO)
+#define ISCSI_LU_RESET_TMO		(1ULL << ISCSI_PARAM_LU_RESET_TMO)
+#define ISCSI_HOST_RESET_TMO		(1ULL << ISCSI_PARAM_HOST_RESET_TMO)
+#define ISCSI_PING_TMO			(1ULL << ISCSI_PARAM_PING_TMO)
+#define ISCSI_RECV_TMO			(1ULL << ISCSI_PARAM_RECV_TMO)
+#define ISCSI_IFACE_NAME		(1ULL << ISCSI_PARAM_IFACE_NAME)
+#define ISCSI_ISID			(1ULL << ISCSI_PARAM_ISID)
+#define ISCSI_INITIATOR_NAME		(1ULL << ISCSI_PARAM_INITIATOR_NAME)
+
+/* iSCSI HBA params */
+enum iscsi_host_param {
+	ISCSI_HOST_PARAM_HWADDRESS,
+	ISCSI_HOST_PARAM_INITIATOR_NAME,
+	ISCSI_HOST_PARAM_NETDEV_NAME,
+	ISCSI_HOST_PARAM_IPADDRESS,
+	ISCSI_HOST_PARAM_MAX,
+};
+
+#define ISCSI_HOST_HWADDRESS		(1ULL << ISCSI_HOST_PARAM_HWADDRESS)
+#define ISCSI_HOST_INITIATOR_NAME	(1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME)
+#define ISCSI_HOST_NETDEV_NAME		(1ULL << ISCSI_HOST_PARAM_NETDEV_NAME)
+#define ISCSI_HOST_IPADDRESS		(1ULL << ISCSI_HOST_PARAM_IPADDRESS)
+
+#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
+#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
+
+/*
+ * These flags presents iSCSI Data-Path capabilities.
+ */
+#define CAP_RECOVERY_L0		0x1
+#define CAP_RECOVERY_L1		0x2
+#define CAP_RECOVERY_L2		0x4
+#define CAP_MULTI_R2T		0x8
+#define CAP_HDRDGST		0x10
+#define CAP_DATADGST		0x20
+#define CAP_MULTI_CONN		0x40
+#define CAP_TEXT_NEGO		0x80
+#define CAP_MARKERS		0x100
+#define CAP_FW_DB		0x200
+#define CAP_SENDTARGETS_OFFLOAD	0x400	/* offload discovery process */
+#define CAP_DATA_PATH_OFFLOAD	0x800	/* offload entire IO path */
+#define CAP_DIGEST_OFFLOAD	0x1000	/* offload hdr and data digests */
+#define CAP_PADDING_OFFLOAD	0x2000	/* offload padding insertion, removal,
+					 and verification */
+
+/*
+ * These flags describes reason of stop_conn() call
+ */
+#define STOP_CONN_TERM		0x1
+#define STOP_CONN_SUSPEND	0x2
+#define STOP_CONN_RECOVER	0x3
+
+#define ISCSI_STATS_CUSTOM_MAX		32
+#define ISCSI_STATS_CUSTOM_DESC_MAX	64
+struct iscsi_stats_custom {
+	char desc[ISCSI_STATS_CUSTOM_DESC_MAX];
+	uint64_t value;
+};
+
+/*
+ * struct iscsi_stats - iSCSI Statistics (iSCSI MIB)
+ *
+ * Note: this structure contains counters collected on per-connection basis.
+ */
+struct iscsi_stats {
+	/* octets */
+	uint64_t txdata_octets;
+	uint64_t rxdata_octets;
+
+	/* xmit pdus */
+	uint32_t noptx_pdus;
+	uint32_t scsicmd_pdus;
+	uint32_t tmfcmd_pdus;
+	uint32_t login_pdus;
+	uint32_t text_pdus;
+	uint32_t dataout_pdus;
+	uint32_t logout_pdus;
+	uint32_t snack_pdus;
+
+	/* recv pdus */
+	uint32_t noprx_pdus;
+	uint32_t scsirsp_pdus;
+	uint32_t tmfrsp_pdus;
+	uint32_t textrsp_pdus;
+	uint32_t datain_pdus;
+	uint32_t logoutrsp_pdus;
+	uint32_t r2t_pdus;
+	uint32_t async_pdus;
+	uint32_t rjt_pdus;
+
+	/* errors */
+	uint32_t digest_err;
+	uint32_t timeout_err;
+
+	/*
+	 * iSCSI Custom Statistics support, i.e. Transport could
+	 * extend existing MIB statistics with its own specific statistics
+	 * up to ISCSI_STATS_CUSTOM_MAX
+	 */
+	uint32_t custom_length;
+	struct iscsi_stats_custom custom[0]
+		__attribute__ ((aligned (sizeof(uint64_t))));
+};
+
+/*
+ * Network interface configuration
+ */
+enum iscsi_net_param {
+	ISCSI_NET_PARAM_UNKNOWN			= 0x00,
+	ISCSI_NET_PARAM_MAC_ADDR		= ISCSI_NET_PARAM_UNKNOWN + 1,
+	ISCSI_NET_PARAM_IPV4_ADDR		= ISCSI_NET_PARAM_UNKNOWN + 2,
+	ISCSI_NET_PARAM_IPV6_ADDR		= ISCSI_NET_PARAM_UNKNOWN + 3,
+	ISCSI_NET_PARAM_IPV4_NETMASK		= ISCSI_NET_PARAM_UNKNOWN + 4,
+	ISCSI_NET_PARAM_IPV6_NETMASK		= ISCSI_NET_PARAM_UNKNOWN + 5,
+	ISCSI_NET_PARAM_IPV4_GATEWAY		= ISCSI_NET_PARAM_UNKNOWN + 6,
+	ISCSI_NET_PARAM_IPV6_GATEWAY		= ISCSI_NET_PARAM_UNKNOWN + 7,
+	ISCSI_NET_PARAM_BOOTPROTO		= ISCSI_NET_PARAM_UNKNOWN + 8,
+	ISCSI_NET_PARAM_IPV6_AUTO_PARAM		= ISCSI_NET_PARAM_UNKNOWN + 9,
+	ISCSI_NET_PARAM_MTU			= ISCSI_NET_PARAM_UNKNOWN + 10,
+	ISCSI_NET_PARAM_VLAN			= ISCSI_NET_PARAM_UNKNOWN + 11,
+};
+
+struct iscsi_net_config {
+	uint32_t param;
+	uint32_t length;
+	uint8_t value[1];
+};
+
+#endif
diff --git a/brcm_iscsi_uio/include/iscsi_proto.h b/brcm_iscsi_uio/include/iscsi_proto.h
new file mode 100644
index 0000000..d1e0589
--- /dev/null
+++ b/brcm_iscsi_uio/include/iscsi_proto.h
@@ -0,0 +1,637 @@
+/*
+ * RFC 3720 (iSCSI) protocol data types
+ *
+ * Copyright (C) 2005 Dmitry Yusupov
+ * Copyright (C) 2005 Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#ifndef ISCSI_PROTO_H
+#define ISCSI_PROTO_H
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+#include <linux/types.h>
+
+#define ISCSI_DRAFT20_VERSION	0x00
+
+/* default iSCSI listen port for incoming connections */
+#define ISCSI_LISTEN_PORT	3260
+
+/* Padding word length */
+#define ISCSI_PAD_LEN		4
+
+/*
+ * useful common(control and data pathes) macro
+ */
+#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
+#define hton24(p, v) { \
+        p[0] = (((v) >> 16) & 0xFF); \
+        p[1] = (((v) >> 8) & 0xFF); \
+        p[2] = ((v) & 0xFF); \
+}
+#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
+
+/*
+ * If running svn modules we may need to define these.
+ * This should not go upstream since this is already properly defined there
+ */
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+/* initiator tags; opaque for target */
+typedef uint32_t __bitwise__ itt_t;
+/* below makes sense only for initiator that created this tag */
+#define build_itt(itt, age) ((__force itt_t)\
+	((itt) | ((age) << ISCSI_AGE_SHIFT)))
+#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
+#define RESERVED_ITT ((__force itt_t)0xffffffff)
+
+/*
+ * iSCSI Template Message Header
+ */
+struct iscsi_hdr {
+	uint8_t		opcode;
+	uint8_t		flags;		/* Final bit */
+	uint8_t		rsvd2[2];
+	uint8_t		hlength;	/* AHSs total length */
+	uint8_t		dlength[3];	/* Data length */
+	uint8_t		lun[8];
+	itt_t		itt;		/* Initiator Task Tag, opaque for target */
+	__be32		ttt;		/* Target Task Tag */
+	__be32		statsn;
+	__be32		exp_statsn;
+	__be32		max_statsn;
+	uint8_t		other[12];
+};
+
+/************************* RFC 3720 Begin *****************************/
+
+#define ISCSI_RESERVED_TAG		0xffffffff
+
+/* Opcode encoding bits */
+#define ISCSI_OP_RETRY			0x80
+#define ISCSI_OP_IMMEDIATE		0x40
+#define ISCSI_OPCODE_MASK		0x3F
+
+/* Initiator Opcode values */
+#define ISCSI_OP_NOOP_OUT		0x00
+#define ISCSI_OP_SCSI_CMD		0x01
+#define ISCSI_OP_SCSI_TMFUNC		0x02
+#define ISCSI_OP_LOGIN			0x03
+#define ISCSI_OP_TEXT			0x04
+#define ISCSI_OP_SCSI_DATA_OUT		0x05
+#define ISCSI_OP_LOGOUT			0x06
+#define ISCSI_OP_SNACK			0x10
+
+#define ISCSI_OP_VENDOR1_CMD		0x1c
+#define ISCSI_OP_VENDOR2_CMD		0x1d
+#define ISCSI_OP_VENDOR3_CMD		0x1e
+#define ISCSI_OP_VENDOR4_CMD		0x1f
+
+/* Target Opcode values */
+#define ISCSI_OP_NOOP_IN		0x20
+#define ISCSI_OP_SCSI_CMD_RSP		0x21
+#define ISCSI_OP_SCSI_TMFUNC_RSP	0x22
+#define ISCSI_OP_LOGIN_RSP		0x23
+#define ISCSI_OP_TEXT_RSP		0x24
+#define ISCSI_OP_SCSI_DATA_IN		0x25
+#define ISCSI_OP_LOGOUT_RSP		0x26
+#define ISCSI_OP_R2T			0x31
+#define ISCSI_OP_ASYNC_EVENT		0x32
+#define ISCSI_OP_REJECT			0x3f
+
+struct iscsi_ahs_hdr {
+	__be16 ahslength;
+	uint8_t ahstype;
+	uint8_t ahspec[5];
+};
+
+#define ISCSI_AHSTYPE_CDB		1
+#define ISCSI_AHSTYPE_RLENGTH		2
+#define ISCSI_CDB_SIZE			16
+
+/* iSCSI PDU Header */
+struct iscsi_cmd {
+	uint8_t opcode;
+	uint8_t flags;
+	__be16 rsvd2;
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32 data_length;
+	__be32 cmdsn;
+	__be32 exp_statsn;
+	uint8_t cdb[ISCSI_CDB_SIZE];	/* SCSI Command Block */
+	/* Additional Data (Command Dependent) */
+};
+
+/* Command PDU flags */
+#define ISCSI_FLAG_CMD_FINAL		0x80
+#define ISCSI_FLAG_CMD_READ		0x40
+#define ISCSI_FLAG_CMD_WRITE		0x20
+#define ISCSI_FLAG_CMD_ATTR_MASK	0x07	/* 3 bits */
+
+/* SCSI Command Attribute values */
+#define ISCSI_ATTR_UNTAGGED		0
+#define ISCSI_ATTR_SIMPLE		1
+#define ISCSI_ATTR_ORDERED		2
+#define ISCSI_ATTR_HEAD_OF_QUEUE	3
+#define ISCSI_ATTR_ACA			4
+
+struct iscsi_rlength_ahdr {
+	__be16 ahslength;
+	uint8_t ahstype;
+	uint8_t reserved;
+	__be32 read_length;
+};
+
+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+	__be16 ahslength;	/* CDB length - 15, including reserved byte */
+	uint8_t ahstype;
+	uint8_t reserved;
+	/* 4-byte aligned extended CDB spillover */
+	uint8_t ecdb[260 - ISCSI_CDB_SIZE];
+};
+
+/* SCSI Response Header */
+struct iscsi_cmd_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t response;
+	uint8_t cmd_status;
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32	rsvd1;
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	__be32	exp_datasn;
+	__be32	bi_residual_count;
+	__be32	residual_count;
+	/* Response or Sense Data (optional) */
+};
+
+/* Command Response PDU flags */
+#define ISCSI_FLAG_CMD_BIDI_OVERFLOW	0x10
+#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW	0x08
+#define ISCSI_FLAG_CMD_OVERFLOW		0x04
+#define ISCSI_FLAG_CMD_UNDERFLOW	0x02
+
+/* iSCSI Status values. Valid if Rsp Selector bit is not set */
+#define ISCSI_STATUS_CMD_COMPLETED	0
+#define ISCSI_STATUS_TARGET_FAILURE	1
+#define ISCSI_STATUS_SUBSYS_FAILURE	2
+
+/* Asynchronous Event Header */
+struct iscsi_async {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2[2];
+	uint8_t rsvd3;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	uint8_t rsvd4[8];
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	uint8_t async_event;
+	uint8_t async_vcode;
+	__be16	param1;
+	__be16	param2;
+	__be16	param3;
+	uint8_t rsvd5[4];
+};
+
+/* iSCSI Event Codes */
+#define ISCSI_ASYNC_MSG_SCSI_EVENT			0
+#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT			1
+#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION		2
+#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS	3
+#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION		4
+#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC			255
+
+/* NOP-Out Message */
+struct iscsi_nopout {
+	uint8_t opcode;
+	uint8_t flags;
+	__be16	rsvd2;
+	uint8_t rsvd3;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32	ttt;	/* Target Transfer Tag */
+	__be32	cmdsn;
+	__be32	exp_statsn;
+	uint8_t rsvd4[16];
+};
+
+/* NOP-In Message */
+struct iscsi_nopin {
+	uint8_t opcode;
+	uint8_t flags;
+	__be16	rsvd2;
+	uint8_t rsvd3;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32	ttt;	/* Target Transfer Tag */
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	uint8_t rsvd4[12];
+};
+
+/* SCSI Task Management Message Header */
+struct iscsi_tm {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd1[2];
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	itt_t	 rtt;	/* Reference Task Tag */
+	__be32	cmdsn;
+	__be32	exp_statsn;
+	__be32	refcmdsn;
+	__be32	exp_datasn;
+	uint8_t rsvd2[8];
+};
+
+#define ISCSI_FLAG_TM_FUNC_MASK			0x7F
+
+/* Function values */
+#define ISCSI_TM_FUNC_ABORT_TASK		1
+#define ISCSI_TM_FUNC_ABORT_TASK_SET		2
+#define ISCSI_TM_FUNC_CLEAR_ACA			3
+#define ISCSI_TM_FUNC_CLEAR_TASK_SET		4
+#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET	5
+#define ISCSI_TM_FUNC_TARGET_WARM_RESET		6
+#define ISCSI_TM_FUNC_TARGET_COLD_RESET		7
+#define ISCSI_TM_FUNC_TASK_REASSIGN		8
+
+/* SCSI Task Management Response Header */
+struct iscsi_tm_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t response;	/* see Response values below */
+	uint8_t qualifier;
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd2[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	itt_t	 rtt;	/* Reference Task Tag */
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	uint8_t rsvd3[12];
+};
+
+/* Response values */
+#define ISCSI_TMF_RSP_COMPLETE		0x00
+#define ISCSI_TMF_RSP_NO_TASK		0x01
+#define ISCSI_TMF_RSP_NO_LUN		0x02
+#define ISCSI_TMF_RSP_TASK_ALLEGIANT	0x03
+#define ISCSI_TMF_RSP_NO_FAILOVER	0x04
+#define ISCSI_TMF_RSP_NOT_SUPPORTED	0x05
+#define ISCSI_TMF_RSP_AUTH_FAILED	0x06
+#define ISCSI_TMF_RSP_REJECTED		0xff
+
+/* Ready To Transfer Header */
+struct iscsi_r2t_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2[2];
+	uint8_t	hlength;
+	uint8_t	dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32	ttt;	/* Target Transfer Tag */
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	__be32	r2tsn;
+	__be32	data_offset;
+	__be32	data_length;
+};
+
+/* SCSI Data Hdr */
+struct iscsi_data {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2[2];
+	uint8_t rsvd3;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;
+	__be32	ttt;
+	__be32	rsvd4;
+	__be32	exp_statsn;
+	__be32	rsvd5;
+	__be32	datasn;
+	__be32	offset;
+	__be32	rsvd6;
+	/* Payload */
+};
+
+/* SCSI Data Response Hdr */
+struct iscsi_data_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2;
+	uint8_t cmd_status;
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t lun[8];
+	itt_t	 itt;
+	__be32	ttt;
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	__be32	datasn;
+	__be32	offset;
+	__be32	residual_count;
+};
+
+/* Data Response PDU flags */
+#define ISCSI_FLAG_DATA_ACK		0x40
+#define ISCSI_FLAG_DATA_OVERFLOW	0x04
+#define ISCSI_FLAG_DATA_UNDERFLOW	0x02
+#define ISCSI_FLAG_DATA_STATUS		0x01
+
+/* Text Header */
+struct iscsi_text {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2[2];
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd4[8];
+	itt_t	 itt;
+	__be32	ttt;
+	__be32	cmdsn;
+	__be32	exp_statsn;
+	uint8_t rsvd5[16];
+	/* Text - key=value pairs */
+};
+
+#define ISCSI_FLAG_TEXT_CONTINUE	0x40
+
+/* Text Response Header */
+struct iscsi_text_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2[2];
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd4[8];
+	itt_t	 itt;
+	__be32	ttt;
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	uint8_t rsvd5[12];
+	/* Text Response - key:value pairs */
+};
+
+/* Login Header */
+struct iscsi_login {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t max_version;	/* Max. version supported */
+	uint8_t min_version;	/* Min. version supported */
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t isid[6];	/* Initiator Session ID */
+	__be16	tsih;	/* Target Session Handle */
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be16	cid;
+	__be16	rsvd3;
+	__be32	cmdsn;
+	__be32	exp_statsn;
+	uint8_t rsvd5[16];
+};
+
+/* Login PDU flags */
+#define ISCSI_FLAG_LOGIN_TRANSIT		0x80
+#define ISCSI_FLAG_LOGIN_CONTINUE		0x40
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK	0x0C	/* 2 bits */
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK	0x03	/* 2 bits */
+
+#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
+	((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
+#define ISCSI_LOGIN_NEXT_STAGE(flags) \
+	(flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
+
+/* Login Response Header */
+struct iscsi_login_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t max_version;	/* Max. version supported */
+	uint8_t active_version;	/* Active version */
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t isid[6];	/* Initiator Session ID */
+	__be16	tsih;	/* Target Session Handle */
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32	rsvd3;
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	uint8_t status_class;	/* see Login RSP ststus classes below */
+	uint8_t status_detail;	/* see Login RSP Status details below */
+	uint8_t rsvd4[10];
+};
+
+/* Login stage (phase) codes for CSG, NSG */
+#define ISCSI_INITIAL_LOGIN_STAGE		-1
+#define ISCSI_SECURITY_NEGOTIATION_STAGE	0
+#define ISCSI_OP_PARMS_NEGOTIATION_STAGE	1
+#define ISCSI_FULL_FEATURE_PHASE		3
+
+/* Login Status response classes */
+#define ISCSI_STATUS_CLS_SUCCESS		0x00
+#define ISCSI_STATUS_CLS_REDIRECT		0x01
+#define ISCSI_STATUS_CLS_INITIATOR_ERR		0x02
+#define ISCSI_STATUS_CLS_TARGET_ERR		0x03
+
+/* Login Status response detail codes */
+/* Class-0 (Success) */
+#define ISCSI_LOGIN_STATUS_ACCEPT		0x00
+
+/* Class-1 (Redirection) */
+#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP	0x01
+#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM	0x02
+
+/* Class-2 (Initiator Error) */
+#define ISCSI_LOGIN_STATUS_INIT_ERR		0x00
+#define ISCSI_LOGIN_STATUS_AUTH_FAILED		0x01
+#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN	0x02
+#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND	0x03
+#define ISCSI_LOGIN_STATUS_TGT_REMOVED		0x04
+#define ISCSI_LOGIN_STATUS_NO_VERSION		0x05
+#define ISCSI_LOGIN_STATUS_ISID_ERROR		0x06
+#define ISCSI_LOGIN_STATUS_MISSING_FIELDS	0x07
+#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED	0x08
+#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE	0x09
+#define ISCSI_LOGIN_STATUS_NO_SESSION		0x0a
+#define ISCSI_LOGIN_STATUS_INVALID_REQUEST	0x0b
+
+/* Class-3 (Target Error) */
+#define ISCSI_LOGIN_STATUS_TARGET_ERROR		0x00
+#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE	0x01
+#define ISCSI_LOGIN_STATUS_NO_RESOURCES		0x02
+
+/* Logout Header */
+struct iscsi_logout {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd1[2];
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd2[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be16	cid;
+	uint8_t rsvd3[2];
+	__be32	cmdsn;
+	__be32	exp_statsn;
+	uint8_t rsvd4[16];
+};
+
+/* Logout PDU flags */
+#define ISCSI_FLAG_LOGOUT_REASON_MASK	0x7F
+
+/* logout reason_code values */
+
+#define ISCSI_LOGOUT_REASON_CLOSE_SESSION	0
+#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION	1
+#define ISCSI_LOGOUT_REASON_RECOVERY		2
+#define ISCSI_LOGOUT_REASON_AEN_REQUEST		3
+
+/* Logout Response Header */
+struct iscsi_logout_rsp {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t response;	/* see Logout response values below */
+	uint8_t rsvd2;
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd3[8];
+	itt_t	 itt;	/* Initiator Task Tag */
+	__be32	rsvd4;
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	__be32	rsvd5;
+	__be16	t2wait;
+	__be16	t2retain;
+	__be32	rsvd6;
+};
+
+/* logout response status values */
+
+#define ISCSI_LOGOUT_SUCCESS			0
+#define ISCSI_LOGOUT_CID_NOT_FOUND		1
+#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED	2
+#define ISCSI_LOGOUT_CLEANUP_FAILED		3
+
+/* SNACK Header */
+struct iscsi_snack {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t rsvd2[14];
+	itt_t	 itt;
+	__be32	begrun;
+	__be32	runlength;
+	__be32	exp_statsn;
+	__be32	rsvd3;
+	__be32	exp_datasn;
+	uint8_t rsvd6[8];
+};
+
+/* SNACK PDU flags */
+#define ISCSI_FLAG_SNACK_TYPE_MASK	0x0F	/* 4 bits */
+
+/* Reject Message Header */
+struct iscsi_reject {
+	uint8_t opcode;
+	uint8_t flags;
+	uint8_t reason;
+	uint8_t rsvd2;
+	uint8_t hlength;
+	uint8_t dlength[3];
+	uint8_t rsvd3[8];
+	__be32  ffffffff;
+	uint8_t rsvd4[4];
+	__be32	statsn;
+	__be32	exp_cmdsn;
+	__be32	max_cmdsn;
+	__be32	datasn;
+	uint8_t rsvd5[8];
+	/* Text - Rejected hdr */
+};
+
+/* Reason for Reject */
+#define ISCSI_REASON_CMD_BEFORE_LOGIN	1
+#define ISCSI_REASON_DATA_DIGEST_ERROR	2
+#define ISCSI_REASON_DATA_SNACK_REJECT	3
+#define ISCSI_REASON_PROTOCOL_ERROR	4
+#define ISCSI_REASON_CMD_NOT_SUPPORTED	5
+#define ISCSI_REASON_IMM_CMD_REJECT		6
+#define ISCSI_REASON_TASK_IN_PROGRESS	7
+#define ISCSI_REASON_INVALID_SNACK		8
+#define ISCSI_REASON_BOOKMARK_INVALID	9
+#define ISCSI_REASON_BOOKMARK_NO_RESOURCES	10
+#define ISCSI_REASON_NEGOTIATION_RESET	11
+
+/* Max. number of Key=Value pairs in a text message */
+#define MAX_KEY_VALUE_PAIRS	8192
+
+/* maximum length for text keys/values */
+#define KEY_MAXLEN		64
+#define VALUE_MAXLEN		255
+#define TARGET_NAME_MAXLEN	VALUE_MAXLEN
+
+#define ISCSI_DEF_MAX_RECV_SEG_LEN		8192
+#define ISCSI_MIN_MAX_RECV_SEG_LEN		512
+#define ISCSI_MAX_MAX_RECV_SEG_LEN		16777215
+
+#define ISCSI_DEF_FIRST_BURST_LEN		65536
+#define ISCSI_MIN_FIRST_BURST_LEN		512
+#define ISCSI_MAX_FIRST_BURST_LEN		16777215
+
+#define ISCSI_DEF_MAX_BURST_LEN			262144
+#define ISCSI_MIN_MAX_BURST_LEN			512
+#define ISCSI_MAX_MAX_BURST_LEN			16777215
+
+#define ISCSI_DEF_TIME2WAIT			2
+
+/************************* RFC 3720 End *****************************/
+
+#endif /* ISCSI_PROTO_H */
diff --git a/brcm_iscsi_uio/include/list.h b/brcm_iscsi_uio/include/list.h
new file mode 100644
index 0000000..bbf3425
--- /dev/null
+++ b/brcm_iscsi_uio/include/list.h
@@ -0,0 +1,93 @@
+#ifndef __LIST_H__
+#define __LIST_H__
+
+#include <stddef.h>
+/* taken from linux kernel */
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({			\
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head);				 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = entry->prev = NULL;
+}
+
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+#endif
diff --git a/brcm_iscsi_uio/include/mgmt_ipc.h b/brcm_iscsi_uio/include/mgmt_ipc.h
new file mode 100644
index 0000000..94827ea
--- /dev/null
+++ b/brcm_iscsi_uio/include/mgmt_ipc.h
@@ -0,0 +1,147 @@
+/*
+ * iSCSI Daemon/Admin Management IPC
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#ifndef MGMT_IPC_H
+#define MGMT_IPC_H
+
+//#include "types.h"
+#include "iscsi_if.h"
+#include "config.h"
+
+#define ISCSIADM_NAMESPACE	"ISCSIADM_ABSTRACT_NAMESPACE"
+#define PEERUSER_MAX		64
+
+typedef enum mgmt_ipc_err {
+	MGMT_IPC_OK			= 0,
+	MGMT_IPC_ERR			= 1,
+	MGMT_IPC_ERR_NOT_FOUND		= 2,
+	MGMT_IPC_ERR_NOMEM		= 3,
+	MGMT_IPC_ERR_TRANS_FAILURE	= 4,
+	MGMT_IPC_ERR_LOGIN_FAILURE	= 5,
+	MGMT_IPC_ERR_IDBM_FAILURE	= 6,
+	MGMT_IPC_ERR_INVAL		= 7,
+	MGMT_IPC_ERR_TRANS_TIMEOUT	= 8,
+	MGMT_IPC_ERR_INTERNAL		= 9,
+	MGMT_IPC_ERR_LOGOUT_FAILURE	= 10,
+	MGMT_IPC_ERR_PDU_TIMEOUT	= 11,
+	MGMT_IPC_ERR_TRANS_NOT_FOUND	= 12,
+	MGMT_IPC_ERR_ACCESS		= 13,
+	MGMT_IPC_ERR_TRANS_CAPS		= 14,
+	MGMT_IPC_ERR_EXISTS		= 15,
+	MGMT_IPC_ERR_INVALID_REQ	= 16,
+	MGMT_IPC_ERR_ISNS_UNAVAILABLE	= 17,
+	MGMT_IPC_ERR_ISCSID_COMM_ERR	= 18,
+	MGMT_IPC_ERR_FATAL_LOGIN_FAILURE = 19,
+	MGMT_IPC_ERR_ISCSID_NOTCONN	= 20,
+} mgmt_ipc_err_e;
+
+typedef enum iscsiadm_cmd {
+	MGMT_IPC_UNKNOWN		= 0,
+	MGMT_IPC_SESSION_LOGIN		= 1,
+	MGMT_IPC_SESSION_LOGOUT		= 2,
+	MGMT_IPC_SESSION_ACTIVESTAT	= 4,
+	MGMT_IPC_CONN_ADD		= 5,
+	MGMT_IPC_CONN_REMOVE		= 6,
+	MGMT_IPC_SESSION_STATS		= 7,
+	MGMT_IPC_CONFIG_INAME		= 8,
+	MGMT_IPC_CONFIG_IALIAS		= 9,
+	MGMT_IPC_CONFIG_FILE		= 10,
+	MGMT_IPC_IMMEDIATE_STOP		= 11,
+	MGMT_IPC_SESSION_SYNC		= 12,
+	MGMT_IPC_SESSION_INFO		= 13,
+	MGMT_IPC_ISNS_DEV_ATTR_QUERY	= 14,
+	MGMT_IPC_SEND_TARGETS		= 15,
+	MGMT_IPC_SET_HOST_PARAM		= 16,
+	MGMT_IPC_NOTIFY_ADD_NODE	= 17,
+	MGMT_IPC_NOTIFY_DEL_NODE	= 18,
+	MGMT_IPC_NOTIFY_ADD_PORTAL	= 19,
+	MGMT_IPC_NOTIFY_DEL_PORTAL	= 20,
+	MGMT_IPC_GET_IPADDR		= 21,
+
+	__MGMT_IPC_MAX_COMMAND
+} iscsiadm_cmd_e;
+
+/* IPC Request */
+typedef struct iscsiadm_req {
+	iscsiadm_cmd_e command;
+	uint32_t payload_len;
+
+	union {
+		/* messages */
+		struct ipc_msg_session {
+			int sid;
+//			node_rec_t rec;
+		} session;
+		struct ipc_msg_conn {
+			int sid;
+			int cid;
+		} conn;
+		struct ipc_msg_send_targets {
+			int host_no;
+			int do_login;
+			struct sockaddr_storage ss;
+		} st;
+		struct ipc_msg_set_host_param {
+			int host_no;
+			int param;
+			/* TODO: make this variable len to support */
+			char value[IFNAMSIZ + 1];
+
+		} set_host_param;
+	} u;
+} iscsiadm_req_t;
+
+/* IPC Response */
+typedef struct iscsiadm_rsp {
+	iscsiadm_cmd_e command;
+	mgmt_ipc_err_e err;
+
+	union {
+#define MGMT_IPC_GETSTATS_BUF_MAX	(sizeof(struct iscsi_uevent) + \
+					sizeof(struct iscsi_stats) + \
+					sizeof(struct iscsi_stats_custom) * \
+						ISCSI_STATS_CUSTOM_MAX)
+		struct ipc_msg_getstats {
+			struct iscsi_uevent ev;
+			struct iscsi_stats stats;
+			char custom[sizeof(struct iscsi_stats_custom) *
+					ISCSI_STATS_CUSTOM_MAX];
+		} getstats;
+		struct ipc_msg_config {
+			char var[VALUE_MAXLEN];
+		} config;
+		struct ipc_msg_session_state {
+			int session_state;
+			int conn_state;
+		} session_state;
+		struct ipc_msg_get_ipaddr {
+			int addr;
+		} get_ipaddr;
+	} u;
+} iscsiadm_rsp_t;
+
+struct queue_task;
+typedef mgmt_ipc_err_e	mgmt_ipc_fn_t(struct queue_task *);
+
+struct queue_task;
+void mgmt_ipc_write_rsp(struct queue_task *qtask, mgmt_ipc_err_e err);
+int mgmt_ipc_listen(void);
+void mgmt_ipc_close(int fd);
+void mgmt_ipc_handle(int accept_fd);
+
+#endif /* MGMT_IPC_H */
diff --git a/brcm_iscsi_uio/include/sysdeps.h b/brcm_iscsi_uio/include/sysdeps.h
new file mode 100644
index 0000000..2f18e3b
--- /dev/null
+++ b/brcm_iscsi_uio/include/sysdeps.h
@@ -0,0 +1,27 @@
+/*
+ * wrapping of libc features and kernel interfaces
+ *
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	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 version 2 of the License.
+ *
+ *	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, write to the Free Software Foundation, Inc.,
+ *	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef _SYSDEPS_H_
+#define _SYSDEPS_H_
+
+extern size_t strlcpy(char *dst, const char *src, size_t size);
+extern size_t strlcat(char *dst, const char *src, size_t size);
+
+#endif
diff --git a/brcm_iscsi_uio/include/uip_mgmt_ipc.h b/brcm_iscsi_uio/include/uip_mgmt_ipc.h
new file mode 100644
index 0000000..79c9b79
--- /dev/null
+++ b/brcm_iscsi_uio/include/uip_mgmt_ipc.h
@@ -0,0 +1,64 @@
+/*
+ * uIP iSCSI Daemon/Admin Management IPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#ifndef UIP_MGMT_IPC_H
+#define UIP_MGMT_IPC_H
+
+//#include "types.h"
+#include "iscsi_if.h"
+#include "config.h"
+#include "mgmt_ipc.h"
+
+#define ISCSID_UIP_NAMESPACE	"ISCSID_UIP_ABSTRACT_NAMESPACE"
+
+typedef enum iscsid_uip_cmd {
+	ISCSID_UIP_IPC_UNKNOWN                  = 0,
+	ISCSID_UIP_IPC_GET_IFACE                = 1,
+
+	__ISCSID_UIP_IPC_MAX_COMMAND
+} iscsid_uip_cmd_e;
+
+
+typedef struct iscsid_uip_broadcast_header {
+	iscsid_uip_cmd_e command;
+	uint32_t payload_len;
+} iscsid_uip_broadcast_header_t;
+
+/* IPC Request */
+typedef struct iscsid_uip_broadcast {
+	struct iscsid_uip_broadcast_header header;
+
+	union {
+		/* messages */
+		struct ipc_broadcast_iface_rec {
+			struct iface_rec rec;
+		} iface_rec;
+	} u;
+} iscsid_uip_broadcast_t;
+
+typedef enum iscsid_uip_mgmt_ipc_err {
+	ISCSID_UIP_MGMT_IPC_OK                     = 0,
+	ISCISD_UIP_MGMT_IPC_ERR                    = 1,
+	ISCISD_UIP_MGMT_IPC_ERR_NOT_FOUND          = 2,
+	ISCISD_UIP_MGMT_IPC_ERR_NOMEM              = 3,
+} iscsid_uip_mgmt_ipc_err_e;
+
+/* IPC Response */
+typedef struct iscsid_uip_mgmt_rsp {
+	iscsid_uip_cmd_e command;
+	iscsid_uip_mgmt_ipc_err_e err;
+} iscsid_uip_rsp_t;
+
+#endif /* UIP_MGMT_IPC_H */
diff --git a/brcm_iscsi_uio/src/Makefile.am b/brcm_iscsi_uio/src/Makefile.am
new file mode 100644
index 0000000..44b0085
--- /dev/null
+++ b/brcm_iscsi_uio/src/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apps uip unix
diff --git a/brcm_iscsi_uio/src/README b/brcm_iscsi_uio/src/README
new file mode 100644
index 0000000..b501538
--- /dev/null
+++ b/brcm_iscsi_uio/src/README
@@ -0,0 +1,13 @@
+uIP is a very small implementation of the TCP/IP stack that is written
+by Adam Dunkels <adam@sics.se>. More information can be obtained 
+at the uIP homepage at http://www.sics.se/~adam/uip/.
+
+This is version $Name: uip-1-0 $.
+
+The directory structure look as follows:
+
+apps/  - Example applications
+doc/   - Documentation
+lib/   - Library code used by some applications
+uip/   - uIP TCP/IP stack code
+unix/  - uIP as a user space process under FreeBSD or Linux
diff --git a/brcm_iscsi_uio/src/apps/Makefile.am b/brcm_iscsi_uio/src/apps/Makefile.am
new file mode 100644
index 0000000..08ed18d
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = dhcpc brcm-iscsi
diff --git a/brcm_iscsi_uio/src/apps/README b/brcm_iscsi_uio/src/apps/README
new file mode 100644
index 0000000..0096c4e
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/README
@@ -0,0 +1,2 @@
+This directory contains a few example applications. They are not all
+heavily tested, however.
diff --git a/brcm_iscsi_uio/src/apps/brcm-iscsi/Makefile.am b/brcm_iscsi_uio/src/apps/brcm-iscsi/Makefile.am
new file mode 100644
index 0000000..1b30671
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/brcm-iscsi/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES =	-I${top_srcdir}/src/unix	\
+		-I${top_srcdir}/src/uip		\
+		-I${top_srcdir}/src/apps/dhcpc	\
+		-I${top_srcdir}/src/apps/brcm-iscsi	\
+		-I${top_srcdir}/include
+
+noinst_LIBRARIES = libbrcm_apps_brcm_iscsi.a
+
+libbrcm_apps_brcm_iscsi_a_SOURCES = 	brcm_iscsi.c
+
+libbrcm_apps_brcm_iscsi_a_CFLAGS =	$(AM_CFLAGS)             \
+					-DBYTE_ORDER=@ENDIAN@
diff --git a/brcm_iscsi_uio/src/apps/brcm-iscsi/Makefile.brcm-iscsi b/brcm_iscsi_uio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
new file mode 100644
index 0000000..732275f
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
@@ -0,0 +1 @@
+APP_SOURCES += brcm-iscsi.c
diff --git a/brcm_iscsi_uio/src/apps/brcm-iscsi/brcm_iscsi.c b/brcm_iscsi_uio/src/apps/brcm-iscsi/brcm_iscsi.c
new file mode 100644
index 0000000..8ac75cc
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/brcm-iscsi/brcm_iscsi.c
@@ -0,0 +1,53 @@
+/**
+ * \addtogroup brcm-iscsi
+ * @{
+ */
+
+/**
+ * \file
+ *         An example of how to write uIP applications
+ *         with protosockets.
+ * \author
+ *         Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * This is a short example of how to write uIP applications using
+ * protosockets.
+ */
+
+/*
+ * We define the application state (struct hello_world_state) in the
+ * hello-world.h file, so we need to include it here. We also include
+ * uip.h (since this cannot be included in hello-world.h) and
+ * <string.h>, since we use the memcpy() function in the code.
+ */
+#include "brcm_iscsi.h"
+#include "uip.h"
+#include <string.h>
+#include <stdio.h>
+
+#include "uip_arp.h"
+
+/*---------------------------------------------------------------------------*/
+/*
+ * The initialization function. We must explicitly call this function
+ * from the system initialization code, some time after uip_init() is
+ * called.
+ */
+void
+brcm_iscsi_init(void)
+{
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * In hello-world.h we have defined the UIP_APPCALL macro to
+ * hello_world_appcall so that this funcion is uIP's application
+ * function. This function is called whenever an uIP event occurs
+ * (e.g. when a new connection is established, new data arrives, sent
+ * data is acknowledged, data needs to be retransmitted, etc.).
+ */
+void
+brcm_iscsi_appcall(struct uip_stack *ustack)
+{
+}
diff --git a/brcm_iscsi_uio/src/apps/brcm-iscsi/brcm_iscsi.h b/brcm_iscsi_uio/src/apps/brcm-iscsi/brcm_iscsi.h
new file mode 100644
index 0000000..94a67ae
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/brcm-iscsi/brcm_iscsi.h
@@ -0,0 +1,54 @@
+/**
+ * \addtogroup apps
+ * @{
+ */
+
+/**
+ * \defgroup helloworld Hello, world
+ * @{
+ *
+ * A small example showing how to write applications with
+ * \ref psock "protosockets".
+ */
+
+/**
+ * \file
+ *         Header file for an example of how to write uIP applications
+ *         with protosockets.
+ * \author
+ *         Benjamin Li <benli@broadcom.com>
+ */
+
+#ifndef __BRCM_ISCSI_H__
+#define __BRCM_ISCSI_H__
+
+/* Since this file will be included by uip.h, we cannot include uip.h
+   here. But we might need to include uipopt.h if we need the u8_t and
+   u16_t datatypes. */
+#include "uipopt.h"
+#include "uip.h"
+#include "psock.h"
+
+/* Next, we define the uip_tcp_appstate_t datatype. This is the state
+   of our application, and the memory required for this state is
+   allocated together with each TCP connection. One application state
+   for each TCP connection. */
+typedef struct hello_world_state {
+  struct psock p;
+  u8_t inputbuffer[32];
+  u8_t name[40];
+
+  struct uip_udp_conn *conn;
+} uip_tcp_appstate_t;
+
+/* Finally we define the application function to be called by uIP. */
+void brcm_iscsi_appcall(struct uip_stack *ustack);
+#ifndef UIP_APPCALL
+#define UIP_APPCALL brcm_iscsi_appcall 
+#endif /* UIP_APPCALL */
+
+void brcm_iscsi_init(void);
+
+#endif /* __BRCM_ISCSI_H__ */
+/** @} */
+/** @} */
diff --git a/brcm_iscsi_uio/src/apps/dhcpc/Makefile.am b/brcm_iscsi_uio/src/apps/dhcpc/Makefile.am
new file mode 100644
index 0000000..936c7f1
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/dhcpc/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES =	-I${top_srcdir}/src/unix	\
+		-I${top_srcdir}/src/uip		\
+		-I${top_srcdir}/src/apps/dhcpc	\
+		-I${top_srcdir}/src/apps/brcm-iscsi \
+		-I${top_srcdir}/include
+
+noinst_LIBRARIES = libbrcm_apps_dhcpc.a
+
+libbrcm_apps_dhcpc_a_SOURCES = 	dhcpc.c
+
+libbrcm_apps_dhcpc_a_CFLAGS =	$(AM_CFLAGS)             \
+				-DBYTE_ORDER=@ENDIAN@
+
+
diff --git a/brcm_iscsi_uio/src/apps/dhcpc/Makefile.dhcpc b/brcm_iscsi_uio/src/apps/dhcpc/Makefile.dhcpc
new file mode 100644
index 0000000..f84c84f
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/dhcpc/Makefile.dhcpc
@@ -0,0 +1 @@
+APP_SOURCES += dhcpc.c timer.c
diff --git a/brcm_iscsi_uio/src/apps/dhcpc/dhcpc.c b/brcm_iscsi_uio/src/apps/dhcpc/dhcpc.c
new file mode 100644
index 0000000..425eb51
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/dhcpc/dhcpc.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2005, Swedish Institute of Computer Science
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include "uip.h"
+#include "dhcpc.h"
+#include "timer.h"
+#include "pt.h"
+
+#include "debug.h"
+#include "logger.h"
+#include "nic.h"
+#include "nic_utils.h"
+
+struct __attribute__ ((__packed__)) dhcp_msg {
+	u8_t op, htype, hlen, hops;
+	u8_t xid[4];
+	u16_t secs, flags;
+	u8_t ciaddr[4];
+	u8_t yiaddr[4];
+	u8_t siaddr[4];
+	u8_t giaddr[4];
+	u8_t chaddr[16];
+#ifndef UIP_CONF_DHCP_LIGHT
+	u8_t sname[64];
+	u8_t file[128];
+#endif
+	u8_t options[312];
+};
+
+#define BOOTP_BROADCAST 0x8000
+
+#define DHCP_REQUEST        1
+#define DHCP_REPLY          2
+#define DHCP_HTYPE_ETHERNET 1
+#define DHCP_HLEN_ETHERNET  6
+#define DHCP_MSG_LEN      236
+
+#define DHCPC_SERVER_PORT  67
+#define DHCPC_CLIENT_PORT  68
+
+#define DHCPDISCOVER  1
+#define DHCPOFFER     2
+#define DHCPREQUEST   3
+#define DHCPDECLINE   4
+#define DHCPACK       5
+#define DHCPNAK       6
+#define DHCPRELEASE   7
+
+#define DHCP_OPTION_SUBNET_MASK   1
+#define DHCP_OPTION_ROUTER        3
+#define DHCP_OPTION_DNS_SERVER    6
+#define DHCP_OPTION_REQ_IPADDR   50
+#define DHCP_OPTION_LEASE_TIME   51
+#define DHCP_OPTION_MSG_TYPE     53
+#define DHCP_OPTION_SERVER_ID    54
+#define DHCP_OPTION_REQ_LIST     55
+#define DHCP_OPTION_END         255
+
+static u8_t xid[4] = { 0xad, 0xde, 0x12, 0x23 };
+static const u8_t magic_cookie[4] = { 99, 130, 83, 99 };
+
+struct dhcpc_options dhcpc_opt = {
+	.enable_random_xid = 1,
+};
+
+/*---------------------------------------------------------------------------*/
+static u8_t *add_msg_type(u8_t * optptr, u8_t type)
+{
+	*optptr++ = DHCP_OPTION_MSG_TYPE;
+	*optptr++ = 1;
+	*optptr++ = type;
+	return optptr;
+}
+
+/*---------------------------------------------------------------------------*/
+static u8_t *add_server_id(struct dhcpc_state *s, u8_t * optptr)
+{
+	*optptr++ = DHCP_OPTION_SERVER_ID;
+	*optptr++ = 4;
+	memcpy(optptr, s->serverid, 4);
+	return optptr + 4;
+}
+
+/*---------------------------------------------------------------------------*/
+static u8_t *add_req_ipaddr(struct dhcpc_state *s, u8_t * optptr)
+{
+	*optptr++ = DHCP_OPTION_REQ_IPADDR;
+	*optptr++ = 4;
+	memcpy(optptr, s->ipaddr, 4);
+	return optptr + 4;
+}
+
+/*---------------------------------------------------------------------------*/
+static u8_t *add_req_options(u8_t * optptr)
+{
+	*optptr++ = DHCP_OPTION_REQ_LIST;
+	*optptr++ = 3;
+	*optptr++ = DHCP_OPTION_SUBNET_MASK;
+	*optptr++ = DHCP_OPTION_ROUTER;
+	*optptr++ = DHCP_OPTION_DNS_SERVER;
+	return optptr;
+}
+
+/*---------------------------------------------------------------------------*/
+static u8_t *add_end(u8_t * optptr)
+{
+	*optptr++ = DHCP_OPTION_END;
+	return optptr;
+}
+
+/*---------------------------------------------------------------------------*/
+static void create_msg(struct dhcpc_state *s, struct dhcp_msg *m)
+{
+	m->op = DHCP_REQUEST;
+	m->htype = DHCP_HTYPE_ETHERNET;
+	m->hlen = s->mac_len;
+	m->hops = 0;
+	memcpy(m->xid, xid, sizeof(m->xid));
+	m->secs = 0;
+	m->flags = const_htons(BOOTP_BROADCAST);	/*  Broadcast bit. */
+	/*  uip_ipaddr_copy(m->ciaddr, uip_hostaddr); */
+	memcpy(m->ciaddr, s->ustack->hostaddr, sizeof(m->ciaddr));
+	memset(m->yiaddr, 0, sizeof(m->yiaddr));
+	memset(m->siaddr, 0, sizeof(m->siaddr));
+	memset(m->giaddr, 0, sizeof(m->giaddr));
+	memcpy(m->chaddr, s->mac_addr, s->mac_len);
+	memset(&m->chaddr[s->mac_len], 0, sizeof(m->chaddr) - s->mac_len);
+#ifndef UIP_CONF_DHCP_LIGHT
+	memset(m->sname, 0, sizeof(m->sname));
+	memset(m->file, 0, sizeof(m->file));
+#endif
+
+	memcpy(m->options, magic_cookie, sizeof(magic_cookie));
+}
+
+/*---------------------------------------------------------------------------*/
+static void send_discover(struct dhcpc_state *s)
+{
+	u8_t *end;
+	struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata;
+
+	create_msg(s, m);
+
+	end = add_msg_type(&m->options[4], DHCPDISCOVER);
+	end = add_req_options(end);
+	end = add_end(end);
+
+	uip_send(s->ustack, s->ustack->uip_appdata,
+		 end - (u8_t *) s->ustack->uip_appdata);
+}
+
+/*---------------------------------------------------------------------------*/
+static void send_request(struct dhcpc_state *s)
+{
+	u8_t *end;
+	struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata;
+
+	create_msg(s, m);
+
+	end = add_msg_type(&m->options[4], DHCPREQUEST);
+	end = add_server_id(s, end);
+	end = add_req_ipaddr(s, end);
+	end = add_end(end);
+
+	uip_send(s->ustack, s->ustack->uip_appdata,
+		 end - (u8_t *) s->ustack->uip_appdata);
+}
+
+/*---------------------------------------------------------------------------*/
+static u8_t parse_options(struct dhcpc_state *s, u8_t * optptr, int len)
+{
+	u8_t *end = optptr + len;
+	u8_t type = 0;
+
+	while (optptr < end) {
+		switch (*optptr) {
+		case DHCP_OPTION_SUBNET_MASK:
+			memcpy(s->netmask, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_ROUTER:
+			memcpy(s->default_router, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_DNS_SERVER:
+			memcpy(s->dnsaddr, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_MSG_TYPE:
+			type = *(optptr + 2);
+			break;
+		case DHCP_OPTION_SERVER_ID:
+			memcpy(s->serverid, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_LEASE_TIME:
+			memcpy(s->lease_time, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_END:
+			return type;
+		}
+
+		optptr += optptr[1] + 2;
+	}
+	return type;
+}
+
+/*---------------------------------------------------------------------------*/
+static u8_t parse_msg(struct dhcpc_state *s)
+{
+	struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata;
+
+	if (m->op == DHCP_REPLY &&
+	    memcmp(m->xid, xid, sizeof(xid)) == 0 &&
+	    memcmp(m->chaddr, s->mac_addr, s->mac_len) == 0) {
+		memcpy(s->ipaddr, m->yiaddr, 4);
+		return parse_options(s, &m->options[4], uip_datalen(s->ustack));
+	}
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static PT_THREAD(handle_dhcp(struct uip_stack *ustack))
+{
+	struct dhcpc_state *s;
+	s = ustack->dhcpc;
+
+	PT_BEGIN(&s->pt);
+
+	if(s == NULL)
+	{
+		LOG_WARN("Could not find dhcpc state");
+		goto dhcpc_state_null;
+	}
+
+	/* try_again: */
+	s->state = STATE_SENDING;
+	s->ticks = CLOCK_SECOND;
+
+	do {
+		send_discover(s);
+		timer_set(&s->timer, s->ticks);
+		PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)
+			      || timer_expired(&s->timer));
+
+		if (uip_newdata(s->ustack) && parse_msg(s) == DHCPOFFER) {
+			s->state = STATE_OFFER_RECEIVED;
+			break;
+		}
+
+		if (s->ticks < CLOCK_SECOND * 60) {
+			s->ticks *= 2;
+		}
+	} while (s->state != STATE_OFFER_RECEIVED);
+
+	s->ticks = CLOCK_SECOND;
+
+	do {
+		send_request(s);
+		timer_set(&s->timer, s->ticks);
+		s->ustack->uip_flags &= ~UIP_NEWDATA;
+		PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)
+			      || timer_expired(&s->timer));
+
+		if (uip_newdata(s->ustack) && parse_msg(s) == DHCPACK) {
+			s->state = STATE_CONFIG_RECEIVED;
+			break;
+		}
+
+		if (s->ticks <= CLOCK_SECOND * 10) {
+			s->ticks += CLOCK_SECOND;
+		} else {
+			PT_RESTART(&s->pt);
+		}
+	} while (s->state != STATE_CONFIG_RECEIVED);
+
+	LOG_INFO("Got IP address %d.%d.%d.%d",
+		 uip_ipaddr1(s->ipaddr), uip_ipaddr2(s->ipaddr),
+		 uip_ipaddr3(s->ipaddr), uip_ipaddr4(s->ipaddr));
+	LOG_INFO("Got netmask %d.%d.%d.%d",
+		 uip_ipaddr1(s->netmask), uip_ipaddr2(s->netmask),
+		 uip_ipaddr3(s->netmask), uip_ipaddr4(s->netmask));
+	LOG_INFO("Got DNS server %d.%d.%d.%d",
+		 uip_ipaddr1(s->dnsaddr), uip_ipaddr2(s->dnsaddr),
+		 uip_ipaddr3(s->dnsaddr), uip_ipaddr4(s->dnsaddr));
+	LOG_INFO("Got default router %d.%d.%d.%d",
+		 uip_ipaddr1(s->default_router), uip_ipaddr2(s->default_router),
+		 uip_ipaddr3(s->default_router), uip_ipaddr4(s->default_router));
+	LOG_INFO("Lease expires in %ld seconds",
+		 ntohs(s->lease_time[0]) * 65536ul + ntohs(s->lease_time[1]));
+
+	s->last_update = time(NULL);
+
+	set_uip_stack(s->ustack,
+		      (uip_ip4addr_t *) s->ipaddr,
+		      (uip_ip4addr_t *) s->netmask,
+		      (uip_ip4addr_t *) s->default_router,
+		      (uint8_t  *) s->mac_addr);
+
+	/*  Put the stack thread back into a long sleep */
+	s->nic->state |= NIC_LONG_SLEEP;
+
+	/*  timer_stop(&s.timer); */
+
+	/*
+	 * PT_END restarts the thread so we do this instead. Eventually we
+	 * should reacquire expired leases here.
+	 */
+
+dhcpc_state_null:
+
+	while (1) {
+		PT_YIELD(&s->pt);
+	}
+
+	PT_END(&(s->pt));
+}
+
+/*---------------------------------------------------------------------------*/
+int dhcpc_init(nic_t *nic, struct uip_stack *ustack,
+	       const void *mac_addr, int mac_len)
+{
+	uip_ip4addr_t addr;
+
+	struct dhcpc_state *s = malloc(sizeof(*s));
+	if(s == NULL)
+	{
+		LOG_ERR("Couldn't allocate size for dhcpc info");
+		return -ENOMEM;
+	}
+
+	memset(s, 0, sizeof(*s));
+	s->nic    = nic;
+	s->ustack = ustack;
+	s->mac_addr = mac_addr;
+	s->mac_len  = mac_len;
+	s->state    = STATE_INITIAL;
+
+	/*  Initialize XID to randomly */
+	if (dhcpc_opt.enable_random_xid == 1) {
+		u32_t gen_xid;
+		gen_xid = random();
+		memcpy(xid, &gen_xid, sizeof(gen_xid));
+	}
+
+	s->state = STATE_INITIAL;
+	uip_ipaddr(addr, 255, 255, 255, 255);
+	s->conn = uip_udp_new(ustack, &addr, const_htons(DHCPC_SERVER_PORT));
+	if (s->conn != NULL) {
+		uip_udp_bind(s->conn, const_htons(DHCPC_CLIENT_PORT));
+	}
+
+	ustack->dhcpc = s;
+
+	/* Let the RX poll value take over */
+	nic->state &= ~NIC_LONG_SLEEP;
+
+	PT_INIT(&s->pt);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+void dhcpc_appcall(struct uip_stack *ustack)
+{
+	handle_dhcp(ustack);
+}
+
+/*---------------------------------------------------------------------------*/
+void dhcpc_request(struct uip_stack *ustack)
+{
+	struct dhcpc_state *s = ustack->dhcpc;
+
+	if (s != NULL &&
+	    s->state == STATE_INITIAL) {
+		handle_dhcp(ustack);
+	}
+}
+
+/*---------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/apps/dhcpc/dhcpc.h b/brcm_iscsi_uio/src/apps/dhcpc/dhcpc.h
new file mode 100644
index 0000000..81f8aa0
--- /dev/null
+++ b/brcm_iscsi_uio/src/apps/dhcpc/dhcpc.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005, Swedish Institute of Computer Science
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * @(#)$Id: dhcpc.h,v 1.3 2006/06/11 21:46:37 adam Exp $
+ */
+#ifndef __DHCPC_H__
+#define __DHCPC_H__
+
+#include <time.h>
+
+#include "nic.h"
+#include "timer.h"
+#include "pt.h"
+#include "uip.h"
+
+#define STATE_INITIAL         0
+#define STATE_SENDING         1
+#define STATE_OFFER_RECEIVED  2
+#define STATE_CONFIG_RECEIVED 3
+
+struct dhcpc_state {
+	struct pt pt;
+	
+	nic_t  *nic;
+	struct uip_stack *ustack;
+	char state;
+	struct uip_udp_conn *conn;
+	struct timer timer;
+	u16_t ticks;
+	const void *mac_addr;
+	int mac_len;
+
+	u8_t serverid[4];
+
+	u16_t lease_time[2];
+	u16_t ipaddr[2];
+	u16_t netmask[2];
+	u16_t dnsaddr[2];
+	u16_t default_router[2];
+
+	time_t last_update;
+};
+
+struct dhcpc_options {
+	u8_t enable_random_xid;
+	u8_t xid[4];
+};
+
+int dhcpc_init(nic_t *nic, struct uip_stack *ustack,
+	       const void *mac_addr, int mac_len);
+void dhcpc_request(struct uip_stack *ustack);
+
+void dhcpc_appcall(struct uip_stack *ustack);
+
+void dhcpc_configured(const struct dhcpc_state *s);
+
+typedef struct dhcpc_state uip_udp_appstate_t;
+#define UIP_UDP_APPCALL dhcpc_appcall
+
+#endif /* __DHCPC_H__ */
diff --git a/brcm_iscsi_uio/src/uip-1.0-changelog.txt b/brcm_iscsi_uio/src/uip-1.0-changelog.txt
new file mode 100644
index 0000000..1e6c61c
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip-1.0-changelog.txt
@@ -0,0 +1,98 @@
+* A new API: protosockets that are similar to BSD sockets but does not
+  require any underlying multithreading system. 
+
+* Very rudimentary IPv6 support
+
+* New application: DHCP client. Web server rewritten with protosockets.
+
+* Removed uIP zero-copy functionality in order to simplify uIP device
+  driver coding: outbound packets are now *always* stored in full in
+  the uip_buf buffer.
+
+* Checksum computation is now part of uip.c, but it still is possible
+  to implement them in assembly code by specifying a configuration
+  option. Checksum code now runs on architectures with 2-byte alignment.
+  
+* Added TCP persistent timer.
+
+* Made all IP address representations use the new uip_ipaddr_ip
+  datatype for clarity.
+
+* Updated window behavior so that sending to a host with a small open
+  window works better now.
+
+* UDP API change: uip_udp_new() now takes port numbers in network byte
+  order like TCP functions.
+
+* Allow reception of packets when no IP address is configured to make
+  DHCP work.
+
+* Moved Ethernet address into main uIP module from ARP module.
+
+* Made constants explicit #defines and moved them out of the code
+  (header sizes, TCP options, TCP header length field). 
+
+* If uip_len is less than that reported by the IP header, the packet
+  is discarded. If uip_len is greater than the length reported by the
+  IP header, uip_len is adjusted.
+
+* Moved header size definitions into header file.
+
+* Added uIP call for polling an application without triggering any
+  timer events. Removed redundant assignments of uip_len and uip_slen.
+
+* Removed compiler warning about icmp_input label being defined when
+  UIP_PINGADDRCONF was not used.
+
+* Added UIP_APPDATA_SIZE macro that holds the available buffer size
+  for user data.
+
+* Added uip_udp_bind() call.
+
+* Moved checksum code into main uIP module.
+
+* Switched the TCP, UDP and IP header structures to be structs rather
+  than typedefs.
+
+* Prefixed TCP state names with UIP_ to avoid name space
+  contamination. 
+
+* Changed declarations of uip_appdatap and friends to void * to avoid
+  explicit typecasts. 
+
+* Bugfixes
+ 
+  o TCP: Fixed bug with high byte of peer window size.
+
+  o TCP: Fixed bug that in some cases prevented concurrent reception and
+    transmission of TCP data.
+
+  o TCP: uip_connect() didn't correctly calculate age of TIME_WAIT
+    connections.
+
+  o TCP: Array index for uip_conns[] array was out of bounds in
+    comparison. Comparison changed to make index within bounds.
+
+  o TCP: if the remote host crashes and tries to reestablish an old
+    connection, uIP should respond with an ACK with the correct
+    sequence and acknowledgment numbers, to which the remote host
+    should respond with an ACK. uIP did not respond with the correct
+    ACK.
+
+  o TCP: Fixed check for SYNACK segment: now checks only relevant TCP
+    control flags and discards flags reserved for future expansion.
+
+  o TCP: Fixed bug where uIP did not inform application that a connection
+    had been aborted during an active open.
+
+  o TCP: FIN segment was accepted even though application had stopped
+    incoming data with uip_stop().
+
+  o TCP: A FINACK segment would not always correctly acknowledge data.
+
+  o UDP: checksums are now calculated after all fields have been
+    filled in.
+
+  o UDP: network byte order on lastport in uip_udp_new().
+
+  o IP: memset() bugs in IP fragment reassembly code fixed.
diff --git a/brcm_iscsi_uio/src/uip/Makefile.am b/brcm_iscsi_uio/src/uip/Makefile.am
new file mode 100644
index 0000000..ea054b0
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES =	-I${top_srcdir}/src/unix	\
+		-I${top_srcdir}/src/apps/dhcpc	\
+		-I${top_srcdir}/src/apps/brcm-iscsi \
+		-I${top_srcdir}/include
+
+noinst_LIBRARIES = libbrcm_iscsi_uip.a
+
+libbrcm_iscsi_uip_a_SOURCES = 	uip.c		\
+				uip_arp.c	\
+				uiplib.c	\
+				psock.c		\
+				timer.c		\
+				uip-neighbor.c	\
+				uip_eth.c
+
+libbrcm_iscsi_uip_a_CFLAGS = 	-DBYTE_ORDER=@ENDIAN@
diff --git a/brcm_iscsi_uio/src/uip/Makefile.include b/brcm_iscsi_uio/src/uip/Makefile.include
new file mode 100644
index 0000000..5e042ca
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/Makefile.include
@@ -0,0 +1,47 @@
+
+
+ifdef APPS
+  APPDIRS = $(foreach APP, $(APPS), ../apps/$(APP))
+  -include $(foreach APP, $(APPS), ../apps/$(APP)/Makefile.$(APP))
+  CFLAGS += $(addprefix -I../apps/,$(APPS))
+endif
+
+ifndef CCDEP
+  CCDEP = $(CC)
+endif
+ifndef CCDEPCFLAGS
+  CCDEPCFLAGS = $(CFLAGS)
+endif
+ifndef OBJECTDIR
+  OBJECTDIR = obj
+endif
+
+ifeq (${wildcard $(OBJECTDIR)},)
+  DUMMY := ${shell mkdir $(OBJECTDIR)}
+endif
+
+
+vpath %.c . ../uip ../lib $(APPDIRS)
+
+$(OBJECTDIR)/%.o: %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJECTDIR)/%.d: %.c
+	@set -e; rm -f $@; \
+	$(CCDEP) -MM $(CCDEPCFLAGS) $< > $@.$$$$; \
+	sed 's,\($*\)\.o[ :]*,$(OBJECTDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \
+	rm -f $@.$$$$
+
+UIP_SOURCES=uip.c uip_arp.c uiplib.c psock.c timer.c uip-neighbor.c uip_eth.c
+
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(addprefix $(OBJECTDIR)/,$(UIP_SOURCES:.c=.d) \
+                                   $(APP_SOURCES:.c=.d))
+endif
+
+libuip.a: ${addprefix $(OBJECTDIR)/, $(UIP_SOURCES:.c=.o)}
+	$(AR) rc $@ $^
+
+libapps.a: ${addprefix $(OBJECTDIR)/, $(APP_SOURCES:.c=.o)}
+	$(AR) rc $@ $^
diff --git a/brcm_iscsi_uio/src/uip/clock.h b/brcm_iscsi_uio/src/uip/clock.h
new file mode 100644
index 0000000..f34d78f
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/clock.h
@@ -0,0 +1,88 @@
+/**
+ * \defgroup clock Clock interface
+ *
+ * The clock interface is the interface between the \ref timer "timer library"
+ * and the platform specific clock functionality. The clock
+ * interface must be implemented for each platform that uses the \ref
+ * timer "timer library".
+ *
+ * The clock interface does only one this: it measures time. The clock
+ * interface provides a macro, CLOCK_SECOND, which corresponds to one
+ * second of system time.
+ *
+ * \sa \ref timer "Timer library"
+ *
+ * @{
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: clock.h,v 1.3 2006/06/11 21:46:39 adam Exp $
+ */
+#ifndef __CLOCK_H__
+#define __CLOCK_H__
+
+#include "clock-arch.h"
+
+/**
+ * Initialize the clock library.
+ *
+ * This function initializes the clock library and should be called
+ * from the main() function of the system.
+ *
+ */
+void clock_init(void);
+
+/**
+ * Get the current clock time.
+ *
+ * This function returns the current system clock time.
+ *
+ * \return The current clock time, measured in system ticks.
+ */
+clock_time_t clock_time(void);
+
+/**
+ * A second, measured in system clock time.
+ *
+ * \hideinitializer
+ */
+#ifdef CLOCK_CONF_SECOND
+#define CLOCK_SECOND CLOCK_CONF_SECOND
+#else
+#define CLOCK_SECOND (clock_time_t)32
+#endif
+
+#endif /* __CLOCK_H__ */
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/debug.h b/brcm_iscsi_uio/src/uip/debug.h
new file mode 100644
index 0000000..9d5ebbe
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/debug.h
@@ -0,0 +1,9 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#ifdef DEBUG
+#define UIP_DEBUG(args...)  fprintf(stdout, args); fflush(stdout)
+#else
+#endif
+
+#endif
diff --git a/brcm_iscsi_uio/src/uip/lc-addrlabels.h b/brcm_iscsi_uio/src/uip/lc-addrlabels.h
new file mode 100644
index 0000000..fe1387e
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/lc-addrlabels.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc-addrlabels.h,v 1.3 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \addtogroup lc
+ * @{
+ */
+
+/**
+ * \file
+ * Implementation of local continuations based on the "Labels as
+ * values" feature of gcc
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ * This implementation of local continuations is based on a special
+ * feature of the GCC C compiler called "labels as values". This
+ * feature allows assigning pointers with the address of the code
+ * corresponding to a particular C label.
+ *
+ * For more information, see the GCC documentation:
+ * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+ *
+ * Thanks to dividuum for finding the nice local scope label
+ * implementation.
+ */
+
+#ifndef __LC_ADDRLABELS_H__
+#define __LC_ADDRLABELS_H__
+
+/** \hideinitializer */
+typedef void * lc_t;
+
+#define LC_INIT(s) s = NULL
+
+
+#define LC_RESUME(s)                            \
+  do {                                          \
+    if(s != NULL) {                             \
+      goto *s;                                  \
+    }                                           \
+  } while(0)
+
+#define LC_SET(s)                               \
+  do { ({ __label__ resume; resume: (s) = &&resume; }); }while(0)
+
+#define LC_END(s)
+
+#endif /* __LC_ADDRLABELS_H__ */
+
+/**  @} */
diff --git a/brcm_iscsi_uio/src/uip/lc-switch.h b/brcm_iscsi_uio/src/uip/lc-switch.h
new file mode 100644
index 0000000..f32885f
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/lc-switch.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc-switch.h,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \addtogroup lc
+ * @{
+ */
+
+/**
+ * \file
+ * Implementation of local continuations based on switch() statment
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ * This implementation of local continuations uses the C switch()
+ * statement to resume execution of a function somewhere inside the
+ * function's body. The implementation is based on the fact that
+ * switch() statements are able to jump directly into the bodies of
+ * control structures such as if() or while() statmenets.
+ *
+ * This implementation borrows heavily from Simon Tatham's coroutines
+ * implementation in C:
+ * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
+ */
+
+#ifndef __LC_SWITCH_H__
+#define __LC_SWTICH_H__
+
+/* WARNING! lc implementation using switch() does not work if an
+   LC_SET() is done within another switch() statement! */
+
+/** \hideinitializer */
+typedef unsigned short lc_t;
+
+#define LC_INIT(s) s = 0;
+
+#define LC_RESUME(s) switch(s) { case 0:
+
+#define LC_SET(s) s = __LINE__; case __LINE__:
+
+#define LC_END(s) }
+
+#endif /* __LC_SWITCH_H__ */
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/lc.h b/brcm_iscsi_uio/src/uip/lc.h
new file mode 100644
index 0000000..a9e9d46
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/lc.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc.h,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \defgroup lc Local continuations
+ * @{
+ *
+ * Local continuations form the basis for implementing protothreads. A
+ * local continuation can be <i>set</i> in a specific function to
+ * capture the state of the function. After a local continuation has
+ * been set can be <i>resumed</i> in order to restore the state of the
+ * function at the point where the local continuation was set.
+ *
+ *
+ */
+
+/**
+ * \file lc.h
+ * Local continuations
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifdef DOXYGEN
+/**
+ * Initialize a local continuation.
+ *
+ * This operation initializes the local continuation, thereby
+ * unsetting any previously set continuation state.
+ *
+ * \hideinitializer
+ */
+#define LC_INIT(lc)
+
+/**
+ * Set a local continuation.
+ *
+ * The set operation saves the state of the function at the point
+ * where the operation is executed. As far as the set operation is
+ * concerned, the state of the function does <b>not</b> include the
+ * call-stack or local (automatic) variables, but only the program
+ * counter and such CPU registers that needs to be saved.
+ *
+ * \hideinitializer
+ */
+#define LC_SET(lc)
+
+/**
+ * Resume a local continuation.
+ *
+ * The resume operation resumes a previously set local continuation, thus
+ * restoring the state in which the function was when the local
+ * continuation was set. If the local continuation has not been
+ * previously set, the resume operation does nothing.
+ *
+ * \hideinitializer
+ */
+#define LC_RESUME(lc)
+
+/**
+ * Mark the end of local continuation usage.
+ *
+ * The end operation signifies that local continuations should not be
+ * used any more in the function. This operation is not needed for
+ * most implementations of local continuation, but is required by a
+ * few implementations.
+ *
+ * \hideinitializer
+ */
+#define LC_END(lc)
+
+/**
+ * \var typedef lc_t;
+ *
+ * The local continuation type.
+ *
+ * \hideinitializer
+ */
+#endif /* DOXYGEN */
+
+#ifndef __LC_H__
+#define __LC_H__
+
+#ifdef LC_CONF_INCLUDE
+#include LC_CONF_INCLUDE
+#else
+#include "lc-switch.h"
+#endif /* LC_CONF_INCLUDE */
+
+#endif /* __LC_H__ */
+
+/** @} */
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/psock.c b/brcm_iscsi_uio/src/uip/psock.c
new file mode 100644
index 0000000..80fdb85
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/psock.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: psock.c,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "uipopt.h"
+#include "psock.h"
+#include "uip.h"
+
+#define STATE_NONE 0
+#define STATE_ACKED 1
+#define STATE_READ 2
+#define STATE_BLOCKED_NEWDATA 3
+#define STATE_BLOCKED_CLOSE 4
+#define STATE_BLOCKED_SEND 5
+#define STATE_DATA_SENT 6
+
+/*
+ * Return value of the buffering functions that indicates that a
+ * buffer was not filled by incoming data.
+ *
+ */
+#define BUF_NOT_FULL 0
+#define BUF_NOT_FOUND 0
+
+/*
+ * Return value of the buffering functions that indicates that a
+ * buffer was completely filled by incoming data.
+ *
+ */
+#define BUF_FULL 1
+
+/*
+ * Return value of the buffering functions that indicates that an
+ * end-marker byte was found.
+ *
+ */
+#define BUF_FOUND 2
+
+/*---------------------------------------------------------------------------*/
+static void
+buf_setup(struct psock_buf *buf,
+	  u8_t *bufptr, u16_t bufsize)
+{
+  buf->ptr = bufptr;
+  buf->left = bufsize;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t
+buf_bufdata(struct psock_buf *buf, u16_t len,
+	    u8_t **dataptr, u16_t *datalen)
+{
+  if(*datalen < buf->left) {
+    memcpy(buf->ptr, *dataptr, *datalen);
+    buf->ptr += *datalen;
+    buf->left -= *datalen;
+    *dataptr += *datalen;
+    *datalen = 0;
+    return BUF_NOT_FULL;
+  } else if(*datalen == buf->left) {
+    memcpy(buf->ptr, *dataptr, *datalen);
+    buf->ptr += *datalen;
+    buf->left = 0;
+    *dataptr += *datalen;
+    *datalen = 0;
+    return BUF_FULL;
+  } else {
+    memcpy(buf->ptr, *dataptr, buf->left);
+    buf->ptr += buf->left;
+    *datalen -= buf->left;
+    *dataptr += buf->left;
+    buf->left = 0;
+    return BUF_FULL;
+  }
+}
+/*---------------------------------------------------------------------------*/
+static u8_t
+buf_bufto(register struct psock_buf *buf, u8_t endmarker,
+	  register u8_t **dataptr, register u16_t *datalen)
+{
+  u8_t c;
+  while(buf->left > 0 && *datalen > 0) {
+    c = *buf->ptr = **dataptr;
+    ++*dataptr;
+    ++buf->ptr;
+    --*datalen;
+    --buf->left;
+    
+    if(c == endmarker) {
+      return BUF_FOUND;
+    }
+  }
+
+  if(*datalen == 0) {
+    return BUF_NOT_FOUND;
+  }
+
+  while(*datalen > 0) {
+    c = **dataptr;
+    --*datalen;
+    ++*dataptr;
+    
+    if(c == endmarker) {
+      return BUF_FOUND | BUF_FULL;
+    }
+  }
+  
+  return BUF_FULL;
+}
+/*---------------------------------------------------------------------------*/
+static char
+send_data(register struct psock *s)
+{
+  if(s->state != STATE_DATA_SENT || uip_rexmit(s->ustack)) {
+    if(s->sendlen > uip_mss(s->ustack)) {
+      uip_send(s->ustack, s->sendptr, uip_mss(s->ustack));
+    } else {
+      uip_send(s->ustack, s->sendptr, s->sendlen);
+    }
+    s->state = STATE_DATA_SENT;
+    return 1;
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+static char
+data_acked(struct psock *s)
+{
+  if(s->state == STATE_DATA_SENT && uip_acked(s->ustack)) {
+    if(s->sendlen > uip_mss(s->ustack)) {
+      s->sendlen -= uip_mss(s->ustack);
+      s->sendptr += uip_mss(s->ustack);
+    } else {
+      s->sendptr += s->sendlen;
+      s->sendlen = 0;
+    }
+    s->state = STATE_ACKED;
+    return 1;
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_send(struct uip_stack *ustack,
+		     register struct psock *s, const u8_t *buf,
+		     unsigned int len))
+{
+  PT_BEGIN(&s->psockpt);
+
+  /* If there is no data to send, we exit immediately. */
+  if(len == 0) {
+    PT_EXIT(&s->psockpt);
+  }
+
+  /* Save the length of and a pointer to the data that is to be
+     sent. */
+  s->sendptr = buf;
+  s->sendlen = len;
+
+  s->state = STATE_NONE;
+
+  /* We loop here until all data is sent. The s->sendlen variable is
+     updated by the data_sent() function. */
+  while(s->sendlen > 0) {
+
+    /*
+     * The condition for this PT_WAIT_UNTIL is a little tricky: the
+     * protothread will wait here until all data has been acknowledged
+     * (data_acked() returns true) and until all data has been sent
+     * (send_data() returns true). The two functions data_acked() and
+     * send_data() must be called in succession to ensure that all
+     * data is sent. Therefore the & operator is used instead of the
+     * && operator, which would cause only the data_acked() function
+     * to be called when it returns false.
+     */
+    PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
+  }
+
+  s->state = STATE_NONE;
+  
+  PT_END(&s->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_generator_send(register struct psock *s,
+			       unsigned short (*generate)(void *), void *arg))
+{
+  PT_BEGIN(&s->psockpt);
+
+  /* Ensure that there is a generator function to call. */
+  if(generate == NULL) {
+    PT_EXIT(&s->psockpt);
+  }
+
+  /* Call the generator function to generate the data in the
+     uip_appdata buffer. */
+  s->sendlen = generate(arg);
+  s->sendptr = s->ustack->uip_appdata;
+
+  s->state = STATE_NONE;  
+  do {
+    /* Call the generator function again if we are called to perform a
+       retransmission. */
+    if(uip_rexmit(s->ustack)) {
+      generate(arg);
+    }
+    /* Wait until all data is sent and acknowledged. */
+    PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
+  } while(s->sendlen > 0);
+  
+  s->state = STATE_NONE;
+  
+  PT_END(&s->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+u16_t
+psock_datalen(struct psock *psock)
+{
+  return psock->bufsize - psock->buf.left;
+}
+/*---------------------------------------------------------------------------*/
+char
+psock_newdata(struct psock *s)
+{
+  if(s->readlen > 0) {
+    /* There is data in the uip_appdata buffer that has not yet been
+       read with the PSOCK_READ functions. */
+    return 1;
+  } else if(s->state == STATE_READ) {
+    /* All data in uip_appdata buffer already consumed. */
+    s->state = STATE_BLOCKED_NEWDATA;
+    return 0;
+  } else if(uip_newdata(s->ustack)) {
+    /* There is new data that has not been consumed. */
+    return 1;
+  } else {
+    /* There is no new data. */
+    return 0;
+  }
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_readto(register struct psock *psock, u8_t c))
+{
+  PT_BEGIN(&psock->psockpt);
+
+  buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
+  
+  /* XXX: Should add buf_checkmarker() before do{} loop, if
+     incoming data has been handled while waiting for a write. */
+
+  do {
+    if(psock->readlen == 0) {
+      PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
+      psock->state = STATE_READ;
+      psock->readptr = (u8_t *)psock->ustack->uip_appdata;
+      psock->readlen = uip_datalen(psock->ustack);
+    }
+  } while((buf_bufto(&psock->buf, c,
+		     &psock->readptr,
+		     &psock->readlen) & BUF_FOUND) == 0);
+  
+  if(psock_datalen(psock) == 0) {
+    psock->state = STATE_NONE;
+    PT_RESTART(&psock->psockpt);
+  }
+  PT_END(&psock->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_readbuf(register struct psock *psock))
+{
+  PT_BEGIN(&psock->psockpt);
+
+  buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
+  
+  /* XXX: Should add buf_checkmarker() before do{} loop, if
+     incoming data has been handled while waiting for a write. */
+
+  do {
+    if(psock->readlen == 0) {
+      PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
+      printf("Waited for newdata\n");
+      psock->state = STATE_READ;
+      psock->readptr = (u8_t *)psock->ustack->uip_appdata;
+      psock->readlen = uip_datalen(psock->ustack);
+    }
+  } while(buf_bufdata(&psock->buf, psock->bufsize,
+			 &psock->readptr,
+			 &psock->readlen) != BUF_FULL);
+
+  if(psock_datalen(psock) == 0) {
+    psock->state = STATE_NONE;
+    PT_RESTART(&psock->psockpt);
+  }
+  PT_END(&psock->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+void
+psock_init(struct uip_stack *ustack,
+	   register struct psock *psock, u8_t *buffer, unsigned int buffersize)
+{
+  psock->state = STATE_NONE;
+  psock->readlen = 0;
+  psock->bufptr = buffer;
+  psock->bufsize = buffersize;
+  psock->ustack  = ustack;
+  buf_setup(&psock->buf, buffer, buffersize);
+  PT_INIT(&psock->pt);
+  PT_INIT(&psock->psockpt);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/uip/psock.h b/brcm_iscsi_uio/src/uip/psock.h
new file mode 100644
index 0000000..ac2aade
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/psock.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: psock.h,v 1.3 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \defgroup psock Protosockets library
+ * @{
+ *
+ * The protosocket library provides an interface to the uIP stack that is
+ * similar to the traditional BSD socket interface. Unlike programs
+ * written for the ordinary uIP event-driven interface, programs
+ * written with the protosocket library are executed in a sequential
+ * fashion and does not have to be implemented as explicit state
+ * machines.
+ *
+ * Protosockets only work with TCP connections.
+ *
+ * The protosocket library uses \ref pt protothreads to provide
+ * sequential control flow. This makes the protosockets lightweight in
+ * terms of memory, but also means that protosockets inherits the
+ * functional limitations of protothreads. Each protosocket lives only
+ * within a single function. Automatic variables (stack variables) are
+ * not retained across a protosocket library function call.
+ *
+ * \note Because the protosocket library uses protothreads, local
+ * variables will not always be saved across a call to a protosocket
+ * library function. It is therefore advised that local variables are
+ * used with extreme care.
+ *
+ * The protosocket library provides functions for sending data without
+ * having to deal with retransmissions and acknowledgements, as well
+ * as functions for reading data without having to deal with data
+ * being split across more than one TCP segment.
+ *
+ * Because each protosocket runs as a protothread, the protosocket has to be
+ * started with a call to PSOCK_BEGIN() at the start of the function
+ * in which the protosocket is used. Similarly, the protosocket protothread can
+ * be terminated by a call to PSOCK_EXIT().
+ *
+ */
+
+/**
+ * \file
+ * Protosocket library header file
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PSOCK_H__
+#define __PSOCK_H__
+
+#include "uip.h"
+#include "uipopt.h"
+#include "pt.h"
+
+ /*
+ * The structure that holds the state of a buffer.
+ *
+ * This structure holds the state of a uIP buffer. The structure has
+ * no user-visible elements, but is used through the functions
+ * provided by the library.
+ *
+ */
+struct psock_buf {
+  u8_t *ptr;
+  unsigned short left;
+};
+
+/**
+ * The representation of a protosocket.
+ *
+ * The protosocket structrure is an opaque structure with no user-visible
+ * elements.
+ */
+struct psock {
+  struct pt pt, psockpt; /* Protothreads - one that's using the psock
+			    functions, and one that runs inside the
+			    psock functions. */
+  const u8_t *sendptr;   /* Pointer to the next data to be sent. */
+  u8_t *readptr;         /* Pointer to the next data to be read. */
+  
+  u8_t *bufptr;          /* Pointer to the buffer used for buffering
+			    incoming data. */
+  
+  u16_t sendlen;         /* The number of bytes left to be sent. */
+  u16_t readlen;         /* The number of bytes left to be read. */
+
+  struct psock_buf buf;  /* The structure holding the state of the
+			    input buffer. */
+  unsigned int bufsize;  /* The size of the input buffer. */
+  
+  unsigned char state;   /* The state of the protosocket. */
+
+  struct uip_stack *ustack;
+};
+
+void psock_init(struct uip_stack *ustack,
+		struct psock *psock, u8_t *buffer, unsigned int buffersize);
+/**
+ * Initialize a protosocket.
+ *
+ * This macro initializes a protosocket and must be called before the
+ * protosocket is used. The initialization also specifies the input buffer
+ * for the protosocket.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket to be
+ * initialized
+ *
+ * \param buffer (char *) A pointer to the input buffer for the
+ * protosocket.
+ *
+ * \param buffersize (unsigned int) The size of the input buffer.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_INIT(psock, buffer, buffersize) \
+  psock_init(psock, buffer, buffersize)
+
+/**
+ * Start the protosocket protothread in a function.
+ *
+ * This macro starts the protothread associated with the protosocket and
+ * must come before other protosocket calls in the function it is used.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket to be
+ * started.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))
+
+PT_THREAD(psock_send(struct uip_stack *ustack, 
+		     struct psock *psock, const u8_t *buf, unsigned int len));
+/**
+ * Send data.
+ *
+ * This macro sends data over a protosocket. The protosocket protothread blocks
+ * until all data has been sent and is known to have been received by
+ * the remote end of the TCP connection.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket over which
+ * data is to be sent.
+ *
+ * \param data (char *) A pointer to the data that is to be sent.
+ *
+ * \param datalen (unsigned int) The length of the data that is to be
+ * sent.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_SEND(psock, data, datalen)		\
+    PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen))
+
+/**
+ * \brief      Send a null-terminated string.
+ * \param psock Pointer to the protosocket.
+ * \param str  The string to be sent.
+ *
+ *             This function sends a null-terminated string over the
+ *             protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_SEND_STR(psock, str)      		\
+    PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str)))
+
+PT_THREAD(psock_generator_send(struct psock *psock,
+			       unsigned short (*f)(void *), void *arg));
+
+/**
+ * \brief      Generate data with a function and send it
+ * \param psock Pointer to the protosocket.
+ * \param generator Pointer to the generator function
+ * \param arg   Argument to the generator function
+ *
+ *             This function generates data and sends it over the
+ *             protosocket. This can be used to dynamically generate
+ *             data for a transmission, instead of generating the data
+ *             in a buffer beforehand. This function reduces the need for
+ *             buffer memory. The generator function is implemented by
+ *             the application, and a pointer to the function is given
+ *             as an argument with the call to PSOCK_GENERATOR_SEND().
+ *
+ *             The generator function should place the generated data
+ *             directly in the uip_appdata buffer, and return the
+ *             length of the generated data. The generator function is
+ *             called by the protosocket layer when the data first is
+ *             sent, and once for every retransmission that is needed.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_GENERATOR_SEND(psock, generator, arg)     \
+    PT_WAIT_THREAD(&((psock)->pt),					\
+		   psock_generator_send(psock, generator, arg))
+
+
+/**
+ * Close a protosocket.
+ *
+ * This macro closes a protosocket and can only be called from within the
+ * protothread in which the protosocket lives.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket that is to
+ * be closed.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_CLOSE(psock) uip_close()
+
+PT_THREAD(psock_readbuf(struct psock *psock));
+/**
+ * Read data until the buffer is full.
+ *
+ * This macro will block waiting for data and read the data into the
+ * input buffer specified with the call to PSOCK_INIT(). Data is read
+ * until the buffer is full..
+ *
+ * \param psock (struct psock *) A pointer to the protosocket from which
+ * data should be read.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_READBUF(psock)				\
+  PT_WAIT_THREAD(&((psock)->pt), psock_readbuf(psock))
+
+PT_THREAD(psock_readto(struct psock *psock, unsigned char c));
+/**
+ * Read data up to a specified character.
+ *
+ * This macro will block waiting for data and read the data into the
+ * input buffer specified with the call to PSOCK_INIT(). Data is only
+ * read until the specifieed character appears in the data stream.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket from which
+ * data should be read.
+ *
+ * \param c (char) The character at which to stop reading.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_READTO(psock, c)				\
+  PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c))
+
+/**
+ * The length of the data that was previously read.
+ *
+ * This macro returns the length of the data that was previously read
+ * using PSOCK_READTO() or PSOCK_READ().
+ *
+ * \param psock (struct psock *) A pointer to the protosocket holding the data.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_DATALEN(psock) psock_datalen(psock)
+
+u16_t psock_datalen(struct psock *psock);
+
+/**
+ * Exit the protosocket's protothread.
+ *
+ * This macro terminates the protothread of the protosocket and should
+ * almost always be used in conjunction with PSOCK_CLOSE().
+ *
+ * \sa PSOCK_CLOSE_EXIT()
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt))
+
+/**
+ * Close a protosocket and exit the protosocket's protothread.
+ *
+ * This macro closes a protosocket and exits the protosocket's protothread.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_CLOSE_EXIT(psock)		\
+  do {						\
+    PSOCK_CLOSE(psock);			\
+    PSOCK_EXIT(psock);			\
+  } while(0)
+
+/**
+ * Declare the end of a protosocket's protothread.
+ *
+ * This macro is used for declaring that the protosocket's protothread
+ * ends. It must always be used together with a matching PSOCK_BEGIN()
+ * macro.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_END(psock) PT_END(&((psock)->pt))
+
+char psock_newdata(struct psock *s);
+
+/**
+ * Check if new data has arrived on a protosocket.
+ *
+ * This macro is used in conjunction with the PSOCK_WAIT_UNTIL()
+ * macro to check if data has arrived on a protosocket.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_NEWDATA(psock) psock_newdata(psock)
+
+/**
+ * Wait until a condition is true.
+ *
+ * This macro blocks the protothread until the specified condition is
+ * true. The macro PSOCK_NEWDATA() can be used to check if new data
+ * arrives when the protosocket is waiting.
+ *
+ * Typically, this macro is used as follows:
+ *
+ \code
+ PT_THREAD(thread(struct psock *s, struct timer *t))
+ {
+   PSOCK_BEGIN(s);
+
+   PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t));
+   
+   if(PSOCK_NEWDATA(s)) {
+     PSOCK_READTO(s, '\n');
+   } else {
+     handle_timed_out(s);
+   }
+   
+   PSOCK_END(s);
+ }
+ \endcode
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ * \param condition The condition to wait for.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_WAIT_UNTIL(psock, condition)    \
+  PT_WAIT_UNTIL(&((psock)->pt), (condition));
+
+#define PSOCK_WAIT_THREAD(psock, condition)   \
+  PT_WAIT_THREAD(&((psock)->pt), (condition))
+
+#endif /* __PSOCK_H__ */
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/pt.h b/brcm_iscsi_uio/src/uip/pt.h
new file mode 100644
index 0000000..9f1f64d
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/pt.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: pt.h,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \file
+ * Protothreads implementation.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PT_H__
+#define __PT_H__
+
+#include "lc.h"
+
+struct pt {
+  lc_t lc;
+};
+
+#define PT_WAITING 0
+#define PT_EXITED  1
+#define PT_ENDED   2
+#define PT_YIELDED 3
+
+/**
+ * \name Initialization
+ * @{
+ */
+
+/**
+ * Initialize a protothread.
+ *
+ * Initializes a protothread. Initialization must be done prior to
+ * starting to execute the protothread.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \sa PT_SPAWN()
+ *
+ * \hideinitializer
+ */
+#define PT_INIT(pt)   LC_INIT((pt)->lc)
+
+/** @} */
+
+/**
+ * \name Declaration and definition
+ * @{
+ */
+
+/**
+ * Declaration of a protothread.
+ *
+ * This macro is used to declare a protothread. All protothreads must
+ * be declared with this macro.
+ *
+ * \param name_args The name and arguments of the C function
+ * implementing the protothread.
+ *
+ * \hideinitializer
+ */
+#define PT_THREAD(name_args) char name_args
+
+/**
+ * Declare the start of a protothread inside the C function
+ * implementing the protothread.
+ *
+ * This macro is used to declare the starting point of a
+ * protothread. It should be placed at the start of the function in
+ * which the protothread runs. All C statements above the PT_BEGIN()
+ * invokation will be executed each time the protothread is scheduled.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
+
+/**
+ * Declare the end of a protothread.
+ *
+ * This macro is used for declaring that a protothread ends. It must
+ * always be used together with a matching PT_BEGIN() macro.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
+                   PT_INIT(pt); return PT_ENDED; }
+
+/** @} */
+
+/**
+ * \name Blocked wait
+ * @{
+ */
+
+/**
+ * Block and wait until condition is true.
+ *
+ * This macro blocks the protothread until the specified condition is
+ * true.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param condition The condition.
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_UNTIL(pt, condition)	        \
+  do {						\
+    LC_SET((pt)->lc);				\
+    if(!(condition)) {				\
+      return PT_WAITING;			\
+    }						\
+  } while(0)
+
+/**
+ * Block and wait while condition is true.
+ *
+ * This function blocks and waits while condition is true. See
+ * PT_WAIT_UNTIL().
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param cond The condition.
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_WHILE(pt, cond)  PT_WAIT_UNTIL((pt), !(cond))
+
+/** @} */
+
+/**
+ * \name Hierarchical protothreads
+ * @{
+ */
+
+/**
+ * Block and wait until a child protothread completes.
+ *
+ * This macro schedules a child protothread. The current protothread
+ * will block until the child protothread completes.
+ *
+ * \note The child protothread must be manually initialized with the
+ * PT_INIT() function before this function is used.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param thread The child protothread with arguments
+ *
+ * \sa PT_SPAWN()
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
+
+/**
+ * Spawn a child protothread and wait until it exits.
+ *
+ * This macro spawns a child protothread and waits until it exits. The
+ * macro can only be used within a protothread.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param child A pointer to the child protothread's control structure.
+ * \param thread The child protothread with arguments
+ *
+ * \hideinitializer
+ */
+#define PT_SPAWN(pt, child, thread)		\
+  do {						\
+    PT_INIT((child));				\
+    PT_WAIT_THREAD((pt), (thread));		\
+  } while(0)
+
+/** @} */
+
+/**
+ * \name Exiting and restarting
+ * @{
+ */
+
+/**
+ * Restart the protothread.
+ *
+ * This macro will block and cause the running protothread to restart
+ * its execution at the place of the PT_BEGIN() call.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_RESTART(pt)				\
+  do {						\
+    PT_INIT(pt);				\
+    return PT_WAITING;			\
+  } while(0)
+
+/**
+ * Exit the protothread.
+ *
+ * This macro causes the protothread to exit. If the protothread was
+ * spawned by another protothread, the parent protothread will become
+ * unblocked and can continue to run.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_EXIT(pt)				\
+  do {						\
+    PT_INIT(pt);				\
+    return PT_EXITED;			\
+  } while(0)
+
+/** @} */
+
+/**
+ * \name Calling a protothread
+ * @{
+ */
+
+/**
+ * Schedule a protothread.
+ *
+ * This function shedules a protothread. The return value of the
+ * function is non-zero if the protothread is running or zero if the
+ * protothread has exited.
+ *
+ * \param f The call to the C function implementing the protothread to
+ * be scheduled
+ *
+ * \hideinitializer
+ */
+#define PT_SCHEDULE(f) ((f) == PT_WAITING)
+
+/** @} */
+
+/**
+ * \name Yielding from a protothread
+ * @{
+ */
+
+/**
+ * Yield from the current protothread.
+ *
+ * This function will yield the protothread, thereby allowing other
+ * processing to take place in the system.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_YIELD(pt)				\
+  do {						\
+    PT_YIELD_FLAG = 0;				\
+    LC_SET((pt)->lc);				\
+    if(PT_YIELD_FLAG == 0) {			\
+      return PT_YIELDED;			\
+    }						\
+  } while(0)
+
+/**
+ * \brief      Yield from the protothread until a condition occurs.
+ * \param pt   A pointer to the protothread control structure.
+ * \param cond The condition.
+ *
+ *             This function will yield the protothread, until the
+ *             specified condition evaluates to true.
+ *
+ *
+ * \hideinitializer
+ */
+#define PT_YIELD_UNTIL(pt, cond)		\
+  do {						\
+    PT_YIELD_FLAG = 0;				\
+    LC_SET((pt)->lc);				\
+    if((PT_YIELD_FLAG == 0) || !(cond)) {	\
+      return PT_YIELDED;			\
+    }						\
+  } while(0)
+
+/** @} */
+
+#endif /* __PT_H__ */
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/timer.c b/brcm_iscsi_uio/src/uip/timer.c
new file mode 100644
index 0000000..74eedf6
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/timer.c
@@ -0,0 +1,127 @@
+/**
+ * \addtogroup timer
+ * @{
+ */
+
+/**
+ * \file
+ * Timer library implementation.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+#include "clock.h"
+#include "timer.h"
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Set a timer.
+ *
+ * This function is used to set a timer for a time sometime in the
+ * future. The function timer_expired() will evaluate to true after
+ * the timer has expired.
+ *
+ * \param t A pointer to the timer
+ * \param interval The interval before the timer expires.
+ *
+ */
+void
+timer_set(struct timer *t, clock_time_t interval)
+{
+  t->interval = interval;
+  t->start = clock_time();
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Reset the timer with the same interval.
+ *
+ * This function resets the timer with the same interval that was
+ * given to the timer_set() function. The start point of the interval
+ * is the exact time that the timer last expired. Therefore, this
+ * function will cause the timer to be stable over time, unlike the
+ * timer_rester() function.
+ *
+ * \param t A pointer to the timer.
+ *
+ * \sa timer_restart()
+ */
+void
+timer_reset(struct timer *t)
+{
+  t->start += t->interval;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Restart the timer from the current point in time
+ *
+ * This function restarts a timer with the same interval that was
+ * given to the timer_set() function. The timer will start at the
+ * current time.
+ *
+ * \note A periodic timer will drift if this function is used to reset
+ * it. For preioric timers, use the timer_reset() function instead.
+ *
+ * \param t A pointer to the timer.
+ *
+ * \sa timer_reset()
+ */
+void
+timer_restart(struct timer *t)
+{
+  t->start = clock_time();
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Check if a timer has expired.
+ *
+ * This function tests if a timer has expired and returns true or
+ * false depending on its status.
+ *
+ * \param t A pointer to the timer
+ *
+ * \return Non-zero if the timer has expired, zero otherwise.
+ *
+ */
+int
+timer_expired(struct timer *t)
+{
+  return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval;
+}
+/*---------------------------------------------------------------------------*/
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/timer.h b/brcm_iscsi_uio/src/uip/timer.h
new file mode 100644
index 0000000..057bea4
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/timer.h
@@ -0,0 +1,86 @@
+/**
+ * \defgroup timer Timer library
+ *
+ * The timer library provides functions for setting, resetting and
+ * restarting timers, and for checking if a timer has expired. An
+ * application must "manually" check if its timers have expired; this
+ * is not done automatically.
+ *
+ * A timer is declared as a \c struct \c timer and all access to the
+ * timer is made by a pointer to the declared timer.
+ *
+ * \note The timer library uses the \ref clock "Clock library" to
+ * measure time. Intervals should be specified in the format used by
+ * the clock library.
+ *
+ * @{
+ */
+
+
+/**
+ * \file
+ * Timer library header file.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $
+ */
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include "clock.h"
+
+/**
+ * A timer.
+ *
+ * This structure is used for declaring a timer. The timer must be set
+ * with timer_set() before it can be used.
+ *
+ * \hideinitializer
+ */
+struct timer {
+  clock_time_t start;
+  clock_time_t interval;
+};
+
+void timer_set(struct timer *t, clock_time_t interval);
+void timer_reset(struct timer *t);
+void timer_restart(struct timer *t);
+int timer_expired(struct timer *t);
+
+#endif /* __TIMER_H__ */
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/uip-fw.c b/brcm_iscsi_uio/src/uip/uip-fw.c
new file mode 100644
index 0000000..01858ea
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip-fw.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-fw.c,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uipfw uIP packet forwarding
+ * @{
+ *
+ */
+
+/**
+ * \file
+ * uIP packet forwarding.
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ * This file implements a number of simple functions which do packet
+ * forwarding over multiple network interfaces with uIP.
+ *
+ */
+
+#include "uip.h"
+#include "uip_arch.h"
+#include "uip-fw.h"
+
+#include <string.h> /* for memcpy() */
+
+/*
+ * The list of registered network interfaces.
+ */
+static struct uip_fw_netif *netifs = NULL;
+
+/*
+ * A pointer to the default network interface.
+ */
+static struct uip_fw_netif *defaultnetif = NULL;
+
+struct tcpip_hdr {
+  /* IP header. */
+  u8_t vhl,
+    tos;
+  u16_t len,
+    ipid,
+    ipoffset;
+  u8_t ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+  
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+};
+
+struct icmpip_hdr {
+  /* IP header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+  u16_t id, seqno;
+  u8_t payload[1];
+};
+
+/* ICMP ECHO. */
+#define ICMP_ECHO 8
+
+/* ICMP TIME-EXCEEDED. */
+#define ICMP_TE 11
+
+/*
+ * Pointer to the TCP/IP headers of the packet in the uip_buf buffer.
+ */
+#define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+/*
+ * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer.
+ */
+#define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+/*
+ * Certain fields of an IP packet that are used for identifying
+ * duplicate packets.
+ */
+struct fwcache_entry {
+  u16_t timer;
+  
+  u16_t srcipaddr[2];
+  u16_t destipaddr[2];
+  u16_t ipid;
+  u8_t proto;
+  u8_t unused;
+
+#if notdef
+  u16_t payload[2];
+#endif
+
+#if UIP_REASSEMBLY > 0
+  u16_t len, offset;
+#endif
+};
+
+/*
+ * The number of packets to remember when looking for duplicates.
+ */
+#ifdef UIP_CONF_FWCACHE_SIZE
+#define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE
+#else
+#define FWCACHE_SIZE 2
+#endif
+
+
+/*
+ * A cache of packet header fields which are used for
+ * identifying duplicate packets.
+ */
+static struct fwcache_entry fwcache[FWCACHE_SIZE];
+
+/**
+ * \internal
+ * The time that a packet cache is active.
+ */
+#define FW_TIME 20
+
+/*------------------------------------------------------------------------------*/
+/**
+ * Initialize the uIP packet forwarding module.
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_init(void)
+{
+  struct uip_fw_netif *t;
+  defaultnetif = NULL;
+  while(netifs != NULL) {
+    t = netifs;
+    netifs = netifs->next;
+    t->next = NULL;
+  }
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Check if an IP address is within the network defined by an IP
+ * address and a netmask.
+ *
+ * \param ipaddr The IP address to be checked.
+ * \param netipaddr The IP address of the network.
+ * \param netmask The netmask of the network.
+ *
+ * \return Non-zero if IP address is in network, zero otherwise.
+ */
+/*------------------------------------------------------------------------------*/
+static unsigned char
+ipaddr_maskcmp(u16_t *ipaddr, u16_t *netipaddr, u16_t *netmask)
+{
+  return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) &&
+    (ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]);
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Send out an ICMP TIME-EXCEEDED message.
+ *
+ * This function replaces the packet in the uip_buf buffer with the
+ * ICMP packet.
+ */
+/*------------------------------------------------------------------------------*/
+static void
+time_exceeded(void)
+{
+  u16_t tmp16;
+
+  /* We don't send out ICMP errors for ICMP messages. */
+  if(ICMPBUF->proto == UIP_PROTO_ICMP) {
+    uip_len = 0;
+    return;
+  }
+  /* Copy fields from packet header into payload of this ICMP packet. */
+  memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28);
+
+  /* Set the ICMP type and code. */
+  ICMPBUF->type = ICMP_TE;
+  ICMPBUF->icode = 0;
+
+  /* Calculate the ICMP checksum. */
+  ICMPBUF->icmpchksum = 0;
+  ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36);
+
+  /* Set the IP destination address to be the source address of the
+     original packet. */
+  tmp16= BUF->destipaddr[0];
+  BUF->destipaddr[0] = BUF->srcipaddr[0];
+  BUF->srcipaddr[0] = tmp16;
+  tmp16 = BUF->destipaddr[1];
+  BUF->destipaddr[1] = BUF->srcipaddr[1];
+  BUF->srcipaddr[1] = tmp16;
+
+  /* Set our IP address as the source address. */
+  BUF->srcipaddr[0] = uip_hostaddr[0];
+  BUF->srcipaddr[1] = uip_hostaddr[1];
+
+  /* The size of the ICMP time exceeded packet is 36 + the size of the
+     IP header (20) = 56. */
+  uip_len = 56;
+  ICMPBUF->len[0] = 0;
+  ICMPBUF->len[1] = uip_len;
+
+  /* Fill in the other fields in the IP header. */
+  ICMPBUF->vhl = 0x45;
+  ICMPBUF->tos = 0;
+  ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0;
+  ICMPBUF->ttl  = UIP_TTL;
+  ICMPBUF->proto = UIP_PROTO_ICMP;
+  
+  /* Calculate IP checksum. */
+  ICMPBUF->ipchksum = 0;
+  ICMPBUF->ipchksum = ~(uip_ipchksum());
+
+
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Register a packet in the forwarding cache so that it won't be
+ * forwarded again.
+ */
+/*------------------------------------------------------------------------------*/
+static void
+fwcache_register(void)
+{
+  struct fwcache_entry *fw;
+  int i, oldest;
+
+  oldest = FW_TIME;
+  fw = NULL;
+  
+  /* Find the oldest entry in the cache. */
+  for(i = 0; i < FWCACHE_SIZE; ++i) {
+    if(fwcache[i].timer == 0) {
+      fw = &fwcache[i];
+      break;
+    } else if(fwcache[i].timer <= oldest) {
+      fw = &fwcache[i];
+      oldest = fwcache[i].timer;
+    }
+  }
+
+  fw->timer = FW_TIME;
+  fw->ipid = BUF->ipid;
+  fw->srcipaddr[0] = BUF->srcipaddr[0];
+  fw->srcipaddr[1] = BUF->srcipaddr[1];
+  fw->destipaddr[0] = BUF->destipaddr[0];
+  fw->destipaddr[1] = BUF->destipaddr[1];
+  fw->proto = BUF->proto;
+#if notdef
+  fw->payload[0] = BUF->srcport;
+  fw->payload[1] = BUF->destport;
+#endif
+#if UIP_REASSEMBLY > 0
+  fw->len = BUF->len;
+  fw->offset = BUF->ipoffset;
+#endif
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Find a network interface for the IP packet in uip_buf.
+ */
+/*------------------------------------------------------------------------------*/
+static struct uip_fw_netif *
+find_netif(void)
+{
+  struct uip_fw_netif *netif;
+  
+  /* Walk through every network interface to check for a match. */
+  for(netif = netifs; netif != NULL; netif = netif->next) {
+    if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr,
+		      netif->netmask)) {
+      /* If there was a match, we break the loop. */
+      return netif;
+    }
+  }
+  
+  /* If no matching netif was found, we use default netif. */
+  return defaultnetif;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Output an IP packet on the correct network interface.
+ *
+ * The IP packet should be present in the uip_buf buffer and its
+ * length in the global uip_len variable.
+ *
+ * \retval UIP_FW_ZEROLEN Indicates that a zero-length packet
+ * transmission was attempted and that no packet was sent.
+ *
+ * \retval UIP_FW_NOROUTE No suitable network interface could be found
+ * for the outbound packet, and the packet was not sent.
+ *
+ * \return The return value from the actual network interface output
+ * function is passed unmodified as a return value.
+ */
+/*------------------------------------------------------------------------------*/
+u8_t
+uip_fw_output(void)
+{
+  struct uip_fw_netif *netif;
+
+  if(uip_len == 0) {
+    return UIP_FW_ZEROLEN;
+  }
+
+  fwcache_register();
+
+#if UIP_BROADCAST
+  /* Link local broadcasts go out on all interfaces. */
+  if(/*BUF->proto == UIP_PROTO_UDP &&*/
+     BUF->destipaddr[0] == 0xffff &&
+     BUF->destipaddr[1] == 0xffff) {
+    if(defaultnetif != NULL) {
+      defaultnetif->output();
+    }
+    for(netif = netifs; netif != NULL; netif = netif->next) {
+      netif->output();
+    }
+    return UIP_FW_OK;
+  }
+#endif /* UIP_BROADCAST */
+  
+  netif = find_netif();
+  /*  printf("uip_fw_output: netif %p ->output %p len %d\n", netif,
+	 netif->output,
+	 uip_len);*/
+
+  if(netif == NULL) {
+    return UIP_FW_NOROUTE;
+  }
+  /* If we now have found a suitable network interface, we call its
+     output function to send out the packet. */
+  return netif->output();
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Forward an IP packet in the uip_buf buffer.
+ *
+ *
+ *
+ * \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if
+ * the packet should be processed locally.
+ */
+/*------------------------------------------------------------------------------*/
+u8_t
+uip_fw_forward(void)
+{
+  struct fwcache_entry *fw;
+
+  /* First check if the packet is destined for ourselves and return 0
+     to indicate that the packet should be processed locally. */
+  if(BUF->destipaddr[0] == uip_hostaddr[0] &&
+     BUF->destipaddr[1] == uip_hostaddr[1]) {
+    return UIP_FW_LOCAL;
+  }
+
+  /* If we use ping IP address configuration, and our IP address is
+     not yet configured, we should intercept all ICMP echo packets. */
+#if UIP_PINGADDRCONF
+  if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 &&
+     BUF->proto == UIP_PROTO_ICMP &&
+     ICMPBUF->type == ICMP_ECHO) {
+    return UIP_FW_LOCAL;
+  }
+#endif /* UIP_PINGADDRCONF */
+
+  /* Check if the packet is in the forwarding cache already, and if so
+     we drop it. */
+
+  for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
+    if(fw->timer != 0 &&
+#if UIP_REASSEMBLY > 0
+       fw->len == BUF->len &&
+       fw->offset == BUF->ipoffset &&
+#endif
+       fw->ipid == BUF->ipid &&
+       fw->srcipaddr[0] == BUF->srcipaddr[0] &&
+       fw->srcipaddr[1] == BUF->srcipaddr[1] &&
+       fw->destipaddr[0] == BUF->destipaddr[0] &&
+       fw->destipaddr[1] == BUF->destipaddr[1] &&
+#if notdef
+       fw->payload[0] == BUF->srcport &&
+       fw->payload[1] == BUF->destport &&
+#endif
+       fw->proto == BUF->proto) {
+      /* Drop packet. */
+      return UIP_FW_FORWARDED;
+    }
+  }
+
+  /* If the TTL reaches zero we produce an ICMP time exceeded message
+     in the uip_buf buffer and forward that packet back to the sender
+     of the packet. */
+  if(BUF->ttl <= 1) {
+    /* No time exceeded for broadcasts and multicasts! */
+    if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
+      return UIP_FW_LOCAL;
+    }
+    time_exceeded();
+  }
+  
+  /* Decrement the TTL (time-to-live) value in the IP header */
+  BUF->ttl = BUF->ttl - 1;
+  
+  /* Update the IP checksum. */
+  if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) {
+    BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1;
+  } else {
+    BUF->ipchksum = BUF->ipchksum + HTONS(0x0100);
+  }
+
+  if(uip_len > 0) {
+    uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN];
+    uip_fw_output();
+  }
+
+#if UIP_BROADCAST
+  if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) {
+    return UIP_FW_LOCAL;
+  }
+#endif /* UIP_BROADCAST */
+
+  /* Return non-zero to indicate that the packet was forwarded and that no
+     other processing should be made. */
+  return UIP_FW_FORWARDED;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Register a network interface with the forwarding module.
+ *
+ * \param netif A pointer to the network interface that is to be
+ * registered.
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_register(struct uip_fw_netif *netif)
+{
+  netif->next = netifs;
+  netifs = netif;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Register a default network interface.
+ *
+ * All packets that don't go out on any of the other interfaces will
+ * be routed to the default interface.
+ *
+ * \param netif A pointer to the network interface that is to be
+ * registered.
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_default(struct uip_fw_netif *netif)
+{
+  defaultnetif = netif;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Perform periodic processing.
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_periodic(void)
+{
+  struct fwcache_entry *fw;
+  for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) {
+    if(fw->timer > 0) {
+      --fw->timer;
+    }
+  }
+}
+/*------------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/uip/uip-fw.h b/brcm_iscsi_uio/src/uip/uip-fw.h
new file mode 100644
index 0000000..9033850
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip-fw.h
@@ -0,0 +1,176 @@
+/**
+ * \addtogroup uipfw
+ * @{
+ */
+
+/**
+ * \file
+ * uIP packet forwarding header file.
+ * \author Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-fw.h,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+#ifndef __UIP_FW_H__
+#define __UIP_FW_H__
+
+#include "uip.h"
+
+/**
+ * Representation of a uIP network interface.
+ */
+struct uip_fw_netif {
+  struct uip_fw_netif *next;  /**< Pointer to the next interface when
+				 linked in a list. */
+  u16_t ipaddr[2];            /**< The IP address of this interface. */
+  u16_t netmask[2];           /**< The netmask of the interface. */
+  u8_t (* output)(void);
+                              /**< A pointer to the function that
+				 sends a packet. */
+};
+
+/**
+ * Intantiating macro for a uIP network interface.
+ *
+ * Example:
+ \code
+ struct uip_fw_netif slipnetif =
+   {UIP_FW_NETIF(192,168,76,1, 255,255,255,0, slip_output)};
+ \endcode
+ * \param ip1,ip2,ip3,ip4 The IP address of the network interface.
+ *
+ * \param nm1,nm2,nm3,nm4 The netmask of the network interface.
+ *
+ * \param outputfunc A pointer to the output function of the network interface.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_NETIF(ip1,ip2,ip3,ip4, nm1,nm2,nm3,nm4, outputfunc) \
+        NULL, \
+	{HTONS((ip1 << 8) | ip2), HTONS((ip3 << 8) | ip4)}, \
+	{HTONS((nm1 << 8) | nm2), HTONS((nm3 << 8) | nm4)}, \
+        outputfunc
+
+/**
+ * Set the IP address of a network interface.
+ *
+ * \param netif A pointer to the uip_fw_netif structure for the network interface.
+ *
+ * \param addr A pointer to an IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_fw_setipaddr(netif, addr) \
+        do { (netif)->ipaddr[0] = ((u16_t *)(addr))[0]; \
+             (netif)->ipaddr[1] = ((u16_t *)(addr))[1]; } while(0)
+/**
+ * Set the netmask of a network interface.
+ *
+ * \param netif A pointer to the uip_fw_netif structure for the network interface.
+ *
+ * \param addr A pointer to an IP address representing the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_fw_setnetmask(netif, addr) \
+        do { (netif)->netmask[0] = ((u16_t *)(addr))[0]; \
+             (netif)->netmask[1] = ((u16_t *)(addr))[1]; } while(0)
+
+void uip_fw_init(void);
+u8_t uip_fw_forward(void);
+u8_t uip_fw_output(void);
+void uip_fw_register(struct uip_fw_netif *netif);
+void uip_fw_default(struct uip_fw_netif *netif);
+void uip_fw_periodic(void);
+
+
+/**
+ * A non-error message that indicates that a packet should be
+ * processed locally.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_LOCAL     0
+
+/**
+ * A non-error message that indicates that something went OK.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_OK        0
+
+/**
+ * A non-error message that indicates that a packet was forwarded.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_FORWARDED 1
+
+/**
+ * A non-error message that indicates that a zero-length packet
+ * transmission was attempted, and that no packet was sent.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_ZEROLEN   2
+
+/**
+ * An error message that indicates that a packet that was too large
+ * for the outbound network interface was detected.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_TOOLARGE  3
+
+/**
+ * An error message that indicates that no suitable interface could be
+ * found for an outbound packet.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_NOROUTE   4
+
+/**
+ * An error message that indicates that a packet that should be
+ * forwarded or output was dropped.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_DROPPED   5
+
+
+#endif /* __UIP_FW_H__ */
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/uip-neighbor.c b/brcm_iscsi_uio/src/uip/uip-neighbor.c
new file mode 100644
index 0000000..c4b11bf
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip-neighbor.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: uip-neighbor.c,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \file
+ *         Database of link-local neighbors, used by IPv6 code and
+ *         to be used by a future ARP code rewrite.
+ * \author
+ *         Adam Dunkels <adam@sics.se>
+ */
+
+#include "logger.h"
+#include "uip.h"
+#include "uip-neighbor.h"
+
+#include <string.h>
+#include <arpa/inet.h>
+
+#define MAX_TIME 128
+
+/*---------------------------------------------------------------------------*/
+void
+uip_neighbor_init(struct uip_stack *ustack)
+{
+  int i;
+
+  for(i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+    ustack->neighbor_entries[i].time = MAX_TIME;
+  }
+}
+/*---------------------------------------------------------------------------*/
+#if 0
+void
+uip_neighbor_periodic(void)
+{
+  int i;
+
+  for(i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+    if(entries[i].time < MAX_TIME) {
+      entries[i].time++;
+    }
+  }
+}
+#endif
+/*---------------------------------------------------------------------------*/
+void
+uip_neighbor_add(struct uip_stack *ustack,
+		 uip_ip6addr_t ipaddr, struct uip_eth_addr *addr)
+{
+  int i, oldest;
+  u8_t oldest_time;
+  char buf[128];
+
+   inet_ntop(AF_INET6, ipaddr, buf, sizeof(buf));
+
+   LOG_INFO("Adding neighbor %s with link address %02x:%02x:%02x:%02x:%02x:%02x\n",
+   	   buf,
+	   addr[0], addr[1], addr[2],
+	   addr[3], addr[4], addr[5]);
+  
+  /* Find the first unused entry or the oldest used entry. */
+  oldest_time = 0;
+  oldest = 0;
+  for(i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+    if(ustack->neighbor_entries[i].time == MAX_TIME) {
+      oldest = i;
+      break;
+    }
+    if(uip_ip6addr_cmp(ustack->neighbor_entries[i].ipaddr, ipaddr)) {
+      oldest = i;
+      break;
+    }
+    if(ustack->neighbor_entries[i].time > oldest_time) {
+      oldest = i;
+      oldest_time = ustack->neighbor_entries[i].time;
+    }
+  }
+
+  /* Use the oldest or first free entry (either pointed to by the
+     "oldest" variable). */
+  ustack->neighbor_entries[oldest].time = 0;
+  uip_ip6addr_copy(ustack->neighbor_entries[oldest].ipaddr, ipaddr);
+  memcpy(&ustack->neighbor_entries[oldest].addr,
+  	 addr, sizeof(struct uip_eth_addr));
+}
+/*---------------------------------------------------------------------------*/
+static struct neighbor_entry *
+find_entry(struct uip_stack *ustack,
+	   uip_ip6addr_t ipaddr)
+{
+  int i;
+  char buf[128];
+  inet_ntop(AF_INET6, ipaddr, buf, sizeof(buf));
+  
+  for(i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+    if(uip_ip6addr_cmp(ustack->neighbor_entries[i].ipaddr, ipaddr)) {
+
+      LOG_DEBUG("found %s at %02x:%02x:%02x:%02x:%02x:%02x\n",
+           buf,
+	   ustack->neighbor_entries[i].addr.addr[0],
+	   ustack->neighbor_entries[i].addr.addr[1],
+	   ustack->neighbor_entries[i].addr.addr[2],
+	   ustack->neighbor_entries[i].addr.addr[3],
+	   ustack->neighbor_entries[i].addr.addr[4],
+	   ustack->neighbor_entries[i].addr.addr[5]);
+
+      return &ustack->neighbor_entries[i];
+    }
+  }
+
+
+  LOG_WARN("Could not find entry: %s",
+  	   buf);
+
+  return NULL;
+}
+/*---------------------------------------------------------------------------*/
+void
+uip_neighbor_update(struct uip_stack *ustack, uip_ip6addr_t ipaddr)
+{
+  struct neighbor_entry *e;
+
+  e = find_entry(ustack, ipaddr);
+  if(e != NULL) {
+    e->time = 0;
+  }
+}
+/*---------------------------------------------------------------------------*/
+struct uip_eth_addr *
+uip_neighbor_lookup(struct uip_stack *ustack, uip_ip6addr_t ipaddr)
+{
+  struct neighbor_entry *e;
+
+  e = find_entry(ustack, ipaddr);
+  if(e != NULL) {
+    /*    printf("Lookup neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n",
+	   e->addr.addr.addr[0], e->addr.addr.addr[1], e->addr.addr.addr[2], e->addr.addr.addr[3],
+	   e->addr.addr.addr[4], e->addr.addr.addr[5]);*/
+
+    return &e->addr;
+  }
+  return NULL;
+}
+
+void
+uip_neighbor_out(struct uip_stack *ustack)
+{
+  struct neighbor_entry *e;
+  struct uip_ipv6_hdr *ipv6_hdr = (struct uip_ipv6_hdr *)IPv6_BUF(ustack);
+  
+  /* Find the destination IP address in the neighbor table and construct
+     the Ethernet header. If the destination IP addres isn't on the
+     local network, we use the default router's IP address instead.
+
+     If not ARP table entry is found, we overwrite the original IP
+     packet with an ARP request for the IP address. */
+  e = find_entry(ustack, ipv6_hdr->destipaddr);
+
+  if(e == NULL)
+  	/* TODO determine what to do in IPv6 case */
+  	return;
+
+  memcpy(ETH_BUF(ustack)->dest.addr, &e->addr, 6);
+  memcpy(ETH_BUF(ustack)->src.addr, ustack->uip_ethaddr.addr, 6);
+  
+  ETH_BUF(ustack)->type = htons(UIP_ETHTYPE_IPv6);
+
+  ustack->uip_len += sizeof(struct uip_eth_hdr);
+}
+
+/*---------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/uip/uip-neighbor.h b/brcm_iscsi_uio/src/uip/uip-neighbor.h
new file mode 100644
index 0000000..6664e11
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip-neighbor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: uip-neighbor.h,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+/**
+ * \file
+ *         Header file for database of link-local neighbors, used by
+ *         IPv6 code and to be used by future ARP code.
+ * \author
+ *         Adam Dunkels <adam@sics.se>
+ */
+
+#ifndef __UIP_NEIGHBOR_H__
+#define __UIP_NEIGHBOR_H__
+
+#include "uip.h"
+#include "uip_eth.h"
+
+void uip_neighbor_init(struct uip_stack *ustack);
+void uip_neighbor_add(struct uip_stack *ustack,
+		      uip_ip6addr_t ipaddr, struct uip_eth_addr *addr);
+void uip_neighbor_update(struct uip_stack *ustack, uip_ip6addr_t ipaddr);
+struct uip_eth_addr *uip_neighbor_lookup(struct uip_stack *ustack,
+					 uip_ip6addr_t ipaddr);
+void uip_neighbor_periodic(void);
+void uip_neighbor_out(struct uip_stack *ustack);
+
+
+#endif /* __UIP-NEIGHBOR_H__ */
diff --git a/brcm_iscsi_uio/src/uip/uip-split.c b/brcm_iscsi_uio/src/uip/uip-split.c
new file mode 100644
index 0000000..a910ee6
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip-split.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-split.c,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+
+#include <string.h>
+
+#include "uip-split.h"
+#include "uip.h"
+#include "uip-fw.h"
+#include "uip_arch.h"
+
+
+
+#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+/*-----------------------------------------------------------------------------*/
+void
+uip_split_output(void)
+{
+  u16_t tcplen, len1, len2;
+
+  /* We only try to split maximum sized TCP segments. */
+  if(BUF->proto == UIP_PROTO_TCP &&
+     uip_len == UIP_BUFSIZE - UIP_LLH_LEN) {
+
+    tcplen = uip_len - UIP_TCPIP_HLEN;
+    /* Split the segment in two. If the original packet length was
+       odd, we make the second packet one byte larger. */
+    len1 = len2 = tcplen / 2;
+    if(len1 + len2 < tcplen) {
+      ++len2;
+    }
+
+    /* Create the first packet. This is done by altering the length
+       field of the IP header and updating the checksums. */
+    uip_len = len1 + UIP_TCPIP_HLEN;
+#if UIP_CONF_IPV6
+    /* For IPv6, the IP length field does not include the IPv6 IP header
+       length. */
+    BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
+    BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
+#else /* UIP_CONF_IPV6 */
+    BUF->len[0] = uip_len >> 8;
+    BUF->len[1] = uip_len & 0xff;
+#endif /* UIP_CONF_IPV6 */
+    
+    /* Recalculate the TCP checksum. */
+    BUF->tcpchksum = 0;
+    BUF->tcpchksum = ~(uip_tcpchksum());
+
+#if !UIP_CONF_IPV6
+    /* Recalculate the IP checksum. */
+    BUF->ipchksum = 0;
+    BUF->ipchksum = ~(uip_ipchksum());
+#endif /* UIP_CONF_IPV6 */
+    
+    /* Transmit the first packet. */
+    /*    uip_fw_output();*/
+    tcpip_output();
+
+    /* Now, create the second packet. To do this, it is not enough to
+       just alter the length field, but we must also update the TCP
+       sequence number and point the uip_appdata to a new place in
+       memory. This place is detemined by the length of the first
+       packet (len1). */
+    uip_len = len2 + UIP_TCPIP_HLEN;
+#if UIP_CONF_IPV6
+    /* For IPv6, the IP length field does not include the IPv6 IP header
+       length. */
+    BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
+    BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
+#else /* UIP_CONF_IPV6 */
+    BUF->len[0] = uip_len >> 8;
+    BUF->len[1] = uip_len & 0xff;
+#endif /* UIP_CONF_IPV6 */
+    
+    /*    uip_appdata += len1;*/
+    memcpy(uip_appdata, (u8_t *)uip_appdata + len1, len2);
+
+    uip_add32(BUF->seqno, len1);
+    BUF->seqno[0] = uip_acc32[0];
+    BUF->seqno[1] = uip_acc32[1];
+    BUF->seqno[2] = uip_acc32[2];
+    BUF->seqno[3] = uip_acc32[3];
+    
+    /* Recalculate the TCP checksum. */
+    BUF->tcpchksum = 0;
+    BUF->tcpchksum = ~(uip_tcpchksum());
+
+#if !UIP_CONF_IPV6
+    /* Recalculate the IP checksum. */
+    BUF->ipchksum = 0;
+    BUF->ipchksum = ~(uip_ipchksum());
+#endif /* UIP_CONF_IPV6 */
+
+    /* Transmit the second packet. */
+    /*    uip_fw_output();*/
+    tcpip_output();
+  } else {
+    /*    uip_fw_output();*/
+    tcpip_output();
+  }
+     
+}
+/*-----------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/uip/uip-split.h b/brcm_iscsi_uio/src/uip/uip-split.h
new file mode 100644
index 0000000..c2c1789
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip-split.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-split.h,v 1.2 2006/06/12 08:00:30 adam Exp $
+ */
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uipsplit uIP TCP throughput booster hack
+ * @{
+ *
+ * The basic uIP TCP implementation only allows each TCP connection to
+ * have a single TCP segment in flight at any given time. Because of
+ * the delayed ACK algorithm employed by most TCP receivers, uIP's
+ * limit on the amount of in-flight TCP segments seriously reduces the
+ * maximum achievable throughput for sending data from uIP.
+ *
+ * The uip-split module is a hack which tries to remedy this
+ * situation. By splitting maximum sized outgoing TCP segments into
+ * two, the delayed ACK algorithm is not invoked at TCP
+ * receivers. This improves the throughput when sending data from uIP
+ * by orders of magnitude.
+ *
+ * The uip-split module uses the uip-fw module (uIP IP packet
+ * forwarding) for sending packets. Therefore, the uip-fw module must
+ * be set up with the appropriate network interfaces for this module
+ * to work.
+ */
+
+
+/**
+ * \file
+ * Module for splitting outbound TCP segments in two to avoid the
+ * delayed ACK throughput degradation.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __UIP_SPLIT_H__
+#define __UIP_SPLIT_H__
+
+/**
+ * Handle outgoing packets.
+ *
+ * This function inspects an outgoing packet in the uip_buf buffer and
+ * sends it out using the uip_fw_output() function. If the packet is a
+ * full-sized TCP segment it will be split into two segments and
+ * transmitted separately. This function should be called instead of
+ * the actual device driver output function, or the uip_fw_output()
+ * function.
+ *
+ * The headers of the outgoing packet is assumed to be in the uip_buf
+ * buffer and the payload is assumed to be wherever uip_appdata
+ * points. The length of the outgoing packet is assumed to be in the
+ * uip_len variable.
+ *
+ */
+void uip_split_output(void);
+
+#endif /* __UIP_SPLIT_H__ */
+
+/** @} */
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/uip.c b/brcm_iscsi_uio/src/uip/uip.c
new file mode 100644
index 0000000..a702561
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip.c
@@ -0,0 +1,2394 @@
+#include <arpa/inet.h>
+#include "uip.h"
+#include "dhcpc.h"
+#include "brcm_iscsi.h"
+
+/**
+ * \defgroup uip The uIP TCP/IP stack
+ * @{
+ *
+ * uIP is an implementation of the TCP/IP protocol stack intended for
+ * small 8-bit and 16-bit microcontrollers.
+ *
+ * uIP provides the necessary protocols for Internet communication,
+ * with a very small code footprint and RAM requirements - the uIP
+ * code size is on the order of a few kilobytes and RAM usage is on
+ * the order of a few hundred bytes.
+ */
+
+/**
+ * \file
+ * The uIP TCP/IP stack code.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $
+ *
+ */
+
+/*
+ * uIP is a small implementation of the IP, UDP and TCP protocols (as
+ * well as some basic ICMP stuff). The implementation couples the IP,
+ * UDP, TCP and the application layers very tightly. To keep the size
+ * of the compiled code down, this code frequently uses the goto
+ * statement. While it would be possible to break the uip_process()
+ * function into many smaller functions, this would increase the code
+ * size because of the overhead of parameter passing and the fact that
+ * the optimier would not be as efficient.
+ *
+ * The principle is that we have a small buffer, called the uip_buf,
+ * in which the device driver puts an incoming packet. The TCP/IP
+ * stack parses the headers in the packet, and calls the
+ * application. If the remote host has sent data to the application,
+ * this data is present in the uip_buf and the application read the
+ * data from there. It is up to the application to put this data into
+ * a byte stream if needed. The application will not be fed with data
+ * that is out of sequence.
+ *
+ * If the application whishes to send data to the peer, it should put
+ * its data into the uip_buf. The uip_appdata pointer points to the
+ * first available byte. The TCP/IP stack will calculate the
+ * checksums, and fill in the necessary header fields and finally send
+ * the packet back to the peer.
+*/
+
+#include "logger.h"
+
+#include "uip.h"
+#include "uipopt.h"
+#include "uip_arch.h"
+#include "uip_eth.h"
+#include "uip-neighbor.h"
+
+#include <string.h>
+
+/*******************************************************************************
+ * Constants
+ ******************************************************************************/
+#define PFX "uip "
+
+static const uip_ip6addr_t all_ones_addr6 =
+  {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff};
+static const uip_ip4addr_t all_ones_addr4 =
+  {0xffff,0xffff};
+
+const uip_ip6addr_t all_zeroes_addr6 =
+  {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
+const uip_ip4addr_t all_zeroes_addr4 =
+  {0x0000,0x0000};
+
+/* Structures and definitions. */
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_PSH 0x08
+#define TCP_ACK 0x10
+#define TCP_URG 0x20
+#define TCP_CTL 0x3f
+
+#define TCP_OPT_END     0   /* End of TCP options list */
+#define TCP_OPT_NOOP    1   /* "No-operation" TCP option */
+#define TCP_OPT_MSS     2   /* Maximum segment size TCP option */
+
+#define TCP_OPT_MSS_LEN 4   /* Length of TCP MSS option. */
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO       8
+
+#define ICMP6_ECHO_REPLY             129
+#define ICMP6_ECHO                   128
+#define ICMP6_NEIGHBOR_SOLICITATION  135
+#define ICMP6_NEIGHBOR_ADVERTISEMENT 136
+
+#define ICMP6_FLAG_S (1 << 6)
+
+#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
+#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
+
+
+/* Macros. */
+#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
+#define UDPBUF(ustack) ((struct uip_udpip_hdr *)&ustack->uip_buf[UIP_LLH_LEN])
+
+/******************************************************************************
+ * Utility Functions
+ *****************************************************************************/
+int is_ipv6(struct uip_stack *ustack) {
+	return ntohs(ETH_BUF(ustack)->type) ==  UIP_ETHTYPE_IPv6 ? 1 : 0;
+}
+
+void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr)
+{
+	pthread_mutex_lock(&ustack->lock);
+	uip_ip4addr_copy(ustack->hostaddr, (addr));
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr)
+{
+	pthread_mutex_lock(&ustack->lock);
+	uip_ip4addr_copy(ustack->default_route_addr, (addr));
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr)
+{
+	pthread_mutex_lock(&ustack->lock);
+	uip_ip4addr_copy(ustack->netmask, (addr));
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac)
+{
+	pthread_mutex_lock(&ustack->lock);
+	memcpy(ustack->uip_ethaddr.addr, (mac), 6);
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void set_uip_stack(struct uip_stack *ustack, 
+		   uip_ip4addr_t *ip,
+		   uip_ip4addr_t *netmask,
+		   uip_ip4addr_t *default_route,
+		   uint8_t  *mac_addr)
+{
+	uip_sethostaddr4(ustack, ip);
+	uip_setnetmask4(ustack, netmask);
+	uip_setdraddr4(ustack, default_route);
+	uip_setethernetmac(ustack, mac_addr);
+
+	set_ipv6_link_local_address(ustack);
+	uip_ip6addr_copy(ustack->hostaddr6, ustack->link_local_addr);
+	/* resolv_conf(s->dnsaddr); */
+
+	if(LOG_LEVEL_INFO <= main_log.level)
+	{
+		char buf[128];
+
+	 	inet_ntop(AF_INET6, ustack->hostaddr6,
+			  buf, sizeof(buf));
+
+		LOG_INFO(PFX "ustack->uip_hostaddr6 IP: %s", buf);
+
+	 	inet_ntop(AF_INET6, ustack->link_local_addr,
+			  buf, sizeof(buf));
+
+		LOG_INFO(PFX "ustack->link_local_addr IP: %s", buf);
+	}
+}
+
+#if ! UIP_ARCH_ADD32
+void
+uip_add32(u8_t *op32, u16_t op16, u8_t *uip_acc32)
+{
+  uip_acc32[3] = op32[3] + (op16 & 0xff);
+  uip_acc32[2] = op32[2] + (op16 >> 8);
+  uip_acc32[1] = op32[1];
+  uip_acc32[0] = op32[0];
+  
+  if(uip_acc32[2] < (op16 >> 8)) {
+    ++uip_acc32[1];
+    if(uip_acc32[1] == 0) {
+      ++uip_acc32[0];
+    }
+  }
+  
+  
+  if(uip_acc32[3] < (op16 & 0xff)) {
+    ++uip_acc32[2];
+    if(uip_acc32[2] == 0) {
+      ++uip_acc32[1];
+      if(uip_acc32[1] == 0) {
+	++uip_acc32[0];
+      }
+    }
+  }
+}
+
+#endif /* UIP_ARCH_ADD32 */
+
+#if ! UIP_ARCH_CHKSUM
+/*---------------------------------------------------------------------------*/
+static u16_t
+chksum(u16_t sum, const u8_t *data, u16_t len)
+{
+  u16_t t;
+  const u8_t *dataptr;
+  const u8_t *last_byte;
+
+  dataptr = data;
+  last_byte = data + len - 1;
+  
+  while(dataptr < last_byte) {	/* At least two more bytes */
+    t = (dataptr[0] << 8) + dataptr[1];
+    sum += t;
+    if(sum < t) {
+      sum++;		/* carry */
+    }
+    dataptr += 2;
+  }
+  
+  if(dataptr == last_byte) {
+    t = (dataptr[0] << 8) + 0;
+    sum += t;
+    if(sum < t) {
+      sum++;		/* carry */
+    }
+  }
+
+  /* Return sum in host byte order. */
+  return sum;
+}
+/*---------------------------------------------------------------------------*/
+u16_t
+uip_chksum(u16_t *data, u16_t len)
+{
+  return htons(chksum(0, (u8_t *)data, len));
+}
+/*---------------------------------------------------------------------------*/
+#ifndef UIP_ARCH_IPCHKSUM
+u16_t
+uip_ipchksum(struct uip_stack *ustack)
+{
+  u16_t sum;
+  u16_t uip_iph_len;
+
+  if(is_ipv6(ustack))
+    uip_iph_len = UIP_IPv6_H_LEN;
+  else
+    uip_iph_len = UIP_IPv4_H_LEN;
+
+  sum = chksum(0, &ustack->uip_buf[UIP_LLH_LEN], uip_iph_len);
+  return (sum == 0) ? 0xffff : htons(sum);
+}
+#endif
+/*---------------------------------------------------------------------------*/
+static u16_t
+upper_layer_chksum(struct uip_stack *ustack, u8_t proto)
+{
+  u16_t upper_layer_len;
+  u16_t sum;
+  struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL;
+
+  tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)&ustack->uip_buf[UIP_LLH_LEN];
+  
+  if(is_ipv6(ustack))
+    upper_layer_len = (((u16_t)(IPv6_BUF(ustack)->len[0]) << 8) + 
+    				IPv6_BUF(ustack)->len[1]);
+  else
+    upper_layer_len = (((u16_t)(tcp_ipv4_hdr->len[0]) << 8) +
+    				tcp_ipv4_hdr->len[1]) - UIP_IPv4_H_LEN;
+
+  /* First sum pseudoheader. */
+  
+  /* IP protocol and length fields. This addition cannot carry. */
+  sum = upper_layer_len + proto;
+
+  /* Sum IP source and destination addresses. */
+  if(is_ipv6(ustack)) {
+	  sum = chksum(sum, (u8_t *)&IPv6_BUF(ustack)->srcipaddr[0], 2 * sizeof(uip_ip6addr_t));
+	  /* Sum TCP header and data. */
+	  sum = chksum(sum, &ustack->uip_buf[UIP_IPv6_H_LEN + UIP_LLH_LEN],
+		       upper_layer_len);
+
+  } else {
+	  sum = chksum(sum, (u8_t *)&tcp_ipv4_hdr->srcipaddr[0], 2 * sizeof(uip_ip4addr_t));
+	  /* Sum TCP header and data. */
+	  sum = chksum(sum, &ustack->uip_buf[UIP_IPv4_H_LEN + UIP_LLH_LEN],
+		       upper_layer_len);
+  }
+
+  return (sum == 0) ? 0xffff : htons(sum);
+}
+/*---------------------------------------------------------------------------*/
+
+u16_t
+uip_icmp6chksum(struct uip_stack *ustack)
+{
+  return upper_layer_chksum(ustack, UIP_PROTO_ICMP6);
+}
+
+/*---------------------------------------------------------------------------*/
+u16_t
+uip_tcpchksum(struct uip_stack *ustack)
+{
+  return upper_layer_chksum(ustack, UIP_PROTO_TCP);
+}
+/*---------------------------------------------------------------------------*/
+#if UIP_UDP_CHECKSUMS
+u16_t
+uip_udpchksum(struct uip_stack *ustack)
+{
+  return upper_layer_chksum(ustack, UIP_PROTO_UDP);
+}
+#endif /* UIP_UDP_CHECKSUMS */
+#endif /* UIP_ARCH_CHKSUM */
+/*---------------------------------------------------------------------------*/
+void
+uip_init(struct uip_stack *ustack, uint8_t ipv6_enabled)
+{
+  u8_t c;
+
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    ustack->uip_listenports[c] = 0;
+  }
+  for(c = 0; c < UIP_CONNS; ++c) {
+    ustack->uip_conns[c].tcpstateflags = UIP_CLOSED;
+  }
+#if UIP_ACTIVE_OPEN
+  ustack->lastport = 1024;
+#endif /* UIP_ACTIVE_OPEN */
+
+#if UIP_UDP
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    ustack->uip_udp_conns[c].lport = 0;
+  }
+#endif /* UIP_UDP */
+  
+
+  /* IPv4 initialization. */
+#if UIP_FIXEDADDR == 0
+  /*  uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
+#endif /* UIP_FIXEDADDR */
+
+  /*  zero out the uIP statistics */
+  memset(&ustack->stats, 0, sizeof(ustack->stats));
+
+  /*  prepare the uIP lock */
+  pthread_mutex_init(&ustack->lock, NULL);
+
+  if(ipv6_enabled) {
+     ustack->enable_IPv6 = UIP_SUPPORT_IPv6_ENABLED;
+     uip_neighbor_init(ustack);
+  }else
+    ustack->enable_IPv6 = UIP_SUPPORT_IPv6_DISABLED;
+
+  ustack->dhcpc = NULL;
+}
+void
+uip_reset(struct uip_stack *ustack)
+{
+	/*  There was an associated DHCP object, this memory needs to be
+	 *  freed */
+	if(ustack->dhcpc)
+		free(ustack->dhcpc);
+
+	memset(ustack, 0, sizeof(*ustack));
+}
+/*---------------------------------------------------------------------------*/
+#if UIP_ACTIVE_OPEN
+struct uip_conn *
+uip_connect(struct uip_stack *ustack, uip_ip4addr_t *ripaddr, u16_t rport)
+{
+  u8_t c;
+  register struct uip_conn *conn, *cconn;
+  
+  /* Find an unused local port. */
+ again:
+  ++ustack->lastport;
+
+  if(ustack->lastport >= 32000) {
+    ustack->lastport = 4096;
+  }
+
+  /* Check if this port is already in use, and if so try to find
+     another one. */
+  for(c = 0; c < UIP_CONNS; ++c) {
+    conn = &ustack->uip_conns[c];
+    if(conn->tcpstateflags != UIP_CLOSED &&
+       conn->lport == htons(ustack->lastport)) {
+      goto again;
+    }
+  }
+
+  conn = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    cconn = &ustack->uip_conns[c];
+    if(cconn->tcpstateflags == UIP_CLOSED) {
+      conn = cconn;
+      break;
+    }
+    if(cconn->tcpstateflags == UIP_TIME_WAIT) {
+      if(conn == 0 ||
+	 cconn->timer > conn->timer) {
+	conn = cconn;
+      }
+    }
+  }
+
+  if(conn == 0) {
+    return 0;
+  }
+  
+  conn->tcpstateflags = UIP_SYN_SENT;
+
+  conn->snd_nxt[0] = ustack->iss[0];
+  conn->snd_nxt[1] = ustack->iss[1];
+  conn->snd_nxt[2] = ustack->iss[2];
+  conn->snd_nxt[3] = ustack->iss[3];
+
+  conn->initialmss = conn->mss = UIP_TCP_MSS;
+  
+  conn->len = 1;   /* TCP length of the SYN is one. */
+  conn->nrtx = 0;
+  conn->timer = 1; /* Send the SYN next time around. */
+  conn->rto = UIP_RTO;
+  conn->sa = 0;
+  conn->sv = 16;   /* Initial value of the RTT variance. */
+  conn->lport = htons(ustack->lastport);
+  conn->rport = rport;
+  uip_ip4addr_copy(&conn->ripaddr, ripaddr);
+  
+  return conn;
+}
+#endif /* UIP_ACTIVE_OPEN */
+/*---------------------------------------------------------------------------*/
+#if UIP_UDP
+struct uip_udp_conn *
+uip_udp_new(struct uip_stack *ustack, uip_ip4addr_t *ripaddr, u16_t rport)
+{
+  u8_t c;
+  register struct uip_udp_conn *conn;
+  
+  /* Find an unused local port. */
+ again:
+  ++ustack->lastport;
+
+  if(ustack->lastport >= 32000) {
+    ustack->lastport = 4096;
+  }
+  
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    if(ustack->uip_udp_conns[c].lport == htons(ustack->lastport)) {
+      goto again;
+    }
+  }
+
+
+  conn = 0;
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    if(ustack->uip_udp_conns[c].lport == 0) {
+      conn = &ustack->uip_udp_conns[c];
+      break;
+    }
+  }
+
+  if(conn == 0) {
+    return 0;
+  }
+
+  conn->lport = htons(ustack->lastport);
+  conn->rport = rport;
+  if(ripaddr == NULL) {
+    memset(conn->ripaddr, 0, sizeof(uip_ip4addr_t));
+  } else {
+    uip_ip4addr_copy(&conn->ripaddr, ripaddr);
+  }
+  conn->ttl = UIP_TTL;
+  
+  return conn;
+}
+#endif /* UIP_UDP */
+/*---------------------------------------------------------------------------*/
+void
+uip_unlisten(struct uip_stack *ustack, u16_t port)
+{
+  u8_t c;
+
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(ustack->uip_listenports[c] == port) {
+      ustack->uip_listenports[c] = 0;
+      return;
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+uip_listen(struct uip_stack *ustack, u16_t port)
+{
+  u8_t c;
+
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(ustack->uip_listenports[c] == 0) {
+      ustack->uip_listenports[c] = port;
+      return;
+    }
+  }
+}
+
+
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+int uip_newdata(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_NEWDATA;
+}
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data.
+ *
+ * \hideinitializer
+ */
+#define uip_acked()   (uip_flags & UIP_ACKDATA)
+
+/**
+ * Has the connection just been connected?
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+int uip_connected(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_CONNECTED;
+}
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+int uip_closed(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_CLOSE;
+}
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+int uip_aborted(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_ABORT;
+}
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+int uip_timedout(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_TIMEDOUT;
+}
+
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+int uip_rexmit(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_REXMIT;
+}
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */
+int uip_poll(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_POLL;
+}
+
+int uip_initialmss(struct uip_stack *ustack)
+{
+	return ustack->uip_conn->initialmss;
+}
+
+int uip_mss(struct uip_stack *ustack)
+{
+	return ustack->uip_conn->mss;
+}
+
+/*---------------------------------------------------------------------------*/
+/* XXX: IP fragment reassembly: not well-tested. */
+
+#if UIP_REASSEMBLY && !UIP_CONF_IPV6
+#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
+static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
+static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
+static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
+				    0x0f, 0x07, 0x03, 0x01};
+static u16_t uip_reasslen;
+static u8_t uip_reassflags;
+#define UIP_REASS_FLAG_LASTFRAG 0x01
+static u8_t uip_reasstmr;
+
+#define IP_MF   0x20
+
+static u8_t
+uip_reass(void)
+{
+  u16_t offset, len;
+  u16_t i;
+
+  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
+     write the IP header of the fragment into the reassembly
+     buffer. The timer is updated with the maximum age. */
+  if(uip_reasstmr == 0) {
+    memcpy(uip_reassbuf, &BUF(ustack)->vhl, uip_iph_len);
+    uip_reasstmr = UIP_REASS_MAXAGE;
+    uip_reassflags = 0;
+    /* Clear the bitmap. */
+    memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
+  }
+
+  /* Check if the incoming fragment matches the one currently present
+     in the reasembly buffer. If so, we proceed with copying the
+     fragment into the buffer. */
+  if(BUF(ustack)->srcipaddr[0] == FBUF(ustack)->srcipaddr[0] &&
+     BUF(ustack)->srcipaddr[1] == FBUF(ustack)->srcipaddr[1] &&
+     BUF(ustack)->destipaddr[0] == FBUF(ustack)->destipaddr[0] &&
+     BUF(ustack)->destipaddr[1] == FBUF(ustack)->destipaddr[1] &&
+     BUF(ustack)->ipid[0] == FBUF(ustack)->ipid[0] &&
+     BUF(ustack)->ipid[1] == FBUF(ustack)->ipid[1]) {
+
+    len = (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1] - (BUF(ustack)->vhl & 0x0f) * 4;
+    offset = (((BUF(ustack)->ipoffset[0] & 0x3f) << 8) + BUF(ustack)->ipoffset[1]) * 8;
+
+    /* If the offset or the offset + fragment length overflows the
+       reassembly buffer, we discard the entire packet. */
+    if(offset > UIP_REASS_BUFSIZE ||
+       offset + len > UIP_REASS_BUFSIZE) {
+      uip_reasstmr = 0;
+      goto nullreturn;
+    }
+
+    /* Copy the fragment into the reassembly buffer, at the right
+       offset. */
+    memcpy(&uip_reassbuf[uip_iph_len + offset],
+	   (char *)BUF + (int)((BUF(ustack)->vhl & 0x0f) * 4),
+	   len);
+      
+    /* Update the bitmap. */
+    if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
+      /* If the two endpoints are in the same byte, we only update
+	 that byte. */
+	     
+      uip_reassbitmap[offset / (8 * 8)] |=
+	     bitmap_bits[(offset / 8 ) & 7] &
+	     ~bitmap_bits[((offset + len) / 8 ) & 7];
+    } else {
+      /* If the two endpoints are in different bytes, we update the
+	 bytes in the endpoints and fill the stuff inbetween with
+	 0xff. */
+      uip_reassbitmap[offset / (8 * 8)] |=
+	bitmap_bits[(offset / 8 ) & 7];
+      for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
+	uip_reassbitmap[i] = 0xff;
+      }
+      uip_reassbitmap[(offset + len) / (8 * 8)] |=
+	~bitmap_bits[((offset + len) / 8 ) & 7];
+    }
+    
+    /* If this fragment has the More Fragments flag set to zero, we
+       know that this is the last fragment, so we can calculate the
+       size of the entire packet. We also set the
+       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
+       the final fragment. */
+
+    if((BUF(ustack)->ipoffset[0] & IP_MF) == 0) {
+      uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
+      uip_reasslen = offset + len;
+    }
+    
+    /* Finally, we check if we have a full packet in the buffer. We do
+       this by checking if we have the last fragment and if all bits
+       in the bitmap are set. */
+    if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
+      /* Check all bytes up to and including all but the last byte in
+	 the bitmap. */
+      for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
+	if(uip_reassbitmap[i] != 0xff) {
+	  goto nullreturn;
+	}
+      }
+      /* Check the last byte in the bitmap. It should contain just the
+	 right amount of bits. */
+      if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
+	 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
+	goto nullreturn;
+      }
+
+      /* If we have come this far, we have a full packet in the
+	 buffer, so we allocate a pbuf and copy the packet into it. We
+	 also reset the timer. */
+      uip_reasstmr = 0;
+      memcpy(BUF, FBUF, uip_reasslen);
+
+      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
+	 from now on. */
+      BUF(ustack)->ipoffset[0] = BUF(ustack)->ipoffset[1] = 0;
+      BUF(ustack)->len[0] = uip_reasslen >> 8;
+      BUF(ustack)->len[1] = uip_reasslen & 0xff;
+      BUF(ustack)->ipchksum = 0;
+      BUF(ustack)->ipchksum = ~(uip_ipchksum());
+
+      return uip_reasslen;
+    }
+  }
+
+ nullreturn:
+  return 0;
+}
+#endif /* UIP_REASSEMBLY */
+/*---------------------------------------------------------------------------*/
+static void
+uip_add_rcv_nxt(struct uip_stack *ustack, u16_t n)
+{
+  u8_t uip_acc32[4];
+
+  uip_add32(ustack->uip_conn->rcv_nxt, n, uip_acc32);
+  ustack->uip_conn->rcv_nxt[0] = uip_acc32[0];
+  ustack->uip_conn->rcv_nxt[1] = uip_acc32[1];
+  ustack->uip_conn->rcv_nxt[2] = uip_acc32[2];
+  ustack->uip_conn->rcv_nxt[3] = uip_acc32[3];
+}
+/*---------------------------------------------------------------------------*/
+
+/** @} */
+
+/**
+ * \defgroup uipdevfunc uIP device driver functions
+ * @{
+ *
+ * These functions are used by a network device driver for interacting
+ * with uIP.
+ */
+
+/**
+ * Process an incoming packet.
+ *
+ * This function should be called when the device driver has received
+ * a packet from the network. The packet from the device driver must
+ * be present in the uip_buf buffer, and the length of the packet
+ * should be placed in the uip_len variable.
+ *
+ * When the function returns, there may be an outbound packet placed
+ * in the uip_buf packet buffer. If so, the uip_len variable is set to
+ * the length of the packet. If no packet is to be sent out, the
+ * uip_len variable is set to 0.
+ *
+ * The usual way of calling the function is presented by the source
+ * code below.
+ \code
+  uip_len = devicedriver_poll();
+  if(uip_len > 0) {
+    uip_input();
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uIP ARP code before calling
+ * this function:
+ \code
+  #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  uip_len = ethernet_devicedrver_poll();
+  if(uip_len > 0) {
+    if(BUF(ustack)->type == HTONS(UIP_ETHTYPE_IP)) {
+      uip_arp_ipin();
+      uip_input();
+      if(uip_len > 0) {
+        uip_arp_out();
+        ethernet_devicedriver_send();
+      }
+    } else if(BUF(ustack)->type == HTONS(UIP_ETHTYPE_ARP)) {
+      uip_arp_arpin();
+      if(uip_len > 0) {
+        ethernet_devicedriver_send();
+      }
+    }
+ \endcode
+ *
+ * \hideinitializer
+ */
+void uip_input(struct uip_stack *ustack)
+{
+	uip_process(ustack, UIP_DATA);
+}
+
+/**
+ * Periodic processing for a connection identified by its number.
+ *
+ * This function does the necessary periodic processing (timers,
+ * polling) for a uIP TCP conneciton, and should be called when the
+ * periodic uIP timer goes off. It should be called for every
+ * connection, regardless of whether they are open of closed.
+ *
+ * When the function returns, it may have an outbound packet waiting
+ * for service in the uIP packet buffer, and if so the uip_len
+ * variable is set to a value larger than zero. The device driver
+ * should be called to send out the packet.
+ *
+ * The ususal way of calling the function is through a for() loop like
+ * this:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uip_arp_out() function before
+ * calling the device driver:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the connection which is to be periodically polled.
+ *
+ * \hideinitializer
+ */
+void uip_periodic(struct uip_stack *ustack, int conn) 
+{
+	ustack->uip_conn = &ustack->uip_conns[conn];
+	uip_process(ustack, UIP_TIMER);
+}
+
+#if UIP_UDP
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_periodic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+void uip_udp_periodic(struct uip_stack *ustack, int conn)
+{
+	ustack->uip_udp_conn = &ustack->uip_udp_conns[conn];
+	uip_process(ustack, UIP_UDP_TIMER);
+}
+#endif
+
+
+void
+uip_process(struct uip_stack *ustack, u8_t flag)
+{
+  u8_t  c;
+  u16_t tmp16;
+  register struct uip_conn *uip_connr = ustack->uip_conn;
+
+  u16_t uip_iph_len     = 0;
+  u16_t uip_ip_udph_len = 0;
+  u16_t uip_ip_tcph_len = 0;
+  struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL;
+  struct uip_tcp_hdr *tcp_hdr = NULL;
+  struct uip_icmpv4_hdr *icmpv4_hdr = NULL;
+  struct uip_icmpv6_hdr *icmpv6_hdr = NULL;
+  struct uip_udp_hdr *udp_hdr = NULL;
+
+  if(is_ipv6(ustack))
+  {
+    uint8_t *buf;
+    uip_iph_len     = UIP_IPv6_H_LEN;
+    uip_ip_udph_len = UIP_IPv6_UDPH_LEN;
+    uip_ip_tcph_len = UIP_IPv6_TCPH_LEN;
+
+    buf = ustack->network_layer;
+    buf += sizeof(struct uip_ipv6_hdr);
+    tcp_hdr = (struct uip_tcp_hdr *) buf;
+
+    buf = ustack->network_layer;
+    buf += sizeof(struct uip_ipv6_hdr);
+    udp_hdr = (struct uip_udp_hdr *) buf;
+
+    buf = ustack->network_layer;
+    buf += sizeof(struct uip_ipv6_hdr);
+    icmpv6_hdr = (struct uip_icmpv6_hdr *) buf;
+  }
+  else
+  {
+    uint8_t *buf;
+
+    uip_iph_len     = UIP_IPv4_H_LEN;
+    uip_ip_udph_len = UIP_IPv4_UDPH_LEN; 
+    uip_ip_tcph_len = UIP_IPv4_TCPH_LEN;
+
+    tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *) ustack->network_layer;
+
+    buf = ustack->network_layer;
+    buf += sizeof(struct uip_ipv4_hdr);
+    tcp_hdr = (struct uip_tcp_hdr *) buf;
+
+    buf = ustack->network_layer;
+    buf += sizeof(struct uip_ipv4_hdr);
+    icmpv4_hdr = (struct uip_icmpv4_hdr *) buf;
+
+    buf = ustack->network_layer;
+    buf += sizeof(struct uip_ipv4_hdr);
+    udp_hdr = (struct uip_udp_hdr *) buf;
+  }
+
+#if UIP_UDP
+  if(flag == UIP_UDP_SEND_CONN) {
+    goto udp_send;
+  }
+#endif /* UIP_UDP */
+  
+  ustack->uip_sappdata = ustack->uip_appdata = &ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN];
+
+  /* Check if we were invoked because of a poll request for a
+     particular connection. */
+  if(flag == UIP_POLL_REQUEST) {
+    if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED &&
+       !uip_outstanding(uip_connr)) {
+	ustack->uip_flags = UIP_POLL;
+	UIP_APPCALL(ustack);
+	goto appsend;
+    }
+    goto drop;
+    
+    /* Check if we were invoked because of the perodic timer fireing. */
+  } else if(flag == UIP_TIMER) {
+#if UIP_REASSEMBLY
+    if(uip_reasstmr != 0) {
+      --uip_reasstmr;
+    }
+#endif /* UIP_REASSEMBLY */
+    /* Increase the initial sequence number. */
+    if(++ustack->iss[3] == 0) {
+      if(++ustack->iss[2] == 0) {
+	if(++ustack->iss[1] == 0) {
+	  ++ustack->iss[0];
+	}
+      }
+    }
+
+    /* Reset the length variables. */
+    ustack->uip_len = 0;
+    ustack->uip_slen = 0;
+
+    /* Check if the connection is in a state in which we simply wait
+       for the connection to time out. If so, we increase the
+       connection's timer and remove the connection if it times
+       out. */
+    if(uip_connr->tcpstateflags == UIP_TIME_WAIT ||
+       uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
+      ++(uip_connr->timer);
+      if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
+	uip_connr->tcpstateflags = UIP_CLOSED;
+      }
+    } else if(uip_connr->tcpstateflags != UIP_CLOSED) {
+      /* If the connection has outstanding data, we increase the
+	 connection's timer and see if it has reached the RTO value
+	 in which case we retransmit. */
+      if(uip_outstanding(uip_connr)) {
+	if(uip_connr->timer-- == 0) {
+	  if(uip_connr->nrtx == UIP_MAXRTX ||
+	     ((uip_connr->tcpstateflags == UIP_SYN_SENT ||
+	       uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
+	      uip_connr->nrtx == UIP_MAXSYNRTX)) {
+	    uip_connr->tcpstateflags = UIP_CLOSED;
+
+	    /* We call UIP_APPCALL() with uip_flags set to
+	       UIP_TIMEDOUT to inform the application that the
+	       connection has timed out. */
+	    ustack->uip_flags = UIP_TIMEDOUT;
+	    UIP_APPCALL(ustack);
+
+	    /* We also send a reset packet to the remote host. */
+	    tcp_hdr->flags = TCP_RST | TCP_ACK;
+	    goto tcp_send_nodata;
+	  }
+
+	  /* Exponential backoff. */
+	  uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
+					 4:
+					 uip_connr->nrtx);
+	  ++(uip_connr->nrtx);
+	  
+	  /* Ok, so we need to retransmit. We do this differently
+	     depending on which state we are in. In ESTABLISHED, we
+	     call upon the application so that it may prepare the
+	     data for the retransmit. In SYN_RCVD, we resend the
+	     SYNACK that we sent earlier and in LAST_ACK we have to
+	     retransmit our FINACK. */
+	  ++ustack->stats.tcp.rexmit;
+	  switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
+	  case UIP_SYN_RCVD:
+	    /* In the SYN_RCVD state, we should retransmit our
+               SYNACK. */
+	    goto tcp_send_synack;
+	    
+#if UIP_ACTIVE_OPEN
+	  case UIP_SYN_SENT:
+	    /* In the SYN_SENT state, we retransmit out SYN. */
+	    tcp_hdr->flags = 0;
+	    goto tcp_send_syn;
+#endif /* UIP_ACTIVE_OPEN */
+	    
+	  case UIP_ESTABLISHED:
+	    /* In the ESTABLISHED state, we call upon the application
+               to do the actual retransmit after which we jump into
+               the code for sending out the packet (the apprexmit
+               label). */
+	    ustack->uip_flags = UIP_REXMIT;
+	    UIP_APPCALL(ustack);
+	    goto apprexmit;
+	    
+	  case UIP_FIN_WAIT_1:
+	  case UIP_CLOSING:
+	  case UIP_LAST_ACK:
+	    /* In all these states we should retransmit a FINACK. */
+	    goto tcp_send_finack;
+	    
+	  }
+	}
+      } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {
+	/* If there was no need for a retransmission, we poll the
+           application for new data. */
+	ustack->uip_flags = UIP_POLL;
+	UIP_APPCALL(ustack);
+	goto appsend;
+      }
+    }
+    goto drop;
+  }
+#if UIP_UDP
+  if(flag == UIP_UDP_TIMER) {
+    if(ustack->uip_udp_conn->lport != 0) {
+      ustack->uip_conn = NULL;
+      ustack->uip_sappdata = ustack->uip_appdata = ustack->uip_buf + UIP_LLH_LEN + uip_ip_udph_len;
+      ustack->uip_len = ustack->uip_slen = 0;
+      ustack->uip_flags = UIP_POLL;
+      UIP_UDP_APPCALL(ustack);
+      goto udp_send;
+    } else {
+      goto drop;
+    }
+  }
+#endif
+
+  /* This is where the input processing starts. */
+  ++ustack->stats.ip.recv;
+
+  /* Start of IP input header processing code. */
+  
+  if(is_ipv6(ustack)) {
+	  /* Check validity of the IP header. */
+	  if((IPv6_BUF(ustack)->vtc & 0xf0) != 0x60)  { /* IP version and header length. */
+	    ++ustack->stats.ip.drop;
+	    ++ustack->stats.ip.vhlerr;
+	    LOG_ERR(PFX "ipv6: invalid version.");
+	    goto drop;
+	  }
+  } else {
+	  /* Check validity of the IP header. */
+	  if(tcp_ipv4_hdr->vhl != 0x45)  { /* IP version and header length. */
+	    ++ustack->stats.ip.drop;
+	    ++ustack->stats.ip.vhlerr;
+	    LOG_ERR(PFX "ipv4: invalid version or header length.");
+	    goto drop;
+	  }
+  }
+  
+  /* Check the size of the packet. If the size reported to us in
+     uip_len is smaller the size reported in the IP header, we assume
+     that the packet has been corrupted in transit. If the size of
+     uip_len is larger than the size reported in the IP packet header,
+     the packet has been padded and we set uip_len to the correct
+     value.. */
+
+  if(is_ipv6(ustack)) {
+	  if((IPv6_BUF(ustack)->len[0] << 8) + 
+	      IPv6_BUF(ustack)->len[1] <= ustack->uip_len) {
+	    ustack->uip_len = (IPv6_BUF(ustack)->len[0] << 8) +
+	    		       IPv6_BUF(ustack)->len[1];
+	    ustack->uip_len += 40; /* The length reported in the IPv6 header is the
+				      length of the payload that follows the
+				      header. However, uIP uses the uip_len variable
+				      for holding the size of the entire packet,
+				      including the IP header. For IPv4 this is not a
+				      problem as the length field in the IPv4 header
+				      contains the length of the entire packet. But
+				      for IPv6 we need to add the size of the IPv6
+				      header (40 bytes). */
+	  } else {
+	    LOG_WARN(PFX "ip: packet shorter than reported in IP header:"
+	    		 "IPv6_BUF(ustack)->len: %d ustack->uip_len:%d.",
+	             (IPv6_BUF(ustack)->len[0] << 8) + IPv6_BUF(ustack)->len[1],
+		     ustack->uip_len);
+	    goto drop;
+	  }
+   } else {
+	  if((tcp_ipv4_hdr->len[0] << 8) +
+	      tcp_ipv4_hdr->len[1] <= ustack->uip_len) {
+	    ustack->uip_len = (tcp_ipv4_hdr->len[0] << 8) +
+	    		       tcp_ipv4_hdr->len[1];
+	  } else {
+	    LOG_WARN(PFX "ip: packet shorter than reported in IP header: "
+	    		 "tcp_ipv4_hdr->len: %d ustack->uip_len:%d.",
+	             (tcp_ipv4_hdr->len[0] << 8) + tcp_ipv4_hdr->len[1],
+		     ustack->uip_len);
+	    goto drop;
+	  }
+   }
+
+   if(!is_ipv6(ustack)) {
+ 	 /* Check the fragment flag. */
+	  if((tcp_ipv4_hdr->ipoffset[0] & 0x3f) != 0 ||
+	      tcp_ipv4_hdr->ipoffset[1] != 0) {
+#if UIP_REASSEMBLY
+	    uip_len = uip_reass();
+	    if(uip_len == 0) {
+	      goto drop;
+	    }
+#else /* UIP_REASSEMBLY */
+	    ++ustack->stats.ip.drop;
+	    ++ustack->stats.ip.fragerr;
+	    LOG_WARN(PFX "ip: fragment dropped.");
+	    goto drop;
+#endif /* UIP_REASSEMBLY */
+	  }
+  }
+
+  if(is_ipv6(ustack)) {
+	  if(uip_ip6addr_cmp(ustack->hostaddr6, all_zeroes_addr6)) {
+	  } else {
+	    /* If IP broadcast support is configured, we check for a broadcast
+	       UDP packet, which may be destined to us. */
+#if UIP_BROADCAST
+	    if(IPv6_BUF(ustack)->proto == UIP_PROTO_UDP &&
+	       uip_ip4addr_cmp(IPv6_BUF(ustack)->destipaddr, all_ones_addr)
+	       /*&&
+		 uip_ipchksum() == 0xffff*/) {
+	      goto udp_input;
+	    }
+#endif	    
+    /* For IPv6, packet reception is a little trickier as we need to
+       make sure that we listen to certain multicast addresses (all
+       hosts multicast address, and the solicited-node multicast
+       address) as well. However, we will cheat here and accept all
+       multicast packets that are sent to the ff02::/16 addresses. */
+    if(!uip_ip6addr_cmp(IPv6_BUF(ustack)->destipaddr, ustack->hostaddr6) &&
+       IPv6_BUF(ustack)->destipaddr[0] != htons(0xff02)) {
+      ++ustack->stats.ip.drop;
+      goto drop;
+    }
+    }
+  } else {
+	  if(uip_ip4addr_cmp(ustack->hostaddr, all_zeroes_addr4)) {
+	    /* If we are configured to use ping IP address configuration and
+	       hasn't been assigned an IP address yet, we accept all ICMP
+	       packets. */
+#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
+	    if(tcp_ipv4_hdr->proto == UIP_PROTO_ICMP) {
+	      LOG_WARN(PFX "ip: possible ping config packet received.");
+	      goto icmp_input;
+	    } else {
+	      LOG_WARN(PFX "ip: packet dropped since no address assigned.");
+	      goto drop;
+	    }
+#endif /* UIP_PINGADDRCONF */
+
+	  } else {
+	    /* If IP broadcast support is configured, we check for a broadcast
+	       UDP packet, which may be destined to us. */
+#if UIP_BROADCAST
+	    if(tcp_ipv4_hdr->proto == UIP_PROTO_UDP &&
+	       uip_ip4addr_cmp(tcp_ipv4_hdr->destipaddr, all_ones_addr)
+	       /*&&
+		 uip_ipchksum() == 0xffff*/) {
+	      goto udp_input;
+	    }
+#endif /* UIP_BROADCAST */
+    
+    /* Check if the packet is destined for our IP address. */
+	    if(!uip_ip4addr_cmp(tcp_ipv4_hdr->destipaddr,
+	    	ustack->hostaddr)) {
+	      ++ustack->stats.ip.drop;
+	      goto drop;
+	    }
+	}
+
+	  if(uip_ipchksum(ustack) != 0xffff) { /* Compute and check the IP header
+				    checksum. */
+	    ++ustack->stats.ip.drop;
+	    ++ustack->stats.ip.chkerr;
+	    LOG_ERR(PFX "ip: bad checksum.");
+	    goto drop;
+	  }
+  }
+
+ if( is_ipv6(ustack)) {
+	  if(IPv6_BUF(ustack)->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
+					       proceed with TCP input
+					       processing. */
+	    goto tcp_input;
+	  }
+
+#if UIP_UDP
+	  if(IPv6_BUF(ustack)->proto == UIP_PROTO_UDP) {
+	    goto udp_input;
+	  }
+#endif /* UIP_UDP */
+
+	  /* This is IPv6 ICMPv6 processing code. */
+	  LOG_DEBUG(PFX "icmp6_input: length %d\n", ustack->uip_len);
+
+	  if(IPv6_BUF(ustack)->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from
+					 here. */
+	    ++ustack->stats.ip.drop;
+	    ++ustack->stats.ip.protoerr;
+	    LOG_ERR(PFX "ip: neither tcp nor icmp6.");
+	    goto drop;
+	  }
+
+	  ++ustack->stats.icmp.recv;
+
+	  /* If we get a neighbor solicitation for our address we should send
+	     a neighbor advertisement message back. */
+	  if(icmpv6_hdr->type == ICMP6_NEIGHBOR_SOLICITATION) {
+	    if(uip_ip6addr_cmp(icmpv6_hdr->icmp6data,
+	    		       ustack->hostaddr6)) {
+
+	      if(icmpv6_hdr->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) {
+		/* Save the sender's address in our neighbor list. */
+
+		uip_neighbor_add(ustack,
+				 IPv6_BUF(ustack)->srcipaddr,
+				 (struct uip_eth_addr *) &(icmpv6_hdr->options[2]));
+	      }
+      
+	      /* We should now send a neighbor advertisement back to where the
+		 neighbor solicication came from. */
+	      icmpv6_hdr->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
+	      icmpv6_hdr->flags = ICMP6_FLAG_S; /* Solicited flag. */
+      
+	      icmpv6_hdr->reserved1 = icmpv6_hdr->reserved2 = icmpv6_hdr->reserved3 = 0;
+      
+	      uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
+	      		       IPv6_BUF(ustack)->srcipaddr);
+	      uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
+	      		       ustack->hostaddr6);
+	      icmpv6_hdr->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
+	      icmpv6_hdr->options[1] = 1;  /* Options length, 1 = 8 bytes. */
+	      memcpy(&(icmpv6_hdr->options[2]),
+	      	     &ustack->uip_ethaddr, sizeof(struct uip_eth_addr));
+	      icmpv6_hdr->icmpchksum = 0;
+	      icmpv6_hdr->icmpchksum = ~uip_icmp6chksum(ustack);
+	      goto send;
+      
+	    }
+	    goto drop;
+	  } else if(icmpv6_hdr->type == ICMP6_ECHO) {
+	    /* ICMP echo (i.e., ping) processing. This is simple, we only
+	       change the ICMP type from ECHO to ECHO_REPLY and update the
+	       ICMP checksum before we return the packet. */
+
+	    icmpv6_hdr->type = ICMP6_ECHO_REPLY;
+    
+	    uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
+	    		     IPv6_BUF(ustack)->srcipaddr);
+	    uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
+	    		     ustack->hostaddr6);
+	    icmpv6_hdr->icmpchksum = 0;
+	    icmpv6_hdr->icmpchksum = ~uip_icmp6chksum(ustack);
+    
+	    ++ustack->stats.icmp.sent;
+	    goto send;
+	  } else {
+	    LOG_DEBUG(PFX "Unknown icmp6 message type %d\n",
+	    		 icmpv6_hdr->type);
+	    ++ustack->stats.icmp.drop;
+	    ++ustack->stats.icmp.typeerr;
+	    LOG_ERR(PFX "icmpv6: unknown ICMP message.");
+	    goto drop;
+	  }
+
+	  /* End of IPv6 ICMP processing. */
+ } else {
+	  if(tcp_ipv4_hdr->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
+					       proceed with TCP input
+					       processing. */
+	    goto tcp_input;
+	  }
+
+#if UIP_UDP
+	  if(tcp_ipv4_hdr->proto == UIP_PROTO_UDP) {
+	    goto udp_input;
+	  }
+#endif /* UIP_UDP */
+
+	  /* ICMPv4 processing code follows. */
+	  if(tcp_ipv4_hdr->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
+					here. */
+	    ++ustack->stats.ip.drop;
+	    ++ustack->stats.ip.protoerr;
+	    LOG_ERR(PFX "ip: neither tcp nor icmp.");
+	    goto drop;
+	  }
+
+	#if UIP_PINGADDRCONF
+icmp_input:
+	#endif /* UIP_PINGADDRCONF */
+	  ++ustack->stats.icmp.recv;
+
+	  /* ICMP echo (i.e., ping) processing. This is simple, we only change
+	     the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
+	     checksum before we return the packet. */
+	  if(icmpv4_hdr->type != ICMP_ECHO) {
+	    ++ustack->stats.icmp.drop;
+	    ++ustack->stats.icmp.typeerr;
+	    LOG_ERR(PFX "icmp: not icmp echo.");
+	    goto drop;
+	  }
+
+	  /* If we are configured to use ping IP address assignment, we use
+	     the destination IP address of this ping packet and assign it to
+	     ourself. */
+#if UIP_PINGADDRCONF
+	  if((ustack->hostaddr[0] | ustack->hostaddr[1]) == 0) {
+	    ustack->hostaddr[0] = tcp_ipv4_hdr->destipaddr[0];
+	    ustack->hostaddr[1] = tcp_ipv4_hdr->destipaddr[1];
+  }
+#endif /* UIP_PINGADDRCONF */
+
+	  icmpv4_hdr->type = ICMP_ECHO_REPLY;
+
+	  if(icmpv4_hdr->icmpchksum >= htons(0xffff - (ICMP_ECHO << 8))) {
+	     icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8) + 1;
+	  } else {
+	     icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8);
+	  }
+
+	  /* Swap IP addresses. */
+	  uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
+	  		   tcp_ipv4_hdr->srcipaddr);
+	  uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
+
+	  ++ustack->stats.icmp.sent;
+	  goto send;
+
+  /* End of IPv4 input header processing code. */
+
+  }
+
+#if UIP_UDP
+  /* UDP input processing. */
+ udp_input:
+  /* UDP processing is really just a hack. We don't do anything to the
+     UDP/IP headers, but let the UDP application do all the hard
+     work. If the application sets uip_slen, it has a packet to
+     send. */
+#if UIP_UDP_CHECKSUMS
+  ustack->uip_len = ustack->uip_len - uip_ip_udph_len;
+  ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + uip_ip_udph_len];
+  if(UDPBUF(ustack)->udpchksum != 0 && uip_udpchksum(ustack) != 0xffff) {
+    ++ustack->stats.udp.drop;
+    ++ustack->stats.udp.chkerr;
+    LOG_ERR(PFX "udp: bad checksum.");
+    goto drop;
+  }
+#else /* UIP_UDP_CHECKSUMS */
+  uip_len = uip_len - uip_ip_udph_len;
+#endif /* UIP_UDP_CHECKSUMS */
+
+  /* Demultiplex this UDP packet between the UDP "connections". */
+  for(ustack->uip_udp_conn = &ustack->uip_udp_conns[0];
+      ustack->uip_udp_conn < &ustack->uip_udp_conns[UIP_UDP_CONNS];
+      ++ustack->uip_udp_conn) {
+    /* If the local UDP port is non-zero, the connection is considered
+       to be used. If so, the local port number is checked against the
+       destination port number in the received packet. If the two port
+       numbers match, the remote port number is checked if the
+       connection is bound to a remote port. Finally, if the
+       connection is bound to a remote IP address, the source IP
+       address of the packet is checked. */
+
+    if(is_ipv6(ustack)) {
+	    if(ustack->uip_udp_conn->lport != 0 &&
+	       udp_hdr->destport == ustack->uip_udp_conn->lport &&
+	       (ustack->uip_udp_conn->rport == 0 ||
+	       udp_hdr->srcport == ustack->uip_udp_conn->rport) &&
+	       (uip_ip6addr_cmp(ustack->uip_udp_conn->ripaddr,
+	       			all_zeroes_addr6) ||
+		uip_ip6addr_cmp(ustack->uip_udp_conn->ripaddr,
+				all_ones_addr6) ||
+		uip_ip6addr_cmp(IPv6_BUF(ustack)->srcipaddr,
+				ustack->uip_udp_conn->ripaddr))) {
+	      goto udp_found;
+	    }
+    } else {
+	    if(ustack->uip_udp_conn->lport != 0 &&
+	       UDPBUF(ustack)->destport == ustack->uip_udp_conn->lport &&
+	       (ustack->uip_udp_conn->rport == 0 ||
+	        UDPBUF(ustack)->srcport == ustack->uip_udp_conn->rport) &&
+	       (uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr,
+	       			all_zeroes_addr4) ||
+		uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr,
+				all_ones_addr4) ||
+		uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr,
+				ustack->uip_udp_conn->ripaddr))) {
+	      goto udp_found;
+	    }
+    }
+  }
+  LOG_ERR(PFX "udp: no matching connection found");
+  goto drop;
+  
+ udp_found:
+  ustack->uip_conn = NULL;
+  ustack->uip_flags = UIP_NEWDATA;
+  ustack->uip_sappdata = ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + uip_ip_udph_len];
+  ustack->uip_slen = 0;
+  UIP_UDP_APPCALL(ustack);
+ udp_send:
+  if(ustack->uip_slen == 0) {
+    goto drop;
+  }
+
+  ustack->uip_len = ustack->uip_slen + uip_ip_udph_len;
+
+  if(is_ipv6(ustack)) {
+	  /* For IPv6, the IP length field does not include the IPv6 IP header
+	     length. */
+	  IPv6_BUF(ustack)->len[0] = ((ustack->uip_len - uip_iph_len) >> 8);
+	  IPv6_BUF(ustack)->len[1] = ((ustack->uip_len - uip_iph_len) & 0xff);
+	  IPv6_BUF(ustack)->ttl = ustack->uip_udp_conn->ttl;
+	  IPv6_BUF(ustack)->proto = UIP_PROTO_UDP;
+  } else {
+	  tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8);
+	  tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
+	  tcp_ipv4_hdr->ttl = ustack->uip_udp_conn->ttl;
+	  tcp_ipv4_hdr->proto = UIP_PROTO_UDP;
+  }
+
+  udp_hdr->udplen = htons(ustack->uip_slen + UIP_UDPH_LEN);
+  udp_hdr->udpchksum = 0;
+
+  udp_hdr->srcport  = ustack->uip_udp_conn->lport;
+  udp_hdr->destport = ustack->uip_udp_conn->rport;
+
+  if(is_ipv6(ustack)) {
+	  uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
+	  		   ustack->hostaddr6);
+	  uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
+	  		   ustack->uip_udp_conn->ripaddr);
+  } else {
+	  uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr,
+	  		   ustack->hostaddr);
+	  uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
+	  		   ustack->uip_udp_conn->ripaddr);
+  }
+  ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + uip_ip_tcph_len];
+
+#if UIP_UDP_CHECKSUMS
+  /* Calculate UDP checksum. */
+  udp_hdr->udpchksum = ~(uip_udpchksum(ustack));
+  if(udp_hdr->udpchksum == 0) {
+    udp_hdr->udpchksum = 0xffff;
+  }
+#endif /* UIP_UDP_CHECKSUMS */
+  
+  goto ip_send_nolen;
+#endif /* UIP_UDP */
+  
+  /* TCP input processing. */
+ tcp_input:
+  ++ustack->stats.tcp.recv;
+
+  /* Start of TCP input header processing code. */
+  
+  if(uip_tcpchksum(ustack) != 0xffff) {   /* Compute and check the TCP
+				       checksum. */
+    ++ustack->stats.tcp.drop;
+    ++ustack->stats.tcp.chkerr;
+    LOG_ERR(PFX "tcp: bad checksum.");
+    goto drop;
+  }
+  
+  if(is_ipv6(ustack)) {
+	  /* Demultiplex this segment. */
+	  /* First check any active connections. */
+	  for(uip_connr = &ustack->uip_conns[0]; 
+	      uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
+	      ++uip_connr) {
+	    if(uip_connr->tcpstateflags != UIP_CLOSED &&
+	       tcp_hdr->destport == uip_connr->lport &&
+	       tcp_hdr->srcport == uip_connr->rport &&
+	       uip_ip6addr_cmp(IPv6_BUF(ustack)->srcipaddr,
+	       		       uip_connr->ripaddr)) {
+	      goto found;
+	    }
+	  }
+  } else {
+	  /* Demultiplex this segment. */
+	  /* First check any active connections. */
+	  for(uip_connr = &ustack->uip_conns[0]; 
+	      uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
+	      ++uip_connr) {
+	    if(uip_connr->tcpstateflags != UIP_CLOSED &&
+	       tcp_hdr->destport == uip_connr->lport &&
+	       tcp_hdr->srcport == uip_connr->rport &&
+	       uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr,
+	       		       uip_connr->ripaddr)) {
+	      goto found;
+	    }
+	  }
+  }
+
+  /* If we didn't find and active connection that expected the packet,
+     either this packet is an old duplicate, or this is a SYN packet
+     destined for a connection in LISTEN. If the SYN flag isn't set,
+     it is an old packet and we send a RST. */
+  if((tcp_hdr->flags & TCP_CTL) != TCP_SYN) {
+    goto reset;
+  }
+  
+  tmp16 = tcp_hdr->destport;
+  /* Next, check listening connections. */
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(tmp16 == ustack->uip_listenports[c])
+      goto found_listen;
+  }
+  
+  /* No matching connection found, so we send a RST packet. */
+  ++ustack->stats.tcp.synrst;
+ reset:
+
+  /* We do not send resets in response to resets. */
+  if(tcp_hdr->flags & TCP_RST) {
+    goto drop;
+  }
+
+  ++ustack->stats.tcp.rst;
+  
+  tcp_hdr->flags = TCP_RST | TCP_ACK;
+  ustack->uip_len = uip_ip_tcph_len;
+  tcp_hdr->tcpoffset = 5 << 4;
+
+  /* Flip the seqno and ackno fields in the TCP header. */
+  c = tcp_hdr->seqno[3];
+  tcp_hdr->seqno[3] = tcp_hdr->ackno[3];
+  tcp_hdr->ackno[3] = c;
+  
+  c = tcp_hdr->seqno[2];
+  tcp_hdr->seqno[2] = tcp_hdr->ackno[2];
+  tcp_hdr->ackno[2] = c;
+  
+  c = tcp_hdr->seqno[1];
+  tcp_hdr->seqno[1] = tcp_hdr->ackno[1];
+  tcp_hdr->ackno[1] = c;
+  
+  c = tcp_hdr->seqno[0];
+  tcp_hdr->seqno[0] = tcp_hdr->ackno[0];
+  tcp_hdr->ackno[0] = c;
+
+  /* We also have to increase the sequence number we are
+     acknowledging. If the least significant byte overflowed, we need
+     to propagate the carry to the other bytes as well. */
+  if(++tcp_hdr->ackno[3] == 0) {
+    if(++tcp_hdr->ackno[2] == 0) {
+      if(++tcp_hdr->ackno[1] == 0) {
+	++tcp_hdr->ackno[0];
+      }
+    }
+  }
+ 
+  /* Swap port numbers. */
+  tmp16 = tcp_hdr->srcport;
+  tcp_hdr->srcport = tcp_hdr->destport;
+  tcp_hdr->destport = tmp16;
+  
+  /* Swap IP addresses. */
+  if(is_ipv6(ustack)) {
+	  uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
+	  		   IPv6_BUF(ustack)->srcipaddr);
+	  uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
+	  		   ustack->hostaddr6);
+  } else {
+	  uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
+	  		   tcp_ipv4_hdr->srcipaddr);
+	  uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr,
+	  		   ustack->hostaddr);
+  }
+
+  /* And send out the RST packet! */
+  goto tcp_send_noconn;
+
+  /* This label will be jumped to if we matched the incoming packet
+     with a connection in LISTEN. In that case, we should create a new
+     connection and send a SYNACK in return. */
+ found_listen:
+  /* First we check if there are any connections avaliable. Unused
+     connections are kept in the same table as used connections, but
+     unused ones have the tcpstate set to CLOSED. Also, connections in
+     TIME_WAIT are kept track of and we'll use the oldest one if no
+     CLOSED connections are found. Thanks to Eddie C. Dost for a very
+     nice algorithm for the TIME_WAIT search. */
+  uip_connr = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    if(ustack->uip_conns[c].tcpstateflags == UIP_CLOSED) {
+      uip_connr = &ustack->uip_conns[c];
+      break;
+    }
+    if(ustack->uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
+      if(uip_connr == 0 ||
+	 ustack->uip_conns[c].timer > uip_connr->timer) {
+	uip_connr = &ustack->uip_conns[c];
+      }
+    }
+  }
+
+  if(uip_connr == 0) {
+    /* All connections are used already, we drop packet and hope that
+       the remote end will retransmit the packet at a time when we
+       have more spare connections. */
+    ++ustack->stats.tcp.syndrop;
+    LOG_WARN(PFX "tcp: found no unused connections.");
+    goto drop;
+  }
+  ustack->uip_conn = uip_connr;
+  
+  /* Fill in the necessary fields for the new connection. */
+  uip_connr->rto = uip_connr->timer = UIP_RTO;
+  uip_connr->sa = 0;
+  uip_connr->sv = 4;
+  uip_connr->nrtx = 0;
+  uip_connr->lport = tcp_hdr->destport;
+  uip_connr->rport = tcp_hdr->srcport;
+  if(is_ipv6(ustack)) {
+	  uip_ip6addr_copy(uip_connr->ripaddr, IPv6_BUF(ustack)->srcipaddr);
+  } else {
+	  uip_ip4addr_copy(uip_connr->ripaddr, tcp_ipv4_hdr->srcipaddr);
+  }
+  uip_connr->tcpstateflags = UIP_SYN_RCVD;
+
+  uip_connr->snd_nxt[0] = ustack->iss[0];
+  uip_connr->snd_nxt[1] = ustack->iss[1];
+  uip_connr->snd_nxt[2] = ustack->iss[2];
+  uip_connr->snd_nxt[3] = ustack->iss[3];
+  uip_connr->len = 1;
+
+  /* rcv_nxt should be the seqno from the incoming packet + 1. */
+  uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3];
+  uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2];
+  uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1];
+  uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0];
+  uip_add_rcv_nxt(ustack, 1);
+
+  /* Parse the TCP MSS option, if present. */
+  if((tcp_hdr->tcpoffset & 0xf0) > 0x50) {
+    for(c = 0; c < ((tcp_hdr->tcpoffset >> 4) - 5) << 2 ;) {
+      ustack->opt = ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + c];
+      if(ustack->opt == TCP_OPT_END) {
+	/* End of options. */
+	break;
+      } else if(ustack->opt == TCP_OPT_NOOP) {
+	++c;
+	/* NOP option. */
+      } else if(ustack->opt == TCP_OPT_MSS &&
+		ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
+	/* An MSS option with the right option length. */
+	tmp16 = ((u16_t)ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 2 + c] << 8) |
+	  (u16_t)ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 3 + c];
+	uip_connr->initialmss = uip_connr->mss =
+	  tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+	
+	/* And we are done processing options. */
+	break;
+      } else {
+	/* All other options have a length field, so that we easily
+	   can skip past them. */
+	if(ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c] == 0) {
+	  /* If the length field is zero, the options are malformed
+	     and we don't process them further. */
+	  break;
+	}
+	c += ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c];
+      }
+    }
+  }
+  
+  /* Our response will be a SYNACK. */
+#if UIP_ACTIVE_OPEN
+ tcp_send_synack:
+  tcp_hdr->flags = TCP_ACK;
+  
+ tcp_send_syn:
+  tcp_hdr->flags |= TCP_SYN;
+#else /* UIP_ACTIVE_OPEN */
+ tcp_send_synack:
+  tcp_hdr->flags = TCP_SYN | TCP_ACK;
+#endif /* UIP_ACTIVE_OPEN */
+  
+  /* We send out the TCP Maximum Segment Size option with our
+     SYNACK. */
+  tcp_hdr->optdata[0] = TCP_OPT_MSS;
+  tcp_hdr->optdata[1] = TCP_OPT_MSS_LEN;
+  tcp_hdr->optdata[2] = (UIP_TCP_MSS) / 256;
+  tcp_hdr->optdata[3] = (UIP_TCP_MSS) & 255;
+  ustack->uip_len = uip_ip_tcph_len + TCP_OPT_MSS_LEN;
+  tcp_hdr->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
+  goto tcp_send;
+
+  /* This label will be jumped to if we found an active connection. */
+ found:
+  ustack->uip_conn = uip_connr;
+  ustack->uip_flags = 0;
+  /* We do a very naive form of TCP reset processing; we just accept
+     any RST and kill our connection. We should in fact check if the
+     sequence number of this reset is wihtin our advertised window
+     before we accept the reset. */
+  if(tcp_hdr->flags & TCP_RST) {
+    uip_connr->tcpstateflags = UIP_CLOSED;
+    LOG_ERR(PFX "tcp: got reset, aborting connection.");
+    ustack->uip_flags = UIP_ABORT;
+    UIP_APPCALL(ustack);
+    goto drop;
+  }
+  /* Calculated the length of the data, if the application has sent
+     any data to us. */
+  c = (tcp_hdr->tcpoffset >> 4) << 2;
+  /* uip_len will contain the length of the actual TCP data. This is
+     calculated by subtracing the length of the TCP header (in
+     c) and the length of the IP header (20 bytes). */
+  ustack->uip_len = ustack->uip_len - c - uip_iph_len;
+
+  /* First, check if the sequence number of the incoming packet is
+     what we're expecting next. If not, we send out an ACK with the
+     correct numbers in. */
+  if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) &&
+       ((tcp_hdr->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
+    if((ustack->uip_len > 0 || ((tcp_hdr->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
+       (tcp_hdr->seqno[0] != uip_connr->rcv_nxt[0] ||
+	tcp_hdr->seqno[1] != uip_connr->rcv_nxt[1] ||
+	tcp_hdr->seqno[2] != uip_connr->rcv_nxt[2] ||
+	tcp_hdr->seqno[3] != uip_connr->rcv_nxt[3])) {
+      goto tcp_send_ack;
+    }
+  }
+
+  {
+    u8_t uip_acc32[4];
+
+  /* Next, check if the incoming segment acknowledges any outstanding
+     data. If so, we update the sequence number, reset the length of
+     the outstanding data, calculate RTT estimations, and reset the
+     retransmission timer. */
+  if((tcp_hdr->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
+    uip_add32(uip_connr->snd_nxt, uip_connr->len, uip_acc32);
+
+    if(tcp_hdr->ackno[0] == uip_acc32[0] &&
+       tcp_hdr->ackno[1] == uip_acc32[1] &&
+       tcp_hdr->ackno[2] == uip_acc32[2] &&
+       tcp_hdr->ackno[3] == uip_acc32[3]) {
+      /* Update sequence number. */
+      uip_connr->snd_nxt[0] = uip_acc32[0];
+      uip_connr->snd_nxt[1] = uip_acc32[1];
+      uip_connr->snd_nxt[2] = uip_acc32[2];
+      uip_connr->snd_nxt[3] = uip_acc32[3];
+	
+
+      /* Do RTT estimation, unless we have done retransmissions. */
+      if(uip_connr->nrtx == 0) {
+	signed char m;
+	m = uip_connr->rto - uip_connr->timer;
+	/* This is taken directly from VJs original code in his paper */
+	m = m - (uip_connr->sa >> 3);
+	uip_connr->sa += m;
+	if(m < 0) {
+	  m = -m;
+	}
+	m = m - (uip_connr->sv >> 2);
+	uip_connr->sv += m;
+	uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
+
+      }
+      /* Set the acknowledged flag. */
+      ustack->uip_flags = UIP_ACKDATA;
+      /* Reset the retransmission timer. */
+      uip_connr->timer = uip_connr->rto;
+
+      /* Reset length of outstanding data. */
+      uip_connr->len = 0;
+    }
+    
+  }
+
+  }
+
+  /* Do different things depending on in what state the connection is. */
+  switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
+    /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
+	implemented, since we force the application to close when the
+	peer sends a FIN (hence the application goes directly from
+	ESTABLISHED to LAST_ACK). */
+  case UIP_SYN_RCVD:
+    /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
+       we are waiting for an ACK that acknowledges the data we sent
+       out the last time. Therefore, we want to have the UIP_ACKDATA
+       flag set. If so, we enter the ESTABLISHED state. */
+    if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_ESTABLISHED;
+      ustack->uip_flags = UIP_CONNECTED;
+      uip_connr->len = 0;
+      if(ustack->uip_len > 0) {
+        ustack->uip_flags |= UIP_NEWDATA;
+        uip_add_rcv_nxt(ustack, ustack->uip_len);
+      }
+      ustack->uip_slen = 0;
+      UIP_APPCALL(ustack);
+      goto appsend;
+    }
+    goto drop;
+#if UIP_ACTIVE_OPEN
+  case UIP_SYN_SENT:
+    /* In SYN_SENT, we wait for a SYNACK that is sent in response to
+       our SYN. The rcv_nxt is set to sequence number in the SYNACK
+       plus one, and we send an ACK. We move into the ESTABLISHED
+       state. */
+    if((ustack->uip_flags & UIP_ACKDATA) &&
+       (tcp_hdr->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
+
+      /* Parse the TCP MSS option, if present. */
+      if((tcp_hdr->tcpoffset & 0xf0) > 0x50) {
+	for(c = 0; c < ((tcp_hdr->tcpoffset >> 4) - 5) << 2 ;) {
+	  ustack->opt = ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + c];
+	  if(ustack->opt == TCP_OPT_END) {
+	    /* End of options. */
+	    break;
+	  } else if(ustack->opt == TCP_OPT_NOOP) {
+	    ++c;
+	    /* NOP option. */
+	  } else if(ustack->opt == TCP_OPT_MSS &&
+		    ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
+	    /* An MSS option with the right option length. */
+	    tmp16 = (ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 2 + c] << 8) |
+	      ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 3 + c];
+	    uip_connr->initialmss =
+	      uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+
+	    /* And we are done processing options. */
+	    break;
+	  } else {
+	    /* All other options have a length field, so that we easily
+	       can skip past them. */
+	    if(ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c] == 0) {
+	      /* If the length field is zero, the options are malformed
+		 and we don't process them further. */
+	      break;
+	    }
+	    c += ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c];
+	  }
+	}
+      }
+      uip_connr->tcpstateflags = UIP_ESTABLISHED;
+      uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0];
+      uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1];
+      uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2];
+      uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3];
+      uip_add_rcv_nxt(ustack, 1);
+      ustack->uip_flags = UIP_CONNECTED | UIP_NEWDATA;
+      uip_connr->len = 0;
+      ustack->uip_len = 0;
+      ustack->uip_slen = 0;
+      UIP_APPCALL(ustack);
+      goto appsend;
+    }
+    /* Inform the application that the connection failed */
+    ustack->uip_flags = UIP_ABORT;
+    UIP_APPCALL(ustack);
+    /* The connection is closed after we send the RST */
+    ustack->uip_conn->tcpstateflags = UIP_CLOSED;
+    goto reset;
+#endif /* UIP_ACTIVE_OPEN */
+    
+  case UIP_ESTABLISHED:
+    /* In the ESTABLISHED state, we call upon the application to feed
+    data into the uip_buf. If the UIP_ACKDATA flag is set, the
+    application should put new data into the buffer, otherwise we are
+    retransmitting an old segment, and the application should put that
+    data into the buffer.
+
+    If the incoming packet is a FIN, we should close the connection on
+    this side as well, and we send out a FIN and enter the LAST_ACK
+    state. We require that there is no outstanding data; otherwise the
+    sequence numbers will be screwed up. */
+
+    if(tcp_hdr->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+      if(uip_outstanding(uip_connr)) {
+	goto drop;
+      }
+      uip_add_rcv_nxt(ustack, 1 + ustack->uip_len);
+      ustack->uip_flags |= UIP_CLOSE;
+      if(ustack->uip_len > 0) {
+	ustack->uip_flags |= UIP_NEWDATA;
+      }
+      UIP_APPCALL(ustack);
+      uip_connr->len = 1;
+      uip_connr->tcpstateflags = UIP_LAST_ACK;
+      uip_connr->nrtx = 0;
+    tcp_send_finack:
+      tcp_hdr->flags = TCP_FIN | TCP_ACK;
+      goto tcp_send_nodata;
+    }
+
+    /* Check the URG flag. If this is set, the segment carries urgent
+       data that we must pass to the application. */
+    if((tcp_hdr->flags & TCP_URG) != 0) {
+#if UIP_URGDATA > 0
+      uip_urglen = (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1];
+      if(uip_urglen > uip_len) {
+	/* There is more urgent data in the next segment to come. */
+	uip_urglen = uip_len;
+      }
+      uip_add_rcv_nxt(uip_urglen);
+      uip_len -= uip_urglen;
+      uip_urgdata = uip_appdata;
+      uip_appdata += uip_urglen;
+    } else {
+      uip_urglen = 0;
+#else /* UIP_URGDATA > 0 */
+      ustack->uip_appdata = ((char *)ustack->uip_appdata) + ((tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1]);
+      ustack->uip_len -= (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1];
+#endif /* UIP_URGDATA > 0 */
+    }
+
+    /* If uip_len > 0 we have TCP data in the packet, and we flag this
+       by setting the UIP_NEWDATA flag and update the sequence number
+       we acknowledge. If the application has stopped the dataflow
+       using uip_stop(), we must not accept any data packets from the
+       remote host. */
+    if(ustack->uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+      ustack->uip_flags |= UIP_NEWDATA;
+      uip_add_rcv_nxt(ustack, ustack->uip_len);
+    }
+
+    /* Check if the available buffer space advertised by the other end
+       is smaller than the initial MSS for this connection. If so, we
+       set the current MSS to the window size to ensure that the
+       application does not send more data than the other end can
+       handle.
+
+       If the remote host advertises a zero window, we set the MSS to
+       the initial MSS so that the application will send an entire MSS
+       of data. This data will not be acknowledged by the receiver,
+       and the application will retransmit it. This is called the
+       "persistent timer" and uses the retransmission mechanim.
+    */
+    tmp16 = ((u16_t)tcp_hdr->wnd[0] << 8) + (u16_t)tcp_hdr->wnd[1];
+    if(tmp16 > uip_connr->initialmss ||
+       tmp16 == 0) {
+      tmp16 = uip_connr->initialmss;
+    }
+    uip_connr->mss = tmp16;
+
+    /* If this packet constitutes an ACK for outstanding data (flagged
+       by the UIP_ACKDATA flag, we should call the application since it
+       might want to send more data. If the incoming packet had data
+       from the peer (as flagged by the UIP_NEWDATA flag), the
+       application must also be notified.
+
+       When the application is called, the global variable uip_len
+       contains the length of the incoming data. The application can
+       access the incoming data through the global pointer
+       uip_appdata, which usually points uip_ip_tcph_len + UIP_LLH_LEN
+       bytes into the uip_buf array.
+
+       If the application wishes to send any data, this data should be
+       put into the uip_appdata and the length of the data should be
+       put into uip_len. If the application don't have any data to
+       send, uip_len must be set to 0. */
+    if(ustack->uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
+      ustack->uip_slen = 0;
+      UIP_APPCALL(ustack);
+
+    appsend:
+      
+      if(ustack->uip_flags & UIP_ABORT) {
+	ustack->uip_slen = 0;
+	uip_connr->tcpstateflags = UIP_CLOSED;
+	tcp_hdr->flags = TCP_RST | TCP_ACK;
+	goto tcp_send_nodata;
+      }
+
+      if(ustack->uip_flags & UIP_CLOSE) {
+	ustack->uip_slen = 0;
+	uip_connr->len = 1;
+	uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
+	uip_connr->nrtx = 0;
+	tcp_hdr->flags = TCP_FIN | TCP_ACK;
+	goto tcp_send_nodata;
+      }
+
+      /* If uip_slen > 0, the application has data to be sent. */
+      if(ustack->uip_slen > 0) {
+
+	/* If the connection has acknowledged data, the contents of
+	   the ->len variable should be discarded. */
+	if((ustack->uip_flags & UIP_ACKDATA) != 0) {
+	  uip_connr->len = 0;
+	}
+
+	/* If the ->len variable is non-zero the connection has
+	   already data in transit and cannot send anymore right
+	   now. */
+	if(uip_connr->len == 0) {
+
+	  /* The application cannot send more than what is allowed by
+	     the mss (the minumum of the MSS and the available
+	     window). */
+	  if(ustack->uip_slen > uip_connr->mss) {
+	    ustack->uip_slen = uip_connr->mss;
+	  }
+
+	  /* Remember how much data we send out now so that we know
+	     when everything has been acknowledged. */
+	  uip_connr->len = ustack->uip_slen;
+	} else {
+
+	  /* If the application already had unacknowledged data, we
+	     make sure that the application does not send (i.e.,
+	     retransmit) out more than it previously sent out. */
+	  ustack->uip_slen = uip_connr->len;
+	}
+      }
+      uip_connr->nrtx = 0;
+    apprexmit:
+      ustack->uip_appdata = ustack->uip_sappdata;
+      
+      /* If the application has data to be sent, or if the incoming
+         packet had new data in it, we must send out a packet. */
+      if(ustack->uip_slen > 0 && uip_connr->len > 0) {
+	/* Add the length of the IP and TCP headers. */
+	ustack->uip_len = uip_connr->len + uip_ip_tcph_len;
+	/* We always set the ACK flag in response packets. */
+	tcp_hdr->flags = TCP_ACK | TCP_PSH;
+	/* Send the packet. */
+	goto tcp_send_noopts;
+      }
+      /* If there is no data to send, just send out a pure ACK if
+	 there is newdata. */
+      if(ustack->uip_flags & UIP_NEWDATA) {
+	ustack->uip_len = uip_ip_tcph_len;
+	tcp_hdr->flags = TCP_ACK;
+	goto tcp_send_noopts;
+      }
+    }
+    goto drop;
+  case UIP_LAST_ACK:
+    /* We can close this connection if the peer has acknowledged our
+       FIN. This is indicated by the UIP_ACKDATA flag. */
+    if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_CLOSED;
+      ustack->uip_flags = UIP_CLOSE;
+      UIP_APPCALL(ustack);
+    }
+    break;
+    
+  case UIP_FIN_WAIT_1:
+    /* The application has closed the connection, but the remote host
+       hasn't closed its end yet. Thus we do nothing but wait for a
+       FIN from the other side. */
+    if(ustack->uip_len > 0) {
+      uip_add_rcv_nxt(ustack, ustack->uip_len);
+    }
+    if(tcp_hdr->flags & TCP_FIN) {
+      if(ustack->uip_flags & UIP_ACKDATA) {
+	uip_connr->tcpstateflags = UIP_TIME_WAIT;
+	uip_connr->timer = 0;
+	uip_connr->len = 0;
+      } else {
+	uip_connr->tcpstateflags = UIP_CLOSING;
+      }
+      uip_add_rcv_nxt(ustack, 1);
+      ustack->uip_flags = UIP_CLOSE;
+      UIP_APPCALL(ustack);
+      goto tcp_send_ack;
+    } else if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
+      uip_connr->len = 0;
+      goto drop;
+    }
+    if(ustack->uip_len > 0) {
+      goto tcp_send_ack;
+    }
+    goto drop;
+      
+  case UIP_FIN_WAIT_2:
+    if(ustack->uip_len > 0) {
+      uip_add_rcv_nxt(ustack, ustack->uip_len);
+    }
+    if(tcp_hdr->flags & TCP_FIN) {
+      uip_connr->tcpstateflags = UIP_TIME_WAIT;
+      uip_connr->timer = 0;
+      uip_add_rcv_nxt(ustack, 1);
+      ustack->uip_flags = UIP_CLOSE;
+      UIP_APPCALL(ustack);
+      goto tcp_send_ack;
+    }
+    if(ustack->uip_len > 0) {
+      goto tcp_send_ack;
+    }
+    goto drop;
+
+  case UIP_TIME_WAIT:
+    goto tcp_send_ack;
+    
+  case UIP_CLOSING:
+    if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_TIME_WAIT;
+      uip_connr->timer = 0;
+    }
+  }
+  goto drop;
+  
+
+  /* We jump here when we are ready to send the packet, and just want
+     to set the appropriate TCP sequence numbers in the TCP header. */
+ tcp_send_ack:
+  tcp_hdr->flags = TCP_ACK;
+ tcp_send_nodata:
+  ustack->uip_len = uip_ip_tcph_len;
+ tcp_send_noopts:
+  tcp_hdr->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
+ tcp_send:
+  /* We're done with the input processing. We are now ready to send a
+     reply. Our job is to fill in all the fields of the TCP and IP
+     headers before calculating the checksum and finally send the
+     packet. */
+  tcp_hdr->ackno[0] = uip_connr->rcv_nxt[0];
+  tcp_hdr->ackno[1] = uip_connr->rcv_nxt[1];
+  tcp_hdr->ackno[2] = uip_connr->rcv_nxt[2];
+  tcp_hdr->ackno[3] = uip_connr->rcv_nxt[3];
+  
+  tcp_hdr->seqno[0] = uip_connr->snd_nxt[0];
+  tcp_hdr->seqno[1] = uip_connr->snd_nxt[1];
+  tcp_hdr->seqno[2] = uip_connr->snd_nxt[2];
+  tcp_hdr->seqno[3] = uip_connr->snd_nxt[3];
+
+  if(is_ipv6(ustack)) {
+	  IPv6_BUF(ustack)->proto = UIP_PROTO_TCP;
+	  uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr, ustack->hostaddr6);
+	  uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr, uip_connr->ripaddr);
+  } else {
+	  tcp_ipv4_hdr->proto = UIP_PROTO_TCP;
+	  uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
+	  uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr, uip_connr->ripaddr);
+  }
+  
+  tcp_hdr->srcport  = uip_connr->lport;
+  tcp_hdr->destport = uip_connr->rport;
+
+  if(uip_connr->tcpstateflags & UIP_STOPPED) {
+    /* If the connection has issued uip_stop(), we advertise a zero
+       window so that the remote host will stop sending data. */
+    tcp_hdr->wnd[0] = tcp_hdr->wnd[1] = 0;
+  } else {
+    tcp_hdr->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
+    tcp_hdr->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
+  }
+
+ tcp_send_noconn:
+  if(is_ipv6(ustack)) {
+	  IPv6_BUF(ustack)->ttl = UIP_TTL;
+
+	  /* For IPv6, the IP length field does not include the IPv6 IP header
+	     length. */
+	  IPv6_BUF(ustack)->len[0] = ((ustack->uip_len - uip_iph_len) >> 8);
+	  IPv6_BUF(ustack)->len[1] = ((ustack->uip_len - uip_iph_len) & 0xff);
+  } else {
+	  tcp_ipv4_hdr->ttl = UIP_TTL;
+	  tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8);
+	  tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
+  }
+
+  tcp_hdr->urgp[0] = tcp_hdr->urgp[1] = 0;
+  
+  /* Calculate TCP checksum. */
+  tcp_hdr->tcpchksum = 0;
+  tcp_hdr->tcpchksum = ~(uip_tcpchksum(ustack));
+  
+ ip_send_nolen:
+
+  if(is_ipv6(ustack)) {
+	  IPv6_BUF(ustack)->vtc = 0x60;
+	  IPv6_BUF(ustack)->tcflow = 0x00;
+	  IPv6_BUF(ustack)->flow = 0x00;
+  } else {
+	  tcp_ipv4_hdr->vhl = 0x45;
+	  tcp_ipv4_hdr->tos = 0;
+	  tcp_ipv4_hdr->ipoffset[0] = tcp_ipv4_hdr->ipoffset[1] = 0;
+	  ++ustack->ipid;
+	  tcp_ipv4_hdr->ipid[0] = ustack->ipid >> 8;
+	  tcp_ipv4_hdr->ipid[1] = ustack->ipid & 0xff;
+	  /* Calculate IP checksum. */
+	  tcp_ipv4_hdr->ipchksum = 0;
+	  tcp_ipv4_hdr->ipchksum = ~(uip_ipchksum(ustack));
+  }
+
+  ++ustack->stats.tcp.sent;
+ send:
+  if(is_ipv6(ustack)) {
+	  LOG_DEBUG(PFX "Sending packet with length %d (%d)", ustack->uip_len,
+		       (IPv6_BUF(ustack)->len[0] << 8) | IPv6_BUF(ustack)->len[1]);
+  } else {
+	  LOG_DEBUG(PFX "Sending packet with length %d (%d)", ustack->uip_len,
+		       (tcp_ipv4_hdr->len[0] << 8) | tcp_ipv4_hdr->len[1]);
+  }
+
+  ++ustack->stats.ip.sent;
+  /* Return and let the caller do the actual transmission. */
+  ustack->uip_flags = 0;
+  return;
+ drop:
+  ustack->uip_len = 0;
+  ustack->uip_flags = 0;
+  return;
+}
+#if 0
+/*---------------------------------------------------------------------------*/
+u16_t
+htons(u16_t val)
+{
+  return HTONS(val);
+}
+#endif
+/*---------------------------------------------------------------------------*/
+void
+uip_send(struct uip_stack *ustack, const void *data, int len)
+{
+  if(len > 0) {
+    ustack->uip_slen = len;
+    if(data != ustack->uip_sappdata) {
+      memcpy(ustack->uip_sappdata, (data), ustack->uip_slen);
+    }
+  }
+}
+
+u16_t
+uip_datalen(struct uip_stack *ustack)
+{
+	return ustack->uip_len;
+}
+/** @} */
+
+#define IPV6_LEN        16
+
+int set_ipv6_link_local_address(struct uip_stack *ustack)
+{
+	u8_t *link_local_addr = (u8_t *) ustack->link_local_addr;
+	memset(ustack->link_local_addr, 0, IPV6_LEN);
+
+	link_local_addr[0] = 0xfe;
+	link_local_addr[1] = 0x80;
+
+	link_local_addr[IPV6_LEN - 8] = ustack->uip_ethaddr.addr[0];
+	link_local_addr[IPV6_LEN - 7] = ustack->uip_ethaddr.addr[1];
+	link_local_addr[IPV6_LEN - 6] = ustack->uip_ethaddr.addr[2];
+	link_local_addr[IPV6_LEN - 5] = 0xff;
+	link_local_addr[IPV6_LEN - 4] = 0xfe;
+	link_local_addr[IPV6_LEN - 3] = ustack->uip_ethaddr.addr[3];
+	link_local_addr[IPV6_LEN - 2] = ustack->uip_ethaddr.addr[4];
+	link_local_addr[IPV6_LEN - 1] = ustack->uip_ethaddr.addr[5];
+
+	return 0;
+}
diff --git a/brcm_iscsi_uio/src/uip/uip.h b/brcm_iscsi_uio/src/uip/uip.h
new file mode 100644
index 0000000..3db1a08
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip.h
@@ -0,0 +1,1643 @@
+
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \file
+ * Header file for the uIP TCP/IP stack.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The uIP TCP/IP stack header file contains definitions for a number
+ * of C macros that are used by uIP programs as well as internal uIP
+ * structures, TCP/IP header structures and function declarations.
+ *
+ */
+
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.h,v 1.40 2006/06/08 07:12:07 adam Exp $
+ *
+ */
+
+#ifndef __UIP_H__
+#define __UIP_H__
+
+#include <pthread.h>
+
+#include "uipopt.h"
+
+#include "debug.h"
+
+#include "uip_eth.h"
+
+/*  Forware declaration */
+struct uip_stack;
+
+/**
+ * Repressentation of an IP address.
+ *
+ */
+typedef u16_t uip_ip4addr_t[2];
+typedef u16_t uip_ip6addr_t[8];
+
+const uip_ip6addr_t all_zeroes_addr6;
+const uip_ip4addr_t all_zeroes_addr4;
+
+
+#define ETH_BUF(buf) ((struct uip_eth_hdr *)buf)
+#define VLAN_ETH_BUF(buf) ((struct uip_vlan_eth_hdr *)buf)
+#define IPv4_BUF(buf) ((struct uip_tcp_ipv4_hdr *)buf)
+#define IPv6_BUF(buf) ((struct uip_tcp_ipv6_hdr *)buf)
+
+/*---------------------------------------------------------------------------*/
+/* First, the functions that should be called from the
+ * system. Initialization, the periodic timer and incoming packets are
+ * handled by the following three functions.
+ */
+
+/**
+ * \defgroup uipconffunc uIP configuration functions
+ * @{
+ *
+ * The uIP configuration functions are used for setting run-time
+ * parameters in uIP such as IP addresses.
+ */
+
+int is_ipv6(struct uip_stack *ustack);
+
+/**
+ * Set the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * Example:
+ \code
+
+ uip_ipaddr_t addr;
+
+ uip_ipaddr(&addr, 192,168,1,2);
+ uip_sethostaddr(&addr);
+ 
+ \endcode
+ * \param addr A pointer to an IP address of type uip_ipaddr_t;
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr);
+
+/**
+ * Set the default router's IP address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the default router.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr);
+
+/**
+ * Set the netmask.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the netmask.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr);
+
+/**
+ * Set the ethernet MAC address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the netmask.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac);
+
+/**
+ * Get the default router's IP address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the IP address of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr)
+
+/**
+ * Get the netmask.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the value of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask)
+
+
+void set_uip_stack(struct uip_stack *ustack,
+		   uip_ip4addr_t *ip,
+		   uip_ip4addr_t *netmask,
+		   uip_ip4addr_t *default_route,
+		   uint8_t  *mac_addr);
+
+
+/** @} */
+
+/**
+ * \defgroup uipinit uIP initialization functions
+ * @{
+ *
+ * The uIP initialization functions are used for booting uIP.
+ */
+
+/**
+ * uIP initialization function.
+ *
+ * This function should be called at boot up to initilize the uIP
+ * TCP/IP stack.
+ */
+void uip_init(struct uip_stack *ustack, uint8_t enable_ipv6);
+
+
+/**
+ * uIP reset function.
+ *
+ * This function should be called at to reset the uIP TCP/IP stack.
+ */
+void uip_reset(struct uip_stack *ustack);
+
+/**
+ * uIP initialization function.
+ *
+ * This function may be used at boot time to set the initial ip_id.
+ */
+void uip_setipid(u16_t id);
+
+/**
+ *
+ *
+ */
+#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED)
+
+#if UIP_UDP
+
+#if 0
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_periodic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
+                                uip_process(UIP_UDP_TIMER); } while (0)
+
+/**
+ * Periodic processing for a UDP connection identified by a pointer to
+ * its structure.
+ *
+ * Same as uip_udp_periodic() but takes a pointer to the actual
+ * uip_conn struct instead of an integer as its argument. This
+ * function can be used to force periodic processing of a specific
+ * connection.
+ *
+ * \param conn A pointer to the uip_udp_conn struct for the connection
+ * to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \
+                                         uip_process(UIP_UDP_TIMER); } while (0)
+
+#endif
+
+void uip_udp_periodic(struct uip_stack *ustack, int conn);
+#endif /* UIP_UDP */
+
+/**
+ * The uIP packet buffer.
+ *
+ * The uip_buf array is used to hold incoming and outgoing
+ * packets. The device driver should place incoming data into this
+ * buffer. When sending data, the device driver should read the link
+ * level headers and the TCP/IP headers from this buffer. The size of
+ * the link level headers is configured by the UIP_LLH_LEN define.
+ *
+ * \note The application data need not be placed in this buffer, so
+ * the device driver must read it from the place pointed to by the
+ * uip_appdata pointer as illustrated by the following example:
+ \code
+ void
+ devicedriver_send(void)
+ {
+    hwsend(&uip_buf[0], UIP_LLH_LEN);
+    if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+      hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
+    } else {
+      hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
+      hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
+    }
+ }
+ \endcode
+ */
+//extern u8_t uip_buf[UIP_BUFSIZE+2];
+
+/** @} */
+
+/*---------------------------------------------------------------------------*/
+/* Functions that are used by the uIP application program. Opening and
+ * closing connections, sending and receiving data, etc. is all
+ * handled by the functions below.
+*/
+/**
+ * \defgroup uipappfunc uIP application functions
+ * @{
+ *
+ * Functions used by an application running of top of uIP.
+ */
+
+/**
+ * Start listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_listen(HTONS(80));
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_listen(struct uip_stack *ustack, u16_t port);
+
+/**
+ * Stop listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_unlisten(HTONS(80));
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_unlisten(struct uip_stack *ustack, u16_t port);
+
+/**
+ * Connect to a remote host using TCP.
+ *
+ * This function is used to start a new connection to the specified
+ * port on the specied host. It allocates a new connection identifier,
+ * sets the connection to the SYN_SENT state and sets the
+ * retransmission timer to 0. This will cause a TCP SYN segment to be
+ * sent out the next time this connection is periodically processed,
+ * which usually is done within 0.5 seconds after the call to
+ * uip_connect().
+ *
+ * \note This function is avaliable only if support for active open
+ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
+ *
+ * \note Since this function requires the port number to be in network
+ * byte order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_ipaddr_t ipaddr;
+
+ uip_ipaddr(&ipaddr, 192,168,1,2);
+ uip_connect(&ipaddr, HTONS(80));
+ \endcode
+ *
+ * \param ripaddr The IP address of the remote hot.
+ *
+ * \param port A 16-bit port number in network byte order.
+ *
+ * \return A pointer to the uIP connection identifier for the new connection,
+ * or NULL if no connection could be allocated.
+ *
+ */
+struct uip_conn *uip_connect(struct uip_stack *ustack, 
+			     uip_ip4addr_t *ripaddr, u16_t port);
+
+
+
+/**
+ * \internal
+ *
+ * Check if a connection has outstanding (i.e., unacknowledged) data.
+ *
+ * \param conn A pointer to the uip_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_outstanding(conn) ((conn)->len)
+
+/**
+ * Send data on the current connection.
+ *
+ * This function is used to send out a single segment of TCP
+ * data. Only applications that have been invoked by uIP for event
+ * processing can send data.
+ *
+ * The amount of data that actually is sent out after a call to this
+ * funcion is determined by the maximum amount of data TCP allows. uIP
+ * will automatically crop the data so that only the appropriate
+ * amount of data is sent. The function uip_mss() can be used to query
+ * uIP for the amount of data that actually will be sent.
+ *
+ * \note This function does not guarantee that the sent data will
+ * arrive at the destination. If the data is lost in the network, the
+ * application will be invoked with the uip_rexmit() event being
+ * set. The application will then have to resend the data using this
+ * function.
+ *
+ * \param data A pointer to the data which is to be sent.
+ *
+ * \param len The maximum amount of data bytes to be sent.
+ *
+ * \hideinitializer
+ */
+void uip_send(struct uip_stack *ustack, const void *data, int len);
+
+/**
+ * The length of any incoming data that is currently avaliable (if avaliable)
+ * in the uip_appdata buffer.
+ *
+ * The test function uip_data() must first be used to check if there
+ * is any data available at all.
+ *
+ * \hideinitializer
+ */
+/*void uip_datalen(void);*/
+u16_t uip_datalen(struct uip_stack *ustack);
+
+/**
+ * The length of any out-of-band data (urgent data) that has arrived
+ * on the connection.
+ *
+ * \note The configuration parameter UIP_URGDATA must be set for this
+ * function to be enabled.
+ *
+ * \hideinitializer
+ */
+#define uip_urgdatalen()    uip_urglen
+
+/**
+ * Close the current connection.
+ *
+ * This function will close the current connection in a nice way.
+ *
+ * \hideinitializer
+ */
+#define uip_close()         (uip_flags = UIP_CLOSE)
+
+/**
+ * Abort the current connection.
+ *
+ * This function will abort (reset) the current connection, and is
+ * usually used when an error has occured that prevents using the
+ * uip_close() function.
+ *
+ * \hideinitializer
+ */
+#define uip_abort()         (uip_flags = UIP_ABORT)
+
+/**
+ * Tell the sending host to stop sending data.
+ *
+ * This function will close our receiver's window so that we stop
+ * receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_stop()          (uip_conn->tcpstateflags |= UIP_STOPPED)
+
+/**
+ * Find out if the current connection has been previously stopped with
+ * uip_stop().
+ *
+ * \hideinitializer
+ */
+#define uip_stopped(conn)   ((conn)->tcpstateflags & UIP_STOPPED)
+
+/**
+ * Restart the current connection, if is has previously been stopped
+ * with uip_stop().
+ *
+ * This function will open the receiver's window again so that we
+ * start receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_restart()         do { uip_flags |= UIP_NEWDATA; \
+                                   uip_conn->tcpstateflags &= ~UIP_STOPPED; \
+                              } while(0)
+
+
+/* uIP tests that can be made to determine in what state the current
+   connection is, and what the application function should do. */
+
+/**
+ * Is the current connection a UDP connection?
+ *
+ * This function checks whether the current connection is a UDP connection.
+ *
+ * \hideinitializer
+ *
+ */
+#define uip_udpconnection() (uip_conn == NULL)
+
+/** 
+ *  Function declarations for hte uip_flags 
+ */
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+int uip_newdata(struct uip_stack *ustack);
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data.
+ *
+ * \hideinitializer
+ */
+int uip_acked(struct uip_stack *ustack);
+
+/**
+ * Has the connection just been connected?
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+int uip_connected(struct uip_stack *ustack);
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+int uip_closed(struct uip_stack *ustack);
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+int uip_aborted(struct uip_stack *ustack);
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+int uip_timedout(struct uip_stack *ustack);
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+int uip_rexmit(struct uip_stack *ustack);
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */
+int uip_poll(struct uip_stack *ustack);
+
+/**
+ * Get the initial maxium segment size (MSS) of the current
+ * connection.
+ *
+ * \hideinitializer
+ */
+int uip_initialmss(struct uip_stack *ustack);
+
+/**
+ * Get the current maxium segment size that can be sent on the current
+ * connection.
+ *
+ * The current maxiumum segment size that can be sent on the
+ * connection is computed from the receiver's window and the MSS of
+ * the connection (which also is available by calling
+ * uip_initialmss()).
+ *
+ * \hideinitializer
+ */
+int uip_mss(struct uip_stack *ustack);
+
+/**
+ * Set up a new UDP connection.
+ *
+ * This function sets up a new UDP connection. The function will
+ * automatically allocate an unused local port for the new
+ * connection. However, another port can be chosen by using the
+ * uip_udp_bind() call, after the uip_udp_new() function has been
+ * called.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t addr;
+ struct uip_udp_conn *c;
+ 
+ uip_ipaddr(&addr, 192,168,2,1);
+ c = uip_udp_new(&addr, HTONS(12345));
+ if(c != NULL) {
+   uip_udp_bind(c, HTONS(12344));
+ }
+ \endcode
+ * \param ripaddr The IP address of the remote host.
+ *
+ * \param rport The remote port number in network byte order.
+ *
+ * \return The uip_udp_conn structure for the new connection or NULL
+ * if no connection could be allocated.
+ */
+struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack,
+				 uip_ip4addr_t *ripaddr, u16_t rport);
+
+/**
+ * Removed a UDP connection.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_remove(conn) (conn)->lport = 0
+
+/**
+ * Bind a UDP connection to a local port.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the
+ * connection.
+ *
+ * \param port The local port number, in network byte order.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_bind(conn, port) (conn)->lport = port
+
+/**
+ * Send a UDP datagram of length len on the current connection.
+ *
+ * This function can only be called in response to a UDP event (poll
+ * or newdata). The data must be present in the uip_buf buffer, at the
+ * place pointed to by the uip_appdata pointer.
+ *
+ * \param len The length of the data in the uip_buf buffer.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_send(len) uip_send((char *)uip_appdata, len)
+
+/** @} */
+
+/* uIP convenience and converting functions. */
+
+/**
+ * \defgroup uipconvfunc uIP conversion functions
+ * @{
+ *
+ * These functions can be used for converting between different data
+ * formats used by uIP.
+ */
+ 
+/**
+ * Construct an IP address from four bytes.
+ *
+ * This function constructs an IP address of the type that uIP handles
+ * internally from four bytes. The function is handy for specifying IP
+ * addresses to use with e.g. the uip_connect() function.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ struct uip_conn *c;
+ 
+ uip_ipaddr(&ipaddr, 192,168,1,2);
+ c = uip_connect(&ipaddr, HTONS(80));
+ \endcode
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the IP address.
+ *
+ * \param addr0 The first octet of the IP address.
+ * \param addr1 The second octet of the IP address.
+ * \param addr2 The third octet of the IP address.
+ * \param addr3 The forth octet of the IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
+                     ((u16_t *)(addr))[0] = const_htons(((addr0) << 8) | (addr1)); \
+                     ((u16_t *)(addr))[1] = const_htons(((addr2) << 8) | (addr3)); \
+                  } while(0)
+
+/**
+ * Construct an IPv6 address from eight 16-bit words.
+ *
+ * This function constructs an IPv6 address.
+ *
+ * \hideinitializer
+ */
+#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \
+                     ((u16_t *)(addr))[0] = HTONS((addr0)); \
+                     ((u16_t *)(addr))[1] = HTONS((addr1)); \
+                     ((u16_t *)(addr))[2] = HTONS((addr2)); \
+                     ((u16_t *)(addr))[3] = HTONS((addr3)); \
+                     ((u16_t *)(addr))[4] = HTONS((addr4)); \
+                     ((u16_t *)(addr))[5] = HTONS((addr5)); \
+                     ((u16_t *)(addr))[6] = HTONS((addr6)); \
+                     ((u16_t *)(addr))[7] = HTONS((addr7)); \
+                  } while(0)
+
+/**
+ * Copy an IP address to another IP address.
+ *
+ * Copies an IP address from one place to another.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr_copy(&ipaddr2, &ipaddr1);
+ \endcode
+ *
+ * \param dest The destination for the copy.
+ * \param src The source from where to copy.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip4addr_t))
+#define uip_ip6addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t))
+
+/**
+ * Compare two IP addresses
+ *
+ * Compares two IP addresses.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip4addr_t)) == 0)
+#define uip_ip6addr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
+
+/**
+ * Compare two IP addresses with netmasks
+ *
+ * Compares two IP addresses with netmasks. The masks are used to mask
+ * out the bits that are to be compared.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2, mask;
+
+ uip_ipaddr(&mask, 255,255,255,0);
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr(&ipaddr2, 192,16,1,3);
+ if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_maskcmp(addr1, addr2, mask) \
+                          (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
+                            (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
+                           ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
+                            (((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
+
+
+/**
+ * Mask out the network part of an IP address.
+ *
+ * Masks out the network part of an IP address, given the address and
+ * the netmask.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2, netmask;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr(&netmask, 255,255,255,0);
+ uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
+ \endcode
+ *
+ * In the example above, the variable "ipaddr2" will contain the IP
+ * address 192.168.1.0.
+ *
+ * \param dest Where the result is to be placed.
+ * \param src The IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_mask(dest, src, mask) do { \
+                     ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
+                     ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
+                  } while(0)
+
+/**
+ * Pick the first octet of an IP address.
+ *
+ * Picks out the first octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr1(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 1.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8)
+
+/**
+ * Pick the second octet of an IP address.
+ *
+ * Picks out the second octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr2(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 2.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff)
+
+/**
+ * Pick the third octet of an IP address.
+ *
+ * Picks out the third octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr3(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 3.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8)
+
+/**
+ * Pick the fourth octet of an IP address.
+ *
+ * Picks out the fourth octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr4(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 4.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff)
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This macro is primarily used for converting constants from host
+ * byte order to network byte order. For converting variables to
+ * network byte order, use the htons() function instead.
+ *
+ * \hideinitializer
+ */
+#if 0
+#ifndef HTONS
+#   if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
+#      define HTONS(n) (n)
+#   else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#      define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
+#   endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#else
+#error "HTONS already defined!"
+#endif /* HTONS */
+#endif
+
+#if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
+#      error "Should not be here"
+#      define const_htons(n) (n)
+#   else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#      define const_htons(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
+#   endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+
+/*  BWL */
+#if 0
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This function is primarily used for converting variables from host
+ * byte order to network byte order. For converting constants to
+ * network byte order, use the HTONS() macro instead.
+ */
+#ifndef htons
+u16_t htons(u16_t val);
+#endif /* htons */
+#ifndef ntohs
+#define ntohs htons
+#endif
+#endif
+
+/** @} */
+
+/**
+ * Pointer to the application data in the packet buffer.
+ *
+ * This pointer points to the application data when the application is
+ * called. If the application wishes to send data, the application may
+ * use this space to write the data into before calling uip_send().
+ */
+//extern void *uip_appdata;
+
+#if UIP_URGDATA > 0
+/* u8_t *uip_urgdata:
+ *
+ * This pointer points to any urgent data that has been received. Only
+ * present if compiled with support for urgent data (UIP_URGDATA).
+ */
+extern void *uip_urgdata;
+#endif /* UIP_URGDATA > 0 */
+
+
+/**
+ * \defgroup uipdrivervars Variables used in uIP device drivers
+ * @{
+ *
+ * uIP has a few global variables that are used in device drivers for
+ * uIP.
+ */
+
+/**
+ * The length of the packet in the uip_buf buffer.
+ *
+ * The global variable uip_len holds the length of the packet in the
+ * uip_buf buffer.
+ *
+ * When the network device driver calls the uIP input function,
+ * uip_len should be set to the length of the packet in the uip_buf
+ * buffer.
+ *
+ * When sending packets, the device driver should use the contents of
+ * the uip_len variable to determine the length of the outgoing
+ * packet.
+ *
+ */
+//extern u16_t uip_len;
+
+/** @} */
+
+#if UIP_URGDATA > 0
+extern u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+
+/**
+ * Representation of a uIP TCP connection.
+ *
+ * The uip_conn structure is used for identifying a connection. All
+ * but one field in the structure are to be considered read-only by an
+ * application. The only exception is the appstate field whos purpose
+ * is to let the application store application-specific state (e.g.,
+ * file pointers) for the connection. The type of this field is
+ * configured in the "uipopt.h" header file.
+ */
+struct  __attribute__ ((__packed__)) uip_conn
+{
+  uip_ip4addr_t ripaddr;   /**< The IP address of the remote host. */
+  
+  u16_t lport;        /**< The local TCP port, in network byte order. */
+  u16_t rport;        /**< The local remote TCP port, in network byte
+			 order. */
+  
+  u8_t rcv_nxt[4];    /**< The sequence number that we expect to
+			 receive next. */
+  u8_t snd_nxt[4];    /**< The sequence number that was last sent by
+                         us. */
+  u16_t len;          /**< Length of the data that was previously sent. */
+  u16_t mss;          /**< Current maximum segment size for the
+			 connection. */
+  u16_t initialmss;   /**< Initial maximum segment size for the
+			 connection. */
+  u8_t sa;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t sv;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t rto;           /**< Retransmission time-out. */
+  u8_t tcpstateflags; /**< TCP state and flags. */
+  u8_t timer;         /**< The retransmission timer. */
+  u8_t nrtx;          /**< The number of retransmissions for the last
+			 segment sent. */
+
+  /** The application state. */
+/* BWL */
+//  uip_tcp_appstate_t appstate;
+};
+
+
+/**
+ * \addtogroup uiparch
+ * @{
+ */
+
+/**
+ * 4-byte array used for the 32-bit sequence number calculations.
+ */
+extern u8_t uip_acc32[4];
+
+/** @} */
+
+
+#if UIP_UDP
+/**
+ * Representation of a uIP UDP connection.
+ */
+struct uip_udp_conn {
+  uip_ip4addr_t ripaddr;   /**< The IP address of the remote peer. */
+  u16_t lport;        /**< The local port number in network byte order. */
+  u16_t rport;        /**< The remote port number in network byte order. */
+  u8_t  ttl;          /**< Default time-to-live. */
+
+  /** The application state. */
+//  uip_udp_appstate_t appstate;
+};
+
+#endif /* UIP_UDP */
+
+/**
+ * The structure holding the TCP/IP statistics that are gathered if
+ * UIP_STATISTICS is set to 1.
+ *
+ */
+struct uip_stats {
+  struct {
+    uip_stats_t drop;     /**< Number of dropped packets at the IP
+			     layer. */
+    uip_stats_t recv;     /**< Number of received packets at the IP
+			     layer. */
+    uip_stats_t sent;     /**< Number of sent packets at the IP
+			     layer. */
+    uip_stats_t vhlerr;   /**< Number of packets dropped due to wrong
+			     IP version or header length. */
+    uip_stats_t hblenerr; /**< Number of packets dropped due to wrong
+			     IP length, high byte. */
+    uip_stats_t lblenerr; /**< Number of packets dropped due to wrong
+			     IP length, low byte. */
+    uip_stats_t fragerr;  /**< Number of packets dropped since they
+			     were IP fragments. */
+    uip_stats_t chkerr;   /**< Number of packets dropped due to IP
+			     checksum errors. */
+    uip_stats_t protoerr; /**< Number of packets dropped since they
+			     were neither ICMP, UDP nor TCP. */
+  } ip;                   /**< IP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped ICMP packets. */
+    uip_stats_t recv;     /**< Number of received ICMP packets. */
+    uip_stats_t sent;     /**< Number of sent ICMP packets. */
+    uip_stats_t typeerr;  /**< Number of ICMP packets with a wrong
+			     type. */
+  } icmp;                 /**< ICMP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped TCP segments. */
+    uip_stats_t recv;     /**< Number of recived TCP segments. */
+    uip_stats_t sent;     /**< Number of sent TCP segments. */
+    uip_stats_t chkerr;   /**< Number of TCP segments with a bad
+			     checksum. */
+    uip_stats_t ackerr;   /**< Number of TCP segments with a bad ACK
+			     number. */
+    uip_stats_t rst;      /**< Number of recevied TCP RST (reset) segments. */
+    uip_stats_t rexmit;   /**< Number of retransmitted TCP segments. */
+    uip_stats_t syndrop;  /**< Number of dropped SYNs due to too few
+			     connections was avaliable. */
+    uip_stats_t synrst;   /**< Number of SYNs for closed ports,
+			     triggering a RST. */
+  } tcp;                  /**< TCP statistics. */
+#if UIP_UDP
+  struct {
+    uip_stats_t drop;     /**< Number of dropped UDP segments. */
+    uip_stats_t recv;     /**< Number of recived UDP segments. */
+    uip_stats_t sent;     /**< Number of sent UDP segments. */
+    uip_stats_t chkerr;   /**< Number of UDP segments with a bad
+			     checksum. */
+  } udp;                  /**< UDP statistics. */
+#endif /* UIP_UDP */
+};
+
+
+/*---------------------------------------------------------------------------*/
+/* All the stuff below this point is internal to uIP and should not be
+ * used directly by an application or by a device driver.
+ */
+/*---------------------------------------------------------------------------*/
+/* u8_t uip_flags:
+ *
+ * When the application is called, uip_flags will contain the flags
+ * that are defined in this file. Please read below for more
+ * infomation.
+ */
+//extern u8_t uip_flags;
+
+/* The following flags may be set in the global variable uip_flags
+   before calling the application callback. The UIP_ACKDATA,
+   UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time,
+   whereas the others are mutualy exclusive. Note that these flags
+   should *NOT* be accessed directly, but only through the uIP
+   functions/macros. */
+
+#define UIP_ACKDATA   1     /* Signifies that the outstanding data was
+			       acked and the application should send
+			       out new data instead of retransmitting
+			       the last data. */
+#define UIP_NEWDATA   2     /* Flags the fact that the peer has sent
+			       us new data. */
+#define UIP_REXMIT    4     /* Tells the application to retransmit the
+			       data that was last sent. */
+#define UIP_POLL      8     /* Used for polling the application, to
+			       check if the application has data that
+			       it wants to send. */
+#define UIP_CLOSE     16    /* The remote host has closed the
+			       connection, thus the connection has
+			       gone away. Or the application signals
+			       that it wants to close the
+			       connection. */
+#define UIP_ABORT     32    /* The remote host has aborted the
+			       connection, thus the connection has
+			       gone away. Or the application signals
+			       that it wants to abort the
+			       connection. */
+#define UIP_CONNECTED 64    /* We have got a connection from a remote
+                               host and have set up a new connection
+                               for it, or an active connection has
+                               been successfully established. */
+
+#define UIP_TIMEDOUT  128   /* The connection has been aborted due to
+			       too many retransmissions. */
+
+void uip_input(struct uip_stack *ustack);
+void uip_periodic(struct uip_stack *ustack, int conn);
+
+/* uip_process(flag):
+ *
+ * The actual uIP function which does all the work.
+ */
+void uip_process(struct uip_stack *ustack, u8_t flag);
+
+/* The following flags are passed as an argument to the uip_process()
+   function. They are used to distinguish between the two cases where
+   uip_process() is called. It can be called either because we have
+   incoming data that should be processed, or because the periodic
+   timer has fired. These values are never used directly, but only in
+   the macrose defined in this file. */
+ 
+#define UIP_DATA          1     /* Tells uIP that there is incoming
+				   data in the uip_buf buffer. The
+				   length of the data is stored in the
+				   global variable uip_len. */
+#define UIP_TIMER         2     /* Tells uIP that the periodic timer
+				   has fired. */
+#define UIP_POLL_REQUEST  3     /* Tells uIP that a connection should
+				   be polled. */
+#define UIP_UDP_SEND_CONN 4     /* Tells uIP that a UDP datagram
+				   should be constructed in the
+				   uip_buf buffer. */
+#if UIP_UDP
+#define UIP_UDP_TIMER     5
+#endif /* UIP_UDP */
+
+/* The TCP states used in the uip_conn->tcpstateflags. */
+#define UIP_CLOSED      0
+#define UIP_SYN_RCVD    1
+#define UIP_SYN_SENT    2
+#define UIP_ESTABLISHED 3
+#define UIP_FIN_WAIT_1  4
+#define UIP_FIN_WAIT_2  5
+#define UIP_CLOSING     6
+#define UIP_TIME_WAIT   7
+#define UIP_LAST_ACK    8
+#define UIP_TS_MASK     15
+  
+#define UIP_STOPPED      16
+
+
+struct __attribute__ ((__packed__)) uip_tcp_hdr {
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+};
+
+struct __attribute__ ((__packed__)) uip_ipv4_hdr {
+  /* IPv4 header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+};
+
+struct __attribute__ ((__packed__)) uip_ipv6_hdr {
+  /* IPv6 header. */
+  u8_t vtc,
+    tcflow;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+};
+
+/* The TCP and IPv4 headers. */
+struct __attribute__ ((__packed__)) uip_tcp_ipv4_hdr {
+  /* IPv4 header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+  
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+};
+
+/* The TCP and IP headers. */
+struct __attribute__ ((__packed__)) uip_tcp_ipv6_hdr {
+  /* IPv6 header. */
+  u8_t vtc,
+    tcflow;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+  
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+};
+
+/* The ICMPv4 */
+struct __attribute__ ((__packed__)) uip_icmpv4_hdr {
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+  u16_t id, seqno;
+};
+
+/* The ICMPv6 */
+struct __attribute__ ((__packed__)) uip_icmpv6_hdr {
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+  u8_t flags, reserved1, reserved2, reserved3;
+  u8_t icmp6data[16];
+  u8_t options[1];
+};
+
+/* The ICMP and IP headers. */
+struct __attribute__ ((__packed__)) uip_icmpip_hdr {
+#if UIP_CONF_IPV6
+  /* IPv6 header. */
+  u8_t vtc,
+    tcf;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+#else /* UIP_CONF_IPV6 */
+  /* IPv4 header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+#endif /* UIP_CONF_IPV6 */
+  
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+#if !UIP_CONF_IPV6
+  u16_t id, seqno;
+#else /* !UIP_CONF_IPV6 */
+  u8_t flags, reserved1, reserved2, reserved3;
+  u8_t icmp6data[16];
+  u8_t options[1];
+#endif /* !UIP_CONF_IPV6 */
+};
+
+/* The UDP  */
+struct __attribute__ ((__packed__)) uip_udp_hdr {
+  /* UDP header. */
+  u16_t srcport,
+    destport;
+  u16_t udplen;
+  u16_t udpchksum;
+};
+
+
+/* The UDP and IP headers. */
+struct __attribute__ ((__packed__)) uip_udpip_hdr {
+#if UIP_CONF_IPV6
+  /* IPv6 header. */
+  u8_t vtc,
+    tcf;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+#else /* UIP_CONF_IPV6 */
+  /* IP header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+#endif /* UIP_CONF_IPV6 */
+  
+  /* UDP header. */
+  u16_t srcport,
+    destport;
+  u16_t udplen;
+  u16_t udpchksum;
+};
+
+
+
+/**
+ * The buffer size available for user data in the \ref uip_buf buffer.
+ *
+ * This macro holds the available size for user data in the \ref
+ * uip_buf buffer. The macro is intended to be used for checking
+ * bounds of available user data.
+ *
+ * Example:
+ \code
+ snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
+
+
+#define UIP_PROTO_ICMP  1
+#define UIP_PROTO_TCP   6
+#define UIP_PROTO_UDP   17
+#define UIP_PROTO_ICMP6 58
+
+/* Header sizes. */
+#define UIP_IPv6_H_LEN    40    /* Size of IPv6 header */
+#define UIP_IPv4_H_LEN    20    /* Size of IPv4 header */
+
+#define UIP_UDPH_LEN    8    /* Size of UDP header */
+#define UIP_TCPH_LEN   20    /* Size of TCP header */
+
+#define UIP_IPv4_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv4_H_LEN)    /* Size of IPv4 +
+								UDP
+								header */
+#define UIP_IPv4_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv4_H_LEN)    /* Size of IPv4 +
+								TCP
+								header */
+#define UIP_TCP_IPv4_HLEN UIP_IPv4_TCPH_LEN
+
+#define UIP_IPv6_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv6_H_LEN)    /* Size of IPv6 +
+								UDP
+								header */
+#define UIP_IPv6_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv6_H_LEN)    /* Size of IPv6 +
+								TCP
+								header */
+#define UIP_TCP_IPv6_HLEN UIP_IPv6_TCPH_LEN
+
+
+/**
+ * Calculate the Internet checksum over a buffer.
+ *
+ * The Internet checksum is the one's complement of the one's
+ * complement sum of all 16-bit words in the buffer.
+ *
+ * See RFC1071.
+ *
+ * \param buf A pointer to the buffer over which the checksum is to be
+ * computed.
+ *
+ * \param len The length of the buffer over which the checksum is to
+ * be computed.
+ *
+ * \return The Internet checksum of the buffer.
+ */
+u16_t uip_chksum(u16_t *buf, u16_t len);
+
+/**
+ * Calculate the IP header checksum of the packet header in uip_buf.
+ *
+ * The IP header checksum is the Internet checksum of the 20 bytes of
+ * the IP header.
+ *
+ * \return The IP header checksum of the IP header in the uip_buf
+ * buffer.
+ */
+u16_t uip_ipchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The TCP checksum is the Internet checksum of data contents of the
+ * TCP segment, and a pseudo-header as defined in RFC793.
+ *
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_tcpchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the UDP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The UDP checksum is the Internet checksum of data contents of the
+ * UDP segment, and a pseudo-header as defined in RFC768.
+ *
+ * \return The UDP checksum of the UDP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_udpchksum(struct uip_stack *ustack);
+
+struct neighbor_entry {
+	uip_ip6addr_t ipaddr;
+	struct uip_eth_addr addr;
+	u8_t time;
+};
+
+#define UIP_NEIGHBOR_ENTRIES 8
+
+struct uip_stack {
+	struct uip_eth_addr uip_ethaddr;
+
+	u8_t *uip_buf;
+
+	uint8_t *data_link_layer;	/* Pointer to the data link layer */
+	uint8_t *network_layer;		/* Pointer to the network layer   */
+	void *uip_appdata;		/* The uip_appdata pointer points to
+					    application data. */
+	void *uip_sappdata;		/* The uip_appdata pointer points to
+					    the application data which is to
+					    be sent. */
+#if UIP_URGDATA > 0
+	void *uip_urgdata;		/* The uip_urgdata pointer points to
+					    urgent data (out-of-band data), if
+					    present. */
+	u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+	u16_t uip_len, uip_slen;	/* The uip_len is either 8 or 16 bits,
+					   depending on the maximum packet
+					   size. */
+	u8_t uip_flags;			/* The uip_flags variable is used for
+					  communication between the TCP/IP stack
+					   and the application program. */
+	struct uip_conn *uip_conn;	/* uip_conn always points to the current
+					   connection. */
+
+	struct uip_conn uip_conns[UIP_CONNS];
+				/* The uip_conns array holds all TCP
+				   connections. */
+	u16_t uip_listenports[UIP_LISTENPORTS];
+				/* The uip_listenports list all currently
+				   listning ports. */
+#if UIP_UDP
+	struct uip_udp_conn *uip_udp_conn;
+	struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+	u16_t ipid;			/* This ipid variable is an increasing
+					   number that is used for the IP ID
+					   field. */
+
+	u8_t iss[4];			/* The iss variable is used for the TCP
+					   initial sequence number. */
+
+#if UIP_ACTIVE_OPEN
+	u16_t lastport;			/* Keeps track of the last port used for
+					   a new connection. */
+#endif /* UIP_ACTIVE_OPEN */
+
+#define IP_CONFIG_STATIC		0x01
+#define IP_CONFIG_DHCP			0x02
+        u8_t ip_config;
+
+	uip_ip4addr_t hostaddr, netmask, default_route_addr;
+	uip_ip6addr_t hostaddr6;
+
+	uip_ip6addr_t link_local_addr;
+
+	struct uip_stats stats;
+
+	u8_t opt;
+
+	pthread_mutex_t lock;
+
+	/*  IPv6 support */
+
+#define UIP_SUPPORT_IPv6_ENABLED	0x01
+#define UIP_SUPPORT_IPv6_DISABLED	0x02
+	u8_t	enable_IPv6;
+
+	struct neighbor_entry neighbor_entries[UIP_NEIGHBOR_ENTRIES];
+
+	/*  DHCPC client attached */
+	void *dhcpc;
+};
+
+/*******************************************************************************
+ * IPv6 Support
+ ******************************************************************************/
+int set_ipv6_link_local_address(struct uip_stack *ustack);
+
+
+
+#endif /* __UIP_H__ */
+
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/uip_arch.h b/brcm_iscsi_uio/src/uip/uip_arch.h
new file mode 100644
index 0000000..f8f34e2
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_arch.h
@@ -0,0 +1,138 @@
+/**
+ * \addtogroup uip
+ * {@
+ */
+
+/**
+ * \defgroup uiparch Architecture specific uIP functions
+ * @{
+ *
+ * The functions in the architecture specific module implement the IP
+ * check sum and 32-bit additions.
+ *
+ * The IP checksum calculation is the most computationally expensive
+ * operation in the TCP/IP stack and it therefore pays off to
+ * implement this in efficient assembler. The purpose of the uip-arch
+ * module is to let the checksum functions to be implemented in
+ * architecture specific assembler.
+ *
+ */
+
+/**
+ * \file
+ * Declarations of architecture specific functions.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arch.h,v 1.2 2006/06/07 09:15:19 adam Exp $
+ *
+ */
+
+#ifndef __UIP_ARCH_H__
+#define __UIP_ARCH_H__
+
+#include "uip.h"
+
+/**
+ * Carry out a 32-bit addition.
+ *
+ * Because not all architectures for which uIP is intended has native
+ * 32-bit arithmetic, uIP uses an external C function for doing the
+ * required 32-bit additions in the TCP protocol processing. This
+ * function should add the two arguments and place the result in the
+ * global variable uip_acc32.
+ *
+ * \note The 32-bit integer pointed to by the op32 parameter and the
+ * result in the uip_acc32 variable are in network byte order (big
+ * endian).
+ *
+ * \param op32 A pointer to a 4-byte array representing a 32-bit
+ * integer in network byte order (big endian).
+ *
+ * \param op16 A 16-bit integer in host byte order.
+ */
+void uip_add32(u8_t *op32, u16_t op16, u8_t *uip_add32);
+
+/**
+ * Calculate the Internet checksum over a buffer.
+ *
+ * The Internet checksum is the one's complement of the one's
+ * complement sum of all 16-bit words in the buffer.
+ *
+ * See RFC1071.
+ *
+ * \note This function is not called in the current version of uIP,
+ * but future versions might make use of it.
+ *
+ * \param buf A pointer to the buffer over which the checksum is to be
+ * computed.
+ *
+ * \param len The length of the buffer over which the checksum is to
+ * be computed.
+ *
+ * \return The Internet checksum of the buffer.
+ */
+u16_t uip_chksum(u16_t *buf, u16_t len);
+
+/**
+ * Calculate the IP header checksum of the packet header in uip_buf.
+ *
+ * The IP header checksum is the Internet checksum of the 20 bytes of
+ * the IP header.
+ *
+ * \return The IP header checksum of the IP header in the uip_buf
+ * buffer.
+ */
+u16_t uip_ipchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The TCP checksum is the Internet checksum of data contents of the
+ * TCP segment, and a pseudo-header as defined in RFC793.
+ *
+ * \note The uip_appdata pointer that points to the packet data may
+ * point anywhere in memory, so it is not possible to simply calculate
+ * the Internet checksum of the contents of the uip_buf buffer.
+ *
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_tcpchksum(struct uip_stack *ustack);
+
+u16_t uip_udpchksum(struct uip_stack *ustack);
+
+/** @} */
+/** @} */
+
+#endif /* __UIP_ARCH_H__ */
diff --git a/brcm_iscsi_uio/src/uip/uip_arp.c b/brcm_iscsi_uio/src/uip/uip_arp.c
new file mode 100644
index 0000000..a894d1b
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_arp.c
@@ -0,0 +1,462 @@
+#include <errno.h>
+//#include <net/ethernet.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "logger.h"
+#include "packet.h"
+
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uiparp uIP Address Resolution Protocol
+ * @{
+ *
+ * The Address Resolution Protocol ARP is used for mapping between IP
+ * addresses and link level addresses such as the Ethernet MAC
+ * addresses. ARP uses broadcast queries to ask for the link level
+ * address of a known IP address and the host which is configured with
+ * the IP address for which the query was meant, will respond with its
+ * link level address.
+ *
+ * \note This ARP implementation only supports Ethernet.
+ */
+ 
+/**
+ * \file
+ * Implementation of the ARP Address Resolution Protocol.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $
+ *
+ */
+
+
+#include "uip_arp.h"
+#include "uip_eth.h"
+
+#include <pthread.h>
+#include <string.h>
+
+static const struct uip_eth_addr broadcast_ethaddr =
+  {{0xff,0xff,0xff,0xff,0xff,0xff}};
+static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff};
+
+pthread_mutex_t arp_table_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
+
+static u8_t arptime;
+
+/**
+ * Initialize the ARP module.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_init(void)
+{
+  u8_t i;
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    memset(arp_table[i].ipaddr, 0, 4);
+  }
+
+  pthread_mutex_init(&arp_table_mutex, NULL);
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Periodic ARP processing function.
+ *
+ * This function performs periodic timer processing in the ARP module
+ * and should be called at regular intervals. The recommended interval
+ * is 10 seconds between the calls.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_timer(void)
+{
+  u8_t i;
+  struct arp_entry *tabptr;
+  
+  ++arptime;
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    tabptr = &arp_table[i];
+    if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
+       arptime - tabptr->time >= UIP_ARP_MAXAGE) {
+      memset(tabptr->ipaddr, 0, 4);
+    }
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
+{
+  u8_t i;
+  register struct arp_entry *tabptr;
+  /* Walk through the ARP mapping table and try to find an entry to
+     update. If none is found, the IP -> MAC address mapping is
+     inserted in the ARP table. */
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+
+    tabptr = &arp_table[i];
+    /* Only check those entries that are actually in use. */
+    if(tabptr->ipaddr[0] != 0 &&
+       tabptr->ipaddr[1] != 0) {
+
+      /* Check if the source IP address of the incoming packet matches
+         the IP address in this ARP table entry. */
+      if(ipaddr[0] == tabptr->ipaddr[0] &&
+	 ipaddr[1] == tabptr->ipaddr[1]) {
+	 
+	/* An old entry found, update this and return. */
+	memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
+	tabptr->time = arptime;
+
+	return;
+      }
+    }
+  }
+
+  /* If we get here, no existing ARP table entry was found, so we
+     create one. */
+
+  /* First, we try to find an unused entry in the ARP table. */
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    tabptr = &arp_table[i];
+    if(tabptr->ipaddr[0] == 0 &&
+       tabptr->ipaddr[1] == 0) {
+      break;
+    }
+  }
+
+  /* If no unused entry is found, we try to find the oldest entry and
+     throw it away. */
+  if(i == UIP_ARPTAB_SIZE) {
+    u8_t c;
+    u8_t tmpage = 0;
+    c = 0;
+    for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+      tabptr = &arp_table[i];
+      if(arptime - tabptr->time > tmpage) {
+	tmpage = arptime - tabptr->time;
+	c = i;
+      }
+    }
+    i = c;
+    tabptr = &arp_table[i];
+  }
+
+  /* Now, i is the ARP table entry which we will fill with the new
+     information. */
+  memcpy(tabptr->ipaddr, ipaddr, 4);
+  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
+  tabptr->time = arptime;
+}
+
+/**
+ * ARP processing for incoming ARP packets.
+ *
+ * This function should be called by the device driver when an ARP
+ * packet has been received. The function will act differently
+ * depending on the ARP packet type: if it is a reply for a request
+ * that we previously sent out, the ARP cache will be filled in with
+ * the values from the ARP reply. If the incoming ARP packet is an ARP
+ * request for our IP address, an ARP reply packet is created and put
+ * into the uip_buf[] buffer.
+ *
+ * When the function returns, the value of the global variable uip_len
+ * indicates whether the device driver should send out a packet or
+ * not. If uip_len is zero, no packet should be sent. If uip_len is
+ * non-zero, it contains the length of the outbound packet that is
+ * present in the uip_buf[] buffer.
+ *
+ * This function expects an ARP packet with a prepended Ethernet
+ * header in the uip_buf[] buffer, and the length of the packet in the
+ * global variable uip_len.
+ */
+
+void
+uip_arp_arpin(struct uip_stack *ustack, packet_t *pkt)
+{
+  struct arp_hdr *arp;
+  struct uip_eth_hdr *eth;
+  
+  if(pkt->buf_size < sizeof(struct arp_hdr)) {
+    pkt->buf_size = 0;
+    return;
+  }
+  pkt->buf_size = 0;
+  
+  eth = (struct uip_eth_hdr *)pkt->data_link_layer;
+  arp = (struct arp_hdr *)pkt->network_layer;
+
+  switch(arp->opcode) {
+  case const_htons(ARP_REQUEST):
+    /* ARP request. If it asked for our address, we send out a
+       reply. */
+    if(uip_ip4addr_cmp(arp->dipaddr, ustack->hostaddr)) {
+      /* First, we register the one who made the request in our ARP
+	 table, since it is likely that we will do more communication
+	 with this host in the future. */
+      uip_arp_update(arp->sipaddr, &arp->shwaddr);
+      
+      /* The reply opcode is 2. */
+      arp->opcode = htons(2);
+
+      memcpy(arp->dhwaddr.addr, arp->shwaddr.addr, 6);
+      memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6);
+      memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
+      memcpy(eth->dest.addr, arp->dhwaddr.addr, 6);
+      
+      arp->dipaddr[0] = arp->sipaddr[0];
+      arp->dipaddr[1] = arp->sipaddr[1];
+      arp->sipaddr[0] = ustack->hostaddr[0];
+      arp->sipaddr[1] = ustack->hostaddr[1];
+
+      eth->type = htons(UIP_ETHTYPE_ARP);
+      pkt->buf_size = sizeof(*arp) +  sizeof(*eth);
+    }
+    break;
+  case const_htons(ARP_REPLY):
+      uip_arp_update(arp->sipaddr, &arp->shwaddr);
+    break;
+  default:
+	LOG_WARN("Unknown ARP opcode: %d", ntohs(arp->opcode));
+    break;
+  }
+
+  return;
+}
+
+/**
+ * Prepend Ethernet header to an outbound IP packet and see if we need
+ * to send out an ARP request.
+ *
+ * This function should be called before sending out an IP packet. The
+ * function checks the destination IP address of the IP packet to see
+ * what Ethernet MAC address that should be used as a destination MAC
+ * address on the Ethernet.
+ *
+ * If the destination IP address is in the local network (determined
+ * by logical ANDing of netmask and our IP address), the function
+ * checks the ARP cache to see if an entry for the destination IP
+ * address is found. If so, an Ethernet header is prepended and the
+ * function returns. If no ARP cache entry is found for the
+ * destination IP address, the packet in the uip_buf[] is replaced by
+ * an ARP request packet for the IP address. The IP packet is dropped
+ * and it is assumed that they higher level protocols (e.g., TCP)
+ * eventually will retransmit the dropped packet.
+ *
+ * If the destination IP address is not on the local network, the IP
+ * address of the default router is used instead.
+ *
+ * When the function returns, a packet is present in the uip_buf[]
+ * buffer, and the length of the packet is in the global variable
+ * uip_len.
+ */
+
+dest_ipv4_addr_t
+uip_determine_dest_ipv4_addr(struct uip_stack *ustack,
+			     u16_t *ipaddr)
+{
+  struct arp_hdr *arp;
+  struct ethip_hdr *ethip_buf;
+  struct uip_eth_hdr *eth;
+  
+  arp = (struct arp_hdr *)ustack->network_layer;
+  ethip_buf = (struct ethip_hdr *)ustack->uip_buf;
+  eth = (struct uip_eth_hdr *) ustack->data_link_layer;
+
+  /* Find the destination IP address in the ARP table and construct
+     the Ethernet header. If the destination IP addres isn't on the
+     local network, we use the default router's IP address instead.
+
+     If not ARP table entry is found, we overwrite the original IP
+     packet with an ARP request for the IP address. */
+
+  /* First check if destination is a local broadcast. */
+  if(uip_ip4addr_cmp(ethip_buf->destipaddr, broadcast_ipaddr)) {
+    memcpy(ethip_buf->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
+
+    return LOCAL_BROADCAST;
+  } else {
+    /* Check if the destination address is on the local network. */
+    if(!uip_ip4addr_maskcmp(ethip_buf->destipaddr, 
+    			   ustack->hostaddr, 
+			   ustack->netmask)) {
+      /* Destination address was not on the local network, so we need to
+	 use the default router's IP address instead of the destination
+	 address when determining the MAC address. */
+      uip_ip4addr_copy(ipaddr, ustack->default_route_addr);
+    } else {
+      /* Else, we use the destination IP address. */
+      uip_ip4addr_copy(ipaddr, ethip_buf->destipaddr);
+    }
+
+    return NONLOCAL_BROADCAST;
+  }
+}
+
+arp_out_t
+is_in_arp_table(u16_t *ipaddr,
+		struct arp_entry **tabptr)
+{
+    u8_t i;
+
+    pthread_mutex_lock(&arp_table_mutex);
+
+    for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+      if(uip_ip4addr_cmp(ipaddr, arp_table[i].ipaddr)) {
+        *tabptr = &arp_table[i];
+	break;
+      }
+    }
+
+    pthread_mutex_unlock(&arp_table_mutex);
+
+    if(i == UIP_ARPTAB_SIZE) {
+        return NOT_IN_ARP_TABLE;
+    } else {
+        return IS_IN_ARP_TABLE;
+    }
+}
+
+void
+uip_build_arp_request(struct uip_stack *ustack,
+		      u16_t *ipaddr)
+{
+  struct arp_hdr *arp;
+  struct uip_eth_hdr *eth;
+  
+  arp = (struct arp_hdr *)ustack->network_layer;
+  eth = (struct uip_eth_hdr *) ustack->data_link_layer;
+
+  /* The destination address was not in our ARP table, so we
+     overwrite the IP packet with an ARP request. */
+
+  memset(eth->dest.addr, 0xff, 6);
+  memset(arp->dhwaddr.addr, 0x00, 6);
+  memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
+  memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6);
+    
+  uip_ip4addr_copy(arp->dipaddr, ipaddr);
+  uip_ip4addr_copy(arp->sipaddr, ustack->hostaddr);
+  arp->opcode = const_htons(ARP_REQUEST); /* ARP request. */
+  arp->hwtype = const_htons(ARP_HWTYPE_ETH);
+  arp->protocol = const_htons(UIP_ETHTYPE_IPv4);
+  arp->hwlen = 6;
+  arp->protolen = 4;
+  eth->type = const_htons(UIP_ETHTYPE_ARP);
+
+  ustack->uip_appdata = &ustack->uip_buf[UIP_TCP_IPv4_HLEN + UIP_LLH_LEN];
+  
+  ustack->uip_len = sizeof(*arp) + sizeof(*eth);
+}
+
+void
+uip_build_eth_header(struct uip_stack *ustack,
+		     u16_t *ipaddr,
+		     struct arp_entry *tabptr,
+		     struct packet *pkt)
+{
+  struct uip_ipv4_hdr *ip_buf;
+  struct uip_eth_hdr *eth;
+  
+  ip_buf = (struct uip_ipv4_hdr *)ustack->network_layer;
+  eth = (struct uip_eth_hdr *) ustack->data_link_layer;
+
+  /* First check if destination is a local broadcast. */
+  if(uip_ip4addr_cmp(ip_buf->destipaddr, broadcast_ipaddr)) {
+    memcpy(eth->dest.addr, broadcast_ethaddr.addr, 6);
+  } else {
+    /* Build an ethernet header. */
+    memcpy(eth->dest.addr, tabptr->ethaddr.addr, 6);
+  }
+  memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
+  
+  eth->type = htons(UIP_ETHTYPE_IPv4);
+
+  ustack->uip_len += sizeof(struct uip_eth_hdr);
+  pkt->buf_size += sizeof(struct uip_eth_hdr);
+}
+
+static struct arp_entry *
+uip_get_arp_entry(int index)
+{
+  return &arp_table[index];
+}
+
+int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr)
+{
+    int i;
+    int rc = -EINVAL;
+
+    pthread_mutex_lock(&arp_table_mutex);
+
+    for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+        struct arp_entry *entry = uip_get_arp_entry(i);
+
+        if( ((entry->ipaddr[1] << 16) == (ip_addr & 0xffff0000)) &&
+	    ((entry->ipaddr[0]) == (ip_addr & 0x0000ffff))) {
+	    	struct in_addr addr;
+		char * addr_str;
+		
+		addr.s_addr = ip_addr;
+		addr_str    = inet_ntoa(addr);
+
+		memcpy(mac_addr, entry->ethaddr.addr, 6);
+
+		LOG_INFO("Found %s at %02x:%02x:%02x:%02x:%02x:%02x",
+			 addr_str,
+			 mac_addr[0], mac_addr[1], mac_addr[2],
+			 mac_addr[3], mac_addr[4], mac_addr[5]);
+		rc = 0;
+		break;
+	}
+    }
+
+    pthread_mutex_unlock(&arp_table_mutex);
+    return rc;
+}
+
+/*-----------------------------------------------------------------------------------*/
+
+/** @} */
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/uip_arp.h b/brcm_iscsi_uio/src/uip/uip_arp.h
new file mode 100644
index 0000000..f9e1047
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_arp.h
@@ -0,0 +1,203 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \addtogroup uiparp
+ * @{
+ */
+ 
+/**
+ * \file
+ * Macros and definitions for the ARP module.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+  
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arp.h,v 1.5 2006/06/11 21:46:39 adam Exp $
+ *
+ */
+
+#ifndef __UIP_ARP_H__
+#define __UIP_ARP_H__
+
+#include "packet.h"
+#include "uip.h"
+#include "uip_eth.h"
+
+#define ARP_REQUEST 1
+#define ARP_REPLY   2
+
+#define ARP_HWTYPE_ETH 1
+
+struct  __attribute__ ((__packed__)) arp_hdr {
+  u16_t hwtype;
+  u16_t protocol;
+  u8_t hwlen;
+  u8_t protolen;
+  u16_t opcode;
+  struct uip_eth_addr shwaddr;
+  u16_t sipaddr[2];
+  struct uip_eth_addr dhwaddr;
+  u16_t dipaddr[2];
+};
+
+struct  __attribute__ ((__packed__)) ethip_hdr {
+  struct uip_eth_hdr ethhdr;
+  /* IP header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+};
+
+
+struct arp_entry {
+  u16_t ipaddr[2];
+  struct uip_eth_addr ethaddr;
+  u8_t time;
+};
+
+
+/* The uip_arp_init() function must be called before any of the other
+   ARP functions. */
+void uip_arp_init(void);
+
+/* The uip_arp_ipin() function should be called whenever an IP packet
+   arrives from the Ethernet. This function refreshes the ARP table or
+   inserts a new mapping if none exists. The function assumes that an
+   IP packet with an Ethernet header is present in the uip_buf buffer
+   and that the length of the packet is in the uip_len variable. */
+/*void uip_arp_ipin(void);*/
+#define uip_arp_ipin()
+
+/* The uip_arp_arpin() should be called when an ARP packet is received
+   by the Ethernet driver. This function also assumes that the
+   Ethernet frame is present in the uip_buf buffer. When the
+   uip_arp_arpin() function returns, the contents of the uip_buf
+   buffer should be sent out on the Ethernet if the uip_len variable
+   is > 0. */
+void uip_arp_arpin(struct uip_stack *ustack, struct packet *pkt);
+
+typedef enum {
+	ARP_SENT 		= 1,
+	ETH_HEADER_APPEDEND	= 2,
+} arp_out_t;
+
+typedef enum {
+	LOCAL_BROADCAST		= 1,
+	NONLOCAL_BROADCAST	= 2,
+} dest_ipv4_addr_t;
+
+typedef enum {
+	IS_IN_ARP_TABLE		= 1,
+	NOT_IN_ARP_TABLE	= 2,
+} arp_table_query_t;
+
+dest_ipv4_addr_t
+uip_determine_dest_ipv4_addr(struct uip_stack *ustack,
+                             u16_t *ipaddr);
+arp_out_t
+is_in_arp_table(u16_t *ipaddr,
+		struct arp_entry **tabptr);
+
+void
+uip_build_arp_request(struct uip_stack *ustack,
+                      u16_t *ipaddr);
+
+void
+uip_build_eth_header(struct uip_stack *ustack,
+                     u16_t *ipaddr,
+		     struct arp_entry *tabptr,
+		     struct packet *pkt);
+
+/* The uip_arp_out() function should be called when an IP packet
+   should be sent out on the Ethernet. This function creates an
+   Ethernet header before the IP header in the uip_buf buffer. The
+   Ethernet header will have the correct Ethernet MAC destination
+   address filled in if an ARP table entry for the destination IP
+   address (or the IP address of the default router) is present. If no
+   such table entry is found, the IP packet is overwritten with an ARP
+   request and we rely on TCP to retransmit the packet that was
+   overwritten. In any case, the uip_len variable holds the length of
+   the Ethernet frame that should be transmitted. */
+arp_out_t uip_arp_out(struct uip_stack *ustack);
+
+/* The uip_arp_timer() function should be called every ten seconds. It
+   is responsible for flushing old entries in the ARP table. */
+void uip_arp_timer(void);
+
+int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr);
+
+/** @} */
+
+/**
+ * \addtogroup uipconffunc
+ * @{
+ */
+
+
+/**
+ * Specifiy the Ethernet MAC address.
+ *
+ * The ARP code needs to know the MAC address of the Ethernet card in
+ * order to be able to respond to ARP queries and to generate working
+ * Ethernet headers.
+ *
+ * \note This macro only specifies the Ethernet MAC address to the ARP
+ * code. It cannot be used to change the MAC address of the Ethernet
+ * card.
+ *
+ * \param eaddr A pointer to a struct uip_eth_addr containing the
+ * Ethernet MAC address of the Ethernet card.
+ *
+ * \hideinitializer
+ */
+#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \
+                              uip_ethaddr.addr[1] = eaddr.addr[1];\
+                              uip_ethaddr.addr[2] = eaddr.addr[2];\
+                              uip_ethaddr.addr[3] = eaddr.addr[3];\
+                              uip_ethaddr.addr[4] = eaddr.addr[4];\
+                              uip_ethaddr.addr[5] = eaddr.addr[5];} while(0)
+
+/** @} */
+/** @} */
+
+#endif /* __UIP_ARP_H__ */
diff --git a/brcm_iscsi_uio/src/uip/uip_eth.c b/brcm_iscsi_uio/src/uip/uip_eth.c
new file mode 100644
index 0000000..5d410bf
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_eth.c
@@ -0,0 +1,24 @@
+/* uip_eth.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include "uip.h"
+#include "uip_eth.h"
+
+int is_vlan_packet(struct uip_vlan_eth_hdr *hdr)
+{
+	/*  The TPID field in a 802.1Q Header must be 0x8100 */
+	if(hdr->tpid == const_htons(UIP_ETHTYPE_8021Q))
+	{
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/brcm_iscsi_uio/src/uip/uip_eth.h b/brcm_iscsi_uio/src/uip/uip_eth.h
new file mode 100644
index 0000000..1138e2e
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_eth.h
@@ -0,0 +1,43 @@
+#ifndef __UIP_ETH_H__
+#define __UIP_ETH_H__
+
+#include "uipopt.h"
+
+/*******************************************************************************
+ * Ether types
+ ******************************************************************************/
+#define UIP_ETHTYPE_ARP		0x0806
+#define UIP_ETHTYPE_IPv4	0x0800
+#define UIP_ETHTYPE_8021Q	0x8100
+#define UIP_ETHTYPE_IPv6	0x86dd
+
+/**
+ * Representation of a 48-bit Ethernet address.
+ */
+struct uip_eth_addr {
+  u8_t addr[6];
+};
+
+/**
+ * The Ethernet header.
+ */
+struct __attribute__ ((__packed__)) uip_eth_hdr {
+	struct uip_eth_addr dest;
+	struct uip_eth_addr src;
+	u16_t type;
+};
+
+/**
+ * The 802.1Q Ethernet header (VLAN).
+ */
+struct __attribute__ ((__packed__)) uip_vlan_eth_hdr {
+	struct uip_eth_addr dest;
+	struct uip_eth_addr src;
+	u16_t tpid;
+	u16_t vid;
+	u16_t type;
+};
+
+int is_vlan_packet(struct uip_vlan_eth_hdr *hdr);
+
+#endif /* __UIP_ETH_H__ */
diff --git a/brcm_iscsi_uio/src/uip/uip_ipv6.c b/brcm_iscsi_uio/src/uip/uip_ipv6.c
new file mode 100644
index 0000000..b673b3a
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_ipv6.c
@@ -0,0 +1,2315 @@
+#include <arpa/inet.h>
+#include "uip.h"
+#include "dhcpc.h"
+#include "brcm-iscsi.h"
+
+#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/
+
+/**
+ * \defgroup uip The uIP TCP/IP stack
+ * @{
+ *
+ * uIP is an implementation of the TCP/IP protocol stack intended for
+ * small 8-bit and 16-bit microcontrollers.
+ *
+ * uIP provides the necessary protocols for Internet communication,
+ * with a very small code footprint and RAM requirements - the uIP
+ * code size is on the order of a few kilobytes and RAM usage is on
+ * the order of a few hundred bytes.
+ */
+
+/**
+ * \file
+ * The uIP TCP/IP stack code.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $
+ *
+ */
+
+/*
+ * uIP is a small implementation of the IP, UDP and TCP protocols (as
+ * well as some basic ICMP stuff). The implementation couples the IP,
+ * UDP, TCP and the application layers very tightly. To keep the size
+ * of the compiled code down, this code frequently uses the goto
+ * statement. While it would be possible to break the uip_process()
+ * function into many smaller functions, this would increase the code
+ * size because of the overhead of parameter passing and the fact that
+ * the optimier would not be as efficient.
+ *
+ * The principle is that we have a small buffer, called the uip_buf,
+ * in which the device driver puts an incoming packet. The TCP/IP
+ * stack parses the headers in the packet, and calls the
+ * application. If the remote host has sent data to the application,
+ * this data is present in the uip_buf and the application read the
+ * data from there. It is up to the application to put this data into
+ * a byte stream if needed. The application will not be fed with data
+ * that is out of sequence.
+ *
+ * If the application whishes to send data to the peer, it should put
+ * its data into the uip_buf. The uip_appdata pointer points to the
+ * first available byte. The TCP/IP stack will calculate the
+ * checksums, and fill in the necessary header fields and finally send
+ * the packet back to the peer.
+*/
+
+#include "logger.h"
+
+#include "uip.h"
+#include "uipopt.h"
+#include "uip_arch.h"
+
+#if UIP_CONF_IPV6
+#include "uip-neighbor.h"
+#endif /* UIP_CONF_IPV6 */
+
+#include <string.h>
+
+/*---------------------------------------------------------------------------*/
+/* Variable definitions. */
+
+
+static const uip_ipaddr_t all_ones_addr =
+#if UIP_CONF_IPV6
+  {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff};
+#else /* UIP_CONF_IPV6 */
+  {0xffff,0xffff};
+#endif /* UIP_CONF_IPV6 */
+static const uip_ipaddr_t all_zeroes_addr =
+#if UIP_CONF_IPV6
+  {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
+#else /* UIP_CONF_IPV6 */
+  {0x0000,0x0000};
+#endif /* UIP_CONF_IPV6 */
+
+#if 0
+#if UIP_FIXEDETHADDR
+const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
+					  UIP_ETHADDR1,
+					  UIP_ETHADDR2,
+					  UIP_ETHADDR3,
+					  UIP_ETHADDR4,
+					  UIP_ETHADDR5}};
+#else
+#endif
+#endif
+//struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
+#if 0
+#endif
+
+#if 0
+#ifndef UIP_CONF_EXTERNAL_BUFFER
+u8_t uip_buf[UIP_BUFSIZE + 2];   /* The packet buffer that contains
+				    incoming packets. */
+#endif /* UIP_CONF_EXTERNAL_BUFFER */
+
+void *uip_appdata;               /* The uip_appdata pointer points to
+				    application data. */
+void *uip_sappdata;              /* The uip_appdata pointer points to
+				    the application data which is to
+				    be sent. */
+#if UIP_URGDATA > 0
+void *uip_urgdata;               /* The uip_urgdata pointer points to
+   				    urgent data (out-of-band data), if
+   				    present. */
+u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+u16_t uip_len, uip_slen;
+                             /* The uip_len is either 8 or 16 bits,
+				depending on the maximum packet
+				size. */
+
+u8_t uip_flags;     /* The uip_flags variable is used for
+				communication between the TCP/IP stack
+				and the application program. */
+struct uip_conn *uip_conn;   /* uip_conn always points to the current
+				connection. */
+
+struct uip_conn uip_conns[UIP_CONNS];
+                             /* The uip_conns array holds all TCP
+				connections. */
+u16_t uip_listenports[UIP_LISTENPORTS];
+                             /* The uip_listenports list all currently
+				listning ports. */
+#if UIP_UDP
+struct uip_udp_conn *uip_udp_conn;
+struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+static u16_t ipid;           /* Ths ipid variable is an increasing
+				number that is used for the IP ID
+				field. */
+
+void uip_setipid(u16_t id) { ipid = id; }
+
+static u8_t iss[4];          /* The iss variable is used for the TCP
+				initial sequence number. */
+
+#if UIP_ACTIVE_OPEN
+static u16_t lastport;       /* Keeps track of the last port used for
+				a new connection. */
+#endif /* UIP_ACTIVE_OPEN */
+
+/* Temporary variables. */
+u8_t uip_acc32[4];
+static u8_t c, opt;
+static u16_t tmp16;
+#endif
+
+/* Structures and definitions. */
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_PSH 0x08
+#define TCP_ACK 0x10
+#define TCP_URG 0x20
+#define TCP_CTL 0x3f
+
+#define TCP_OPT_END     0   /* End of TCP options list */
+#define TCP_OPT_NOOP    1   /* "No-operation" TCP option */
+#define TCP_OPT_MSS     2   /* Maximum segment size TCP option */
+
+#define TCP_OPT_MSS_LEN 4   /* Length of TCP MSS option. */
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO       8
+
+#define ICMP6_ECHO_REPLY             129
+#define ICMP6_ECHO                   128
+#define ICMP6_NEIGHBOR_SOLICITATION  135
+#define ICMP6_NEIGHBOR_ADVERTISEMENT 136
+
+#define ICMP6_FLAG_S (1 << 6)
+
+#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
+#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
+
+
+/* Macros. */
+#define BUF(ustack) ((struct uip_tcpip_hdr *)&ustack->uip_buf[UIP_LLH_LEN])
+#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
+#define ICMPBUF(ustack) ((struct uip_icmpip_hdr *)&ustack->uip_buf[UIP_LLH_LEN])
+#define UDPBUF(ustack) ((struct uip_udpip_hdr *)&ustack->uip_buf[UIP_LLH_LEN])
+
+
+void uip_sethostaddr(struct uip_stack *ustack, uip_ipaddr_t *addr)
+{
+	pthread_mutex_lock(&ustack->lock);
+	uip_ipaddr_copy(ustack->uip_hostaddr, (addr));
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setdraddr(struct uip_stack *ustack, uip_ipaddr_t *addr)
+{
+	pthread_mutex_lock(&ustack->lock);
+	uip_ipaddr_copy(ustack->uip_draddr, (addr));
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setnetmask(struct uip_stack *ustack, uip_ipaddr_t *addr)
+{
+	pthread_mutex_lock(&ustack->lock);
+	uip_ipaddr_copy(ustack->uip_netmask, (addr));
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac)
+{
+	pthread_mutex_lock(&ustack->lock);
+	memcpy(ustack->uip_ethaddr.addr, (mac), 6);
+	pthread_mutex_unlock(&ustack->lock);
+}
+
+
+#if ! UIP_ARCH_ADD32
+void
+uip_add32(u8_t *op32, u16_t op16, u8_t *uip_acc32)
+{
+  uip_acc32[3] = op32[3] + (op16 & 0xff);
+  uip_acc32[2] = op32[2] + (op16 >> 8);
+  uip_acc32[1] = op32[1];
+  uip_acc32[0] = op32[0];
+  
+  if(uip_acc32[2] < (op16 >> 8)) {
+    ++uip_acc32[1];
+    if(uip_acc32[1] == 0) {
+      ++uip_acc32[0];
+    }
+  }
+  
+  
+  if(uip_acc32[3] < (op16 & 0xff)) {
+    ++uip_acc32[2];
+    if(uip_acc32[2] == 0) {
+      ++uip_acc32[1];
+      if(uip_acc32[1] == 0) {
+	++uip_acc32[0];
+      }
+    }
+  }
+}
+
+#endif /* UIP_ARCH_ADD32 */
+
+#if ! UIP_ARCH_CHKSUM
+/*---------------------------------------------------------------------------*/
+static u16_t
+chksum(u16_t sum, const u8_t *data, u16_t len)
+{
+  u16_t t;
+  const u8_t *dataptr;
+  const u8_t *last_byte;
+
+  dataptr = data;
+  last_byte = data + len - 1;
+  
+  while(dataptr < last_byte) {	/* At least two more bytes */
+    t = (dataptr[0] << 8) + dataptr[1];
+    sum += t;
+    if(sum < t) {
+      sum++;		/* carry */
+    }
+    dataptr += 2;
+  }
+  
+  if(dataptr == last_byte) {
+    t = (dataptr[0] << 8) + 0;
+    sum += t;
+    if(sum < t) {
+      sum++;		/* carry */
+    }
+  }
+
+  /* Return sum in host byte order. */
+  return sum;
+}
+/*---------------------------------------------------------------------------*/
+u16_t
+uip_chksum(u16_t *data, u16_t len)
+{
+  return htons(chksum(0, (u8_t *)data, len));
+}
+/*---------------------------------------------------------------------------*/
+#ifndef UIP_ARCH_IPCHKSUM
+u16_t
+uip_ipchksum(struct uip_stack *ustack)
+{
+  u16_t sum;
+
+  sum = chksum(0, &ustack->uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
+  DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum);
+  return (sum == 0) ? 0xffff : htons(sum);
+}
+#endif
+/*---------------------------------------------------------------------------*/
+static u16_t
+upper_layer_chksum(struct uip_stack *ustack, u8_t proto)
+{
+  u16_t upper_layer_len;
+  u16_t sum;
+  
+#if UIP_CONF_IPV6
+  upper_layer_len = (((u16_t)(BUF(ustack)->len[0]) << 8) + BUF(ustack)->len[1]);
+#else /* UIP_CONF_IPV6 */
+  upper_layer_len = (((u16_t)(BUF(ustack)->len[0]) << 8) + BUF(ustack)->len[1]) - UIP_IPH_LEN;
+#endif /* UIP_CONF_IPV6 */
+  
+  /* First sum pseudoheader. */
+  
+  /* IP protocol and length fields. This addition cannot carry. */
+  sum = upper_layer_len + proto;
+  /* Sum IP source and destination addresses. */
+  sum = chksum(sum, (u8_t *)&BUF(ustack)->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
+
+  /* Sum TCP header and data. */
+  sum = chksum(sum, &ustack->uip_buf[UIP_IPH_LEN + UIP_LLH_LEN],
+	       upper_layer_len);
+    
+  return (sum == 0) ? 0xffff : htons(sum);
+}
+/*---------------------------------------------------------------------------*/
+#if UIP_CONF_IPV6
+u16_t
+uip_icmp6chksum(void)
+{
+  return upper_layer_chksum(UIP_PROTO_ICMP6);
+  
+}
+#endif /* UIP_CONF_IPV6 */
+/*---------------------------------------------------------------------------*/
+u16_t
+uip_tcpchksum(struct uip_stack *ustack)
+{
+  return upper_layer_chksum(ustack, UIP_PROTO_TCP);
+}
+/*---------------------------------------------------------------------------*/
+#if UIP_UDP_CHECKSUMS
+u16_t
+uip_udpchksum(struct uip_stack *ustack)
+{
+  return upper_layer_chksum(ustack, UIP_PROTO_UDP);
+}
+#endif /* UIP_UDP_CHECKSUMS */
+#endif /* UIP_ARCH_CHKSUM */
+/*---------------------------------------------------------------------------*/
+void
+uip_init(struct uip_stack *ustack, uint8_t ipv6_enabled)
+{
+  u8_t c;
+
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    ustack->uip_listenports[c] = 0;
+  }
+  for(c = 0; c < UIP_CONNS; ++c) {
+    ustack->uip_conns[c].tcpstateflags = UIP_CLOSED;
+  }
+#if UIP_ACTIVE_OPEN
+  ustack->lastport = 1024;
+#endif /* UIP_ACTIVE_OPEN */
+
+#if UIP_UDP
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    ustack->uip_udp_conns[c].lport = 0;
+  }
+#endif /* UIP_UDP */
+  
+
+  /* IPv4 initialization. */
+#if UIP_FIXEDADDR == 0
+  /*  uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
+#endif /* UIP_FIXEDADDR */
+
+  /*  zero out the uIP statistics */
+  memset(&ustack->stats, 0, sizeof(ustack->stats));
+
+  /*  prepare the uIP lock */
+  pthread_mutex_init(&ustack->lock, NULL);
+
+  if(ipv6_enabled)
+    ustack->enable_IPv6 = UIP_SUPPORT_IPv6_ENABLED;
+  else
+    ustack->enable_IPv6 = UIP_SUPPORT_IPv6_DISABLED;
+}
+/*---------------------------------------------------------------------------*/
+#if UIP_ACTIVE_OPEN
+struct uip_conn *
+uip_connect(struct uip_stack *ustack, uip_ipaddr_t *ripaddr, u16_t rport)
+{
+  u8_t c;
+  register struct uip_conn *conn, *cconn;
+  
+  /* Find an unused local port. */
+ again:
+  ++ustack->lastport;
+
+  if(ustack->lastport >= 32000) {
+    ustack->lastport = 4096;
+  }
+
+  /* Check if this port is already in use, and if so try to find
+     another one. */
+  for(c = 0; c < UIP_CONNS; ++c) {
+    conn = &ustack->uip_conns[c];
+    if(conn->tcpstateflags != UIP_CLOSED &&
+       conn->lport == htons(ustack->lastport)) {
+      goto again;
+    }
+  }
+
+  conn = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    cconn = &ustack->uip_conns[c];
+    if(cconn->tcpstateflags == UIP_CLOSED) {
+      conn = cconn;
+      break;
+    }
+    if(cconn->tcpstateflags == UIP_TIME_WAIT) {
+      if(conn == 0 ||
+	 cconn->timer > conn->timer) {
+	conn = cconn;
+      }
+    }
+  }
+
+  if(conn == 0) {
+    return 0;
+  }
+  
+  conn->tcpstateflags = UIP_SYN_SENT;
+
+  conn->snd_nxt[0] = ustack->iss[0];
+  conn->snd_nxt[1] = ustack->iss[1];
+  conn->snd_nxt[2] = ustack->iss[2];
+  conn->snd_nxt[3] = ustack->iss[3];
+
+  conn->initialmss = conn->mss = UIP_TCP_MSS;
+  
+  conn->len = 1;   /* TCP length of the SYN is one. */
+  conn->nrtx = 0;
+  conn->timer = 1; /* Send the SYN next time around. */
+  conn->rto = UIP_RTO;
+  conn->sa = 0;
+  conn->sv = 16;   /* Initial value of the RTT variance. */
+  conn->lport = htons(ustack->lastport);
+  conn->rport = rport;
+  uip_ipaddr_copy(&conn->ripaddr, ripaddr);
+  
+  return conn;
+}
+#endif /* UIP_ACTIVE_OPEN */
+/*---------------------------------------------------------------------------*/
+#if UIP_UDP
+struct uip_udp_conn *
+uip_udp_new(struct uip_stack *ustack, uip_ipaddr_t *ripaddr, u16_t rport)
+{
+  u8_t c;
+  register struct uip_udp_conn *conn;
+  
+  /* Find an unused local port. */
+ again:
+  ++ustack->lastport;
+
+  if(ustack->lastport >= 32000) {
+    ustack->lastport = 4096;
+  }
+  
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    if(ustack->uip_udp_conns[c].lport == htons(ustack->lastport)) {
+      goto again;
+    }
+  }
+
+
+  conn = 0;
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    if(ustack->uip_udp_conns[c].lport == 0) {
+      conn = &ustack->uip_udp_conns[c];
+      break;
+    }
+  }
+
+  if(conn == 0) {
+    return 0;
+  }
+
+  conn->lport = htons(ustack->lastport);
+  conn->rport = rport;
+  if(ripaddr == NULL) {
+    memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t));
+  } else {
+    uip_ipaddr_copy(&conn->ripaddr, ripaddr);
+  }
+  conn->ttl = UIP_TTL;
+  
+  return conn;
+}
+#endif /* UIP_UDP */
+/*---------------------------------------------------------------------------*/
+void
+uip_unlisten(struct uip_stack *ustack, u16_t port)
+{
+  u8_t c;
+
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(ustack->uip_listenports[c] == port) {
+      ustack->uip_listenports[c] = 0;
+      return;
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+uip_listen(struct uip_stack *ustack, u16_t port)
+{
+  u8_t c;
+
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(ustack->uip_listenports[c] == 0) {
+      ustack->uip_listenports[c] = port;
+      return;
+    }
+  }
+}
+
+
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+int uip_newdata(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_NEWDATA;
+}
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data.
+ *
+ * \hideinitializer
+ */
+#define uip_acked()   (uip_flags & UIP_ACKDATA)
+
+/**
+ * Has the connection just been connected?
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+int uip_connected(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_CONNECTED;
+}
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+int uip_closed(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_CLOSE;
+}
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+int uip_aborted(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_ABORT;
+}
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+int uip_timedout(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_TIMEDOUT;
+}
+
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+int uip_rexmit(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_REXMIT;
+}
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */
+int uip_poll(struct uip_stack *ustack)
+{
+	return ustack->uip_flags & UIP_POLL;
+}
+
+int uip_initialmss(struct uip_stack *ustack)
+{
+	return ustack->uip_conn->initialmss;
+}
+
+int uip_mss(struct uip_stack *ustack)
+{
+	return ustack->uip_conn->mss;
+}
+
+/*---------------------------------------------------------------------------*/
+/* XXX: IP fragment reassembly: not well-tested. */
+
+#if UIP_REASSEMBLY && !UIP_CONF_IPV6
+#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
+static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
+static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
+static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
+				    0x0f, 0x07, 0x03, 0x01};
+static u16_t uip_reasslen;
+static u8_t uip_reassflags;
+#define UIP_REASS_FLAG_LASTFRAG 0x01
+static u8_t uip_reasstmr;
+
+#define IP_MF   0x20
+
+static u8_t
+uip_reass(void)
+{
+  u16_t offset, len;
+  u16_t i;
+
+  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
+     write the IP header of the fragment into the reassembly
+     buffer. The timer is updated with the maximum age. */
+  if(uip_reasstmr == 0) {
+    memcpy(uip_reassbuf, &BUF(ustack)->vhl, UIP_IPH_LEN);
+    uip_reasstmr = UIP_REASS_MAXAGE;
+    uip_reassflags = 0;
+    /* Clear the bitmap. */
+    memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
+  }
+
+  /* Check if the incoming fragment matches the one currently present
+     in the reasembly buffer. If so, we proceed with copying the
+     fragment into the buffer. */
+  if(BUF(ustack)->srcipaddr[0] == FBUF(ustack)->srcipaddr[0] &&
+     BUF(ustack)->srcipaddr[1] == FBUF(ustack)->srcipaddr[1] &&
+     BUF(ustack)->destipaddr[0] == FBUF(ustack)->destipaddr[0] &&
+     BUF(ustack)->destipaddr[1] == FBUF(ustack)->destipaddr[1] &&
+     BUF(ustack)->ipid[0] == FBUF(ustack)->ipid[0] &&
+     BUF(ustack)->ipid[1] == FBUF(ustack)->ipid[1]) {
+
+    len = (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1] - (BUF(ustack)->vhl & 0x0f) * 4;
+    offset = (((BUF(ustack)->ipoffset[0] & 0x3f) << 8) + BUF(ustack)->ipoffset[1]) * 8;
+
+    /* If the offset or the offset + fragment length overflows the
+       reassembly buffer, we discard the entire packet. */
+    if(offset > UIP_REASS_BUFSIZE ||
+       offset + len > UIP_REASS_BUFSIZE) {
+      uip_reasstmr = 0;
+      goto nullreturn;
+    }
+
+    /* Copy the fragment into the reassembly buffer, at the right
+       offset. */
+    memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
+	   (char *)BUF + (int)((BUF(ustack)->vhl & 0x0f) * 4),
+	   len);
+      
+    /* Update the bitmap. */
+    if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
+      /* If the two endpoints are in the same byte, we only update
+	 that byte. */
+	     
+      uip_reassbitmap[offset / (8 * 8)] |=
+	     bitmap_bits[(offset / 8 ) & 7] &
+	     ~bitmap_bits[((offset + len) / 8 ) & 7];
+    } else {
+      /* If the two endpoints are in different bytes, we update the
+	 bytes in the endpoints and fill the stuff inbetween with
+	 0xff. */
+      uip_reassbitmap[offset / (8 * 8)] |=
+	bitmap_bits[(offset / 8 ) & 7];
+      for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
+	uip_reassbitmap[i] = 0xff;
+      }
+      uip_reassbitmap[(offset + len) / (8 * 8)] |=
+	~bitmap_bits[((offset + len) / 8 ) & 7];
+    }
+    
+    /* If this fragment has the More Fragments flag set to zero, we
+       know that this is the last fragment, so we can calculate the
+       size of the entire packet. We also set the
+       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
+       the final fragment. */
+
+    if((BUF(ustack)->ipoffset[0] & IP_MF) == 0) {
+      uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
+      uip_reasslen = offset + len;
+    }
+    
+    /* Finally, we check if we have a full packet in the buffer. We do
+       this by checking if we have the last fragment and if all bits
+       in the bitmap are set. */
+    if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
+      /* Check all bytes up to and including all but the last byte in
+	 the bitmap. */
+      for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
+	if(uip_reassbitmap[i] != 0xff) {
+	  goto nullreturn;
+	}
+      }
+      /* Check the last byte in the bitmap. It should contain just the
+	 right amount of bits. */
+      if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
+	 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
+	goto nullreturn;
+      }
+
+      /* If we have come this far, we have a full packet in the
+	 buffer, so we allocate a pbuf and copy the packet into it. We
+	 also reset the timer. */
+      uip_reasstmr = 0;
+      memcpy(BUF, FBUF, uip_reasslen);
+
+      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
+	 from now on. */
+      BUF(ustack)->ipoffset[0] = BUF(ustack)->ipoffset[1] = 0;
+      BUF(ustack)->len[0] = uip_reasslen >> 8;
+      BUF(ustack)->len[1] = uip_reasslen & 0xff;
+      BUF(ustack)->ipchksum = 0;
+      BUF(ustack)->ipchksum = ~(uip_ipchksum());
+
+      return uip_reasslen;
+    }
+  }
+
+ nullreturn:
+  return 0;
+}
+#endif /* UIP_REASSEMBLY */
+/*---------------------------------------------------------------------------*/
+static void
+uip_add_rcv_nxt(struct uip_stack *ustack, u16_t n)
+{
+  u8_t uip_acc32[4];
+
+  uip_add32(ustack->uip_conn->rcv_nxt, n, uip_acc32);
+  ustack->uip_conn->rcv_nxt[0] = uip_acc32[0];
+  ustack->uip_conn->rcv_nxt[1] = uip_acc32[1];
+  ustack->uip_conn->rcv_nxt[2] = uip_acc32[2];
+  ustack->uip_conn->rcv_nxt[3] = uip_acc32[3];
+}
+/*---------------------------------------------------------------------------*/
+
+/** @} */
+
+/**
+ * \defgroup uipdevfunc uIP device driver functions
+ * @{
+ *
+ * These functions are used by a network device driver for interacting
+ * with uIP.
+ */
+
+/**
+ * Process an incoming packet.
+ *
+ * This function should be called when the device driver has received
+ * a packet from the network. The packet from the device driver must
+ * be present in the uip_buf buffer, and the length of the packet
+ * should be placed in the uip_len variable.
+ *
+ * When the function returns, there may be an outbound packet placed
+ * in the uip_buf packet buffer. If so, the uip_len variable is set to
+ * the length of the packet. If no packet is to be sent out, the
+ * uip_len variable is set to 0.
+ *
+ * The usual way of calling the function is presented by the source
+ * code below.
+ \code
+  uip_len = devicedriver_poll();
+  if(uip_len > 0) {
+    uip_input();
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uIP ARP code before calling
+ * this function:
+ \code
+  #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  uip_len = ethernet_devicedrver_poll();
+  if(uip_len > 0) {
+    if(BUF(ustack)->type == HTONS(UIP_ETHTYPE_IP)) {
+      uip_arp_ipin();
+      uip_input();
+      if(uip_len > 0) {
+        uip_arp_out();
+        ethernet_devicedriver_send();
+      }
+    } else if(BUF(ustack)->type == HTONS(UIP_ETHTYPE_ARP)) {
+      uip_arp_arpin();
+      if(uip_len > 0) {
+        ethernet_devicedriver_send();
+      }
+    }
+ \endcode
+ *
+ * \hideinitializer
+ */
+void uip_input(struct uip_stack *ustack)
+{
+	uip_process(ustack, UIP_DATA);
+}
+
+/**
+ * Periodic processing for a connection identified by its number.
+ *
+ * This function does the necessary periodic processing (timers,
+ * polling) for a uIP TCP conneciton, and should be called when the
+ * periodic uIP timer goes off. It should be called for every
+ * connection, regardless of whether they are open of closed.
+ *
+ * When the function returns, it may have an outbound packet waiting
+ * for service in the uIP packet buffer, and if so the uip_len
+ * variable is set to a value larger than zero. The device driver
+ * should be called to send out the packet.
+ *
+ * The ususal way of calling the function is through a for() loop like
+ * this:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uip_arp_out() function before
+ * calling the device driver:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the connection which is to be periodically polled.
+ *
+ * \hideinitializer
+ */
+void uip_periodic(struct uip_stack *ustack, int conn) 
+{
+	ustack->uip_conn = &ustack->uip_conns[conn];
+	uip_process(ustack, UIP_TIMER);
+}
+
+#if 0
+/**
+ * Perform periodic processing for a connection identified by a pointer
+ * to its structure.
+ *
+ * Same as uip_periodic() but takes a pointer to the actual uip_conn
+ * struct instead of an integer as its argument. This function can be
+ * used to force periodic processing of a specific connection.
+ *
+ * \param conn A pointer to the uip_conn struct for the connection to
+ * be processed.
+ *
+ * \hideinitializer
+ */
+void uip_periodic_conn(struct uip_stack *ustack, conn)
+{
+	ustack->uip_conn = conn;
+        uip_process(ustack, UIP_TIMER);
+}
+
+/**
+ * Reuqest that a particular connection should be polled.
+ *
+ * Similar to uip_periodic_conn() but does not perform any timer
+ * processing. The application is polled for new data.
+ *
+ * \param conn A pointer to the uip_conn struct for the connection to
+ * be processed.
+ *
+ * \hideinitializer
+ */
+void uip_poll_conn(struct uip_stack *ustack, conn)
+{
+	uip_conn = conn;
+	uip_process(ustack, UIP_POLL_REQUEST);
+}
+#endif
+
+#if UIP_UDP
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_periodic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+void uip_udp_periodic(struct uip_stack *ustack, int conn)
+{
+	ustack->uip_udp_conn = &ustack->uip_udp_conns[conn];
+	uip_process(ustack, UIP_UDP_TIMER);
+}
+
+#if 0
+/**
+ * Periodic processing for a UDP connection identified by a pointer to
+ * its structure.
+ *
+ * Same as uip_udp_periodic() but takes a pointer to the actual
+ * uip_conn struct instead of an integer as its argument. This
+ * function can be used to force periodic processing of a specific
+ * connection.
+ *
+ * \param conn A pointer to the uip_udp_conn struct for the connection
+ * to be processed.
+ *
+ * \hideinitializer
+ */
+void uip_udp_periodic_conna(struct uip_stack *ustack, int conn) do { uip_udp_conn = conn; \
+                                         uip_process(UIP_UDP_TIMER); } while (0)
+
+#endif
+
+#endif /* UIP_UDP */
+
+
+
+void
+uip_process(struct uip_stack *ustack, u8_t flag)
+{
+  u8_t  c;
+  u16_t tmp16;
+  register struct uip_conn *uip_connr = ustack->uip_conn;
+
+#if UIP_UDP
+  if(flag == UIP_UDP_SEND_CONN) {
+    goto udp_send;
+  }
+#endif /* UIP_UDP */
+  
+  ustack->uip_sappdata = ustack->uip_appdata = &ustack->uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
+
+  /* Check if we were invoked because of a poll request for a
+     particular connection. */
+  if(flag == UIP_POLL_REQUEST) {
+    if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED &&
+       !uip_outstanding(uip_connr)) {
+	ustack->uip_flags = UIP_POLL;
+	UIP_APPCALL();
+	goto appsend;
+    }
+    goto drop;
+    
+    /* Check if we were invoked because of the perodic timer fireing. */
+  } else if(flag == UIP_TIMER) {
+#if UIP_REASSEMBLY
+    if(uip_reasstmr != 0) {
+      --uip_reasstmr;
+    }
+#endif /* UIP_REASSEMBLY */
+    /* Increase the initial sequence number. */
+    if(++ustack->iss[3] == 0) {
+      if(++ustack->iss[2] == 0) {
+	if(++ustack->iss[1] == 0) {
+	  ++ustack->iss[0];
+	}
+      }
+    }
+
+    /* Reset the length variables. */
+    ustack->uip_len = 0;
+    ustack->uip_slen = 0;
+
+    /* Check if the connection is in a state in which we simply wait
+       for the connection to time out. If so, we increase the
+       connection's timer and remove the connection if it times
+       out. */
+    if(uip_connr->tcpstateflags == UIP_TIME_WAIT ||
+       uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
+      ++(uip_connr->timer);
+      if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
+	uip_connr->tcpstateflags = UIP_CLOSED;
+      }
+    } else if(uip_connr->tcpstateflags != UIP_CLOSED) {
+      /* If the connection has outstanding data, we increase the
+	 connection's timer and see if it has reached the RTO value
+	 in which case we retransmit. */
+      if(uip_outstanding(uip_connr)) {
+	if(uip_connr->timer-- == 0) {
+	  if(uip_connr->nrtx == UIP_MAXRTX ||
+	     ((uip_connr->tcpstateflags == UIP_SYN_SENT ||
+	       uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
+	      uip_connr->nrtx == UIP_MAXSYNRTX)) {
+	    uip_connr->tcpstateflags = UIP_CLOSED;
+
+	    /* We call UIP_APPCALL() with uip_flags set to
+	       UIP_TIMEDOUT to inform the application that the
+	       connection has timed out. */
+	    ustack->uip_flags = UIP_TIMEDOUT;
+	    UIP_APPCALL();
+
+	    /* We also send a reset packet to the remote host. */
+	    BUF(ustack)->flags = TCP_RST | TCP_ACK;
+	    goto tcp_send_nodata;
+	  }
+
+	  /* Exponential backoff. */
+	  uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
+					 4:
+					 uip_connr->nrtx);
+	  ++(uip_connr->nrtx);
+	  
+	  /* Ok, so we need to retransmit. We do this differently
+	     depending on which state we are in. In ESTABLISHED, we
+	     call upon the application so that it may prepare the
+	     data for the retransmit. In SYN_RCVD, we resend the
+	     SYNACK that we sent earlier and in LAST_ACK we have to
+	     retransmit our FINACK. */
+	  ++ustack->stats.tcp.rexmit;
+	  switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
+	  case UIP_SYN_RCVD:
+	    /* In the SYN_RCVD state, we should retransmit our
+               SYNACK. */
+	    goto tcp_send_synack;
+	    
+#if UIP_ACTIVE_OPEN
+	  case UIP_SYN_SENT:
+	    /* In the SYN_SENT state, we retransmit out SYN. */
+	    BUF(ustack)->flags = 0;
+	    goto tcp_send_syn;
+#endif /* UIP_ACTIVE_OPEN */
+	    
+	  case UIP_ESTABLISHED:
+	    /* In the ESTABLISHED state, we call upon the application
+               to do the actual retransmit after which we jump into
+               the code for sending out the packet (the apprexmit
+               label). */
+	    ustack->uip_flags = UIP_REXMIT;
+	    UIP_APPCALL();
+	    goto apprexmit;
+	    
+	  case UIP_FIN_WAIT_1:
+	  case UIP_CLOSING:
+	  case UIP_LAST_ACK:
+	    /* In all these states we should retransmit a FINACK. */
+	    goto tcp_send_finack;
+	    
+	  }
+	}
+      } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {
+	/* If there was no need for a retransmission, we poll the
+           application for new data. */
+	ustack->uip_flags = UIP_POLL;
+	UIP_APPCALL();
+	goto appsend;
+      }
+    }
+    goto drop;
+  }
+#if UIP_UDP
+  if(flag == UIP_UDP_TIMER) {
+    if(ustack->uip_udp_conn->lport != 0) {
+      ustack->uip_conn = NULL;
+      ustack->uip_sappdata = ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
+      ustack->uip_len = ustack->uip_slen = 0;
+      ustack->uip_flags = UIP_POLL;
+      UIP_UDP_APPCALL();
+      goto udp_send;
+    } else {
+      goto drop;
+    }
+  }
+#endif
+
+  /* This is where the input processing starts. */
+  ++ustack->stats.ip.recv;
+
+  /* Start of IP input header processing code. */
+  
+#if UIP_CONF_IPV6
+  /* Check validity of the IP header. */
+  if((BUF(ustack)->vtc & 0xf0) != 0x60)  { /* IP version and header length. */
+    ++ustack->stats.ip.drop;
+    ++ustack->stats.ip.vhlerr;
+    LOG_ERR("ipv6: invalid version.");
+    goto drop;
+  }
+#else /* UIP_CONF_IPV6 */
+  /* Check validity of the IP header. */
+  if(BUF(ustack)->vhl != 0x45)  { /* IP version and header length. */
+    ++ustack->stats.ip.drop;
+    ++ustack->stats.ip.vhlerr;
+    LOG_ERR("ip: invalid version or header length.");
+    goto drop;
+  }
+#endif /* UIP_CONF_IPV6 */
+  
+  /* Check the size of the packet. If the size reported to us in
+     uip_len is smaller the size reported in the IP header, we assume
+     that the packet has been corrupted in transit. If the size of
+     uip_len is larger than the size reported in the IP packet header,
+     the packet has been padded and we set uip_len to the correct
+     value.. */
+
+  if((BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1] <= ustack->uip_len) {
+    ustack->uip_len = (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1];
+#if UIP_CONF_IPV6
+    ustack->uip_len += 40; /* The length reported in the IPv6 header is the
+			      length of the payload that follows the
+			      header. However, uIP uses the uip_len variable
+			      for holding the size of the entire packet,
+			      including the IP header. For IPv4 this is not a
+			      problem as the length field in the IPv4 header
+			      contains the length of the entire packet. But
+			      for IPv6 we need to add the size of the IPv6
+			      header (40 bytes). */
+#endif /* UIP_CONF_IPV6 */
+  } else {
+    LOG_WARN("ip: packet shorter than reported in IP header: BUF(ustack)->len: %d ustack->uip_len:%d.",
+            (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1],  ustack->uip_len);
+    goto drop;
+  }
+
+#if !UIP_CONF_IPV6
+  /* Check the fragment flag. */
+  if((BUF(ustack)->ipoffset[0] & 0x3f) != 0 ||
+     BUF(ustack)->ipoffset[1] != 0) {
+#if UIP_REASSEMBLY
+    uip_len = uip_reass();
+    if(uip_len == 0) {
+      goto drop;
+    }
+#else /* UIP_REASSEMBLY */
+    ++ustack->stats.ip.drop;
+    ++ustack->stats.ip.fragerr;
+    LOG_WARN("ip: fragment dropped.");
+    goto drop;
+#endif /* UIP_REASSEMBLY */
+  }
+#endif /* UIP_CONF_IPV6 */
+
+  if(uip_ipaddr_cmp(ustack->uip_hostaddr, all_zeroes_addr)) {
+    /* If we are configured to use ping IP address configuration and
+       hasn't been assigned an IP address yet, we accept all ICMP
+       packets. */
+#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
+    if(BUF(ustack)->proto == UIP_PROTO_ICMP) {
+      LOG_WARN("ip: possible ping config packet received.");
+      goto icmp_input;
+    } else {
+      LOG_WARN("ip: packet dropped since no address assigned.");
+      goto drop;
+    }
+#endif /* UIP_PINGADDRCONF */
+
+  } else {
+    /* If IP broadcast support is configured, we check for a broadcast
+       UDP packet, which may be destined to us. */
+#if UIP_BROADCAST
+    DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum());
+    if(BUF(ustack)->proto == UIP_PROTO_UDP &&
+       uip_ipaddr_cmp(BUF(ustack)->destipaddr, all_ones_addr)
+       /*&&
+	 uip_ipchksum() == 0xffff*/) {
+      goto udp_input;
+    }
+#endif /* UIP_BROADCAST */
+    
+    /* Check if the packet is destined for our IP address. */
+#if !UIP_CONF_IPV6
+    if(!uip_ipaddr_cmp(BUF(ustack)->destipaddr, ustack->uip_hostaddr)) {
+      ++ustack->stats.ip.drop;
+      goto drop;
+    }
+#else /* UIP_CONF_IPV6 */
+    /* For IPv6, packet reception is a little trickier as we need to
+       make sure that we listen to certain multicast addresses (all
+       hosts multicast address, and the solicited-node multicast
+       address) as well. However, we will cheat here and accept all
+       multicast packets that are sent to the ff02::/16 addresses. */
+    if(!uip_ipaddr_cmp(BUF(ustack)->destipaddr, ustack->uip_hostaddr) &&
+       BUF(ustack)->destipaddr[0] != HTONS(0xff02)) {
+      ++ustack->stats.ip.drop;
+      goto drop;
+    }
+#endif /* UIP_CONF_IPV6 */
+  }
+
+#if !UIP_CONF_IPV6
+  if(uip_ipchksum(ustack) != 0xffff) { /* Compute and check the IP header
+				    checksum. */
+    ++ustack->stats.ip.drop;
+    ++ustack->stats.ip.chkerr;
+    LOG_ERR("ip: bad checksum.");
+    goto drop;
+  }
+#endif /* UIP_CONF_IPV6 */
+
+  if(BUF(ustack)->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
+				       proceed with TCP input
+				       processing. */
+    goto tcp_input;
+  }
+
+#if UIP_UDP
+  if(BUF(ustack)->proto == UIP_PROTO_UDP) {
+    goto udp_input;
+  }
+#endif /* UIP_UDP */
+
+#if !UIP_CONF_IPV6
+  /* ICMPv4 processing code follows. */
+  if(BUF(ustack)->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
+					here. */
+    ++ustack->stats.ip.drop;
+    ++ustack->stats.ip.protoerr;
+    LOG_ERR("ip: neither tcp nor icmp.");
+    goto drop;
+  }
+
+#if UIP_PINGADDRCONF
+ icmp_input:
+#endif /* UIP_PINGADDRCONF */
+  ++ustack->stats.icmp.recv;
+
+  /* ICMP echo (i.e., ping) processing. This is simple, we only change
+     the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
+     checksum before we return the packet. */
+  if(ICMPBUF(ustack)->type != ICMP_ECHO) {
+    ++ustack->stats.icmp.drop;
+    ++ustack->stats.icmp.typeerr;
+    LOG_ERR("icmp: not icmp echo.");
+    goto drop;
+  }
+
+  /* If we are configured to use ping IP address assignment, we use
+     the destination IP address of this ping packet and assign it to
+     ourself. */
+#if UIP_PINGADDRCONF
+  if((ustack->uip_hostaddr[0] | ustack->uip_hostaddr[1]) == 0) {
+    ustack->uip_hostaddr[0] = BUF(ustack)->destipaddr[0];
+    ustack->uip_hostaddr[1] = BUF(ustack)->destipaddr[1];
+  }
+#endif /* UIP_PINGADDRCONF */
+
+  ICMPBUF(ustack)->type = ICMP_ECHO_REPLY;
+
+  if(ICMPBUF(ustack)->icmpchksum >= htons(0xffff - (ICMP_ECHO << 8))) {
+    ICMPBUF(ustack)->icmpchksum += htons(ICMP_ECHO << 8) + 1;
+  } else {
+    ICMPBUF(ustack)->icmpchksum += htons(ICMP_ECHO << 8);
+  }
+
+  /* Swap IP addresses. */
+  uip_ipaddr_copy(BUF(ustack)->destipaddr, BUF(ustack)->srcipaddr);
+  uip_ipaddr_copy(BUF(ustack)->srcipaddr, ustack->uip_hostaddr);
+
+  ++ustack->stats.icmp.sent;
+  goto send;
+
+  /* End of IPv4 input header processing code. */
+#else /* !UIP_CONF_IPV6 */
+
+  /* This is IPv6 ICMPv6 processing code. */
+  DEBUG_PRINTF("icmp6_input: length %d\n", uip_len);
+
+  if(BUF(ustack)->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from
+					 here. */
+    ++uip_stat.ip.drop;
+    ++uip_stat.ip.protoerr;
+    LOG_ERR("ip: neither tcp nor icmp6.");
+    goto drop;
+  }
+
+  ++uip_stat.icmp.recv;
+
+  /* If we get a neighbor solicitation for our address we should send
+     a neighbor advertisement message back. */
+  if(ICMPBUF(ustack)->type == ICMP6_NEIGHBOR_SOLICITATION) {
+    if(uip_ipaddr_cmp(ICMPBUF(ustack)->icmp6data, ustack->uip_hostaddr)) {
+
+      if(ICMPBUF(ustack)->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) {
+	/* Save the sender's address in our neighbor list. */
+
+/* FIXME !!!! */
+//	uip_neighbor_add(ICMPBUF(ustack)->srcipaddr, &(ICMPBUF(ustack)->options[2]));
+      }
+      
+      /* We should now send a neighbor advertisement back to where the
+	 neighbor solicication came from. */
+      ICMPBUF(ustack)->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
+      ICMPBUF(ustack)->flags = ICMP6_FLAG_S; /* Solicited flag. */
+      
+      ICMPBUF(ustack)->reserved1 = ICMPBUF(ustack)->reserved2 = ICMPBUF(ustack)->reserved3 = 0;
+      
+      uip_ipaddr_copy(ICMPBUF(ustack)->destipaddr, ICMPBUF(ustack)->srcipaddr);
+      uip_ipaddr_copy(ICMPBUF(ustack)->srcipaddr, ustack->uip_hostaddr);
+      ICMPBUF(ustack)->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
+      ICMPBUF(ustack)->options[1] = 1;  /* Options length, 1 = 8 bytes. */
+      memcpy(&(ICMPBUF(ustack)->options[2]), &uip_ethaddr, sizeof(uip_ethaddr));
+      ICMPBUF(ustack)->icmpchksum = 0;
+      ICMPBUF(ustack)->icmpchksum = ~uip_icmp6chksum();
+      goto send;
+      
+    }
+    goto drop;
+  } else if(ICMPBUF(ustack)->type == ICMP6_ECHO) {
+    /* ICMP echo (i.e., ping) processing. This is simple, we only
+       change the ICMP type from ECHO to ECHO_REPLY and update the
+       ICMP checksum before we return the packet. */
+
+    ICMPBUF(ustack)->type = ICMP6_ECHO_REPLY;
+    
+    uip_ipaddr_copy(BUF(ustack)->destipaddr, BUF(ustack)->srcipaddr);
+    uip_ipaddr_copy(BUF(ustack)->srcipaddr, ustack->uip_hostaddr);
+    ICMPBUF(ustack)->icmpchksum = 0;
+    ICMPBUF(ustack)->icmpchksum = ~uip_icmp6chksum();
+    
+    ++ustack->stats.icmp.sent;
+    goto send;
+  } else {
+    DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF(ustack)->type);
+    ++ustack->stats.icmp.drop;
+    ++ustack->stats.icmp.typeerr;
+    LOG_ERR("icmp: unknown ICMP message.");
+    goto drop;
+  }
+
+  /* End of IPv6 ICMP processing. */
+  
+#endif /* !UIP_CONF_IPV6 */
+
+#if UIP_UDP
+  /* UDP input processing. */
+ udp_input:
+  /* UDP processing is really just a hack. We don't do anything to the
+     UDP/IP headers, but let the UDP application do all the hard
+     work. If the application sets uip_slen, it has a packet to
+     send. */
+#if UIP_UDP_CHECKSUMS
+  ustack->uip_len = ustack->uip_len - UIP_IPUDPH_LEN;
+  ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
+  if(UDPBUF(ustack)->udpchksum != 0 && uip_udpchksum(ustack) != 0xffff) {
+    ++ustack->stats.udp.drop;
+    ++ustack->stats.udp.chkerr;
+    LOG_ERR("udp: bad checksum.");
+    goto drop;
+  }
+#else /* UIP_UDP_CHECKSUMS */
+  uip_len = uip_len - UIP_IPUDPH_LEN;
+#endif /* UIP_UDP_CHECKSUMS */
+
+  /* Demultiplex this UDP packet between the UDP "connections". */
+  for(ustack->uip_udp_conn = &ustack->uip_udp_conns[0];
+      ustack->uip_udp_conn < &ustack->uip_udp_conns[UIP_UDP_CONNS];
+      ++ustack->uip_udp_conn) {
+    /* If the local UDP port is non-zero, the connection is considered
+       to be used. If so, the local port number is checked against the
+       destination port number in the received packet. If the two port
+       numbers match, the remote port number is checked if the
+       connection is bound to a remote port. Finally, if the
+       connection is bound to a remote IP address, the source IP
+       address of the packet is checked. */
+
+/* BWL */
+    LOG_INFO("Looking for UDP source:%d->%d dest:%d->%d", UDPBUF(ustack)->destport, ustack->uip_udp_conn->lport, UDPBUF(ustack)->srcport, ustack->uip_udp_conn->rport);
+
+    if(ustack->uip_udp_conn->lport != 0 &&
+       UDPBUF(ustack)->destport == ustack->uip_udp_conn->lport &&
+       (ustack->uip_udp_conn->rport == 0 ||
+        UDPBUF(ustack)->srcport == ustack->uip_udp_conn->rport) &&
+       (uip_ipaddr_cmp(ustack->uip_udp_conn->ripaddr, all_zeroes_addr) ||
+	uip_ipaddr_cmp(ustack->uip_udp_conn->ripaddr, all_ones_addr) ||
+	uip_ipaddr_cmp(BUF(ustack)->srcipaddr, ustack->uip_udp_conn->ripaddr))) {
+      goto udp_found;
+    }
+  }
+  LOG_ERR("udp: no matching connection found");
+  goto drop;
+  
+ udp_found:
+  ustack->uip_conn = NULL;
+  ustack->uip_flags = UIP_NEWDATA;
+  ustack->uip_sappdata = ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
+  ustack->uip_slen = 0;
+  UIP_UDP_APPCALL();
+ udp_send:
+  if(ustack->uip_slen == 0) {
+    goto drop;
+  }
+
+  ustack->uip_len = ustack->uip_slen + UIP_IPUDPH_LEN;
+#if UIP_CONF_IPV6
+  /* For IPv6, the IP length field does not include the IPv6 IP header
+     length. */
+  BUF(ustack)->len[0] = ((ustack->uip_len - UIP_IPH_LEN) >> 8);
+  BUF(ustack)->len[1] = ((ustack->uip_len - UIP_IPH_LEN) & 0xff);
+#else /* UIP_CONF_IPV6 */
+  BUF(ustack)->len[0] = (ustack->uip_len >> 8);
+  BUF(ustack)->len[1] = (ustack->uip_len & 0xff);
+#endif /* UIP_CONF_IPV6 */
+
+
+  BUF(ustack)->ttl = ustack->uip_udp_conn->ttl;
+  BUF(ustack)->proto = UIP_PROTO_UDP;
+
+  UDPBUF(ustack)->udplen = htons(ustack->uip_slen + UIP_UDPH_LEN);
+LOG_INFO("Sending udp lenth: %d (raw: %d)\n", ntohs(UDPBUF(ustack)->udplen), UDPBUF(ustack)->udplen);  
+
+  UDPBUF(ustack)->udpchksum = 0;
+
+  BUF(ustack)->srcport  = ustack->uip_udp_conn->lport;
+  BUF(ustack)->destport = ustack->uip_udp_conn->rport;
+
+LOG_INFO("Sending src port: %d (raw: %d)\n", ntohs(BUF(ustack)->srcport), BUF(ustack)->srcport);  
+LOG_INFO("Sending dest port: %d (raw: %d)\n", ntohs(BUF(ustack)->destport), BUF(ustack)->destport);  
+
+  uip_ipaddr_copy(BUF(ustack)->srcipaddr, ustack->uip_hostaddr);
+  uip_ipaddr_copy(BUF(ustack)->destipaddr, ustack->uip_udp_conn->ripaddr);
+   
+  ustack->uip_appdata = &ustack->uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
+
+#if UIP_UDP_CHECKSUMS
+  /* Calculate UDP checksum. */
+  UDPBUF(ustack)->udpchksum = ~(uip_udpchksum(ustack));
+  if(UDPBUF(ustack)->udpchksum == 0) {
+    UDPBUF(ustack)->udpchksum = 0xffff;
+  }
+#endif /* UIP_UDP_CHECKSUMS */
+  
+  goto ip_send_nolen;
+#endif /* UIP_UDP */
+  
+  /* TCP input processing. */
+ tcp_input:
+  ++ustack->stats.tcp.recv;
+
+  /* Start of TCP input header processing code. */
+  
+  if(uip_tcpchksum(ustack) != 0xffff) {   /* Compute and check the TCP
+				       checksum. */
+    ++ustack->stats.tcp.drop;
+    ++ustack->stats.tcp.chkerr;
+    LOG_ERR("tcp: bad checksum.");
+    goto drop;
+  }
+  
+  
+  /* Demultiplex this segment. */
+  /* First check any active connections. */
+  for(uip_connr = &ustack->uip_conns[0]; 
+      uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
+      ++uip_connr) {
+    if(uip_connr->tcpstateflags != UIP_CLOSED &&
+       BUF(ustack)->destport == uip_connr->lport &&
+       BUF(ustack)->srcport == uip_connr->rport &&
+       uip_ipaddr_cmp(BUF(ustack)->srcipaddr, uip_connr->ripaddr)) {
+      goto found;
+    }
+  }
+
+  /* If we didn't find and active connection that expected the packet,
+     either this packet is an old duplicate, or this is a SYN packet
+     destined for a connection in LISTEN. If the SYN flag isn't set,
+     it is an old packet and we send a RST. */
+  if((BUF(ustack)->flags & TCP_CTL) != TCP_SYN) {
+    goto reset;
+  }
+  
+  tmp16 = BUF(ustack)->destport;
+  /* Next, check listening connections. */
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(tmp16 == ustack->uip_listenports[c])
+      goto found_listen;
+  }
+  
+  /* No matching connection found, so we send a RST packet. */
+  ++ustack->stats.tcp.synrst;
+ reset:
+
+  /* We do not send resets in response to resets. */
+  if(BUF(ustack)->flags & TCP_RST) {
+    goto drop;
+  }
+
+  ++ustack->stats.tcp.rst;
+  
+  BUF(ustack)->flags = TCP_RST | TCP_ACK;
+  ustack->uip_len = UIP_IPTCPH_LEN;
+  BUF(ustack)->tcpoffset = 5 << 4;
+
+  /* Flip the seqno and ackno fields in the TCP header. */
+  c = BUF(ustack)->seqno[3];
+  BUF(ustack)->seqno[3] = BUF(ustack)->ackno[3];
+  BUF(ustack)->ackno[3] = c;
+  
+  c = BUF(ustack)->seqno[2];
+  BUF(ustack)->seqno[2] = BUF(ustack)->ackno[2];
+  BUF(ustack)->ackno[2] = c;
+  
+  c = BUF(ustack)->seqno[1];
+  BUF(ustack)->seqno[1] = BUF(ustack)->ackno[1];
+  BUF(ustack)->ackno[1] = c;
+  
+  c = BUF(ustack)->seqno[0];
+  BUF(ustack)->seqno[0] = BUF(ustack)->ackno[0];
+  BUF(ustack)->ackno[0] = c;
+
+  /* We also have to increase the sequence number we are
+     acknowledging. If the least significant byte overflowed, we need
+     to propagate the carry to the other bytes as well. */
+  if(++BUF(ustack)->ackno[3] == 0) {
+    if(++BUF(ustack)->ackno[2] == 0) {
+      if(++BUF(ustack)->ackno[1] == 0) {
+	++BUF(ustack)->ackno[0];
+      }
+    }
+  }
+ 
+  /* Swap port numbers. */
+  tmp16 = BUF(ustack)->srcport;
+  BUF(ustack)->srcport = BUF(ustack)->destport;
+  BUF(ustack)->destport = tmp16;
+  
+  /* Swap IP addresses. */
+  uip_ipaddr_copy(BUF(ustack)->destipaddr, BUF(ustack)->srcipaddr);
+  uip_ipaddr_copy(BUF(ustack)->srcipaddr, ustack->uip_hostaddr);
+  
+  /* And send out the RST packet! */
+  goto tcp_send_noconn;
+
+  /* This label will be jumped to if we matched the incoming packet
+     with a connection in LISTEN. In that case, we should create a new
+     connection and send a SYNACK in return. */
+ found_listen:
+  /* First we check if there are any connections avaliable. Unused
+     connections are kept in the same table as used connections, but
+     unused ones have the tcpstate set to CLOSED. Also, connections in
+     TIME_WAIT are kept track of and we'll use the oldest one if no
+     CLOSED connections are found. Thanks to Eddie C. Dost for a very
+     nice algorithm for the TIME_WAIT search. */
+  uip_connr = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    if(ustack->uip_conns[c].tcpstateflags == UIP_CLOSED) {
+      uip_connr = &ustack->uip_conns[c];
+      break;
+    }
+    if(ustack->uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
+      if(uip_connr == 0 ||
+	 ustack->uip_conns[c].timer > uip_connr->timer) {
+	uip_connr = &ustack->uip_conns[c];
+      }
+    }
+  }
+
+  if(uip_connr == 0) {
+    /* All connections are used already, we drop packet and hope that
+       the remote end will retransmit the packet at a time when we
+       have more spare connections. */
+    ++ustack->stats.tcp.syndrop;
+    LOG_WARN("tcp: found no unused connections.");
+    goto drop;
+  }
+  ustack->uip_conn = uip_connr;
+  
+  /* Fill in the necessary fields for the new connection. */
+  uip_connr->rto = uip_connr->timer = UIP_RTO;
+  uip_connr->sa = 0;
+  uip_connr->sv = 4;
+  uip_connr->nrtx = 0;
+  uip_connr->lport = BUF(ustack)->destport;
+  uip_connr->rport = BUF(ustack)->srcport;
+  uip_ipaddr_copy(uip_connr->ripaddr, BUF(ustack)->srcipaddr);
+  uip_connr->tcpstateflags = UIP_SYN_RCVD;
+
+  uip_connr->snd_nxt[0] = ustack->iss[0];
+  uip_connr->snd_nxt[1] = ustack->iss[1];
+  uip_connr->snd_nxt[2] = ustack->iss[2];
+  uip_connr->snd_nxt[3] = ustack->iss[3];
+  uip_connr->len = 1;
+
+  /* rcv_nxt should be the seqno from the incoming packet + 1. */
+  uip_connr->rcv_nxt[3] = BUF(ustack)->seqno[3];
+  uip_connr->rcv_nxt[2] = BUF(ustack)->seqno[2];
+  uip_connr->rcv_nxt[1] = BUF(ustack)->seqno[1];
+  uip_connr->rcv_nxt[0] = BUF(ustack)->seqno[0];
+  uip_add_rcv_nxt(ustack, 1);
+
+  /* Parse the TCP MSS option, if present. */
+  if((BUF(ustack)->tcpoffset & 0xf0) > 0x50) {
+    for(c = 0; c < ((BUF(ustack)->tcpoffset >> 4) - 5) << 2 ;) {
+      ustack->opt = ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
+      if(ustack->opt == TCP_OPT_END) {
+	/* End of options. */
+	break;
+      } else if(ustack->opt == TCP_OPT_NOOP) {
+	++c;
+	/* NOP option. */
+      } else if(ustack->opt == TCP_OPT_MSS &&
+		ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
+	/* An MSS option with the right option length. */
+	tmp16 = ((u16_t)ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+	  (u16_t)ustack->uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
+	uip_connr->initialmss = uip_connr->mss =
+	  tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+	
+	/* And we are done processing options. */
+	break;
+      } else {
+	/* All other options have a length field, so that we easily
+	   can skip past them. */
+	if(ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
+	  /* If the length field is zero, the options are malformed
+	     and we don't process them further. */
+	  break;
+	}
+	c += ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
+      }
+    }
+  }
+  
+  /* Our response will be a SYNACK. */
+#if UIP_ACTIVE_OPEN
+ tcp_send_synack:
+  BUF(ustack)->flags = TCP_ACK;
+  
+ tcp_send_syn:
+  BUF(ustack)->flags |= TCP_SYN;
+#else /* UIP_ACTIVE_OPEN */
+ tcp_send_synack:
+  BUF(ustack)->flags = TCP_SYN | TCP_ACK;
+#endif /* UIP_ACTIVE_OPEN */
+  
+  /* We send out the TCP Maximum Segment Size option with our
+     SYNACK. */
+  BUF(ustack)->optdata[0] = TCP_OPT_MSS;
+  BUF(ustack)->optdata[1] = TCP_OPT_MSS_LEN;
+  BUF(ustack)->optdata[2] = (UIP_TCP_MSS) / 256;
+  BUF(ustack)->optdata[3] = (UIP_TCP_MSS) & 255;
+  ustack->uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
+  BUF(ustack)->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
+  goto tcp_send;
+
+  /* This label will be jumped to if we found an active connection. */
+ found:
+  ustack->uip_conn = uip_connr;
+  ustack->uip_flags = 0;
+  /* We do a very naive form of TCP reset processing; we just accept
+     any RST and kill our connection. We should in fact check if the
+     sequence number of this reset is wihtin our advertised window
+     before we accept the reset. */
+  if(BUF(ustack)->flags & TCP_RST) {
+    uip_connr->tcpstateflags = UIP_CLOSED;
+    LOG_ERR("tcp: got reset, aborting connection.");
+    ustack->uip_flags = UIP_ABORT;
+    UIP_APPCALL();
+    goto drop;
+  }
+  /* Calculated the length of the data, if the application has sent
+     any data to us. */
+  c = (BUF(ustack)->tcpoffset >> 4) << 2;
+  /* uip_len will contain the length of the actual TCP data. This is
+     calculated by subtracing the length of the TCP header (in
+     c) and the length of the IP header (20 bytes). */
+  ustack->uip_len = ustack->uip_len - c - UIP_IPH_LEN;
+
+  /* First, check if the sequence number of the incoming packet is
+     what we're expecting next. If not, we send out an ACK with the
+     correct numbers in. */
+  if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) &&
+       ((BUF(ustack)->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
+    if((ustack->uip_len > 0 || ((BUF(ustack)->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
+       (BUF(ustack)->seqno[0] != uip_connr->rcv_nxt[0] ||
+	BUF(ustack)->seqno[1] != uip_connr->rcv_nxt[1] ||
+	BUF(ustack)->seqno[2] != uip_connr->rcv_nxt[2] ||
+	BUF(ustack)->seqno[3] != uip_connr->rcv_nxt[3])) {
+      goto tcp_send_ack;
+    }
+  }
+
+  {
+    u8_t uip_acc32[4];
+
+  /* Next, check if the incoming segment acknowledges any outstanding
+     data. If so, we update the sequence number, reset the length of
+     the outstanding data, calculate RTT estimations, and reset the
+     retransmission timer. */
+  if((BUF(ustack)->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
+    uip_add32(uip_connr->snd_nxt, uip_connr->len, uip_acc32);
+
+    if(BUF(ustack)->ackno[0] == uip_acc32[0] &&
+       BUF(ustack)->ackno[1] == uip_acc32[1] &&
+       BUF(ustack)->ackno[2] == uip_acc32[2] &&
+       BUF(ustack)->ackno[3] == uip_acc32[3]) {
+      /* Update sequence number. */
+      uip_connr->snd_nxt[0] = uip_acc32[0];
+      uip_connr->snd_nxt[1] = uip_acc32[1];
+      uip_connr->snd_nxt[2] = uip_acc32[2];
+      uip_connr->snd_nxt[3] = uip_acc32[3];
+	
+
+      /* Do RTT estimation, unless we have done retransmissions. */
+      if(uip_connr->nrtx == 0) {
+	signed char m;
+	m = uip_connr->rto - uip_connr->timer;
+	/* This is taken directly from VJs original code in his paper */
+	m = m - (uip_connr->sa >> 3);
+	uip_connr->sa += m;
+	if(m < 0) {
+	  m = -m;
+	}
+	m = m - (uip_connr->sv >> 2);
+	uip_connr->sv += m;
+	uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
+
+      }
+      /* Set the acknowledged flag. */
+      ustack->uip_flags = UIP_ACKDATA;
+      /* Reset the retransmission timer. */
+      uip_connr->timer = uip_connr->rto;
+
+      /* Reset length of outstanding data. */
+      uip_connr->len = 0;
+    }
+    
+  }
+
+  }
+
+  /* Do different things depending on in what state the connection is. */
+  switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
+    /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
+	implemented, since we force the application to close when the
+	peer sends a FIN (hence the application goes directly from
+	ESTABLISHED to LAST_ACK). */
+  case UIP_SYN_RCVD:
+    /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
+       we are waiting for an ACK that acknowledges the data we sent
+       out the last time. Therefore, we want to have the UIP_ACKDATA
+       flag set. If so, we enter the ESTABLISHED state. */
+    if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_ESTABLISHED;
+      ustack->uip_flags = UIP_CONNECTED;
+      uip_connr->len = 0;
+      if(ustack->uip_len > 0) {
+        ustack->uip_flags |= UIP_NEWDATA;
+        uip_add_rcv_nxt(ustack, ustack->uip_len);
+      }
+      ustack->uip_slen = 0;
+      UIP_APPCALL();
+      goto appsend;
+    }
+    goto drop;
+#if UIP_ACTIVE_OPEN
+  case UIP_SYN_SENT:
+    /* In SYN_SENT, we wait for a SYNACK that is sent in response to
+       our SYN. The rcv_nxt is set to sequence number in the SYNACK
+       plus one, and we send an ACK. We move into the ESTABLISHED
+       state. */
+    if((ustack->uip_flags & UIP_ACKDATA) &&
+       (BUF(ustack)->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
+
+      /* Parse the TCP MSS option, if present. */
+      if((BUF(ustack)->tcpoffset & 0xf0) > 0x50) {
+	for(c = 0; c < ((BUF(ustack)->tcpoffset >> 4) - 5) << 2 ;) {
+	  ustack->opt = ustack->uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
+	  if(ustack->opt == TCP_OPT_END) {
+	    /* End of options. */
+	    break;
+	  } else if(ustack->opt == TCP_OPT_NOOP) {
+	    ++c;
+	    /* NOP option. */
+	  } else if(ustack->opt == TCP_OPT_MSS &&
+		    ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
+	    /* An MSS option with the right option length. */
+	    tmp16 = (ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+	      ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
+	    uip_connr->initialmss =
+	      uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+
+	    /* And we are done processing options. */
+	    break;
+	  } else {
+	    /* All other options have a length field, so that we easily
+	       can skip past them. */
+	    if(ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
+	      /* If the length field is zero, the options are malformed
+		 and we don't process them further. */
+	      break;
+	    }
+	    c += ustack->uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
+	  }
+	}
+      }
+      uip_connr->tcpstateflags = UIP_ESTABLISHED;
+      uip_connr->rcv_nxt[0] = BUF(ustack)->seqno[0];
+      uip_connr->rcv_nxt[1] = BUF(ustack)->seqno[1];
+      uip_connr->rcv_nxt[2] = BUF(ustack)->seqno[2];
+      uip_connr->rcv_nxt[3] = BUF(ustack)->seqno[3];
+      uip_add_rcv_nxt(ustack, 1);
+      ustack->uip_flags = UIP_CONNECTED | UIP_NEWDATA;
+      uip_connr->len = 0;
+      ustack->uip_len = 0;
+      ustack->uip_slen = 0;
+      UIP_APPCALL();
+      goto appsend;
+    }
+    /* Inform the application that the connection failed */
+    ustack->uip_flags = UIP_ABORT;
+    UIP_APPCALL();
+    /* The connection is closed after we send the RST */
+    ustack->uip_conn->tcpstateflags = UIP_CLOSED;
+    goto reset;
+#endif /* UIP_ACTIVE_OPEN */
+    
+  case UIP_ESTABLISHED:
+    /* In the ESTABLISHED state, we call upon the application to feed
+    data into the uip_buf. If the UIP_ACKDATA flag is set, the
+    application should put new data into the buffer, otherwise we are
+    retransmitting an old segment, and the application should put that
+    data into the buffer.
+
+    If the incoming packet is a FIN, we should close the connection on
+    this side as well, and we send out a FIN and enter the LAST_ACK
+    state. We require that there is no outstanding data; otherwise the
+    sequence numbers will be screwed up. */
+
+    if(BUF(ustack)->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+      if(uip_outstanding(uip_connr)) {
+	goto drop;
+      }
+      uip_add_rcv_nxt(ustack, 1 + ustack->uip_len);
+      ustack->uip_flags |= UIP_CLOSE;
+      if(ustack->uip_len > 0) {
+	ustack->uip_flags |= UIP_NEWDATA;
+      }
+      UIP_APPCALL();
+      uip_connr->len = 1;
+      uip_connr->tcpstateflags = UIP_LAST_ACK;
+      uip_connr->nrtx = 0;
+    tcp_send_finack:
+      BUF(ustack)->flags = TCP_FIN | TCP_ACK;
+      goto tcp_send_nodata;
+    }
+
+    /* Check the URG flag. If this is set, the segment carries urgent
+       data that we must pass to the application. */
+    if((BUF(ustack)->flags & TCP_URG) != 0) {
+#if UIP_URGDATA > 0
+      uip_urglen = (BUF(ustack)->urgp[0] << 8) | BUF(ustack)->urgp[1];
+      if(uip_urglen > uip_len) {
+	/* There is more urgent data in the next segment to come. */
+	uip_urglen = uip_len;
+      }
+      uip_add_rcv_nxt(uip_urglen);
+      uip_len -= uip_urglen;
+      uip_urgdata = uip_appdata;
+      uip_appdata += uip_urglen;
+    } else {
+      uip_urglen = 0;
+#else /* UIP_URGDATA > 0 */
+      ustack->uip_appdata = ((char *)ustack->uip_appdata) + ((BUF(ustack)->urgp[0] << 8) | BUF(ustack)->urgp[1]);
+      ustack->uip_len -= (BUF(ustack)->urgp[0] << 8) | BUF(ustack)->urgp[1];
+#endif /* UIP_URGDATA > 0 */
+    }
+
+    /* If uip_len > 0 we have TCP data in the packet, and we flag this
+       by setting the UIP_NEWDATA flag and update the sequence number
+       we acknowledge. If the application has stopped the dataflow
+       using uip_stop(), we must not accept any data packets from the
+       remote host. */
+    if(ustack->uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+      ustack->uip_flags |= UIP_NEWDATA;
+      uip_add_rcv_nxt(ustack, ustack->uip_len);
+    }
+
+    /* Check if the available buffer space advertised by the other end
+       is smaller than the initial MSS for this connection. If so, we
+       set the current MSS to the window size to ensure that the
+       application does not send more data than the other end can
+       handle.
+
+       If the remote host advertises a zero window, we set the MSS to
+       the initial MSS so that the application will send an entire MSS
+       of data. This data will not be acknowledged by the receiver,
+       and the application will retransmit it. This is called the
+       "persistent timer" and uses the retransmission mechanim.
+    */
+    tmp16 = ((u16_t)BUF(ustack)->wnd[0] << 8) + (u16_t)BUF(ustack)->wnd[1];
+    if(tmp16 > uip_connr->initialmss ||
+       tmp16 == 0) {
+      tmp16 = uip_connr->initialmss;
+    }
+    uip_connr->mss = tmp16;
+
+    /* If this packet constitutes an ACK for outstanding data (flagged
+       by the UIP_ACKDATA flag, we should call the application since it
+       might want to send more data. If the incoming packet had data
+       from the peer (as flagged by the UIP_NEWDATA flag), the
+       application must also be notified.
+
+       When the application is called, the global variable uip_len
+       contains the length of the incoming data. The application can
+       access the incoming data through the global pointer
+       uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
+       bytes into the uip_buf array.
+
+       If the application wishes to send any data, this data should be
+       put into the uip_appdata and the length of the data should be
+       put into uip_len. If the application don't have any data to
+       send, uip_len must be set to 0. */
+    if(ustack->uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
+      ustack->uip_slen = 0;
+      UIP_APPCALL();
+
+    appsend:
+      
+      if(ustack->uip_flags & UIP_ABORT) {
+	ustack->uip_slen = 0;
+	uip_connr->tcpstateflags = UIP_CLOSED;
+	BUF(ustack)->flags = TCP_RST | TCP_ACK;
+	goto tcp_send_nodata;
+      }
+
+      if(ustack->uip_flags & UIP_CLOSE) {
+	ustack->uip_slen = 0;
+	uip_connr->len = 1;
+	uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
+	uip_connr->nrtx = 0;
+	BUF(ustack)->flags = TCP_FIN | TCP_ACK;
+	goto tcp_send_nodata;
+      }
+
+      /* If uip_slen > 0, the application has data to be sent. */
+      if(ustack->uip_slen > 0) {
+
+	/* If the connection has acknowledged data, the contents of
+	   the ->len variable should be discarded. */
+	if((ustack->uip_flags & UIP_ACKDATA) != 0) {
+	  uip_connr->len = 0;
+	}
+
+	/* If the ->len variable is non-zero the connection has
+	   already data in transit and cannot send anymore right
+	   now. */
+	if(uip_connr->len == 0) {
+
+	  /* The application cannot send more than what is allowed by
+	     the mss (the minumum of the MSS and the available
+	     window). */
+	  if(ustack->uip_slen > uip_connr->mss) {
+	    ustack->uip_slen = uip_connr->mss;
+	  }
+
+	  /* Remember how much data we send out now so that we know
+	     when everything has been acknowledged. */
+	  uip_connr->len = ustack->uip_slen;
+	} else {
+
+	  /* If the application already had unacknowledged data, we
+	     make sure that the application does not send (i.e.,
+	     retransmit) out more than it previously sent out. */
+	  ustack->uip_slen = uip_connr->len;
+	}
+      }
+      uip_connr->nrtx = 0;
+    apprexmit:
+      ustack->uip_appdata = ustack->uip_sappdata;
+      
+      /* If the application has data to be sent, or if the incoming
+         packet had new data in it, we must send out a packet. */
+      if(ustack->uip_slen > 0 && uip_connr->len > 0) {
+	/* Add the length of the IP and TCP headers. */
+	ustack->uip_len = uip_connr->len + UIP_TCPIP_HLEN;
+	/* We always set the ACK flag in response packets. */
+	BUF(ustack)->flags = TCP_ACK | TCP_PSH;
+	/* Send the packet. */
+	goto tcp_send_noopts;
+      }
+      /* If there is no data to send, just send out a pure ACK if
+	 there is newdata. */
+      if(ustack->uip_flags & UIP_NEWDATA) {
+	ustack->uip_len = UIP_TCPIP_HLEN;
+	BUF(ustack)->flags = TCP_ACK;
+	goto tcp_send_noopts;
+      }
+    }
+    goto drop;
+  case UIP_LAST_ACK:
+    /* We can close this connection if the peer has acknowledged our
+       FIN. This is indicated by the UIP_ACKDATA flag. */
+    if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_CLOSED;
+      ustack->uip_flags = UIP_CLOSE;
+      UIP_APPCALL();
+    }
+    break;
+    
+  case UIP_FIN_WAIT_1:
+    /* The application has closed the connection, but the remote host
+       hasn't closed its end yet. Thus we do nothing but wait for a
+       FIN from the other side. */
+    if(ustack->uip_len > 0) {
+      uip_add_rcv_nxt(ustack, ustack->uip_len);
+    }
+    if(BUF(ustack)->flags & TCP_FIN) {
+      if(ustack->uip_flags & UIP_ACKDATA) {
+	uip_connr->tcpstateflags = UIP_TIME_WAIT;
+	uip_connr->timer = 0;
+	uip_connr->len = 0;
+      } else {
+	uip_connr->tcpstateflags = UIP_CLOSING;
+      }
+      uip_add_rcv_nxt(ustack, 1);
+      ustack->uip_flags = UIP_CLOSE;
+      UIP_APPCALL();
+      goto tcp_send_ack;
+    } else if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
+      uip_connr->len = 0;
+      goto drop;
+    }
+    if(ustack->uip_len > 0) {
+      goto tcp_send_ack;
+    }
+    goto drop;
+      
+  case UIP_FIN_WAIT_2:
+    if(ustack->uip_len > 0) {
+      uip_add_rcv_nxt(ustack, ustack->uip_len);
+    }
+    if(BUF(ustack)->flags & TCP_FIN) {
+      uip_connr->tcpstateflags = UIP_TIME_WAIT;
+      uip_connr->timer = 0;
+      uip_add_rcv_nxt(ustack, 1);
+      ustack->uip_flags = UIP_CLOSE;
+      UIP_APPCALL();
+      goto tcp_send_ack;
+    }
+    if(ustack->uip_len > 0) {
+      goto tcp_send_ack;
+    }
+    goto drop;
+
+  case UIP_TIME_WAIT:
+    goto tcp_send_ack;
+    
+  case UIP_CLOSING:
+    if(ustack->uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = UIP_TIME_WAIT;
+      uip_connr->timer = 0;
+    }
+  }
+  goto drop;
+  
+
+  /* We jump here when we are ready to send the packet, and just want
+     to set the appropriate TCP sequence numbers in the TCP header. */
+ tcp_send_ack:
+  BUF(ustack)->flags = TCP_ACK;
+ tcp_send_nodata:
+  ustack->uip_len = UIP_IPTCPH_LEN;
+ tcp_send_noopts:
+  BUF(ustack)->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
+ tcp_send:
+  /* We're done with the input processing. We are now ready to send a
+     reply. Our job is to fill in all the fields of the TCP and IP
+     headers before calculating the checksum and finally send the
+     packet. */
+  BUF(ustack)->ackno[0] = uip_connr->rcv_nxt[0];
+  BUF(ustack)->ackno[1] = uip_connr->rcv_nxt[1];
+  BUF(ustack)->ackno[2] = uip_connr->rcv_nxt[2];
+  BUF(ustack)->ackno[3] = uip_connr->rcv_nxt[3];
+  
+  BUF(ustack)->seqno[0] = uip_connr->snd_nxt[0];
+  BUF(ustack)->seqno[1] = uip_connr->snd_nxt[1];
+  BUF(ustack)->seqno[2] = uip_connr->snd_nxt[2];
+  BUF(ustack)->seqno[3] = uip_connr->snd_nxt[3];
+
+  BUF(ustack)->proto = UIP_PROTO_TCP;
+  
+  BUF(ustack)->srcport  = uip_connr->lport;
+  BUF(ustack)->destport = uip_connr->rport;
+
+  uip_ipaddr_copy(BUF(ustack)->srcipaddr, ustack->uip_hostaddr);
+  uip_ipaddr_copy(BUF(ustack)->destipaddr, uip_connr->ripaddr);
+
+  if(uip_connr->tcpstateflags & UIP_STOPPED) {
+    /* If the connection has issued uip_stop(), we advertise a zero
+       window so that the remote host will stop sending data. */
+    BUF(ustack)->wnd[0] = BUF(ustack)->wnd[1] = 0;
+  } else {
+    BUF(ustack)->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
+    BUF(ustack)->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
+  }
+
+ tcp_send_noconn:
+  BUF(ustack)->ttl = UIP_TTL;
+#if UIP_CONF_IPV6
+  /* For IPv6, the IP length field does not include the IPv6 IP header
+     length. */
+  BUF(ustack)->len[0] = ((ustack->uip_len - UIP_IPH_LEN) >> 8);
+  BUF(ustack)->len[1] = ((ustack->uip_len - UIP_IPH_LEN) & 0xff);
+#else /* UIP_CONF_IPV6 */
+  BUF(ustack)->len[0] = (ustack->uip_len >> 8);
+  BUF(ustack)->len[1] = (ustack->uip_len & 0xff);
+#endif /* UIP_CONF_IPV6 */
+
+  BUF(ustack)->urgp[0] = BUF(ustack)->urgp[1] = 0;
+  
+  /* Calculate TCP checksum. */
+  BUF(ustack)->tcpchksum = 0;
+  BUF(ustack)->tcpchksum = ~(uip_tcpchksum(ustack));
+  
+ ip_send_nolen:
+
+#if UIP_CONF_IPV6
+  BUF(ustack)->vtc = 0x60;
+  BUF(ustack)->tcflow = 0x00;
+  BUF(ustack)->flow = 0x00;
+#else /* UIP_CONF_IPV6 */
+  BUF(ustack)->vhl = 0x45;
+  BUF(ustack)->tos = 0;
+  BUF(ustack)->ipoffset[0] = BUF(ustack)->ipoffset[1] = 0;
+  ++ustack->ipid;
+  BUF(ustack)->ipid[0] = ustack->ipid >> 8;
+  BUF(ustack)->ipid[1] = ustack->ipid & 0xff;
+  /* Calculate IP checksum. */
+  BUF(ustack)->ipchksum = 0;
+  BUF(ustack)->ipchksum = ~(uip_ipchksum(ustack));
+  DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum());
+#endif /* UIP_CONF_IPV6 */
+   
+  ++ustack->stats.tcp.sent;
+ send:
+  DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len,
+	       (BUF(ustack)->len[0] << 8) | BUF(ustack)->len[1]);
+  
+  ++ustack->stats.ip.sent;
+  /* Return and let the caller do the actual transmission. */
+  ustack->uip_flags = 0;
+  return;
+ drop:
+  ustack->uip_len = 0;
+  ustack->uip_flags = 0;
+  return;
+}
+#if 0
+/*---------------------------------------------------------------------------*/
+u16_t
+htons(u16_t val)
+{
+  return HTONS(val);
+}
+#endif
+/*---------------------------------------------------------------------------*/
+void
+uip_send(struct uip_stack *ustack, const void *data, int len)
+{
+  if(len > 0) {
+    ustack->uip_slen = len;
+    if(data != ustack->uip_sappdata) {
+      memcpy(ustack->uip_sappdata, (data), ustack->uip_slen);
+    }
+  }
+}
+
+u16_t
+uip_datalen(struct uip_stack *ustack)
+{
+	return ustack->uip_len;
+}
+/** @} */
+
+#define IPV6_LEN        16
+
+int get_ipv6_link_local_address(struct uip_stack *ustack,
+                                char *addr)
+{
+	memset(addr, 0, IPV6_LEN);
+
+	addr[0] = 0xfe;
+	addr[1] = 0x80;
+
+	addr[IPV6_LEN - 8] = ustack->uip_ethaddr.addr[0];
+	addr[IPV6_LEN - 7] = ustack->uip_ethaddr.addr[1];
+	addr[IPV6_LEN - 6] = ustack->uip_ethaddr.addr[2];
+	addr[IPV6_LEN - 5] = 0xff;
+	addr[IPV6_LEN - 4] = 0xfe;
+	addr[IPV6_LEN - 3] = ustack->uip_ethaddr.addr[3];
+	addr[IPV6_LEN - 2] = ustack->uip_ethaddr.addr[4];
+	addr[IPV6_LEN - 1] = ustack->uip_ethaddr.addr[5];
+
+	return 0;
+}
diff --git a/brcm_iscsi_uio/src/uip/uip_ipv6.h b/brcm_iscsi_uio/src/uip/uip_ipv6.h
new file mode 100644
index 0000000..06b2514
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uip_ipv6.h
@@ -0,0 +1,1539 @@
+
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \file
+ * Header file for the uIP TCP/IP stack.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The uIP TCP/IP stack header file contains definitions for a number
+ * of C macros that are used by uIP programs as well as internal uIP
+ * structures, TCP/IP header structures and function declarations.
+ *
+ */
+
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.h,v 1.40 2006/06/08 07:12:07 adam Exp $
+ *
+ */
+
+#ifndef __UIP_IPv6_H__
+#define __UIP_IPv6_H__
+
+#include <pthread.h>
+
+#include "uipopt.h"
+
+#include "debug.h"
+
+/*  Forware declaration */
+struct uip_stack;
+
+/**
+ * Repressentation of an IPv6 address.
+ *
+ */
+typedef u16_t uip_ip6addr_t[8];
+
+/*---------------------------------------------------------------------------*/
+/* First, the functions that should be called from the
+ * system. Initialization, the periodic timer and incoming packets are
+ * handled by the following three functions.
+ */
+
+/**
+ * \defgroup uipconffunc uIP configuration functions
+ * @{
+ *
+ * The uIP configuration functions are used for setting run-time
+ * parameters in uIP such as IP addresses.
+ */
+
+/**
+ * Set the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * Example:
+ \code
+
+ uip_ipaddr_t addr;
+
+ uip_ipaddr(&addr, 192,168,1,2);
+ uip_sethostaddr(&addr);
+ 
+ \endcode
+ * \param addr A pointer to an IP address of type uip_ipaddr_t;
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_sethostaddr(struct uip_stack *ustack, uip_ipaddr_t *addr);
+
+/**
+ * Set the default router's IP address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the default router.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setdraddr(struct uip_stack *ustack, uip_ipaddr_t *addr);
+
+/**
+ * Set the netmask.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the netmask.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setnetmask(struct uip_stack *ustack, uip_ipaddr_t *addr);
+
+/**
+ * Set the ethernet MAC address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the netmask.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac);
+
+/**
+ * Get the default router's IP address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the IP address of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr)
+
+/**
+ * Get the netmask.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the value of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask)
+
+/** @} */
+
+/**
+ * \defgroup uipinit uIP initialization functions
+ * @{
+ *
+ * The uIP initialization functions are used for booting uIP.
+ */
+
+/**
+ * uIP initialization function.
+ *
+ * This function should be called at boot up to initilize the uIP
+ * TCP/IP stack.
+ */
+void uip_init(struct uip_stack *ustack, uint8_t enable_ipv6);
+
+/**
+ * uIP initialization function.
+ *
+ * This function may be used at boot time to set the initial ip_id.
+ */
+void uip_setipid(u16_t id);
+
+/**
+ *
+ *
+ */
+#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED)
+
+#if UIP_UDP
+
+#if 0
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_periodic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
+                                uip_process(UIP_UDP_TIMER); } while (0)
+
+/**
+ * Periodic processing for a UDP connection identified by a pointer to
+ * its structure.
+ *
+ * Same as uip_udp_periodic() but takes a pointer to the actual
+ * uip_conn struct instead of an integer as its argument. This
+ * function can be used to force periodic processing of a specific
+ * connection.
+ *
+ * \param conn A pointer to the uip_udp_conn struct for the connection
+ * to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \
+                                         uip_process(UIP_UDP_TIMER); } while (0)
+
+#endif
+
+void uip_udp_periodic(struct uip_stack *ustack, int conn);
+#endif /* UIP_UDP */
+
+/**
+ * The uIP packet buffer.
+ *
+ * The uip_buf array is used to hold incoming and outgoing
+ * packets. The device driver should place incoming data into this
+ * buffer. When sending data, the device driver should read the link
+ * level headers and the TCP/IP headers from this buffer. The size of
+ * the link level headers is configured by the UIP_LLH_LEN define.
+ *
+ * \note The application data need not be placed in this buffer, so
+ * the device driver must read it from the place pointed to by the
+ * uip_appdata pointer as illustrated by the following example:
+ \code
+ void
+ devicedriver_send(void)
+ {
+    hwsend(&uip_buf[0], UIP_LLH_LEN);
+    if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+      hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
+    } else {
+      hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
+      hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
+    }
+ }
+ \endcode
+ */
+//extern u8_t uip_buf[UIP_BUFSIZE+2];
+
+/** @} */
+
+/*---------------------------------------------------------------------------*/
+/* Functions that are used by the uIP application program. Opening and
+ * closing connections, sending and receiving data, etc. is all
+ * handled by the functions below.
+*/
+/**
+ * \defgroup uipappfunc uIP application functions
+ * @{
+ *
+ * Functions used by an application running of top of uIP.
+ */
+
+/**
+ * Start listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_listen(HTONS(80));
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_listen(struct uip_stack *ustack, u16_t port);
+
+/**
+ * Stop listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_unlisten(HTONS(80));
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_unlisten(struct uip_stack *ustack, u16_t port);
+
+/**
+ * Connect to a remote host using TCP.
+ *
+ * This function is used to start a new connection to the specified
+ * port on the specied host. It allocates a new connection identifier,
+ * sets the connection to the SYN_SENT state and sets the
+ * retransmission timer to 0. This will cause a TCP SYN segment to be
+ * sent out the next time this connection is periodically processed,
+ * which usually is done within 0.5 seconds after the call to
+ * uip_connect().
+ *
+ * \note This function is avaliable only if support for active open
+ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
+ *
+ * \note Since this function requires the port number to be in network
+ * byte order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_ipaddr_t ipaddr;
+
+ uip_ipaddr(&ipaddr, 192,168,1,2);
+ uip_connect(&ipaddr, HTONS(80));
+ \endcode
+ *
+ * \param ripaddr The IP address of the remote hot.
+ *
+ * \param port A 16-bit port number in network byte order.
+ *
+ * \return A pointer to the uIP connection identifier for the new connection,
+ * or NULL if no connection could be allocated.
+ *
+ */
+struct uip_conn *uip_connect(struct uip_stack *ustack, 
+			     uip_ipaddr_t *ripaddr, u16_t port);
+
+
+
+/**
+ * \internal
+ *
+ * Check if a connection has outstanding (i.e., unacknowledged) data.
+ *
+ * \param conn A pointer to the uip_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_outstanding(conn) ((conn)->len)
+
+/**
+ * Send data on the current connection.
+ *
+ * This function is used to send out a single segment of TCP
+ * data. Only applications that have been invoked by uIP for event
+ * processing can send data.
+ *
+ * The amount of data that actually is sent out after a call to this
+ * funcion is determined by the maximum amount of data TCP allows. uIP
+ * will automatically crop the data so that only the appropriate
+ * amount of data is sent. The function uip_mss() can be used to query
+ * uIP for the amount of data that actually will be sent.
+ *
+ * \note This function does not guarantee that the sent data will
+ * arrive at the destination. If the data is lost in the network, the
+ * application will be invoked with the uip_rexmit() event being
+ * set. The application will then have to resend the data using this
+ * function.
+ *
+ * \param data A pointer to the data which is to be sent.
+ *
+ * \param len The maximum amount of data bytes to be sent.
+ *
+ * \hideinitializer
+ */
+void uip_send(struct uip_stack *ustack, const void *data, int len);
+
+/**
+ * The length of any incoming data that is currently avaliable (if avaliable)
+ * in the uip_appdata buffer.
+ *
+ * The test function uip_data() must first be used to check if there
+ * is any data available at all.
+ *
+ * \hideinitializer
+ */
+/*void uip_datalen(void);*/
+u16_t uip_datalen(struct uip_stack *ustack);
+
+/**
+ * The length of any out-of-band data (urgent data) that has arrived
+ * on the connection.
+ *
+ * \note The configuration parameter UIP_URGDATA must be set for this
+ * function to be enabled.
+ *
+ * \hideinitializer
+ */
+#define uip_urgdatalen()    uip_urglen
+
+/**
+ * Close the current connection.
+ *
+ * This function will close the current connection in a nice way.
+ *
+ * \hideinitializer
+ */
+#define uip_close()         (uip_flags = UIP_CLOSE)
+
+/**
+ * Abort the current connection.
+ *
+ * This function will abort (reset) the current connection, and is
+ * usually used when an error has occured that prevents using the
+ * uip_close() function.
+ *
+ * \hideinitializer
+ */
+#define uip_abort()         (uip_flags = UIP_ABORT)
+
+/**
+ * Tell the sending host to stop sending data.
+ *
+ * This function will close our receiver's window so that we stop
+ * receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_stop()          (uip_conn->tcpstateflags |= UIP_STOPPED)
+
+/**
+ * Find out if the current connection has been previously stopped with
+ * uip_stop().
+ *
+ * \hideinitializer
+ */
+#define uip_stopped(conn)   ((conn)->tcpstateflags & UIP_STOPPED)
+
+/**
+ * Restart the current connection, if is has previously been stopped
+ * with uip_stop().
+ *
+ * This function will open the receiver's window again so that we
+ * start receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_restart()         do { uip_flags |= UIP_NEWDATA; \
+                                   uip_conn->tcpstateflags &= ~UIP_STOPPED; \
+                              } while(0)
+
+
+/* uIP tests that can be made to determine in what state the current
+   connection is, and what the application function should do. */
+
+/**
+ * Is the current connection a UDP connection?
+ *
+ * This function checks whether the current connection is a UDP connection.
+ *
+ * \hideinitializer
+ *
+ */
+#define uip_udpconnection() (uip_conn == NULL)
+
+/** 
+ *  Function declarations for hte uip_flags 
+ */
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+int uip_newdata(struct uip_stack *ustack);
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data.
+ *
+ * \hideinitializer
+ */
+int uip_acked(struct uip_stack *ustack);
+
+/**
+ * Has the connection just been connected?
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+int uip_connected(struct uip_stack *ustack);
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+int uip_closed(struct uip_stack *ustack);
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+int uip_aborted(struct uip_stack *ustack);
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+int uip_timedout(struct uip_stack *ustack);
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+int uip_rexmit(struct uip_stack *ustack);
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */
+int uip_poll(struct uip_stack *ustack);
+
+/**
+ * Get the initial maxium segment size (MSS) of the current
+ * connection.
+ *
+ * \hideinitializer
+ */
+int uip_initialmss(struct uip_stack *ustack);
+
+/**
+ * Get the current maxium segment size that can be sent on the current
+ * connection.
+ *
+ * The current maxiumum segment size that can be sent on the
+ * connection is computed from the receiver's window and the MSS of
+ * the connection (which also is available by calling
+ * uip_initialmss()).
+ *
+ * \hideinitializer
+ */
+int uip_mss(struct uip_stack *ustack);
+
+/**
+ * Set up a new UDP connection.
+ *
+ * This function sets up a new UDP connection. The function will
+ * automatically allocate an unused local port for the new
+ * connection. However, another port can be chosen by using the
+ * uip_udp_bind() call, after the uip_udp_new() function has been
+ * called.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t addr;
+ struct uip_udp_conn *c;
+ 
+ uip_ipaddr(&addr, 192,168,2,1);
+ c = uip_udp_new(&addr, HTONS(12345));
+ if(c != NULL) {
+   uip_udp_bind(c, HTONS(12344));
+ }
+ \endcode
+ * \param ripaddr The IP address of the remote host.
+ *
+ * \param rport The remote port number in network byte order.
+ *
+ * \return The uip_udp_conn structure for the new connection or NULL
+ * if no connection could be allocated.
+ */
+struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack,
+				 uip_ipaddr_t *ripaddr, u16_t rport);
+
+/**
+ * Removed a UDP connection.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_remove(conn) (conn)->lport = 0
+
+/**
+ * Bind a UDP connection to a local port.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the
+ * connection.
+ *
+ * \param port The local port number, in network byte order.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_bind(conn, port) (conn)->lport = port
+
+/**
+ * Send a UDP datagram of length len on the current connection.
+ *
+ * This function can only be called in response to a UDP event (poll
+ * or newdata). The data must be present in the uip_buf buffer, at the
+ * place pointed to by the uip_appdata pointer.
+ *
+ * \param len The length of the data in the uip_buf buffer.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_send(len) uip_send((char *)uip_appdata, len)
+
+/** @} */
+
+/* uIP convenience and converting functions. */
+
+/**
+ * \defgroup uipconvfunc uIP conversion functions
+ * @{
+ *
+ * These functions can be used for converting between different data
+ * formats used by uIP.
+ */
+ 
+/**
+ * Construct an IP address from four bytes.
+ *
+ * This function constructs an IP address of the type that uIP handles
+ * internally from four bytes. The function is handy for specifying IP
+ * addresses to use with e.g. the uip_connect() function.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ struct uip_conn *c;
+ 
+ uip_ipaddr(&ipaddr, 192,168,1,2);
+ c = uip_connect(&ipaddr, HTONS(80));
+ \endcode
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the IP address.
+ *
+ * \param addr0 The first octet of the IP address.
+ * \param addr1 The second octet of the IP address.
+ * \param addr2 The third octet of the IP address.
+ * \param addr3 The forth octet of the IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
+                     ((u16_t *)(addr))[0] = const_htons(((addr0) << 8) | (addr1)); \
+                     ((u16_t *)(addr))[1] = const_htons(((addr2) << 8) | (addr3)); \
+                  } while(0)
+
+/**
+ * Construct an IPv6 address from eight 16-bit words.
+ *
+ * This function constructs an IPv6 address.
+ *
+ * \hideinitializer
+ */
+#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \
+                     ((u16_t *)(addr))[0] = HTONS((addr0)); \
+                     ((u16_t *)(addr))[1] = HTONS((addr1)); \
+                     ((u16_t *)(addr))[2] = HTONS((addr2)); \
+                     ((u16_t *)(addr))[3] = HTONS((addr3)); \
+                     ((u16_t *)(addr))[4] = HTONS((addr4)); \
+                     ((u16_t *)(addr))[5] = HTONS((addr5)); \
+                     ((u16_t *)(addr))[6] = HTONS((addr6)); \
+                     ((u16_t *)(addr))[7] = HTONS((addr7)); \
+                  } while(0)
+
+/**
+ * Copy an IP address to another IP address.
+ *
+ * Copies an IP address from one place to another.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr_copy(&ipaddr2, &ipaddr1);
+ \endcode
+ *
+ * \param dest The destination for the copy.
+ * \param src The source from where to copy.
+ *
+ * \hideinitializer
+ */
+#if !UIP_CONF_IPV6
+#define uip_ipaddr_copy(dest, src) do { \
+                     ((u16_t *)dest)[0] = ((u16_t *)src)[0]; \
+                     ((u16_t *)dest)[1] = ((u16_t *)src)[1]; \
+                  } while(0)
+#else /* !UIP_CONF_IPV6 */
+#define uip_ipaddr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t))
+#endif /* !UIP_CONF_IPV6 */
+
+/**
+ * Compare two IP addresses
+ *
+ * Compares two IP addresses.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ *
+ * \hideinitializer
+ */
+#if !UIP_CONF_IPV6
+#define uip_ipaddr_cmp(addr1, addr2) (((u16_t *)addr1)[0] == ((u16_t *)addr2)[0] && \
+				      ((u16_t *)addr1)[1] == ((u16_t *)addr2)[1])
+#else /* !UIP_CONF_IPV6 */
+#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
+#endif /* !UIP_CONF_IPV6 */
+
+/**
+ * Compare two IP addresses with netmasks
+ *
+ * Compares two IP addresses with netmasks. The masks are used to mask
+ * out the bits that are to be compared.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2, mask;
+
+ uip_ipaddr(&mask, 255,255,255,0);
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr(&ipaddr2, 192,16,1,3);
+ if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr_maskcmp(addr1, addr2, mask) \
+                          (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
+                            (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
+                           ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
+                            (((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
+
+
+/**
+ * Mask out the network part of an IP address.
+ *
+ * Masks out the network part of an IP address, given the address and
+ * the netmask.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2, netmask;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr(&netmask, 255,255,255,0);
+ uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
+ \endcode
+ *
+ * In the example above, the variable "ipaddr2" will contain the IP
+ * address 192.168.1.0.
+ *
+ * \param dest Where the result is to be placed.
+ * \param src The IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr_mask(dest, src, mask) do { \
+                     ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
+                     ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
+                  } while(0)
+
+/**
+ * Pick the first octet of an IP address.
+ *
+ * Picks out the first octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr1(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 1.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8)
+
+/**
+ * Pick the second octet of an IP address.
+ *
+ * Picks out the second octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr2(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 2.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff)
+
+/**
+ * Pick the third octet of an IP address.
+ *
+ * Picks out the third octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr3(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 3.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8)
+
+/**
+ * Pick the fourth octet of an IP address.
+ *
+ * Picks out the fourth octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr4(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 4.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff)
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This macro is primarily used for converting constants from host
+ * byte order to network byte order. For converting variables to
+ * network byte order, use the htons() function instead.
+ *
+ * \hideinitializer
+ */
+#if 0
+#ifndef HTONS
+#   if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
+#      define HTONS(n) (n)
+#   else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#      define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
+#   endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#else
+#error "HTONS already defined!"
+#endif /* HTONS */
+#endif
+
+#if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
+#      error "Should not be here"
+#      define const_htons(n) (n)
+#   else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#      define const_htons(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
+#   endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+
+/*  BWL */
+#if 0
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This function is primarily used for converting variables from host
+ * byte order to network byte order. For converting constants to
+ * network byte order, use the HTONS() macro instead.
+ */
+#ifndef htons
+u16_t htons(u16_t val);
+#endif /* htons */
+#ifndef ntohs
+#define ntohs htons
+#endif
+#endif
+
+/** @} */
+
+/**
+ * Pointer to the application data in the packet buffer.
+ *
+ * This pointer points to the application data when the application is
+ * called. If the application wishes to send data, the application may
+ * use this space to write the data into before calling uip_send().
+ */
+//extern void *uip_appdata;
+
+#if UIP_URGDATA > 0
+/* u8_t *uip_urgdata:
+ *
+ * This pointer points to any urgent data that has been received. Only
+ * present if compiled with support for urgent data (UIP_URGDATA).
+ */
+extern void *uip_urgdata;
+#endif /* UIP_URGDATA > 0 */
+
+
+/**
+ * \defgroup uipdrivervars Variables used in uIP device drivers
+ * @{
+ *
+ * uIP has a few global variables that are used in device drivers for
+ * uIP.
+ */
+
+/**
+ * The length of the packet in the uip_buf buffer.
+ *
+ * The global variable uip_len holds the length of the packet in the
+ * uip_buf buffer.
+ *
+ * When the network device driver calls the uIP input function,
+ * uip_len should be set to the length of the packet in the uip_buf
+ * buffer.
+ *
+ * When sending packets, the device driver should use the contents of
+ * the uip_len variable to determine the length of the outgoing
+ * packet.
+ *
+ */
+//extern u16_t uip_len;
+
+/** @} */
+
+#if UIP_URGDATA > 0
+extern u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+
+/**
+ * Representation of a uIP TCP connection.
+ *
+ * The uip_conn structure is used for identifying a connection. All
+ * but one field in the structure are to be considered read-only by an
+ * application. The only exception is the appstate field whos purpose
+ * is to let the application store application-specific state (e.g.,
+ * file pointers) for the connection. The type of this field is
+ * configured in the "uipopt.h" header file.
+ */
+struct  __attribute__ ((__packed__)) uip_conn
+{
+  uip_ipaddr_t ripaddr;   /**< The IP address of the remote host. */
+  
+  u16_t lport;        /**< The local TCP port, in network byte order. */
+  u16_t rport;        /**< The local remote TCP port, in network byte
+			 order. */
+  
+  u8_t rcv_nxt[4];    /**< The sequence number that we expect to
+			 receive next. */
+  u8_t snd_nxt[4];    /**< The sequence number that was last sent by
+                         us. */
+  u16_t len;          /**< Length of the data that was previously sent. */
+  u16_t mss;          /**< Current maximum segment size for the
+			 connection. */
+  u16_t initialmss;   /**< Initial maximum segment size for the
+			 connection. */
+  u8_t sa;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t sv;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t rto;           /**< Retransmission time-out. */
+  u8_t tcpstateflags; /**< TCP state and flags. */
+  u8_t timer;         /**< The retransmission timer. */
+  u8_t nrtx;          /**< The number of retransmissions for the last
+			 segment sent. */
+
+  /** The application state. */
+/* BWL */
+//  uip_tcp_appstate_t appstate;
+};
+
+
+/**
+ * \addtogroup uiparch
+ * @{
+ */
+
+/**
+ * 4-byte array used for the 32-bit sequence number calculations.
+ */
+extern u8_t uip_acc32[4];
+
+/** @} */
+
+
+#if UIP_UDP
+/**
+ * Representation of a uIP UDP connection.
+ */
+struct uip_udp_conn {
+  uip_ipaddr_t ripaddr;   /**< The IP address of the remote peer. */
+  u16_t lport;        /**< The local port number in network byte order. */
+  u16_t rport;        /**< The remote port number in network byte order. */
+  u8_t  ttl;          /**< Default time-to-live. */
+
+  /** The application state. */
+//  uip_udp_appstate_t appstate;
+};
+
+#endif /* UIP_UDP */
+
+/**
+ * The structure holding the TCP/IP statistics that are gathered if
+ * UIP_STATISTICS is set to 1.
+ *
+ */
+struct uip_stats {
+  struct {
+    uip_stats_t drop;     /**< Number of dropped packets at the IP
+			     layer. */
+    uip_stats_t recv;     /**< Number of received packets at the IP
+			     layer. */
+    uip_stats_t sent;     /**< Number of sent packets at the IP
+			     layer. */
+    uip_stats_t vhlerr;   /**< Number of packets dropped due to wrong
+			     IP version or header length. */
+    uip_stats_t hblenerr; /**< Number of packets dropped due to wrong
+			     IP length, high byte. */
+    uip_stats_t lblenerr; /**< Number of packets dropped due to wrong
+			     IP length, low byte. */
+    uip_stats_t fragerr;  /**< Number of packets dropped since they
+			     were IP fragments. */
+    uip_stats_t chkerr;   /**< Number of packets dropped due to IP
+			     checksum errors. */
+    uip_stats_t protoerr; /**< Number of packets dropped since they
+			     were neither ICMP, UDP nor TCP. */
+  } ip;                   /**< IP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped ICMP packets. */
+    uip_stats_t recv;     /**< Number of received ICMP packets. */
+    uip_stats_t sent;     /**< Number of sent ICMP packets. */
+    uip_stats_t typeerr;  /**< Number of ICMP packets with a wrong
+			     type. */
+  } icmp;                 /**< ICMP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped TCP segments. */
+    uip_stats_t recv;     /**< Number of recived TCP segments. */
+    uip_stats_t sent;     /**< Number of sent TCP segments. */
+    uip_stats_t chkerr;   /**< Number of TCP segments with a bad
+			     checksum. */
+    uip_stats_t ackerr;   /**< Number of TCP segments with a bad ACK
+			     number. */
+    uip_stats_t rst;      /**< Number of recevied TCP RST (reset) segments. */
+    uip_stats_t rexmit;   /**< Number of retransmitted TCP segments. */
+    uip_stats_t syndrop;  /**< Number of dropped SYNs due to too few
+			     connections was avaliable. */
+    uip_stats_t synrst;   /**< Number of SYNs for closed ports,
+			     triggering a RST. */
+  } tcp;                  /**< TCP statistics. */
+#if UIP_UDP
+  struct {
+    uip_stats_t drop;     /**< Number of dropped UDP segments. */
+    uip_stats_t recv;     /**< Number of recived UDP segments. */
+    uip_stats_t sent;     /**< Number of sent UDP segments. */
+    uip_stats_t chkerr;   /**< Number of UDP segments with a bad
+			     checksum. */
+  } udp;                  /**< UDP statistics. */
+#endif /* UIP_UDP */
+};
+
+
+/*---------------------------------------------------------------------------*/
+/* All the stuff below this point is internal to uIP and should not be
+ * used directly by an application or by a device driver.
+ */
+/*---------------------------------------------------------------------------*/
+/* u8_t uip_flags:
+ *
+ * When the application is called, uip_flags will contain the flags
+ * that are defined in this file. Please read below for more
+ * infomation.
+ */
+//extern u8_t uip_flags;
+
+/* The following flags may be set in the global variable uip_flags
+   before calling the application callback. The UIP_ACKDATA,
+   UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time,
+   whereas the others are mutualy exclusive. Note that these flags
+   should *NOT* be accessed directly, but only through the uIP
+   functions/macros. */
+
+#define UIP_ACKDATA   1     /* Signifies that the outstanding data was
+			       acked and the application should send
+			       out new data instead of retransmitting
+			       the last data. */
+#define UIP_NEWDATA   2     /* Flags the fact that the peer has sent
+			       us new data. */
+#define UIP_REXMIT    4     /* Tells the application to retransmit the
+			       data that was last sent. */
+#define UIP_POLL      8     /* Used for polling the application, to
+			       check if the application has data that
+			       it wants to send. */
+#define UIP_CLOSE     16    /* The remote host has closed the
+			       connection, thus the connection has
+			       gone away. Or the application signals
+			       that it wants to close the
+			       connection. */
+#define UIP_ABORT     32    /* The remote host has aborted the
+			       connection, thus the connection has
+			       gone away. Or the application signals
+			       that it wants to abort the
+			       connection. */
+#define UIP_CONNECTED 64    /* We have got a connection from a remote
+                               host and have set up a new connection
+                               for it, or an active connection has
+                               been successfully established. */
+
+#define UIP_TIMEDOUT  128   /* The connection has been aborted due to
+			       too many retransmissions. */
+
+void uip_input(struct uip_stack *ustack);
+void uip_periodic(struct uip_stack *ustack, int conn);
+
+/* uip_process(flag):
+ *
+ * The actual uIP function which does all the work.
+ */
+void uip_process(struct uip_stack *ustack, u8_t flag);
+
+/* The following flags are passed as an argument to the uip_process()
+   function. They are used to distinguish between the two cases where
+   uip_process() is called. It can be called either because we have
+   incoming data that should be processed, or because the periodic
+   timer has fired. These values are never used directly, but only in
+   the macrose defined in this file. */
+ 
+#define UIP_DATA          1     /* Tells uIP that there is incoming
+				   data in the uip_buf buffer. The
+				   length of the data is stored in the
+				   global variable uip_len. */
+#define UIP_TIMER         2     /* Tells uIP that the periodic timer
+				   has fired. */
+#define UIP_POLL_REQUEST  3     /* Tells uIP that a connection should
+				   be polled. */
+#define UIP_UDP_SEND_CONN 4     /* Tells uIP that a UDP datagram
+				   should be constructed in the
+				   uip_buf buffer. */
+#if UIP_UDP
+#define UIP_UDP_TIMER     5
+#endif /* UIP_UDP */
+
+/* The TCP states used in the uip_conn->tcpstateflags. */
+#define UIP_CLOSED      0
+#define UIP_SYN_RCVD    1
+#define UIP_SYN_SENT    2
+#define UIP_ESTABLISHED 3
+#define UIP_FIN_WAIT_1  4
+#define UIP_FIN_WAIT_2  5
+#define UIP_CLOSING     6
+#define UIP_TIME_WAIT   7
+#define UIP_LAST_ACK    8
+#define UIP_TS_MASK     15
+  
+#define UIP_STOPPED      16
+
+/* The TCP and IPv4 headers. */
+struct __attribute__ ((__packed__)) uip_tcpipv4_hdr {
+  /* IPv4 header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+  
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+};
+
+/* The TCP and IPv6 headers. */
+struct __attribute__ ((__packed__)) uip_tcpipv6_hdr {
+  /* IPv6 header. */
+  u8_t vtc,
+    tcflow;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+  
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+};
+
+/* The ICMP and IP headers. */
+struct __attribute__ ((__packed__)) uip_icmpip_hdr {
+#if UIP_CONF_IPV6
+  /* IPv6 header. */
+  u8_t vtc,
+    tcf;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+#else /* UIP_CONF_IPV6 */
+  /* IPv4 header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+#endif /* UIP_CONF_IPV6 */
+  
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+#if !UIP_CONF_IPV6
+  u16_t id, seqno;
+#else /* !UIP_CONF_IPV6 */
+  u8_t flags, reserved1, reserved2, reserved3;
+  u8_t icmp6data[16];
+  u8_t options[1];
+#endif /* !UIP_CONF_IPV6 */
+};
+
+
+/* The UDP and IP headers. */
+struct __attribute__ ((__packed__)) uip_udpip_hdr {
+#if UIP_CONF_IPV6
+  /* IPv6 header. */
+  u8_t vtc,
+    tcf;
+  u16_t flow;
+  u8_t len[2];
+  u8_t proto, ttl;
+  uip_ip6addr_t srcipaddr, destipaddr;
+#else /* UIP_CONF_IPV6 */
+  /* IP header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+#endif /* UIP_CONF_IPV6 */
+  
+  /* UDP header. */
+  u16_t srcport,
+    destport;
+  u16_t udplen;
+  u16_t udpchksum;
+};
+
+
+
+/**
+ * The buffer size available for user data in the \ref uip_buf buffer.
+ *
+ * This macro holds the available size for user data in the \ref
+ * uip_buf buffer. The macro is intended to be used for checking
+ * bounds of available user data.
+ *
+ * Example:
+ \code
+ snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
+
+
+#define UIP_PROTO_ICMP  1
+#define UIP_PROTO_TCP   6
+#define UIP_PROTO_UDP   17
+#define UIP_PROTO_ICMP6 58
+
+/* Header sizes. */
+#if UIP_CONF_IPV6
+#define UIP_IPH_LEN    40
+#else /* UIP_CONF_IPV6 */
+#define UIP_IPH_LEN    20    /* Size of IP header */
+#endif /* UIP_CONF_IPV6 */
+#define UIP_UDPH_LEN    8    /* Size of UDP header */
+#define UIP_TCPH_LEN   20    /* Size of TCP header */
+#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN)    /* Size of IP +
+							  UDP
+							  header */
+#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN)    /* Size of IP +
+							  TCP
+							  header */
+#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN
+
+
+/**
+ * Representation of a 48-bit Ethernet address.
+ */
+struct uip_eth_addr {
+  u8_t addr[6];
+};
+
+/**
+ * Calculate the Internet checksum over a buffer.
+ *
+ * The Internet checksum is the one's complement of the one's
+ * complement sum of all 16-bit words in the buffer.
+ *
+ * See RFC1071.
+ *
+ * \param buf A pointer to the buffer over which the checksum is to be
+ * computed.
+ *
+ * \param len The length of the buffer over which the checksum is to
+ * be computed.
+ *
+ * \return The Internet checksum of the buffer.
+ */
+u16_t uip_chksum(u16_t *buf, u16_t len);
+
+/**
+ * Calculate the IP header checksum of the packet header in uip_buf.
+ *
+ * The IP header checksum is the Internet checksum of the 20 bytes of
+ * the IP header.
+ *
+ * \return The IP header checksum of the IP header in the uip_buf
+ * buffer.
+ */
+u16_t uip_ipchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The TCP checksum is the Internet checksum of data contents of the
+ * TCP segment, and a pseudo-header as defined in RFC793.
+ *
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_tcpchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the UDP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The UDP checksum is the Internet checksum of data contents of the
+ * UDP segment, and a pseudo-header as defined in RFC768.
+ *
+ * \return The UDP checksum of the UDP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_udpchksum(struct uip_stack *ustack);
+
+struct uip_stack {
+	struct uip_eth_addr uip_ethaddr;
+
+#ifndef UIP_CONF_EXTERNAL_BUFFER
+	u8_t uip_buf[UIP_BUFSIZE + 2];	/* The packet buffer that contains
+					    incoming packets. */
+#endif /* UIP_CONF_EXTERNAL_BUFFER */
+
+	void *uip_appdata;		/* The uip_appdata pointer points to
+					    application data. */
+	void *uip_sappdata;		/* The uip_appdata pointer points to
+					    the application data which is to
+					    be sent. */
+#if UIP_URGDATA > 0
+	void *uip_urgdata;		/* The uip_urgdata pointer points to
+					    urgent data (out-of-band data), if
+					    present. */
+	u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+	u16_t uip_len, uip_slen;	/* The uip_len is either 8 or 16 bits,
+					   depending on the maximum packet
+					   size. */
+	u8_t uip_flags;			/* The uip_flags variable is used for
+					  communication between the TCP/IP stack
+					   and the application program. */
+	struct uip_conn *uip_conn;	/* uip_conn always points to the current
+					   connection. */
+
+	struct uip_conn uip_conns[UIP_CONNS];
+				/* The uip_conns array holds all TCP
+				   connections. */
+	u16_t uip_listenports[UIP_LISTENPORTS];
+				/* The uip_listenports list all currently
+				   listning ports. */
+#if UIP_UDP
+	struct uip_udp_conn *uip_udp_conn;
+	struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+	u16_t ipid;			/* This ipid variable is an increasing
+					   number that is used for the IP ID
+					   field. */
+
+	u8_t iss[4];			/* The iss variable is used for the TCP
+					   initial sequence number. */
+
+#if UIP_ACTIVE_OPEN
+	u16_t lastport;			/* Keeps track of the last port used for
+					   a new connection. */
+#endif /* UIP_ACTIVE_OPEN */
+
+	uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr;
+
+	struct uip_stats stats;
+
+	u8_t opt;
+
+	pthread_mutex_t lock;
+
+	/*  IPv6 support */
+
+#define UIP_SUPPORT_IPv6_ENABLED	0x01
+#define UIP_SUPPORT_IPv6_DISABLED	0x02
+	u8_t	enable_IPv6;
+};
+
+/*******************************************************************************
+ * IPv6 Support
+ ******************************************************************************/
+int get_ipv6_link_local_address(struct uip_stack *ustack,
+                                char *addr);
+
+
+
+#endif /* __UIP_H__ */
+
+
+/** @} */
diff --git a/brcm_iscsi_uio/src/uip/uiplib.c b/brcm_iscsi_uio/src/uip/uiplib.c
new file mode 100644
index 0000000..cb5af2c
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uiplib.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2004, Adam Dunkels and the Swedish Institute of
+ * Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: uiplib.c,v 1.2 2006/06/12 08:00:31 adam Exp $
+ *
+ */
+
+
+#include "uip.h"
+#include "uiplib.h"
+
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+uiplib_ipaddrconv(char *addrstr, unsigned char *ipaddr)
+{
+  unsigned char tmp;
+  char c;
+  unsigned char i, j;
+
+  tmp = 0;
+  
+  for(i = 0; i < 4; ++i) {
+    j = 0;
+    do {
+      c = *addrstr;
+      ++j;
+      if(j > 4) {
+	return 0;
+      }
+      if(c == '.' || c == 0) {
+	*ipaddr = tmp;
+	++ipaddr;
+	tmp = 0;
+      } else if(c >= '0' && c <= '9') {
+	tmp = (tmp * 10) + (c - '0');
+      } else {
+	return 0;
+      }
+      ++addrstr;
+    } while(c != '.' && c != 0);
+  }
+  return 1;
+}
+
+/*-----------------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/uip/uiplib.h b/brcm_iscsi_uio/src/uip/uiplib.h
new file mode 100644
index 0000000..c676849
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uiplib.h
@@ -0,0 +1,71 @@
+/**
+ * \file
+ * Various uIP library functions.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: uiplib.h,v 1.1 2006/06/07 09:15:19 adam Exp $
+ *
+ */
+#ifndef __UIPLIB_H__
+#define __UIPLIB_H__
+
+/**
+ * \addtogroup uipconvfunc
+ * @{
+ */
+
+/**
+ * Convert a textual representation of an IP address to a numerical representation.
+ *
+ * This function takes a textual representation of an IP address in
+ * the form a.b.c.d and converts it into a 4-byte array that can be
+ * used by other uIP functions.
+ *
+ * \param addrstr A pointer to a string containing the IP address in
+ * textual form.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the numerical representation of the address.
+ *
+ * \retval 0 If the IP address could not be parsed.
+ * \retval Non-zero If the IP address was parsed.
+ */
+unsigned char uiplib_ipaddrconv(char *addrstr, unsigned char *addr);
+
+/** @} */
+
+#endif /* __UIPLIB_H__ */
diff --git a/brcm_iscsi_uio/src/uip/uipopt.h b/brcm_iscsi_uio/src/uip/uipopt.h
new file mode 100644
index 0000000..98bfb0e
--- /dev/null
+++ b/brcm_iscsi_uio/src/uip/uipopt.h
@@ -0,0 +1,541 @@
+/**
+ * \defgroup uipopt Configuration options for uIP
+ * @{
+ *
+ * uIP is configured using the per-project configuration file
+ * uipopt.h. This file contains all compile-time options for uIP and
+ * should be tweaked to match each specific project. The uIP
+ * distribution contains a documented example "uipopt.h" that can be
+ * copied and modified for each project.
+ *
+ * \note Most of the configuration options in the uipopt.h should not
+ * be changed, but rather the per-project uip-conf.h file.
+ */
+
+/**
+ * \file
+ * Configuration options for uIP.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * This file is used for tweaking various configuration options for
+ * uIP. You should make a copy of this file into one of your project's
+ * directories instead of editing this example "uipopt.h" file that
+ * comes with the uIP distribution.
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uipopt.h,v 1.4 2006/06/12 08:00:31 adam Exp $
+ *
+ */
+
+#ifndef __UIPOPT_H__
+#define __UIPOPT_H__
+
+#ifndef UIP_LITTLE_ENDIAN
+#define UIP_LITTLE_ENDIAN  3412
+#endif /* UIP_LITTLE_ENDIAN */
+#ifndef UIP_BIG_ENDIAN
+#define UIP_BIG_ENDIAN     1234
+#endif /* UIP_BIG_ENDIAN */
+
+#include "uip-conf.h"
+
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \name Static configuration options
+ * @{
+ *
+ * These configuration options can be used for setting the IP address
+ * settings statically, but only if UIP_FIXEDADDR is set to 1. The
+ * configuration options for a specific node includes IP address,
+ * netmask and default router as well as the Ethernet address. The
+ * netmask, default router and Ethernet address are appliciable only
+ * if uIP should be run over Ethernet.
+ *
+ * All of these should be changed to suit your project.
+*/
+
+/**
+ * Determines if uIP should use a fixed IP address or not.
+ *
+ * If uIP should use a fixed IP address, the settings are set in the
+ * uipopt.h file. If not, the macros uip_sethostaddr(),
+ * uip_setdraddr() and uip_setnetmask() should be used instead.
+ *
+ * \hideinitializer
+ */
+#define UIP_FIXEDADDR    0
+
+/**
+ * Ping IP address asignment.
+ *
+ * uIP uses a "ping" packets for setting its own IP address if this
+ * option is set. If so, uIP will start with an empty IP address and
+ * the destination IP address of the first incoming "ping" (ICMP echo)
+ * packet will be used for setting the hosts IP address.
+ *
+ * \note This works only if UIP_FIXEDADDR is 0.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_PINGADDRCONF
+#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF
+#else /* UIP_CONF_PINGADDRCONF */
+#define UIP_PINGADDRCONF 0
+#endif /* UIP_CONF_PINGADDRCONF */
+
+
+/**
+ * Specifies if the uIP ARP module should be compiled with a fixed
+ * Ethernet MAC address or not.
+ *
+ * If this configuration option is 0, the macro uip_setethaddr() can
+ * be used to specify the Ethernet address at run-time.
+ *
+ * \hideinitializer
+ */
+#define UIP_FIXEDETHADDR 0
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \name IP configuration options
+ * @{
+ *
+ */
+/**
+ * The IP TTL (time to live) of IP packets sent by uIP.
+ *
+ * This should normally not be changed.
+ */
+#define UIP_TTL         64
+
+/**
+ * Turn on support for IP packet reassembly.
+ *
+ * uIP supports reassembly of fragmented IP packets. This features
+ * requires an additonal amount of RAM to hold the reassembly buffer
+ * and the reassembly code size is approximately 700 bytes.  The
+ * reassembly buffer is of the same size as the uip_buf buffer
+ * (configured by UIP_BUFSIZE).
+ *
+ * \note IP packet reassembly is not heavily tested.
+ *
+ * \hideinitializer
+ */
+#define UIP_REASSEMBLY 0
+
+/**
+ * The maximum time an IP fragment should wait in the reassembly
+ * buffer before it is dropped.
+ *
+ */
+#define UIP_REASS_MAXAGE 40
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+/**
+ * \name UDP configuration options
+ * @{
+ */
+
+/**
+ * Toggles wether UDP support should be compiled in or not.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_UDP
+#define UIP_UDP UIP_CONF_UDP
+#else /* UIP_CONF_UDP */
+#define UIP_UDP           0
+#endif /* UIP_CONF_UDP */
+
+/**
+ * Toggles if UDP checksums should be used or not.
+ *
+ * \note Support for UDP checksums is currently not included in uIP,
+ * so this option has no function.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_UDP_CHECKSUMS
+#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS
+#else
+#define UIP_UDP_CHECKSUMS 0
+#endif
+
+/**
+ * The maximum amount of concurrent UDP connections.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_UDP_CONNS
+#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS
+#else /* UIP_CONF_UDP_CONNS */
+#define UIP_UDP_CONNS    10
+#endif /* UIP_CONF_UDP_CONNS */
+
+/**
+ * The name of the function that should be called when UDP datagrams arrive.
+ *
+ * \hideinitializer
+ */
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \name TCP configuration options
+ * @{
+ */
+
+/**
+ * Determines if support for opening connections from uIP should be
+ * compiled in.
+ *
+ * If the applications that are running on top of uIP for this project
+ * do not need to open outgoing TCP connections, this configration
+ * option can be turned off to reduce the code size of uIP.
+ *
+ * \hideinitializer
+ */
+#define UIP_ACTIVE_OPEN 1
+
+/**
+ * The maximum number of simultaneously open TCP connections.
+ *
+ * Since the TCP connections are statically allocated, turning this
+ * configuration knob down results in less RAM used. Each TCP
+ * connection requires approximatly 30 bytes of memory.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_MAX_CONNECTIONS
+#define UIP_CONNS       10
+#else /* UIP_CONF_MAX_CONNECTIONS */
+#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS
+#endif /* UIP_CONF_MAX_CONNECTIONS */
+
+
+/**
+ * The maximum number of simultaneously listening TCP ports.
+ *
+ * Each listening TCP port requires 2 bytes of memory.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_MAX_LISTENPORTS
+#define UIP_LISTENPORTS 20
+#else /* UIP_CONF_MAX_LISTENPORTS */
+#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS
+#endif /* UIP_CONF_MAX_LISTENPORTS */
+
+/**
+ * Determines if support for TCP urgent data notification should be
+ * compiled in.
+ *
+ * Urgent data (out-of-band data) is a rarely used TCP feature that
+ * very seldom would be required.
+ *
+ * \hideinitializer
+ */
+#define UIP_URGDATA      0
+
+/**
+ * The initial retransmission timeout counted in timer pulses.
+ *
+ * This should not be changed.
+ */
+#define UIP_RTO         3
+
+/**
+ * The maximum number of times a segment should be retransmitted
+ * before the connection should be aborted.
+ *
+ * This should not be changed.
+ */
+#define UIP_MAXRTX      8
+
+/**
+ * The maximum number of times a SYN segment should be retransmitted
+ * before a connection request should be deemed to have been
+ * unsuccessful.
+ *
+ * This should not need to be changed.
+ */
+#define UIP_MAXSYNRTX      5
+
+/**
+ * The TCP maximum segment size.
+ *
+ * This is should not be to set to more than
+ * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
+ */
+#define UIP_TCP_MSS     (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCP_IPv4_HLEN)
+
+/**
+ * The size of the advertised receiver's window.
+ *
+ * Should be set low (i.e., to the size of the uip_buf buffer) is the
+ * application is slow to process incoming data, or high (32768 bytes)
+ * if the application processes data quickly.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_RECEIVE_WINDOW
+#define UIP_RECEIVE_WINDOW UIP_TCP_MSS
+#else
+#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW
+#endif
+
+/**
+ * How long a connection should stay in the TIME_WAIT state.
+ *
+ * This configiration option has no real implication, and it should be
+ * left untouched.
+ */
+#define UIP_TIME_WAIT_TIMEOUT 120
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \name ARP configuration options
+ * @{
+ */
+
+/**
+ * The size of the ARP table.
+ *
+ * This option should be set to a larger value if this uIP node will
+ * have many connections from the local network.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_ARPTAB_SIZE
+#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE
+#else
+#define UIP_ARPTAB_SIZE 8
+#endif
+
+/**
+ * The maxium age of ARP table entries measured in 10ths of seconds.
+ *
+ * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD
+ * default).
+ */
+#define UIP_ARP_MAXAGE 120
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \name General configuration options
+ * @{
+ */
+
+/**
+ * The size of the uIP packet buffer.
+ *
+ * The uIP packet buffer should not be smaller than 60 bytes, and does
+ * not need to be larger than 1500 bytes. Lower size results in lower
+ * TCP throughput, larger size results in higher TCP throughput.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_BUFFER_SIZE
+#define UIP_BUFSIZE     400
+#else /* UIP_CONF_BUFFER_SIZE */
+#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
+#endif /* UIP_CONF_BUFFER_SIZE */
+
+
+/**
+ * Determines if statistics support should be compiled in.
+ *
+ * The statistics is useful for debugging and to show the user.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_STATISTICS
+#define UIP_STATISTICS  0
+#else /* UIP_CONF_STATISTICS */
+#define UIP_STATISTICS UIP_CONF_STATISTICS
+#endif /* UIP_CONF_STATISTICS */
+
+/**
+ * Determines if logging of certain events should be compiled in.
+ *
+ * This is useful mostly for debugging. The function uip_log()
+ * must be implemented to suit the architecture of the project, if
+ * logging is turned on.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_LOGGING
+#define UIP_LOGGING     0
+#else /* UIP_CONF_LOGGING */
+#define UIP_LOGGING     UIP_CONF_LOGGING
+#endif /* UIP_CONF_LOGGING */
+
+/**
+ * Broadcast support.
+ *
+ * This flag configures IP broadcast support. This is useful only
+ * together with UDP.
+ *
+ * \hideinitializer
+ *
+ */
+#ifndef UIP_CONF_BROADCAST
+#define UIP_BROADCAST 0
+#else /* UIP_CONF_BROADCAST */
+#define UIP_BROADCAST UIP_CONF_BROADCAST
+#endif /* UIP_CONF_BROADCAST */
+
+/**
+ * Print out a uIP log message.
+ *
+ * This function must be implemented by the module that uses uIP, and
+ * is called by uIP whenever a log message is generated.
+ */
+void uip_log(char *msg);
+
+/**
+ * The link level header length.
+ *
+ * This is the offset into the uip_buf where the IP header can be
+ * found. For Ethernet, this should be set to 14. For SLIP, this
+ * should be set to 0.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_LLH_LEN
+#define UIP_LLH_LEN UIP_CONF_LLH_LEN
+#else /* UIP_CONF_LLH_LEN */
+#define UIP_LLH_LEN     14
+#endif /* UIP_CONF_LLH_LEN */
+
+#if 0
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \name CPU architecture configuration
+ * @{
+ *
+ * The CPU architecture configuration is where the endianess of the
+ * CPU on which uIP is to be run is specified. Most CPUs today are
+ * little endian, and the most notable exception are the Motorolas
+ * which are big endian. The BYTE_ORDER macro should be changed to
+ * reflect the CPU architecture on which uIP is to be run.
+ */
+
+/**
+ * The byte order of the CPU architecture on which uIP is to be run.
+ *
+ * This option can be either BIG_ENDIAN (Motorola byte order) or
+ * LITTLE_ENDIAN (Intel byte order).
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_BYTE_ORDER
+#define UIP_BYTE_ORDER     UIP_CONF_BYTE_ORDER
+#else /* UIP_CONF_BYTE_ORDER */
+#define UIP_BYTE_ORDER     UIP_LITTLE_ENDIAN
+#endif /* UIP_CONF_BYTE_ORDER */
+#endif
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \name Appication specific configurations
+ * @{
+ *
+ * An uIP application is implemented using a single application
+ * function that is called by uIP whenever a TCP/IP event occurs. The
+ * name of this function must be registered with uIP at compile time
+ * using the UIP_APPCALL definition.
+ *
+ * uIP applications can store the application state within the
+ * uip_conn structure by specifying the type of the application
+ * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t.
+ *
+ * The file containing the definitions must be included in the
+ * uipopt.h file.
+ *
+ * The following example illustrates how this can look.
+ \code
+
+void httpd_appcall(void);
+#define UIP_APPCALL     httpd_appcall
+
+struct httpd_state {
+  u8_t state;
+  u16_t count;
+  char *dataptr;
+  char *script;
+};
+typedef struct httpd_state uip_tcp_appstate_t
+ \endcode
+ */
+
+/**
+ * \var #define UIP_APPCALL
+ *
+ * The name of the application function that uIP should call in
+ * response to TCP/IP events.
+ *
+ */
+
+/**
+ * \var typedef uip_tcp_appstate_t
+ *
+ * The type of the application state that is to be stored in the
+ * uip_conn structure. This usually is typedef:ed to a struct holding
+ * application state information.
+ */
+
+/**
+ * \var typedef uip_udp_appstate_t
+ *
+ * The type of the application state that is to be stored in the
+ * uip_conn structure. This usually is typedef:ed to a struct holding
+ * application state information.
+ */
+/** @} */
+/** @} */
+
+#endif /* __UIPOPT_H__ */
diff --git a/brcm_iscsi_uio/src/unix/Makefile.am b/brcm_iscsi_uio/src/unix/Makefile.am
new file mode 100644
index 0000000..56ee4f8
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/Makefile.am
@@ -0,0 +1,39 @@
+SUBDIRS= libs
+
+INCLUDES = -I${top_srcdir}/src/uip		\
+	   -I${top_srcdir}/src/apps/brcm-iscsi	\
+	   -I${top_srcdir}/src/apps/dhcpc	\
+	   -I${top_srcdir}/include		\
+	   -I${top_srcdir}/src/unix/libs/
+
+bin_PROGRAMS = brcm_iscsiuio
+
+brcm_iscsiuio_SOURCES =	build_date.c		\
+			main.c			\
+			clock-arch.c		\
+			logger.c		\
+			uevent.c		\
+			nic.c			\
+			nic_id.c		\
+			nic_vlan.c		\
+			nic_nl.c		\
+			nic_utils.c		\
+			packet.c		\
+			iscsid_ipc.c
+
+brcm_iscsiuio_CFLAGS = $(AM_CFLAGS)		\
+		       $(LIBNL_CFLAGS)		\
+		       -DBYTE_ORDER=@ENDIAN@
+
+brcm_iscsiuio_LDFLAGS= $(AM_LDADD)		\
+		       -ldl			\
+		       -rdynamic		\
+		       $(LIBNL_LIBS)		\
+		       -lpthread
+
+brcm_iscsiuio_LDADD  = ${top_srcdir}/src/uip/libbrcm_iscsi_uip.a	\
+		       ${top_srcdir}/src/apps/dhcpc/libbrcm_apps_dhcpc.a\
+		       ${top_srcdir}/src/apps/brcm-iscsi/libbrcm_apps_brcm_iscsi.a \
+		       ${top_srcdir}/src/unix/libs/libbrcm_iscsiuio_hw_cnic.a
+
+brcm_iscsiuio_YFLAGS = -d
diff --git a/brcm_iscsi_uio/src/unix/build_date.c b/brcm_iscsi_uio/src/unix/build_date.c
new file mode 100644
index 0000000..6018481
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/build_date.c
@@ -0,0 +1 @@
+char *build_date ="Thu Dec 10 05:30:25 PST 2009";
diff --git a/brcm_iscsi_uio/src/unix/build_date.h b/brcm_iscsi_uio/src/unix/build_date.h
new file mode 100644
index 0000000..3033db7
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/build_date.h
@@ -0,0 +1 @@
+char *build_date; 
diff --git a/brcm_iscsi_uio/src/unix/clock-arch.c b/brcm_iscsi_uio/src/unix/clock-arch.c
new file mode 100644
index 0000000..d140aaf
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/clock-arch.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: clock-arch.c,v 1.2 2006/06/12 08:00:31 adam Exp $
+ */
+
+/**
+ * \file
+ *         Implementation of architecture-specific clock functionality
+ * \author
+ *         Adam Dunkels <adam@sics.se>
+ */
+
+#include "clock-arch.h"
+#include <sys/time.h>
+
+/*---------------------------------------------------------------------------*/
+clock_time_t
+clock_time(void)
+{
+  struct timeval tv;
+  struct timezone tz;
+
+  gettimeofday(&tv, &tz);
+
+  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/brcm_iscsi_uio/src/unix/clock-arch.h b/brcm_iscsi_uio/src/unix/clock-arch.h
new file mode 100644
index 0000000..e51eee9
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/clock-arch.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: clock-arch.h,v 1.2 2006/06/12 08:00:31 adam Exp $
+ */
+
+#ifndef __CLOCK_ARCH_H__
+#define __CLOCK_ARCH_H__
+
+typedef int clock_time_t;
+#define CLOCK_CONF_SECOND 1000
+
+#endif /* __CLOCK_ARCH_H__ */
diff --git a/brcm_iscsi_uio/src/unix/iscsid_ipc.c b/brcm_iscsi_uio/src/unix/iscsid_ipc.c
new file mode 100644
index 0000000..829f7ed
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/iscsid_ipc.c
@@ -0,0 +1,403 @@
+/* iscsi_ipc.c: Generic NIC management/utility functions
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define PFX "iscsi_ipc "
+
+/* TODO fix me */
+#define IFNAMSIZ 15
+
+#include "nic.h"
+#include "nic_utils.h"
+#include "options.h"
+#include "mgmt_ipc.h"
+#include "iscsid_ipc.h"
+#include "uip.h"
+#include "uip_mgmt_ipc.h"
+
+#include "logger.h"
+#include "uip.h"
+
+/*  private iscsid options stucture */
+struct iscsid_options {
+	int fd;
+	pthread_t thread;
+};
+
+/******************************************************************************
+ *  Globals
+ ******************************************************************************/
+static struct iscsid_options iscsid_opts = {
+	.fd = INVALID_FD,
+        .thread = INVALID_THREAD,
+};
+
+/******************************************************************************
+ *  iscsid Functions
+ ******************************************************************************/
+static void * parse_iface_thread(void * arg) 
+{
+	int rc;
+	nic_t *nic;
+	nic_interface_t *nic_iface;
+        char *transport_name;
+        size_t transport_name_size;
+	nic_lib_handle_t *handle;
+	struct in_addr addr;
+	iscsid_uip_broadcast_t *data;
+
+	data = (iscsid_uip_broadcast_t *) arg;
+
+	/*  Check if we can find the NIC device using the netdev
+	 *  name */
+	rc = from_netdev_name_find_nic(data->u.iface_rec.rec.netdev, &nic);
+
+	if(rc != 0) {
+		LOG_INFO(PFX "Couldn't find interface: %s, creating NIC",
+			 data->u.iface_rec.rec.netdev);
+
+		nic = nic_init();
+		if(nic == NULL) {
+			LOG_ERR(PFX "Could not allocate space for NIC '%s'",
+				data->u.iface_rec.rec.netdev);
+			goto done;
+		}
+
+		nic->config_device_name = strdup(data->u.iface_rec.rec.netdev);
+		if(nic->config_device_name == NULL) {
+			LOG_ERR(PFX "Could not allocate config device name "
+				"for NIC '%s'",
+				data->u.iface_rec.rec.netdev);
+			goto done;
+		}
+		nic->flags |= NIC_CONFIG_NAME_MALLOC;
+		nic->log_name = nic->config_device_name;
+
+	} else {
+		LOG_INFO(PFX "Found interface: %s, using existing NIC",
+			 data->u.iface_rec.rec.netdev);
+	}
+
+	prepare_nic(nic);
+
+	/*  Sanity Check to ensure the transport names are the same */
+	handle = nic->nic_library;
+	if(handle != NULL) {
+		(*handle->ops->lib_ops.get_transport_name)(&transport_name,
+						 &transport_name_size);
+
+		if(strncmp(transport_name,
+			   data->u.iface_rec.rec.transport_name,
+		           transport_name_size) != 0) {
+			LOG_ERR(PFX "%s Transport name is not equal "
+				    "expected: %s got: %s",
+				    nic->log_name, 
+				    data->u.iface_rec.rec.transport_name,
+				    transport_name);
+
+		}
+	}
+
+	/*  Create the network interface if it doesn't exist */
+	nic_iface = nic_find_nic_iface(nic, 0);
+	if(nic_iface == NULL) {
+		/*  Create the vlan interface */
+		nic_iface = nic_iface_init();
+
+		if(nic_iface == NULL) {
+			LOG_ERR(PFX "Could not allocate nic_iface",
+				nic_iface);
+			goto done;
+		}
+
+		nic_add_nic_iface(nic, nic_iface);
+	}
+
+	/*  Check to see if this is using DHCP or if this is
+	 *  a static IPv4 address.  This is done by checking
+	 *  if the IP address is equal to 0.0.0.0.  If it is
+	 *  then the user has specified to use DHCP.  If not
+	 *  then the user has spcicied to use a static IP address
+	 *  an the default netmask will be used */
+	inet_aton(data->u.iface_rec.rec.ipaddress,
+		  (struct in_addr *) &addr);
+
+	if(memcmp(&addr,
+		  all_zeroes_addr4, sizeof(all_zeroes_addr4)) == 0) {
+		LOG_INFO(PFX "%s: configuring using DHCP",
+			 nic->log_name);
+		nic_iface->ustack.ip_config = IP_CONFIG_DHCP;
+	} else {
+		struct in_addr netmask;
+		memcpy(&nic_iface->ustack.hostaddr, &addr, sizeof(addr));
+
+		LOG_INFO(PFX "%s: configuring using static IP\n"
+		             "  IPv4 address :%s",
+			 nic->log_name, inet_ntoa(addr))
+		netmask.s_addr = calculate_default_netmask(addr.s_addr);
+		LOG_INFO(PFX "  netmask :%s", inet_ntoa(netmask));
+
+		 memcpy(&nic_iface->ustack.netmask,
+		 	&netmask,
+		 	sizeof(netmask.s_addr));
+		nic_iface->ustack.ip_config = IP_CONFIG_STATIC;
+	}
+
+	/*  Enable the NIC */
+	rc = nic_enable(nic);
+	if(rc != 0)
+		goto done;
+
+	LOG_INFO(PFX "ISCSID_UIP_IPC_GET_IFACE: command: %x " 
+		 "name: %s, netdev: %s ipaddr: %s transport_name:%s",
+		 data->header.command, data->u.iface_rec.rec.name,
+		 data->u.iface_rec.rec.netdev,
+		 inet_ntoa(addr),
+		 data->u.iface_rec.rec.transport_name);
+
+done:
+	free(data);
+
+	pthread_exit(NULL);
+}
+
+/**
+ *  process_iscsid_broadcast() - This function is used to process the
+ *                               broadcast messages from iscsid
+ */
+int process_iscsid_broadcast(int s2)
+{
+	int rc = 0;
+	iscsid_uip_broadcast_t *data;
+	iscsid_uip_rsp_t rsp;
+	FILE *fd;
+	size_t size;
+	iscsid_uip_cmd_e cmd;
+	uint32_t payload_len;
+	pthread_t tmp_thread;
+
+	fd = fdopen(s2, "r+");
+	if (fd == NULL) {
+		LOG_ERR(PFX "Couldn't open file descriptor: %d(%s)",
+			errno, strerror(errno));
+		return -EIO;
+	}
+
+	/*  This will be freed by parse_iface_thread() */
+	data = (iscsid_uip_broadcast_t *) malloc(sizeof(*data));
+	if(data == NULL) {
+		LOG_ERR(PFX "Couldn't allocate memory for iface data");
+		return -ENOMEM;
+	}
+
+	size = fread(data, sizeof(iscsid_uip_broadcast_header_t), 1, fd);
+	if (size == -1) {
+		LOG_ERR(PFX "Could not read request: %d(%s)",
+			errno, strerror(errno));
+		rc = ferror(fd);
+		goto error;
+	}
+
+	cmd = data->header.command;
+	payload_len = data->header.payload_len;
+
+	LOG_DEBUG(PFX "recv iscsid request: cmd: %d, payload_len: %d",
+		  cmd, payload_len);
+
+	size = fread(&data->u.iface_rec, payload_len, 1, fd);
+	if (size == -1) {
+		LOG_ERR(PFX "Could not read data: %d(%s)",
+			errno, strerror(errno));
+		goto error;
+	}
+
+	switch (cmd) {
+	case ISCSID_UIP_IPC_GET_IFACE:
+		/* This thread will be thrown away when completed */
+		rc = pthread_create(&tmp_thread, NULL,
+				    parse_iface_thread, data);
+		if (rc != 0) {
+			LOG_ERR(PFX "Couldn't start parse_iface thread rc=%d",
+				rc);
+			goto error;
+		}
+		
+		break;
+	default:
+		LOG_WARN(PFX "Unknown iscsid broadcast command: %x",
+			 data->header.command);
+		free(data);
+		break;
+	}
+
+	/*  Send a response back to iscsid to tell it the operation succeeded */
+	rsp.command = cmd;
+	rsp.err =  ISCSID_UIP_MGMT_IPC_OK;
+
+	size = fwrite(&rsp, sizeof(rsp), 1, fd);
+	if (size == -1) {
+		LOG_ERR(PFX "Could not send response: %d(%s)",
+			errno, strerror(errno));
+		rc = ferror(fd);
+	}
+
+error:
+	fclose(fd);
+
+	return rc;
+}
+
+static void iscsid_loop_close(void *arg)
+{
+	close(iscsid_opts.fd);
+
+	LOG_INFO(PFX "Admin socket closed");
+}
+
+/**
+ *  iscsid_loop() - This is the function which will process the broadcast
+ *                  messages from iscsid
+ *
+ */
+static void *iscsid_loop(void *arg)
+{
+	int rc;
+	sigset_t set;
+
+	pthread_cleanup_push(iscsid_loop_close, arg);
+
+	sigfillset(&set);
+	rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
+	if (rc != 0) {
+		LOG_ERR(PFX "Couldn't set signal mask for the iscisd listening thread");
+	}
+
+	LOG_DEBUG(PFX "Started iscsid listening thread");
+
+	while (1) {
+		struct sockaddr_un remote;
+		socklen_t sock_len;
+		int s2;
+
+		sock_len = sizeof(remote);
+		s2 = accept(iscsid_opts.fd,
+			    (struct sockaddr *)&remote, &sock_len);
+		if (s2 == -1) {
+			if (errno == EAGAIN) {
+				LOG_DEBUG("Got EAGAIN from accept");
+				sleep(1);
+				continue;
+			} else if (errno == EINTR) {
+				/*  The program is terminating, time to exit */
+				break;
+			}
+
+			LOG_ERR(PFX "Could not accept: %d(%s)",
+				s2, strerror(errno));
+			continue;
+		}
+
+		process_iscsid_broadcast(s2);
+	}
+
+	pthread_cleanup_pop(0);
+
+	LOG_ERR(PFX "exit iscsid listening thread");
+
+	pthread_exit(NULL);
+}
+
+/******************************************************************************
+ *  Initialize/Cleanup routines
+ ******************************************************************************/
+/**
+ *  iscsid_init() - This function will setup the thread used to listen for
+ *                  the iscsid broadcast messages
+ *  @return 0 on success, <0 on failure
+ */
+int iscsid_init()
+{
+	int rc;
+	struct sockaddr_un addr;
+
+	iscsid_opts.fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (iscsid_opts.fd < 0) {
+		LOG_ERR(PFX "Can not create IPC socket");
+		return iscsid_opts.fd;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_LOCAL;
+	memcpy((char *) &addr.sun_path + 1, ISCSID_UIP_NAMESPACE,
+		strlen(ISCSID_UIP_NAMESPACE));
+
+	rc = bind(iscsid_opts.fd,
+		  (struct sockaddr *) &addr, sizeof(addr));
+	if ( rc < 0) {
+		LOG_ERR(PFX "Can not bind IPC socket: %s", strerror(errno));
+		goto error;
+	}
+
+	rc = listen(iscsid_opts.fd, 32);
+	if ( rc < 0) {
+		LOG_ERR(PFX "Can not listen IPC socket: %s", strerror(errno));
+		goto error;
+	}
+
+	rc = pthread_create(&iscsid_opts.thread, NULL, iscsid_loop, NULL);
+	if (rc != 0) {
+		LOG_ERR(PFX "Could not start iscsid listening thread rc=%d", rc);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	close(iscsid_opts.fd);
+	iscsid_opts.fd = INVALID_FD;
+
+	return rc;
+}
+
+/**
+ *  iscsid_cleanup() - This is called when stoping the thread listening
+ *                     for the iscsid broadcast messages
+ */
+void iscsid_cleanup()
+{
+	int rc;
+
+	if (iscsid_opts.fd != INVALID_FD) {
+		rc = pthread_cancel(iscsid_opts.thread);
+		if (rc != 0) {
+			LOG_ERR("Could not cancel iscsid listening thread: %s",
+				strerror(rc));
+		}
+
+		rc = pthread_join(iscsid_opts.thread, NULL);
+		if (rc != 0) {
+			LOG_ERR("Could not wait for the iscsid listenging thread: %s",
+				strerror(rc));
+		}
+	}
+
+	LOG_INFO(PFX "iscsid listening thread has shutdown");
+}
+
diff --git a/brcm_iscsi_uio/src/unix/iscsid_ipc.h b/brcm_iscsi_uio/src/unix/iscsid_ipc.h
new file mode 100644
index 0000000..e42266d
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/iscsid_ipc.h
@@ -0,0 +1,24 @@
+/* uip_ipc.h: Generic NIC management/utility functions
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __ISCSID_IPC_H__
+#define __ISCSID_IPC_H__
+
+#include "uip.h"
+#include "mgmt_ipc.h"
+
+mgmt_ipc_err_e iscsid_connect(int *fd);
+int iscsid_get_ipaddr(int fd, uip_ip4addr_t *ipaddr);
+
+int iscsid_init();
+void iscsid_cleanup();
+
+#endif /* __ISCSID_IPC_H__ */
diff --git a/brcm_iscsi_uio/src/unix/libs/Makefile.am b/brcm_iscsi_uio/src/unix/libs/Makefile.am
new file mode 100644
index 0000000..dd843d3
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/Makefile.am
@@ -0,0 +1,23 @@
+# src/unix/libs/Makefile.am:  CNIC UIO libs Makefile.am
+#
+# Copyright (c) 2004-2008 Broadcom Corporation
+#
+# 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.
+#
+# Written by: Benjamin Li  (benli@broadcom.com)
+#
+
+INCLUDES = -I${top_srcdir}/src/uip		\
+	   -I${top_srcdir}/src/unix		\
+	   -I${top_srcdir}/src/unix/libs	\
+           -I${top_srcdir}/src/apps/dhcpc	\
+           -I${top_srcdir}/include
+
+noinst_LIBRARIES = libbrcm_iscsiuio_hw_cnic.a
+
+libbrcm_iscsiuio_hw_cnic_a_SOURCES =	../build_date.c \
+					cnic.c 		\
+					bnx2.c		\
+					bnx2x.c
diff --git a/brcm_iscsi_uio/src/unix/libs/bnx2.c b/brcm_iscsi_uio/src/unix/libs/bnx2.c
new file mode 100644
index 0000000..df99152
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/bnx2.c
@@ -0,0 +1,1107 @@
+/* bnx2.c: CNIC user space driver
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#include "build_date.h"
+#include "bnx2.h"
+#include "cnic.h"
+#include "logger.h"
+#include "nic.h"
+#include "nic_utils.h"
+#include "options.h"
+
+#define PFX	"bnx2 "
+
+/*  Foward struct declarations */
+struct nic_ops bnx2_op;
+
+/*  Determine is the CNIC kernel module is loaded or not */
+int lib_bnx2_loaded = 0;
+
+/*******************************************************************************
+ * NIC Library Strings
+ ******************************************************************************/
+static const char library_name[] = "bnx2";
+static const char library_version[] = PACKAGE_VERSION;
+static const char library_uio_name[] = "bnx2_cnic";
+
+/*  Template strings used to read RX parameters from sysfs */
+static const char cnic_sysfs_buf_size_template[] = "/sys/class/uio/uio%d/device/uio_buf_size";
+static const char cnic_sysfs_rx_ring_size_template[] = "/sys/class/uio/uio%d/device/uio_rx_ring_size";
+static const char cnic_sysfs_uio_event_template[] = "/sys/class/uio/uio%d/event";
+
+/*  The name that should be returned from /sys/class/uio/uio0/name */
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
+static const char cnic_uio_sysfs_name[] = "bnx2_cnic";
+
+/*******************************************************************************
+ * String constants used to display human readable adapter name
+ ******************************************************************************/
+static const char brcm_5706C[] = "Broadcom NetXtreme II BCM5706 1000Base-T";
+static const char hp_NC370T[]  = "HP NC370T Multifunction Gigabit Server Adapter";
+static const char hp_NC370I[]  = "HP NC370i Multifunction Gigabit Server Adapter";
+static const char brcm_5706S[] = "Broadcom NetXtreme II BCM5706 1000Base-SX";
+static const char hp_NC370F[]  = "HP NC370F Multifunction Gigabit Server Adapter";
+static const char brcm_5708C[] = "Broadcom NetXtreme II BCM5708 1000Base-T";
+static const char brcm_5708S[] = "Broadcom NetXtreme II BCM5708 1000Base-SX";
+static const char brcm_5709C[] = "Broadcom NetXtreme II BCM5709 1000Base-T";
+static const char brcm_5709S[] = "Broadcom NetXtreme II BCM5709 1000Base-SX";
+static const char brcm_5716C[] = "Broadcom NetXtreme II BCM5716 1000Base-T";
+static const char brcm_5716S[] = "Broadcom NetXtreme II BCM5716 1000Base-SX";
+
+/*******************************************************************************
+ * PCI ID constants
+ ******************************************************************************/
+#define PCI_VENDOR_ID_BROADCOM          0x14e4
+#define PCI_DEVICE_ID_NX2_5709          0x1639
+#define PCI_DEVICE_ID_NX2_5709S         0x163a
+#define PCI_DEVICE_ID_NX2_5706          0x164a
+#define PCI_DEVICE_ID_NX2_5708          0x164c
+#define PCI_DEVICE_ID_NX2_5706S         0x16aa
+#define PCI_DEVICE_ID_NX2_5708S         0x16ac
+
+#define PCI_VENDOR_ID_HP                0x103c
+
+#define PCI_ANY_ID (~0)
+
+/*  This is the table used to match PCI vendor and device ID's to the
+ *  human readable string names of the devices */
+static const struct pci_device_id bnx2_pci_tbl[] = {
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
+          PCI_VENDOR_ID_HP, 0x3101, hp_NC370T },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
+          PCI_VENDOR_ID_HP, 0x3106, hp_NC370I },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5706S },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5708C },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
+          PCI_VENDOR_ID_HP, 0x3102, hp_NC370F },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5706S },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5708S },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5709C },
+        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5709S },
+        { PCI_VENDOR_ID_BROADCOM, 0x163b,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5716C },
+        { PCI_VENDOR_ID_BROADCOM, 0x163c,
+          PCI_ANY_ID, PCI_ANY_ID, brcm_5716S },
+};
+
+/*******************************************************************************
+ * bnx2 Library Functions
+ ******************************************************************************/
+/**
+ *  bnx2_get_library_name() - Used to get the name of this NIC libary
+ *  @param name - This function will return the pointer to this NIC
+ *                library name
+ *  @param name_size
+ */
+static void bnx2_get_library_name(char **name,
+				  size_t *name_size)
+{
+	*name = (char *)library_name;
+	*name_size = sizeof(library_name);
+}
+
+/**
+ *  bnx2_get_library_version() - Used to get the version string of this
+ *                               NIC libary
+ *  @param version - This function will return the pointer to this NIC
+ *                   library version string
+ *  @param version_size - This will be set with the version size 
+ */
+static void bnx2_get_library_version(char **version,
+				     size_t *version_size)
+{
+	*version = (char *) library_version;
+	*version_size = sizeof(library_version);
+}
+
+/**
+ *  bnx2_get_build_date() - Used to get the build date string of this library
+ *  @param version - This function will return the pointer to this NIC
+ *                   library build date string
+ *  @param version_size - This will be set with the build date string size 
+ */
+static void bnx2_get_build_date(char **build,
+				size_t *build_size)
+{
+	*build = (char *) build_date;
+	*build_size = sizeof(build_date);
+}
+
+/**
+ *  bnx2_get_transport_name() - Used to get the transport name associated
+ *                              with this this NIC libary
+ *  @param transport_name - This function will return the pointer to this NIC
+ *                          library's associated transport string
+ *  @param transport_name_size - This will be set with the transport name size
+ */
+static void bnx2_get_transport_name(char **transport_name,
+		  	  	    size_t *transport_name_size)
+{
+	*transport_name = (char *) bnx2i_library_transport_name;
+	*transport_name_size = bnx2i_library_transport_name_size;
+}
+
+/**
+ *  bnx2_get_uio_name() - Used to get the uio name associated with this this 
+ *                        NIC libary
+ *  @param uio_name - This function will return the pointer to this NIC
+ *                    library's associated uio string
+ *  @param transport_name_size - This will be set with the uio name size
+ */
+static void bnx2_get_uio_name(char **uio_name,
+			      size_t *uio_name_size)
+{
+	*uio_name = (char *) library_uio_name;
+	*uio_name_size = sizeof(library_uio_name);
+}
+
+/**
+ *  bnx2_get_pci_table() - Used to get the PCI table for this NIC libary
+ *  			   to determine which NIC's based off of PCI ID's
+ *  			   are supported
+ *  @param table - This function will return the pointer to the PCI table
+ *  @param entries - This function will return the number of entries in the NIC
+ *                   library's PCI table
+ */
+static void bnx2_get_pci_table(struct pci_device_id **table,
+			       uint32_t *entries)
+{
+	*table = (struct pci_device_id *) bnx2_pci_tbl;
+	*entries = (uint32_t) (sizeof(bnx2_pci_tbl)/sizeof(bnx2_pci_tbl[0]));
+}
+
+/**
+ *  bnx2_get_ops() - Used to get the NIC library op table
+ *  @param op - The op table of this NIC library
+ */
+struct nic_ops * bnx2_get_ops()
+{
+	return &bnx2_op;
+}
+
+/*******************************************************************************
+ * bnx2 Utility Functions
+ ******************************************************************************/
+/*******************************************************************************
+ * Utility Functions Used to read register from the CNIC device
+ ******************************************************************************/
+static void bnx2_wr32(bnx2_t *bp, __u32 off, __u32 val)
+{
+	*((volatile __u32 *)(bp->reg + off)) = val;
+}
+
+static void bnx2_wr16(bnx2_t *bp, __u32 off, __u16 val)
+{
+	*((volatile __u16 *)(bp->reg + off)) = val;
+}
+
+static __u32 bnx2_rd32(bnx2_t *bp, __u32 off)
+{
+	return *((volatile __u32 *)(bp->reg + off));
+}
+
+static int bnx2_reg_sync(bnx2_t *bp, __u32 off, __u16 length)
+{
+	return msync(bp->reg + off, length, MS_SYNC);
+}
+
+/**
+ * bnx2_get_chip_id() - Used to retrive the chip ID from the nic
+ * @param dev - Device used to determin NIC type
+ * @return Chip ID read from the MISC ID register
+ */
+static int bnx2_get_chip_id(bnx2_t *bp)
+{
+	return bnx2_rd32(bp, BNX2_MISC_ID);
+}
+
+/**
+ *  bnx2_uio_verify()
+ *
+ */
+static int bnx2_uio_verify(nic_t *nic)
+{
+        char *raw = NULL, *raw_tmp;
+	uint32_t raw_size = 0;
+	char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
+	int rc = 0;
+
+	/*  Build the path to determine uio name */
+	snprintf(temp_path, sizeof(temp_path),
+		 cnic_uio_sysfs_name_tempate, nic->uio_minor);
+
+        rc = capture_file(&raw, &raw_size, temp_path);
+        if(rc != 0)
+        {
+                goto error;
+        }
+
+	/* sanitize name string by replacing newline with null termination */
+	raw_tmp = raw;
+	while(*raw_tmp != '\n')
+		raw_tmp++;
+	*raw_tmp = '\0';
+
+	if (strncmp(raw, cnic_uio_sysfs_name,
+		    sizeof(cnic_uio_sysfs_name)) != 0) {
+		LOG_ERR(PFX "%s: uio names not equal: "
+		            "expecting %s got %s from %s",
+			nic->log_name, cnic_uio_sysfs_name, raw, temp_path);
+		rc = -EIO;
+	}
+
+	free(raw);
+
+	LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
+
+      error:
+	return rc;
+}
+
+/*******************************************************************************
+ * bnx2 Utility Functions to get to the hardware consumer indexes
+ ******************************************************************************/
+static __u16 bnx2_get_rx_msix(bnx2_t *bp)
+{
+	struct status_block_msix *sblk = bp->status_blk.msix;
+	__u16 rx_cons;
+
+	msync(sblk, sizeof(*sblk), MS_SYNC);
+	rx_cons = sblk->status_rx_quick_consumer_index;
+	if ((rx_cons & (MAX_RX_DESC_CNT)) == (MAX_RX_DESC_CNT))
+		rx_cons++;
+
+	return rx_cons;
+}
+
+static __u16 bnx2_get_rx_msi(bnx2_t *bp)
+{
+	struct status_block *sblk = bp->status_blk.msi;
+	__u16 rx_cons;
+
+	msync(sblk, sizeof(*sblk), MS_SYNC);
+	rx_cons = CNIC_SBLK_EVEN_IDX(sblk->rx2);
+	if ((rx_cons & (MAX_RX_DESC_CNT)) == (MAX_RX_DESC_CNT))
+		rx_cons++;
+
+	return rx_cons;
+}
+
+static __u16 bnx2_get_tx_msix(bnx2_t *bp)
+{
+        struct status_block_msix *sblk = bp->status_blk.msix;
+        __u16 tx_cons;
+
+	msync(sblk, sizeof(*sblk), MS_SYNC);
+        tx_cons = sblk->status_tx_quick_consumer_index;
+        if ((tx_cons & (MAX_TX_DESC_CNT)) == (MAX_TX_DESC_CNT))
+                tx_cons++;
+
+        return tx_cons;
+}
+
+static __u16 bnx2_get_tx_msi(bnx2_t *bp)
+{
+	struct status_block *sblk = bp->status_blk.msi;
+	__u16 tx_cons;
+
+	msync(sblk, sizeof(*sblk), MS_SYNC);
+	tx_cons = CNIC_SBLK_EVEN_IDX(sblk->tx2);
+	if ((tx_cons & (MAX_TX_DESC_CNT)) == (MAX_TX_DESC_CNT))
+		tx_cons++;
+
+	return tx_cons;
+}
+
+typedef enum {
+	CNIC_VLAN_STRIPPING_ENABLED = 1,
+	CNIC_VLAN_STRIPPING_DISABLED = 2,
+} CNIC_VLAN_STRIPPING_MODE;
+
+/**
+ *  bnx2_strip_vlan_enabled() - This will query the device to determine whether
+ *                              VLAN tag stripping is enabled or not
+ *  @param dev - device to check stripping or not
+ *  @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled
+ *           CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled
+ */
+static CNIC_VLAN_STRIPPING_MODE bnx2_strip_vlan_enabled(bnx2_t *bp)
+{
+	uint32_t val;
+
+	val = bnx2_rd32(bp, BNX2_EMAC_RX_MODE);
+
+	if(val & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)
+		return CNIC_VLAN_STRIPPING_DISABLED;
+	else
+		return CNIC_VLAN_STRIPPING_ENABLED;
+}
+
+/**
+ *  bnx2_alloc() - Used to allocate a CNIC structure
+ */
+static bnx2_t * bnx2_alloc(nic_t *nic)
+{
+	bnx2_t *bp = malloc(sizeof(*bp));
+	if(bp == NULL)
+	{
+		LOG_ERR(PFX "%s: Could not allocate CNIC space",
+			nic->log_name);
+		return NULL;
+	}
+
+	/*  Clear out the CNIC contents */
+	memset(bp, 0, sizeof(*bp));
+
+	bp->flags = CNIC_UIO_TX_HAS_SENT;
+
+	bp->parent = nic;
+	nic->priv = (void *) bp;
+
+	return bp;
+}
+
+/**
+ * bnx2_open() - This will initialize all the hardware resources 
+ * @param dev - The struct nic device to open
+ * @return 0 on success, on failure a errno will be returned
+ */
+static int bnx2_open(nic_t *nic)
+{
+	bnx2_t *bp; 
+	struct stat uio_stat;
+	int i, rc;
+	__u32 val;
+	uint32_t tx_cid;
+	__u32 msix_vector = 0;
+
+	/*  Sanity Check: validate the parameters */
+	if(nic == NULL) {
+		LOG_ERR(PFX "bnx2_open(): nic == NULL");
+		return -EINVAL;
+	}
+
+	bp = bnx2_alloc(nic);
+	if(bp == NULL)
+		return -ENOMEM;
+
+	while(nic->fd < 0) {
+		nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK);
+		if (nic->fd != INVALID_FD) {
+			LOG_ERR(PFX "%s: uio device has been brought up via pid: %d on fd: %d",
+				nic->uio_device_name, getpid(), nic->fd);
+
+			rc = bnx2_uio_verify(nic);
+			if(rc != 0)
+				continue;
+
+			break;
+		} else {
+			if( lib_bnx2_loaded == 0) {
+				LOG_ERR(PFX "%s: Could not open device: %s, "
+					    "awaiting for the device to appear",
+					nic->log_name, nic->uio_device_name);
+		
+				/*  Time to wait for the device to come up */
+				pthread_mutex_lock(&nic->uio_wait_mutex);
+				pthread_cond_wait(&nic->uio_wait_cond,
+						  &nic->uio_wait_mutex);
+				pthread_mutex_unlock(&nic->uio_wait_mutex);
+
+				/*  udev might not have created the file yet */
+				sleep(2);
+
+				lib_bnx2_loaded = 1;
+			} else {
+				/*  udev might not have created the file yet */
+				sleep(2);
+			}
+		}
+	}
+	if (fstat(nic->fd, &uio_stat) < 0) {
+		LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
+		return -ENODEV;
+	}
+	nic->uio_minor = minor(uio_stat.st_rdev);
+
+	/*  TODO: hardcoded with the cnic driver */
+	bp->rx_ring_size = 3;
+	bp->rx_buffer_size = 0x400;
+
+	LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
+		  nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
+
+	/*  Determine the number of UIO events that have already occured */
+	rc = detemine_initial_uio_events(nic, &nic->intr_count);
+	if(rc != 0) {
+		LOG_ERR("Could not determine the number ofinitial UIO events");
+		nic->intr_count = 0;
+	}
+
+	/*  Allocate space for rx ring pointer */
+	bp->rx_ring = malloc(sizeof(struct l2_fhdr *) * bp->rx_ring_size);
+	if(bp->rx_ring == NULL)
+	{
+		LOG_ERR(PFX "%s: Could not allocate space for rx_ring",
+			nic->log_name);
+		goto error_alloc_rx_ring;
+	}
+	mlock(bp->rx_ring, sizeof(struct l2_fhdr *) * bp->rx_ring_size);
+
+	/*  Allocate space for rx pkt ring */
+	bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
+	if(bp->rx_pkt_ring == NULL)
+	{
+		LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
+			nic->log_name);
+		goto error_alloc_rx_pkt_ring;
+	}
+	mlock(bp->rx_pkt_ring, sizeof(void *) * bp->rx_ring_size);
+
+	bp->reg = mmap(NULL, 0x12800, PROT_READ | PROT_WRITE, MAP_SHARED,
+			 nic->fd, (off_t) 0);
+	if (bp->reg == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Couldn't mmap registers: %s",
+			 nic->log_name, strerror(errno));
+		bp->reg = NULL;
+		goto error_regs;
+	}
+
+	msync(bp->reg, 0x12800, MS_SYNC);
+	LOG_DEBUG(PFX "Chip ID: %x", bnx2_get_chip_id(bp));
+
+	/*  on a 5709 when using MSI-X the status block is at an offset */
+	if(CHIP_NUM(bnx2_get_chip_id(bp)) == CHIP_NUM_5709) {
+		/*  determine if we are using MSI-X */
+		val = bnx2_rd32(bp, BNX2_TSCH_TSS_CFG);
+		if(val) {
+			/*  We are in MSI-X mode */
+			uint32_t base_cid = ((val >> 10) & 0x7ff) << 3;
+			msix_vector = (val >> 24) & 0xf;
+
+			bp->status_blk_size = (128 * 9);
+
+			tx_cid = base_cid + msix_vector - 1;
+			bp->flags |= CNIC_UIO_MSIX_ENABLED;
+
+			bp->get_tx_cons  = bnx2_get_tx_msix;
+			bp->get_rx_cons  = bnx2_get_rx_msix;
+
+			LOG_DEBUG(PFX "%s: tss_cfg: 0x%x tx cid: %d",
+				  nic->log_name, val, tx_cid);
+
+			LOG_INFO(PFX "%s: detected using MSI-X vector: %d",
+				 nic->log_name, msix_vector);
+		} else {
+			/*  We are not in MSI-X mode */
+			bp->status_blk_size = 64;
+			tx_cid = 20;
+
+			bp->get_tx_cons  = bnx2_get_tx_msi;
+			bp->get_rx_cons  = bnx2_get_rx_msi;
+		}
+	} else {
+		bp->status_blk_size = 64;
+		tx_cid = 20;
+
+		bp->get_tx_cons  = bnx2_get_tx_msi;
+		bp->get_rx_cons  = bnx2_get_rx_msi;
+	}
+
+	bp->sblk_map = mmap(NULL, bp->status_blk_size,
+		 	     PROT_READ | PROT_WRITE, MAP_SHARED,
+			     nic->fd, (off_t) getpagesize());
+	if (bp->sblk_map == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Could not mmap status block: %s",
+			 nic->log_name, strerror(errno));
+		goto error_sblk;
+	}
+
+	if(bp->flags & CNIC_UIO_MSIX_ENABLED) {
+		uint8_t *status_blk =  (uint8_t *) bp->sblk_map;
+		status_blk += (msix_vector * 128);
+
+		bp->status_blk.msix = (struct status_block_msix *) status_blk;
+
+		LOG_DEBUG(PFX "%s: msix initial cons: tx:%d rx:%d",
+				nic->log_name,
+			bp->status_blk.msix->status_tx_quick_consumer_index,
+			bp->status_blk.msix->status_rx_quick_consumer_index);
+	} else {
+		bp->status_blk.msi = (struct status_block *) bp->sblk_map;
+
+		LOG_DEBUG(PFX "%s: msi initial tx:%d rx:%d",
+			  nic->log_name,
+			  CNIC_SBLK_EVEN_IDX(bp->status_blk.msi->tx2),
+			  CNIC_SBLK_EVEN_IDX(bp->status_blk.msi->rx2));
+	}
+
+	bp->tx_ring = mmap(NULL, 2 * getpagesize(),
+			    PROT_READ | PROT_WRITE, MAP_SHARED, nic->fd,
+			    (off_t) 2 * getpagesize());
+	if (bp->tx_ring == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Could not mmap tx ring: %s",
+			 nic->log_name, strerror(errno));
+		bp->tx_ring = NULL;
+		goto error_tx_ring;
+	}
+
+	bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
+			 PROT_READ | PROT_WRITE,
+			 MAP_SHARED, nic->fd, (off_t) 3 * getpagesize());
+	if (bp->bufs == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Could not mmap buffers: %s",
+			 nic->log_name, strerror(errno));
+		bp->bufs = NULL;
+		goto error_bufs;
+	}
+
+	bp->tx_bidx_io = MB_GET_CID_ADDR(tx_cid) + BNX2_L2CTX_TX_HOST_BIDX;
+	bp->tx_bseq_io = MB_GET_CID_ADDR(tx_cid) + BNX2_L2CTX_TX_HOST_BSEQ;
+	LOG_INFO(PFX "%s: tx_bidx_io: 0x%x tx_bseq_io: 0x%x",
+		 nic->log_name,
+		 bp->tx_bidx_io, bp->tx_bseq_io);
+
+	bp->rx_bidx_io = MB_GET_CID_ADDR(2) + BNX2_L2CTX_HOST_BDIDX;
+	bp->rx_bseq_io = MB_GET_CID_ADDR(2) + BNX2_L2CTX_HOST_BSEQ;
+
+	bp->tx_cons = 0;
+	bp->tx_prod = 0;
+	bp->tx_pkt = bp->bufs;
+
+	bp->rx_index = 0;
+	bp->rx_cons = 0;
+	bp->rx_prod = bp->rx_ring_size;
+	bp->rx_bseq = bp->rx_prod * bp->rx_buffer_size;
+	bnx2_wr16(bp, bp->rx_bidx_io, bp->rx_prod);
+	bnx2_wr32(bp, bp->rx_bseq_io, bp->rx_bseq);
+
+	bnx2_reg_sync(bp, bp->rx_bidx_io, sizeof(__u16));
+	bnx2_reg_sync(bp, bp->rx_bseq_io, sizeof(__u32));
+
+	for (i = 0; i < bp->rx_ring_size; i++) {
+		void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
+
+		bp->rx_ring[i] = (struct l2_fhdr *)ptr;
+		bp->rx_pkt_ring[i] = ptr + sizeof(struct l2_fhdr) + 2;
+	}
+
+	/*  Read the MAC address used for the iSCSI interface */
+	val = bnx2_rd32(bp, BNX2_EMAC_MAC_MATCH4);
+	nic->mac_addr[0] = (__u8) (val >> 8);
+	nic->mac_addr[1] = (__u8) val;
+
+	val = bnx2_rd32(bp, BNX2_EMAC_MAC_MATCH5);
+	nic->mac_addr[2] = (__u8) (val >> 24);
+	nic->mac_addr[3] = (__u8) (val >> 16);
+	nic->mac_addr[4] = (__u8) (val >> 8);
+	nic->mac_addr[5] = (__u8) val;
+
+	LOG_INFO(PFX "%s:  Using mac address: %2x:%2x:%2x:%2x:%2x:%2x",
+		 nic->log_name,
+		 nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
+		 nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
+
+	/*  Determine if Hardware VLAN tag stripping is enabled or not */
+	if(CNIC_VLAN_STRIPPING_ENABLED == bnx2_strip_vlan_enabled(bp))
+	{
+		nic->flags |= NIC_VLAN_STRIP_ENABLED;
+	}
+
+	/*  Prepare the multicast addresses */
+	rc = enable_multicast(nic);
+	if(rc != 0)
+		goto error_bufs;
+
+	msync(bp->reg, 0x12800, MS_SYNC);
+	LOG_INFO("%s: CNIC uio initialized", nic->log_name);
+
+	return 0;
+
+      error_bufs:
+	munmap(bp->tx_ring, 2 * getpagesize());
+
+      error_tx_ring:
+	munmap(bp->status_blk.msi, bp->status_blk_size);
+
+      error_sblk:
+	munmap(bp->reg, 0x12800);
+
+      error_regs:
+	munlock(bp->rx_pkt_ring, sizeof(void *) * bp->rx_ring_size);
+	free(bp->rx_pkt_ring);
+	bp->rx_pkt_ring = NULL;
+
+      error_alloc_rx_pkt_ring:
+	munlock(bp->rx_ring, sizeof(struct l2_fhdr *) * bp->rx_ring_size);
+	free(bp->rx_ring);
+	bp->rx_ring = NULL;
+
+      error_alloc_rx_ring:
+
+	return errno;
+}
+
+/**
+ *  bnx2_uio_close_resources() - Used to free resource for the NIC/CNIC
+ *  @param nic - NIC device to free resource
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 on success, <0 on failure
+ */
+static int bnx2_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+	int rc = 0;
+
+	/*  Remove the multicast addresses if added */
+	if((nic->flags & NIC_ADDED_MULICAST) &&
+	   (graceful == ALLOW_GRACEFUL_SHUTDOWN))
+		disable_multicast(nic);
+
+	/*  Check if there is an assoicated CNIC device */
+	if(bp == NULL) {
+		LOG_WARN(PFX "%s: when closing resources there is "
+		             "no assoicated bnx2",
+			     nic->log_name);
+		return -EIO;
+	}
+
+	/*  Clean up allocated memory */
+	if(bp->rx_ring != NULL) {
+		free(bp->rx_ring);
+		bp->rx_ring = NULL;
+	}
+
+	if(bp->rx_pkt_ring != NULL) {
+		free(bp->rx_pkt_ring);
+		bp->rx_pkt_ring = NULL;
+	}
+
+	/*  Clean up mapped registers */
+	if (bp->bufs != NULL) {
+		rc = munmap(bp->bufs,
+			    (bp->rx_ring_size + 1) * bp->rx_buffer_size);
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap bufs",
+				 nic->log_name);
+		bp->bufs = NULL;
+	}
+
+	if (bp->tx_ring != NULL) {
+		rc = munmap(bp->tx_ring, 2 * getpagesize());
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap tx_rings",
+				 nic->log_name);
+		bp->tx_ring = NULL;
+	}
+
+	if (bp->status_blk.msix != NULL || 
+	    bp->status_blk.msi  != NULL) {
+		rc = munmap(bp->sblk_map, bp->status_blk_size);
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap status block",
+				 nic->log_name);
+		bp->sblk_map = NULL;
+
+		bp->status_blk.msix = NULL;
+		bp->status_blk.msi = NULL;
+	}
+
+	if (bp->reg != NULL) {
+		rc = munmap(bp->reg, 0x12800);
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap regs",
+				 nic->log_name);
+		bp->reg = NULL;
+	}
+
+	if (nic->fd != INVALID_FD) {
+		rc = close(nic->fd);
+		if (rc != 0) {
+			LOG_WARN(PFX "%s: Couldn't close uio file descriptor: %d",
+				 nic->log_name, nic->fd);
+		} else {
+			LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
+				 nic->log_name, nic->fd);
+		}
+
+		nic->fd = INVALID_FD;
+	} else {
+		LOG_WARN(PFX "%s: Invalid uio file descriptor: %d",
+				 nic->log_name, nic->fd);
+	}
+
+	LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
+
+	return 0;
+}
+
+/**
+ *  bnx2_close() - Used to close the NIC device
+ *  @param nic - NIC device to close
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 if successful, <0 if there is an error
+ */
+static int bnx2_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+	/*  Sanity Check: validate the parameters */
+	if(nic == NULL) {
+		LOG_ERR(PFX "bnx2_close(): nic == NULL");
+		return -EINVAL;
+	}
+
+	LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
+
+	bnx2_uio_close_resources(nic, graceful);
+
+	/*  Free any named strings we might be holding onto */
+	if(nic->flags & NIC_CONFIG_NAME_MALLOC) {
+		free(nic->config_device_name);
+		nic->flags &= ~NIC_CONFIG_NAME_MALLOC;
+	}
+	nic->config_device_name = NULL;
+
+	if(nic->flags & NIC_UIO_NAME_MALLOC) {
+		free(nic->uio_device_name);
+		nic->uio_device_name = NULL;
+
+		nic->flags &= ~NIC_UIO_NAME_MALLOC;
+	}
+
+	return 0;
+}
+
+static void bnx2_prepare_xmit_packet(nic_t *nic,
+				     nic_interface_t *nic_iface,
+				     struct packet *pkt)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+
+	/*  Determine if we need to insert the VLAN tag */
+	if((nic_iface->vlan_id != 0) && 
+	   (NIC_VLAN_STRIP_ENABLED & nic->flags))
+	{
+		uint16_t insert_tpid = const_htons(UIP_ETHTYPE_8021Q);
+		uint16_t insert_vlan_id = htons((0x0FFF & nic_iface->vlan_id) +
+			((0x000F & nic_iface->vlan_priority) << 12));
+
+		/* We need to reinsert the VLAN tag */
+		memcpy(bp->tx_pkt, pkt->buf, 12);
+		memcpy(bp->tx_pkt + 12, &insert_tpid, 2);
+		memcpy(bp->tx_pkt + 14, &insert_vlan_id, 2);
+		memcpy(bp->tx_pkt + 16, pkt->buf + 12, pkt->buf_size - 12);
+
+		pkt->buf_size = pkt->buf_size +4;
+
+		LOG_DEBUG(PFX "%s: Inserted vlan tag id: 0x%x",
+			  nic->log_name,
+			  ntohs(insert_vlan_id));
+	} else {
+		memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
+	}
+
+	msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
+}
+
+/**
+ *  bnx2_get_tx_pkt() - This function is used to a TX packet from the NIC
+ *  @param nic - The NIC device to send the packet
+ *
+ */
+void * bnx2_get_tx_pkt(nic_t *nic)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+	return bp->tx_pkt;
+}
+
+/**
+ *  bnx2_start_xmit() - This function is used to send a packet of data
+ *  @param nic - The NIC device to send the packet
+ *  @param len - the length of the TX packet
+ *
+ */
+void bnx2_start_xmit(nic_t *nic, size_t len)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+	uint16_t ring_prod;
+	struct tx_bd *txbd;
+
+	ring_prod = TX_RING_IDX(bp->tx_prod);
+	txbd = &bp->tx_ring[ring_prod];
+
+	txbd->tx_bd_mss_nbytes = len;
+	txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_END | TX_BD_FLAGS_START;
+
+	bp->tx_bseq += len;
+	bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
+
+	bnx2_wr16(bp, bp->tx_bidx_io, bp->tx_prod);
+	bnx2_wr32(bp, bp->tx_bseq_io, bp->tx_bseq);
+
+	bnx2_reg_sync(bp, bp->tx_bidx_io, sizeof(__u16));
+	bnx2_reg_sync(bp, bp->tx_bseq_io, sizeof(__u32));
+
+	LOG_DEBUG(PFX "%s: sent %d bytes using dev->tx_prod: %d",
+		      nic->log_name, len, bp->tx_prod);
+}
+
+/**
+ *  bnx2_write() - Used to write the data to the hardware
+ *  @param nic - NIC hardware to read from
+ *  @param pkt - The packet which will hold the data to be sent on the wire
+ *  @return 0 if successful, <0 if failed
+ */
+int bnx2_write(nic_t *nic, nic_interface_t *nic_iface,
+		packet_t *pkt)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+	struct uip_stack *uip = &nic_iface->ustack;
+
+	/* Sanity Check: validate the parameters */
+	if(nic == NULL || nic_iface == NULL || pkt == NULL) {
+		LOG_ERR(PFX "%s: bnx2_write() nic == 0x%p || "
+			    " nic_iface == 0x%p || "
+			    " pkt == 0x%x", nic, nic_iface, pkt);
+		return -EINVAL;
+	}
+
+	if(pkt->buf_size == 0) {
+		LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet",
+			nic->log_name);
+		return -EINVAL;
+	}
+
+	if(pthread_mutex_trylock(&nic->xmit_mutex) != 0)
+	{
+		LOG_ERR(PFX "%s: Dropped previous transmitted packet",
+			nic->log_name);
+		return -EINVAL;
+	}
+
+	bnx2_prepare_xmit_packet(nic, nic_iface,
+				 pkt);
+	bnx2_start_xmit(nic, pkt->buf_size);
+
+	/*  bump the bnx2 dev send statistics */
+	nic->stats.tx.packets++;
+	nic->stats.tx.bytes += uip->uip_len;
+
+	LOG_DEBUG(PFX "%s: transmitted %d bytes "
+		      "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bseq:%d",
+		  nic->log_name, pkt->buf_size,
+		  bp->tx_cons, bp->tx_prod, bp->tx_bseq);
+
+	return 0;
+}
+
+/**
+ *  bnx2_read() - Used to read the data from the hardware
+ *  @param nic - NIC hardware to read from
+ *  @param pkt - The packet which will hold the data
+ *  @return 0 if successful, <0 if failed
+ */
+static int bnx2_read(nic_t *nic, packet_t *pkt)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+	int rc = 0;
+	uint16_t hw_cons, sw_cons;
+
+	/* Sanity Check: validate the parameters */
+	if(nic == NULL || pkt == NULL) {
+		LOG_ERR(PFX "%s: bnx2_write() nic == 0x%p || "
+			    " pkt == 0x%x", nic, pkt);
+		return -EINVAL;
+	}
+
+	hw_cons = bp->get_rx_cons(bp);
+	sw_cons = bp->rx_cons;
+
+	if (sw_cons != hw_cons) {
+		uint8_t rx_index = bp->rx_index % 3;
+		struct l2_fhdr *rx_hdr = bp->rx_ring[rx_index];
+		void *rx_pkt = bp->rx_pkt_ring[rx_index];
+		int len;
+		uint16_t errors;
+	
+		LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d",
+			  nic->log_name,
+			  sw_cons, hw_cons);
+
+		msync(rx_hdr, sizeof(struct l2_fhdr), MS_SYNC); 
+		errors = ((rx_hdr->l2_fhdr_status & 0xffff0000) >> 16);
+		len = ((rx_hdr->l2_fhdr_vtag_len & 0xffff0000) >> 16) - 4;
+
+		/*  Doto query MTU size of physical device */
+		/*  Ensure len is valid */
+		if(len > pkt->max_buf_size)
+			LOG_DEBUG(PFX "%s: bad BD length: %d",
+				  nic->log_name, len);
+
+		if ((errors == 0) && (len > 0)) {
+			msync(rx_pkt, len, MS_SYNC); 
+			/*  Copy the data */
+			memcpy(pkt->buf, rx_pkt, len);
+			pkt->buf_size = len;
+
+			/*  Properly set the packet flags */
+			/*  check if there is VLAN tagging on the packet */
+			if(rx_hdr->l2_fhdr_status & L2_FHDR_STATUS_VLAN_TAG) {
+				pkt->vlan_tag = rx_hdr->l2_fhdr_vtag_len & 0x0FFF;
+				pkt->flags |= VLAN_TAGGED;
+			} else {
+				pkt->vlan_tag = 0;
+			}
+
+			rc = 1;
+
+			LOG_DEBUG(PFX "%s: processing packet length: %d",
+				  nic->log_name, len);
+		} else {
+			/*  One of the fields in the BD is bad */
+			uint16_t status = ((rx_hdr->l2_fhdr_status & 0x0000ffff));
+
+			LOG_ERR(PFX "%s: Recv error: %x status: %x len: %d",
+				nic->log_name,
+				errors, status, len);
+
+			rc = 0;
+		}
+
+		bp->rx_index++;
+		sw_cons = NEXT_RX_BD(sw_cons);
+		bp->rx_prod = NEXT_RX_BD(bp->rx_prod);
+		bp->rx_bseq += 0x400;
+
+		bp->rx_cons = sw_cons;
+		bnx2_wr16(bp, bp->rx_bidx_io, bp->rx_prod);
+		bnx2_wr32(bp, bp->rx_bseq_io, bp->rx_bseq);
+
+		bnx2_reg_sync(bp, bp->rx_bidx_io, sizeof(__u16));
+		bnx2_reg_sync(bp, bp->rx_bseq_io, sizeof(__u32));
+
+		/*  bump the bnx2 dev recv statistics */
+		nic->stats.rx.packets++;
+		nic->stats.rx.bytes += pkt->buf_size;
+	}
+
+	return rc;
+}
+/*******************************************************************************
+ * Clearing TX interrupts
+ ******************************************************************************/
+/**
+ *  bnx2_clear_tx_intr() - This routine is called when a TX interrupt occurs
+ *  @param nic - the nic the interrupt occured on
+ *  @return  0 on success
+ */
+static int bnx2_clear_tx_intr(nic_t *nic)
+{
+	bnx2_t *bp = (bnx2_t *) nic->priv;
+	uint16_t hw_cons = bp->get_tx_cons(bp);
+
+	/* Sanity check: ensure the parameters passed in are valid */
+	if(unlikely(nic == NULL)) {
+		LOG_ERR(PFX "bnx2_read() nic == NULL");
+		return -EINVAL;
+	}
+
+	if(bp->flags & CNIC_UIO_TX_HAS_SENT) {
+		bp->flags &= ~CNIC_UIO_TX_HAS_SENT;
+		pthread_mutex_unlock(&nic->xmit_mutex);
+		return 0;
+	}
+
+	if(bp->tx_cons == hw_cons)
+		return 0;
+
+	LOG_DEBUG(PFX "%s: clearing tx interrupt [%d %d]",
+		  nic->log_name,
+		  bp->tx_cons, hw_cons);
+	bp->tx_cons = hw_cons;
+
+	/*  There is a queued TX packet that needs to be sent out.  The usual
+	 *  case is when stack will send an ARP packet out before sending the
+	 *  intended packet */
+	if(nic->tx_packet_queue != NULL)
+	{
+		packet_t *pkt;
+
+		LOG_DEBUG(PFX "%s: sending queued tx packet", nic->log_name);
+		pkt = nic_dequeue_tx_packet(nic);
+
+		/*  Got a TX packet buffer of the TX queue and put it onto
+		 *  the hardware */
+		if(pkt != NULL)
+		{
+			bnx2_prepare_xmit_packet(nic,
+						 pkt->nic_iface,
+						 pkt);
+
+			bnx2_start_xmit(nic, pkt->buf_size);
+
+			LOG_DEBUG(PFX "%s: transmitted queued packet %d bytes "
+				      "dev->tx_cons: %d, dev->tx_prod: %d, "
+				      "dev->tx_bseq:%d",
+					  nic->log_name, pkt->buf_size,
+					  bp->tx_cons, bp->tx_prod,
+					  bp->tx_bseq);
+
+			return 0;
+		}
+	}
+
+	pthread_mutex_unlock(&nic->xmit_mutex);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * bnx2 NIC op's table
+ ******************************************************************************/
+struct nic_ops bnx2_op = {
+	.description	= "bnx2",
+	.open		= bnx2_open,
+	.close		= bnx2_close,
+	.write		= bnx2_write,
+	.get_tx_pkt	= bnx2_get_tx_pkt,
+	.start_xmit	= bnx2_start_xmit,
+	.read		= bnx2_read,
+	.clear_tx_intr	= bnx2_clear_tx_intr,
+	.handle_iscsi_path_req = cnic_handle_iscsi_path_req,
+
+	.lib_ops = {
+		.get_library_name	= bnx2_get_library_name,
+        	.get_pci_table		= bnx2_get_pci_table,
+	        .get_library_version	= bnx2_get_library_version,
+		.get_build_date		= bnx2_get_build_date,
+	        .get_transport_name	= bnx2_get_transport_name,
+	        .get_uio_name		= bnx2_get_uio_name,
+	},
+};
diff --git a/brcm_iscsi_uio/src/unix/libs/bnx2.h b/brcm_iscsi_uio/src/unix/libs/bnx2.h
new file mode 100644
index 0000000..fe3af31
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/bnx2.h
@@ -0,0 +1,273 @@
+/* cnic.h: CNIC user space driver
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __CNIC_H__
+#define __CNIC_H__
+
+#include "nic.h"
+
+/******************************************************************************
+ *  Default CNIC values
+ ******************************************************************************/
+#define DEFAULT_NUM_RXBD	3
+#define DEFAULT_RX_LEN		0x400
+
+
+/******************************************************************************
+ *  CNIC Hardware structures
+ ******************************************************************************/
+/* status_block definition for MSI */
+struct status_block {
+	volatile __u32 status_attn_bits;
+	volatile __u32 status_attn_bits_ack;
+	volatile __u32 tx0;
+	volatile __u32 tx2;
+	volatile __u32 rx0;
+	volatile __u32 rx2;
+	volatile __u32 rx4;
+	volatile __u32 rx6;
+	volatile __u32 rx8;
+	volatile __u32 rx10;
+	volatile __u32 rx12;
+	volatile __u32 rx14;
+	volatile __u32 cmd;
+	volatile __u32 idx;
+};
+
+/* status_block definition for MSI-X */
+struct status_block_msix { 
+#if 0
+#if defined(__BIG_ENDIAN)
+	__u16 status_tx_quick_consumer_index;
+	__u16 status_rx_quick_consumer_index;
+	__u16 status_completion_producer_index;
+	__u16 status_cmd_consumer_index;
+	__u32 status_unused;
+	__u16 status_idx;
+	__u8 status_unused2;
+	__u8 status_blk_num;
+#elif defined(__LITTLE_ENDIAN) 
+	__u16 status_rx_quick_consumer_index;
+	__u16 status_tx_quick_consumer_index;
+	__u16 status_cmd_consumer_index;
+	__u16 status_completion_producer_index;
+	__u32 status_unused;
+	__u8 status_blk_num;
+	__u8 status_unused2;
+	__u16 status_idx;
+#endif
+#endif
+	__u16 status_rx_quick_consumer_index;
+	__u16 status_tx_quick_consumer_index;
+	__u16 status_cmd_consumer_index;
+	__u16 status_completion_producer_index;
+	__u32 status_unused;
+	__u8 status_blk_num;
+	__u8 status_unused2;
+	__u16 status_idx;
+};
+
+/*  TX Buffer descriptor */
+struct tx_bd {
+	__u32 tx_bd_haddr_hi;
+	__u32 tx_bd_haddr_lo;
+	__u32 tx_bd_mss_nbytes;
+	__u32 tx_bd_vlan_tag_flags;
+		#define TX_BD_FLAGS_END			(1<<6)
+		#define TX_BD_FLAGS_START		(1<<7)
+};
+
+/*  RX Buffer descriptor */
+struct rx_bd {
+	__u32 rx_bd_haddr_hi;
+	__u32 rx_bd_haddr_lo;
+
+	__u32 rx_bd_len;
+	__u32 rx_bd_flags;
+#define RX_BD_FLAGS_END			(1<<2)
+#define RX_BD_FLAGS_START		(1<<3)
+
+};
+
+/*  This is the RX L2 Frame header */
+struct l2_fhdr {
+        __u32 l2_fhdr_status;
+	#define L2_FHDR_ERRORS_BAD_CRC          (1<<17)
+	#define L2_FHDR_ERRORS_PHY_DECODE       (1<<18)
+	#define L2_FHDR_ERRORS_ALIGNMENT        (1<<19)
+	#define L2_FHDR_ERRORS_TOO_SHORT        (1<<20)
+	#define L2_FHDR_ERRORS_GIANT_FRAME      (1<<21)
+	#define L2_FHDR_ERRORS_TCP_XSUM         (1<<28)
+	#define L2_FHDR_ERRORS_UDP_XSUM         (1<<31)
+
+	#define L2_FHDR_STATUS_UDP_DATAGRAM	(1<<15)
+	#define L2_FHDR_STATUS_TCP_DATAGRAM	(1<<14)
+	#define L2_FHDR_STATUS_IP_DATAGRAM	(1<<13)
+	#define L2_FHDR_STATUS_LLC_SNAP		(1<<7)
+	#define L2_FHDR_STATUS_VLAN_TAG		(1<<6)
+
+	__u32 l2_fhdr_hash;
+
+	__u32 l2_fhdr_vtag_len;
+	__u32 l2_fhdr_xsum;
+};
+
+/******************************************************************************
+ *  BNX2 Registers Defitions/Values
+ ******************************************************************************/
+#define BNX2_MISC_ID			0x00000808
+#define BNX2_EMAC_MAC_MATCH4		0x00001420
+#define BNX2_EMAC_MAC_MATCH5		0x00001424
+
+#define BNX2_EMAC_RX_MODE				0x000014c8
+#define BNX2_EMAC_RX_MODE_RESET				(1L<<0)
+#define BNX2_EMAC_RX_MODE_FLOW_EN			(1L<<2)
+#define BNX2_EMAC_RX_MODE_KEEP_MAC_CONTROL		(1L<<3)
+#define BNX2_EMAC_RX_MODE_KEEP_PAUSE			(1L<<4)
+#define BNX2_EMAC_RX_MODE_ACCEPT_OVERSIZE		(1L<<5)
+#define BNX2_EMAC_RX_MODE_ACCEPT_RUNTS			(1L<<6)
+#define BNX2_EMAC_RX_MODE_LLC_CHK			(1L<<7)
+#define BNX2_EMAC_RX_MODE_PROMISCUOUS			(1L<<8)
+#define BNX2_EMAC_RX_MODE_NO_CRC_CHK			(1L<<9)
+#define BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG			(1L<<10)
+#define BNX2_EMAC_RX_MODE_FILT_BROADCAST		(1L<<11)
+#define BNX2_EMAC_RX_MODE_SORT_MODE			(1L<<12)
+
+/*
+ * tsch_reg definition
+ * offset: 0x4c00
+ */
+#define BNX2_TSCH_TSS_CFG				0x00004c1c
+#define BNX2_TSCH_TSS_CFG_TSS_START_CID			(0x7ffL<<8)
+#define BNX2_TSCH_TSS_CFG_NUM_OF_TSS_CON		(0xfL<<24)
+#define CNIC_UIO_INVALID_FD	-1
+
+#define BNX2_L2CTX_TX_HOST_BIDX				0x00000088
+#define BNX2_L2CTX_TX_HOST_BSEQ				0x00000090
+
+#define BNX2_L2CTX_HOST_BDIDX				0x00000004
+#define BNX2_L2CTX_HOST_BSEQ				0x00000008
+
+/* Used to determin the CHIP ID */
+/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+#define CHIP_NUM(bp)                    ((bp) & 0xffff0000)
+#define CHIP_NUM_5706                   0x57060000
+#define CHIP_NUM_5708                   0x57080000
+#define CHIP_NUM_5709                   0x57090000
+
+#define CHIP_REV(bp)                    ((bp) & 0x0000f000)
+#define CHIP_REV_Ax                     0x00000000
+#define CHIP_REV_Bx                     0x00001000
+#define CHIP_REV_Cx                     0x00002000
+
+#define CHIP_METAL(bp)                  ((bp) & 0x00000ff0)
+#define CHIP_BONDING(bp)                ((bp) & 0x0000000f)
+
+#define CHIP_ID(bp)                     ((bp) & 0xfffffff0)
+#define CHIP_ID_5706_A0                 0x57060000
+#define CHIP_ID_5706_A1                 0x57060010
+#define CHIP_ID_5706_A2                 0x57060020
+#define CHIP_ID_5708_A0                 0x57080000
+#define CHIP_ID_5708_B0                 0x57081000
+#define CHIP_ID_5708_B1                 0x57081010
+#define CHIP_ID_5709_A0                 0x57090000
+#define CHIP_ID_5709_A1                 0x57090010
+
+#define CHIP_BOND_ID(bp)                ((bp) & 0xf)
+
+
+#define CNIC_SBLK_EVEN_IDX(x)	(((x) & 0xffff0000) >> 16)
+
+#define TX_DESC_CNT  (4096 / sizeof(struct tx_bd))
+#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
+
+#define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==			\
+		(MAX_TX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define TX_RING_IDX(x) ((x) & MAX_TX_DESC_CNT)
+
+
+#define RX_DESC_CNT  (4096 / sizeof(struct rx_bd))
+#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
+
+#define NEXT_RX_BD(x) (((x) & (MAX_RX_DESC_CNT - 1)) ==			\
+		(MAX_RX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define MB_KERNEL_CTX_SHIFT         8
+#define MB_KERNEL_CTX_SIZE          (1 << MB_KERNEL_CTX_SHIFT)
+#define MB_KERNEL_CTX_MASK          (MB_KERNEL_CTX_SIZE - 1)
+#define MB_GET_CID_ADDR(_cid)       (0x10000 + ((_cid) << MB_KERNEL_CTX_SHIFT))
+
+typedef struct bnx2 {
+	nic_t	*parent;
+
+	uint16_t   flags;
+#define CNIC_UIO_UNITIALIZED		0x0001
+#define CNIC_UIO_INITIALIZED		0x0002
+#define CNIC_UIO_ENABLED		0x0004
+#define CNIC_UIO_DISABLED		0x0008
+#define CNIC_UIO_IPv6_ENABLED		0x0010
+#define CNIC_UIO_ADDED_MULICAST		0x0020
+#define CNIC_UIO_MSIX_ENABLED		0x0200
+#define CNIC_UIO_TX_HAS_SENT		0x0400
+
+	void *reg;		/* Pointer to the mapped registers	*/
+
+	__u32 tx_bidx_io;
+	__u32 tx_bseq_io;
+
+	__u16 tx_prod;
+	__u16 tx_cons;
+	__u32 tx_bseq;
+
+	__u32 rx_bidx_io;
+	__u32 rx_bseq_io;
+
+	__u16 rx_prod;
+	__u16 rx_cons;
+	__u32 rx_bseq;
+
+	/*  RX ring parameters */
+	uint32_t rx_ring_size;
+	uint32_t rx_buffer_size;
+
+	void *bufs;		/* Pointer to the mapped buffer space	*/
+
+	/*  Hardware Status Block locations */
+	void *sblk_map;
+        union {
+		struct status_block             *msi;
+		struct status_block_msix        *msix;
+	} status_blk;
+	size_t status_blk_size;
+
+	__u16 (*get_rx_cons)(struct bnx2 *);
+	__u16 (*get_tx_cons)(struct bnx2 *);
+
+	uint16_t rx_index;
+	struct l2_fhdr **rx_ring;
+	void **rx_pkt_ring;
+
+	struct tx_bd *tx_ring;
+	void *tx_pkt;
+
+	struct l2_fhdr rcv_l2_fhdr;
+	__u8  rcv_buf[1500 + 2];
+	__u32 rcv_size;
+} bnx2_t;
+
+/******************************************************************************
+ *  bnx2 Function Declarations
+ ******************************************************************************/
+struct nic_ops * bnx2_get_ops();
+#endif /* __CNIC_H__*/
diff --git a/brcm_iscsi_uio/src/unix/libs/bnx2x.c b/brcm_iscsi_uio/src/unix/libs/bnx2x.c
new file mode 100644
index 0000000..f4eb876
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/bnx2x.c
@@ -0,0 +1,1103 @@
+/* bnx2x.c: bnx2x user space driver
+ *
+ * Copyright (c) 2004-2009 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#include "build_date.h"
+#include "bnx2x.h"
+#include "cnic.h"
+#include "logger.h"
+#include "nic.h"
+#include "nic_utils.h"
+#include "options.h"
+
+#define PFX	"bnx2x "
+
+/*  Foward struct declarations */
+struct nic_ops bnx2x_op;
+
+/*  Determine is the CNIC kernel module is loaded or not */
+int lib_bnx2x_loaded = 0;
+
+/*******************************************************************************
+ * NIC Library Strings
+ ******************************************************************************/
+static const char library_name[] = "bnx2x";
+static const char library_version[] = PACKAGE_VERSION;
+static const char library_uio_name[] = "bnx2x_cnic";
+
+/*  Template strings used to read RX parameters from sysfs */
+static const char cnic_sysfs_buf_size_template[] = "/sys/class/uio/uio%d/device/uio_buf_size";
+static const char cnic_sysfs_rx_ring_size_template[] = "/sys/class/uio/uio%d/device/uio_rx_ring_size";
+static const char cnic_sysfs_uio_event_template[] = "/sys/class/uio/uio%d/event";
+
+/*  The name that should be returned from /sys/class/uio/uio0/name */
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
+static const char bnx2x_uio_sysfs_name[] = "bnx2x_cnic";
+
+static const char cnic_uio_sysfs_resc_tempate[] = "/sys/class/uio/uio%i/device/resource";
+
+/*******************************************************************************
+ * String constants used to display human readable adapter name
+ ******************************************************************************/
+static const char brcm_57710[] = "Broadcom NetXtreme II BCM57710 10-Gigabit";
+static const char brcm_57711[] = "Broadcom NetXtreme II BCM57711 10-Gigabit";
+static const char brcm_57711e[] = "Broadcom NetXtreme II BCM57711E 10-Gigabit";
+
+/*******************************************************************************
+ * PCI ID constants
+ ******************************************************************************/
+#define PCI_VENDOR_ID_BROADCOM          0x14e4
+#define PCI_DEVICE_ID_NX2_57710         0x164e
+#define PCI_DEVICE_ID_NX2_57711         0x164f
+#define PCI_DEVICE_ID_NX2_57711E        0x1650
+#define PCI_ANY_ID (~0)
+
+/*  This is the table used to match PCI vendor and device ID's to the
+ *  human readable string names of the devices */
+static const struct pci_device_id bnx2x_pci_tbl[] = {
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710,
+	   PCI_ANY_ID, PCI_ANY_ID, brcm_57710 },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711,
+	   PCI_ANY_ID, PCI_ANY_ID, brcm_57711 },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E,
+	   PCI_ANY_ID, PCI_ANY_ID, brcm_57711e },
+};
+
+/*******************************************************************************
+ * BNX2X Library Functions
+ ******************************************************************************/
+/**
+ *  bnx2x_get_library_name() - Used to get the name of this NIC libary
+ *  @param name - This function will return the pointer to this NIC
+ *                library name
+ *  @param name_size
+ */
+static void bnx2x_get_library_name(char **name,
+				  size_t *name_size)
+{
+	*name = (char *)library_name;
+	*name_size = sizeof(library_name);
+}
+
+/**
+ *  bnx2x_get_library_version() - Used to get the version string of this
+ *                                NIC libary
+ *  @param version - This function will return the pointer to this NIC
+ *                   library version string
+ *  @param version_size - This will be set with the version size 
+ */
+static void bnx2x_get_library_version(char **version,
+				     size_t *version_size)
+{
+	*version = (char *) library_version;
+	*version_size = sizeof(library_version);
+}
+
+/**
+ *  bnx2x_get_build_date() - Used to get the build date string of this library
+ *  @param version - This function will return the pointer to this NIC
+ *                   library build date string
+ *  @param version_size - This will be set with the build date string size 
+ */
+static void bnx2x_get_build_date(char **build,
+				 size_t *build_size)
+{
+	*build = (char *) build_date;
+	*build_size = sizeof(build_date);
+}
+
+/**
+ *  bnx2x_get_transport_name() - Used to get the transport name associated
+ *                              with this this NIC libary
+ *  @param transport_name - This function will return the pointer to this NIC
+ *                          library's associated transport string
+ *  @param transport_name_size - This will be set with the transport name size
+ */
+static void bnx2x_get_transport_name(char **transport_name,
+			    	     size_t *transport_name_size)
+{
+	*transport_name = (char *) bnx2i_library_transport_name;
+	*transport_name_size = bnx2i_library_transport_name_size;
+}
+
+/**
+ *  bnx2x_get_uio_name() - Used to get the uio name associated with this this 
+ *                        NIC libary
+ *  @param uio_name - This function will return the pointer to this NIC
+ *                    library's associated uio string
+ *  @param transport_name_size - This will be set with the uio name size
+ */
+static void bnx2x_get_uio_name(char **uio_name,
+			      size_t *uio_name_size)
+{
+	*uio_name = (char *) library_uio_name;
+	*uio_name_size = sizeof(library_uio_name);
+}
+
+/**
+ *  bnx2x_get_pci_table() - Used to get the PCI table for this NIC libary to
+ *  			    determine which NIC's based off of PCI ID's are
+ *  			    supported
+ *  @param table - This function will return the pointer to the PCI table
+ *  @param entries - This function will return the number of entries in the NIC
+ *                   library's PCI table
+ */
+static void bnx2x_get_pci_table(struct pci_device_id **table,
+			       uint32_t *entries)
+{
+	*table = (struct pci_device_id *) bnx2x_pci_tbl;
+	*entries = (uint32_t) (sizeof(bnx2x_pci_tbl)/sizeof(bnx2x_pci_tbl[0]));
+}
+
+/**
+ *  bnx2x_get_ops() - Used to get the NIC library op table
+ *  @param op - The op table of this NIC library
+ */
+struct nic_ops * bnx2x_get_ops()
+{
+	return &bnx2x_op;
+}
+
+/*******************************************************************************
+ * bnx2x Utility Functions
+ ******************************************************************************/
+/*******************************************************************************
+ * Utility Functions Used to read register from the bnx2x device
+ ******************************************************************************/
+static void bnx2x_wr32(bnx2x_t *bp, __u32 off, __u32 val)
+{
+	*((volatile __u32 *)(bp->reg + off)) = val;
+}
+
+static void bnx2x_doorbell(bnx2x_t *bp, __u32 off, __u32 val)
+{
+	*((volatile __u32 *)(bp->reg2 + off)) = val;
+}
+
+static __u32 bnx2x_rd32(bnx2x_t *bp, __u32 off)
+{
+	return *((volatile __u32 *)(bp->reg + off));
+}
+
+static int bnx2x_reg_sync(bnx2x_t *bp, __u32 off, __u16 length)
+{
+	return msync(bp->reg + off, length, MS_SYNC);
+}
+
+static void bnx2x_update_rx_prod(bnx2x_t *bp)
+{
+	struct ustorm_eth_rx_producers rx_prods = {0};
+	int i;
+
+	rx_prods.bd_prod = bp->rx_bd_prod;
+	rx_prods.cqe_prod = bp->rx_prod;
+
+	barrier();
+
+	for (i = 0; i < sizeof(struct ustorm_eth_rx_producers)/4; i++)
+		bnx2x_wr32(bp, bp->rx_prod_io + i * 4,
+			   ((__u32 *)&rx_prods)[i]);
+
+	barrier();
+
+	bnx2x_reg_sync(bp, bp->rx_prod_io,
+		       sizeof(struct ustorm_eth_rx_producers));
+}
+
+/**
+ * bnx2x_get_chip_id() - Used to retrive the chip ID from the nic
+ * @param dev - Device used to determin NIC type
+ * @return Chip ID read from the MISC ID register
+ */
+static int bnx2x_get_chip_id(bnx2x_t *bp)
+{
+        int val, id;
+
+        /* Get the chip revision id and number. */
+        /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+        val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_NUM);
+        id = ((val & 0xffff) << 16);
+        val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_REV);
+        id |= ((val & 0xf) << 12);
+        val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_METAL);
+        id |= ((val & 0xff) << 4);
+        val = bnx2x_rd32(bp, BNX2X_MISC_REG_BOND_ID);
+        id |= (val & 0xf); 
+
+        return id;
+}
+
+
+/**
+ *  bnx2x_uio_verify()
+ *
+ */
+static int bnx2x_uio_verify(nic_t *nic)
+{
+        char *raw = NULL, *raw_tmp;
+	uint32_t raw_size = 0;
+	char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
+	int rc = 0;
+
+	/*  Build the path to determine uio name */
+	snprintf(temp_path, sizeof(temp_path),
+		 cnic_uio_sysfs_name_tempate, nic->uio_minor);
+
+        rc = capture_file(&raw, &raw_size, temp_path);
+        if(rc != 0)
+        {
+                goto error;
+        }
+
+	/* sanitize name string by replacing newline with null termination */
+	raw_tmp = raw;
+	while(*raw_tmp != '\n')
+		raw_tmp++;
+	*raw_tmp = '\0';
+
+	if (strncmp(raw, bnx2x_uio_sysfs_name,
+		    sizeof(bnx2x_uio_sysfs_name)) != 0) {
+		LOG_ERR(PFX "%s: uio names not equal: "
+		            "expecting %s got %s from %s",
+			nic->log_name, bnx2x_uio_sysfs_name, raw, temp_path);
+		rc = -EIO;
+	}
+
+	free(raw);
+
+	LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
+
+      error:
+	return rc;
+}
+
+static unsigned long cnic_get_bar2(nic_t *nic)
+{
+        char *raw = NULL, *raw_tmp;
+	uint32_t raw_size = 0;
+	char temp_path[sizeof(cnic_uio_sysfs_resc_tempate) + 8];
+	int rc = 0, i, new_line;
+	unsigned long bar = 0;
+
+	/*  Build the path to determine uio name */
+	snprintf(temp_path, sizeof(temp_path),
+		 cnic_uio_sysfs_resc_tempate, nic->uio_minor);
+
+        rc = capture_file(&raw, &raw_size, temp_path);
+        if(rc != 0)
+		return 0;
+
+	/* Skip 2 lines to get to BAR2 */
+	raw_tmp = raw;
+	i = 0;
+	new_line = 0;
+	while (i++ < raw_size && new_line < 2) {
+		if (*raw_tmp == '\n')
+			new_line++;
+		raw_tmp++;
+	}
+
+	if (new_line == 2)
+		sscanf(raw_tmp, "%lx ", &bar);
+
+	free(raw);
+
+	return bar;
+}
+
+/*******************************************************************************
+ * bnx2x Utility Functions to get to the hardware consumer indexes
+ ******************************************************************************/
+static __u16 bnx2x_get_rx(bnx2x_t *bp)
+{
+	struct host_def_status_block *sblk = bp->status_blk;
+	__u16 rx_comp_cons;
+
+	msync(sblk, sizeof(*sblk), MS_SYNC);
+	rx_comp_cons = sblk->u_def_status_block.index_values[
+			HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS];
+	if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT) == BNX2X_MAX_RCQ_DESC_CNT)
+		rx_comp_cons++;
+
+	return rx_comp_cons;
+}
+
+
+static __u16 bnx2x_get_tx(bnx2x_t *bp)
+{
+	struct host_def_status_block *sblk = bp->status_blk;
+	__u16 tx_cons;
+
+	msync(sblk, sizeof(*sblk), MS_SYNC);
+	tx_cons = sblk->c_def_status_block.index_values[
+			HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS];
+
+	return tx_cons;
+}
+
+
+typedef enum {
+	CNIC_VLAN_STRIPPING_ENABLED = 1,
+	CNIC_VLAN_STRIPPING_DISABLED = 2,
+} CNIC_VLAN_STRIPPING_MODE;
+
+/**
+ *  bnx2x_strip_vlan_enabled() - This will query the device to determine whether
+ *                              VLAN tag stripping is enabled or not
+ *  @param dev - device to check stripping or not
+ *  @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled
+ *           CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled
+ */
+static CNIC_VLAN_STRIPPING_MODE bnx2x_strip_vlan_enabled(bnx2x_t *bp)
+{
+	return CNIC_VLAN_STRIPPING_DISABLED;
+}
+
+/**
+ *  bnx2x_alloc() - Used to allocate a CNIC structure
+ */
+static bnx2x_t * bnx2x_alloc(nic_t *nic)
+{
+	bnx2x_t *bp = malloc(sizeof(*bp));
+
+	if(bp == NULL)
+	{
+		LOG_ERR(PFX "%s: Could not allocate BNX2X space",
+			nic->log_name);
+		return NULL;
+	}
+
+	/*  Clear out the CNIC contents */
+	memset(bp, 0, sizeof(*bp));
+
+	bp->mem_fd = INVALID_FD;
+
+	bp->parent = nic;
+	nic->priv = (void *) bp;
+
+	return bp;
+}
+
+/**
+ * bnx2x_open() - This will initialize all the hardware resources underneath
+ *               a struct cnic_uio device
+ * @param dev - The struct cnic_uio device to attach the hardware with
+ * @return 0 on success, on failure a errno will be returned
+ */
+static int bnx2x_open(nic_t *nic)
+{
+	bnx2x_t *bp; 
+	struct stat uio_stat;
+	int i, rc;
+	__u32 val;
+	unsigned long bar2;
+
+	uint32_t bus;
+	uint32_t slot;
+	uint32_t func;
+
+	/*  Sanity Check: validate the parameters */
+	if(nic == NULL) {
+		LOG_ERR(PFX "cnic_open(): nic == NULL");
+		return -EINVAL;
+	}
+
+	bp = bnx2x_alloc(nic);
+	if(bp == NULL)
+		return -ENOMEM;
+
+	while(nic->fd < 0) {
+		/*  udev might not have created the file yet */
+		sleep(1);
+
+		nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK);
+		if (nic->fd != INVALID_FD) {
+			LOG_ERR(PFX "%s: uio device has been brought up "
+				    "via pid: %d on fd: %d",
+				nic->uio_device_name, getpid(), nic->fd);
+
+			rc = bnx2x_uio_verify(nic);
+			if(rc != 0)
+				continue;
+
+			break;
+		} else {
+			if( lib_bnx2x_loaded == 0) {
+				LOG_ERR(PFX "%s: Could not open device: %s, "
+					    "awaiting for the device to appear",
+					nic->log_name, nic->uio_device_name);
+		
+				/*  Time to wait for the device to come up */
+				pthread_mutex_lock(&nic->uio_wait_mutex);
+				pthread_cond_wait(&nic->uio_wait_cond,
+						  &nic->uio_wait_mutex);
+				pthread_mutex_unlock(&nic->uio_wait_mutex);
+
+				/*  udev might not have created the file yet */
+				sleep(2);
+
+				lib_bnx2x_loaded = 1;
+			} else {
+				/*  udev might not have created the file yet */
+				sleep(2);
+			}
+		}
+	}
+	if (fstat(nic->fd, &uio_stat) < 0) {
+		LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
+		return -ENODEV;
+	}
+	nic->uio_minor = minor(uio_stat.st_rdev);
+
+	bar2 = cnic_get_bar2(nic);
+	if (bar2 == 0) {
+		LOG_ERR(PFX "%s: Could not read BAR2", nic->log_name);
+		return -ENODEV;
+	}
+
+	bp->mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
+	if (bp->mem_fd < 0) {
+		LOG_ERR(PFX "%s: Could not open /dev/mem", nic->log_name);
+		return -ENODEV;
+	}
+
+	bp->reg2 = mmap(NULL, BNX2X_BAR2_SIZE, PROT_READ | PROT_WRITE,
+			MAP_SHARED, bp->mem_fd, (off_t) bar2);
+
+	if (bp->reg2 == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Couldn't mmap BAR2 registers: %s",
+			 nic->log_name, strerror(errno));
+		bp->reg2 = NULL;
+		rc = errno;
+		goto open_error;
+	}
+
+	/*  TODO: hardcoded with the cnic driver */
+	bp->rx_ring_size = 15;
+	bp->rx_buffer_size = 0x400;
+
+	LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
+		  nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
+
+	/*  Determine the number of UIO events that have already occured */
+	rc = detemine_initial_uio_events(nic, &nic->intr_count);
+	if(rc != 0) {
+		LOG_ERR("Could not determine the number ofinitial UIO events");
+		nic->intr_count = 0;
+	}
+
+	/*  Allocate space for rx pkt ring */
+	bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
+	if(bp->rx_pkt_ring == NULL)
+	{
+		LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
+			nic->log_name);
+		rc = errno;
+		goto open_error;
+	}
+
+	bp->reg = mmap(NULL, BNX2X_BAR_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+			 nic->fd, (off_t) 0);
+	if (bp->reg == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Couldn't mmap registers: %s",
+			 nic->log_name, strerror(errno));
+		bp->reg = NULL;
+		rc = errno;
+		goto open_error;
+	}
+
+	msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC);
+
+	bp->status_blk = mmap(NULL, sizeof(struct host_def_status_block),
+		 	     PROT_READ | PROT_WRITE, MAP_SHARED,
+			     nic->fd, (off_t) getpagesize());
+	if (bp->status_blk == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Could not mmap status block: %s",
+			 nic->log_name, strerror(errno));
+		bp->status_blk = NULL;
+		rc = errno;
+		goto open_error;
+	}
+
+	bp->tx_ring = mmap(NULL, 4 * getpagesize(),
+			    PROT_READ | PROT_WRITE,
+			    MAP_SHARED | MAP_LOCKED,
+			    nic->fd, (off_t) 2 * getpagesize());
+	if (bp->tx_ring == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Could not mmap tx ring: %s",
+			 nic->log_name, strerror(errno));
+		bp->tx_ring = NULL;
+		rc = errno;
+		goto open_error;
+	}
+
+	bp->rx_comp_ring = (union eth_rx_cqe *)
+		(((__u8 *) bp->tx_ring) + 2 * getpagesize());
+
+	bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
+			 PROT_READ | PROT_WRITE,
+			 MAP_SHARED | MAP_LOCKED,
+			 nic->fd, (off_t) 3 * getpagesize());
+	if (bp->bufs == MAP_FAILED) {
+		LOG_INFO(PFX "%s: Could not mmap buffers: %s",
+			 nic->log_name, strerror(errno));
+		bp->bufs = NULL;
+		rc = errno;
+		goto open_error;
+	}
+
+	bp->chip_id = bnx2x_get_chip_id(bp);
+	LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id);
+
+	rc = get_bus_slot_func_num(nic, &bus, &slot, &func);
+	if(rc != 0) {
+		LOG_INFO(PFX "%s: Couldn't determine bus:slot.func",
+			 nic->log_name);
+		goto open_error;
+	}
+
+	bp->func = func;
+	bp->port = bp->func % PORT_MAX;
+
+	bp->rx_prod_io = BAR_USTRORM_INTMEM +
+			USTORM_RX_PRODS_OFFSET(bp->port, 17);
+
+	bp->tx_doorbell = 17 * getpagesize() + 0x40;
+
+	bp->tx_cons = 0;
+	bp->tx_prod = 0;
+	bp->tx_bd_prod = 0;
+	bp->tx_pkt = bp->bufs;
+
+	bp->rx_index = 0;
+	bp->rx_cons = 0;
+	bp->rx_bd_cons = 0;
+	bp->rx_prod = 127;
+	bp->rx_bd_prod = bp->rx_ring_size;
+
+	for (i = 0; i < bp->rx_ring_size; i++) {
+		void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
+
+		bp->rx_pkt_ring[i] = ptr;
+	}
+
+	val = bnx2x_rd32(bp, MISC_REG_SHARED_MEM_ADDR);
+
+	bp->shmem_base = val;
+	val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_UPPER(bp));
+	nic->mac_addr[0] = (__u8) (val >> 8);
+	nic->mac_addr[1] = (__u8) val;
+	val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_LOWER(bp));
+	nic->mac_addr[2] = (__u8) (val >> 24);
+	nic->mac_addr[3] = (__u8) (val >> 16);
+	nic->mac_addr[4] = (__u8) (val >> 8);
+	nic->mac_addr[5] = (__u8) val;
+
+	LOG_INFO(PFX "%s:  Using mac address: %02x:%02x:%02x:%02x:%02x:%02x",
+		 nic->log_name,
+		 nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
+		 nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
+
+	/*  Determine if Hardware VLAN tag stripping is enabled or not */
+	if(CNIC_VLAN_STRIPPING_ENABLED == bnx2x_strip_vlan_enabled(bp))
+	{
+		nic->flags |= NIC_VLAN_STRIP_ENABLED;
+	}
+
+	/*  Prepare the multicast addresses */
+	rc = enable_multicast(nic);
+	if(rc != 0)
+		goto open_error;
+
+	msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC);
+	LOG_INFO("%s: bnx2x initialized", nic->log_name);
+
+	bnx2x_update_rx_prod(bp);
+
+	return 0;
+
+open_error:
+	if (bp->tx_ring) {
+		munmap(bp->tx_ring, 4 * getpagesize());
+		bp->tx_ring = NULL;
+	}
+
+	if (bp->status_blk) {
+		munmap(bp->status_blk, sizeof(struct host_def_status_block));
+		bp->status_blk = NULL;
+	}
+
+	if (bp->reg) {
+		munmap(bp->reg, BNX2X_BAR_SIZE);
+		bp->reg = NULL;
+	}
+
+	if (bp->reg2) {
+		munmap(bp->reg2, BNX2X_BAR2_SIZE);
+		bp->reg2 = NULL;
+	}
+
+	if (bp->rx_pkt_ring) {
+		free(bp->rx_pkt_ring);
+		bp->rx_pkt_ring = NULL;
+	}
+
+	if (bp->mem_fd != INVALID_FD) {
+		close(bp->mem_fd);
+		bp->mem_fd = INVALID_FD;
+	}
+
+	return rc;
+}
+
+/**
+ *  bnx2x_uio_close_resources() - Used to free resource for the NIC/CNIC
+ *  @param nic - NIC device to free resource
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 on success, <0 on failure
+ */
+static int bnx2x_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+	int rc = 0;
+
+	/*  Remove the multicast addresses if added */
+	if((nic->flags & NIC_ADDED_MULICAST) &&
+	   (graceful == ALLOW_GRACEFUL_SHUTDOWN))
+		disable_multicast(nic);
+
+	/*  Check if there is an assoicated bnx2x device */
+	if(bp == NULL) {
+		LOG_WARN(PFX "%s: when closing resources there is "
+		             "no assoicated bnx2x",
+			     nic->log_name);
+		return -EIO;
+	}
+
+	/*  Clean up allocated memory */
+
+	if(bp->rx_pkt_ring != NULL) {
+		free(bp->rx_pkt_ring);
+		bp->rx_pkt_ring = NULL;
+	}
+
+	/*  Clean up mapped registers */
+	if (bp->bufs != NULL) {
+		rc = munmap(bp->bufs,
+			    (bp->rx_ring_size + 1) * bp->rx_buffer_size);
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap bufs",
+				 nic->log_name);
+		bp->bufs = NULL;
+	}
+
+	if (bp->tx_ring != NULL) {
+		munlock(bp->tx_ring, 4 * getpagesize());
+		rc = munmap(bp->tx_ring, 4 * getpagesize());
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap tx_rings",
+				 nic->log_name);
+		bp->tx_ring = NULL;
+	}
+
+	if (bp->status_blk != NULL) {
+		rc = munmap(bp->status_blk, sizeof(struct host_def_status_block));
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap status block",
+				 nic->log_name);
+		bp->status_blk = NULL;
+	}
+
+	if (bp->reg != NULL) {
+		rc = munmap(bp->reg, BNX2X_BAR_SIZE);
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap regs",
+				 nic->log_name);
+		bp->reg = NULL;
+	}
+
+	if (bp->reg2 != NULL) {
+		rc = munmap(bp->reg2, BNX2X_BAR2_SIZE);
+		if (rc != 0)
+			LOG_WARN(PFX "%s: Couldn't unmap regs",
+				 nic->log_name);
+		bp->reg2 = NULL;
+	}
+
+	if (bp->mem_fd != INVALID_FD) {
+		close(bp->mem_fd);
+		bp->mem_fd = INVALID_FD;
+	}
+
+	if (nic->fd != INVALID_FD) {
+		rc = close(nic->fd);
+		if (rc != 0) {
+			LOG_WARN(PFX "%s: Couldn't close uio file descriptor: %d",
+				 nic->log_name, nic->fd);
+		} else {
+			LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
+				 nic->log_name, nic->fd);
+		}
+
+		nic->fd = INVALID_FD;
+	} else {
+		LOG_WARN(PFX "%s: Invalid uio file descriptor: %d",
+				 nic->log_name, nic->fd);
+	}
+
+	LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
+
+	return 0;
+}
+
+/**
+ *  cnic_close() - Used to close the NIC device
+ *  @param nic - NIC device to close
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 if successful, <0 if there is an error
+ */
+static int bnx2x_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+	/*  Sanity Check: validate the parameters */
+	if(nic == NULL) {
+		LOG_ERR(PFX "cnic_close(): nic == NULL");
+		return -EINVAL;
+	}
+
+	LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
+
+	bnx2x_uio_close_resources(nic, graceful);
+
+	/*  Free any named strings we might be holding onto */
+	if(nic->flags & NIC_CONFIG_NAME_MALLOC) {
+		free(nic->config_device_name);
+		nic->flags &= ~NIC_CONFIG_NAME_MALLOC;
+	}
+	nic->config_device_name = NULL;
+
+	if(nic->flags & NIC_UIO_NAME_MALLOC) {
+		free(nic->uio_device_name);
+		nic->uio_device_name = NULL;
+
+		nic->flags &= ~NIC_UIO_NAME_MALLOC;
+	}
+
+	return 0;
+}
+
+static void bnx2x_prepare_xmit_packet(nic_t *nic,
+				     nic_interface_t *nic_iface,
+				     struct packet *pkt)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+
+	/*  Determine if we need to insert the VLAN tag */
+	if((nic_iface->vlan_id != 0) && 
+	   (NIC_VLAN_STRIP_ENABLED & nic->flags))
+	{
+		uint16_t insert_tpid = const_htons(UIP_ETHTYPE_8021Q);
+		uint16_t insert_vlan_id = htons((0x0FFF & nic_iface->vlan_id) +
+			((0x000F & nic_iface->vlan_priority) << 12));
+
+		/* We need to reinsert the VLAN tag */
+		memcpy(bp->tx_pkt, pkt->buf, 12);
+		memcpy(bp->tx_pkt + 12, &insert_tpid, 2);
+		memcpy(bp->tx_pkt + 14, &insert_vlan_id, 2);
+		memcpy(bp->tx_pkt + 16, pkt->buf + 12, pkt->buf_size - 12);
+
+		pkt->buf_size = pkt->buf_size +4;
+
+		LOG_DEBUG(PFX "%s: Inserted vlan tag id: 0x%x",
+			  nic->log_name,
+			  ntohs(insert_vlan_id));
+	} else {
+		memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
+	}
+
+	msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
+}
+
+/**
+ *  bnx2x_get_tx_pkt() - This function is used to a TX packet from the NIC
+ *  @param nic - The NIC device to send the packet
+ */
+void * bnx2x_get_tx_pkt(nic_t *nic)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+        return bp->tx_pkt;
+}
+
+
+/**
+ *  bnx2x_start_xmit() - This function is used to send a packet of data
+ *  @param nic - The NIC device to send the packet
+ *  @param len - the length of the TX packet
+ *
+ */
+void bnx2x_start_xmit(nic_t *nic, size_t len)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+	uint16_t ring_prod;
+	struct eth_tx_start_bd *txbd;
+	struct eth_tx_bd *txbd2;
+
+	ring_prod = BNX2X_TX_RING_IDX(bp->tx_bd_prod);
+	txbd = &bp->tx_ring[ring_prod];
+
+	txbd->vlan = bp->tx_prod;
+
+	bp->tx_prod = BNX2X_NEXT_TX_BD(bp->tx_prod);
+	bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod);
+	bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod);
+
+	ring_prod = BNX2X_TX_RING_IDX(bp->tx_bd_prod);
+	txbd2 = (struct eth_tx_bd *) &bp->tx_ring[ring_prod];
+
+	txbd2->nbytes = len - 0x10;
+	txbd2->total_pkt_bytes = len;
+
+	bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod);
+
+	barrier();
+	bnx2x_doorbell(bp, bp->tx_doorbell, 0x02 | (bp->tx_bd_prod << 16));
+
+	LOG_DEBUG(PFX "%s: sent %d bytes using bp->tx_prod: %d",
+		      nic->log_name, len, bp->tx_prod);
+}
+
+/**
+ *  bnx2x_write() - Used to write the data to the hardware
+ *  @param nic - NIC hardware to read from
+ *  @param pkt - The packet which will hold the data to be sent on the wire
+ *  @return 0 if successful, <0 if failed
+ */
+int bnx2x_write(nic_t *nic, nic_interface_t *nic_iface,
+		packet_t *pkt)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+	struct uip_stack *uip = &nic_iface->ustack;
+
+	/* Sanity Check: validate the parameters */
+	if(nic == NULL || nic_iface == NULL || pkt == NULL) {
+		LOG_ERR(PFX "%s: cnic_write() nic == 0x%p || "
+			    " nic_iface == 0x%p || "
+			    " pkt == 0x%x", nic, nic_iface, pkt);
+		return -EINVAL;
+	}
+
+	if(pkt->buf_size == 0) {
+		LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet",
+			nic->log_name);
+		return -EINVAL;
+	}
+
+	if(pthread_mutex_trylock(&nic->xmit_mutex) != 0)
+	{
+		LOG_ERR(PFX "%s: Dropped previous transmitted packet",
+			nic->log_name);
+		return -EINVAL;
+	}
+
+	bnx2x_prepare_xmit_packet(nic, nic_iface,
+				 pkt);
+	bnx2x_start_xmit(nic, pkt->buf_size);
+
+	/*  bump the cnic dev send statistics */
+	nic->stats.tx.packets++;
+	nic->stats.tx.bytes += uip->uip_len;
+
+	LOG_DEBUG(PFX "%s: transmitted %d bytes "
+		      "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
+		  nic->log_name, pkt->buf_size,
+		  bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
+
+	return 0;
+}
+
+/**
+ *  bnx2x_read() - Used to read the data from the hardware
+ *  @param nic - NIC hardware to read from
+ *  @param pkt - The packet which will hold the data
+ *  @return 0 if successful, <0 if failed
+ */
+static int bnx2x_read(nic_t *nic, packet_t *pkt)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+	int rc = 0;
+	uint16_t hw_cons, sw_cons, bd_cons, bd_prod;
+
+	/* Sanity Check: validate the parameters */
+	if(nic == NULL || pkt == NULL) {
+		LOG_ERR(PFX "%s: bnx2x_read() nic == 0x%p || "
+			    " pkt == 0x%x", nic, pkt);
+		return -EINVAL;
+	}
+
+	hw_cons = bnx2x_get_rx(bp);
+	sw_cons = bp->rx_cons;
+	bd_cons = bp->rx_bd_cons;
+	bd_prod = bp->rx_bd_prod;
+
+	if (sw_cons != hw_cons) {
+		uint16_t comp_ring_index = sw_cons & BNX2X_MAX_RCQ_DESC_CNT;
+		uint8_t ring_index;
+		union eth_rx_cqe *cqe;
+		__u8 cqe_fp_flags;
+		void *rx_pkt;
+		int len;
+
+		cqe = &bp->rx_comp_ring[comp_ring_index];
+		cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+
+		LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d",
+			  nic->log_name,
+			  sw_cons, hw_cons);
+
+		msync(cqe, sizeof(*cqe), MS_SYNC); 
+		if (!(cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE)) {
+			ring_index = bd_cons % 15;
+			len = cqe->fast_path_cqe.pkt_len;
+			rx_pkt = bp->rx_pkt_ring[ring_index];
+
+			/*  Doto query MTU size of physical device */
+			/*  Ensure len is valid */
+			if(len > pkt->max_buf_size)
+				LOG_DEBUG(PFX "%s: bad BD length: %d",
+					  nic->log_name, len);
+
+			if (len > 0) {
+				msync(rx_pkt, len, MS_SYNC); 
+				/*  Copy the data */
+				memcpy(pkt->buf, rx_pkt, len);
+				pkt->buf_size = len;
+
+				/* TODO - VLAN tag info */
+				rc = 1;
+
+				LOG_DEBUG(PFX "%s: processing packet length: %d",
+					  nic->log_name, len);
+
+				/*  bump the cnic dev recv statistics */
+				nic->stats.rx.packets++;
+				nic->stats.rx.bytes += pkt->buf_size;
+			}
+
+			bd_cons = BNX2X_NEXT_RX_IDX(bd_cons);
+			bd_prod = BNX2X_NEXT_RX_IDX(bd_prod);
+
+		}
+		sw_cons = BNX2X_NEXT_RCQ_IDX(bd_cons);
+		bp->rx_prod = BNX2X_NEXT_RCQ_IDX(bp->rx_prod);
+	}
+	bp->rx_cons = sw_cons;
+	bp->rx_bd_cons = bd_cons;
+	bp->rx_bd_prod = bd_prod;
+
+	bnx2x_update_rx_prod(bp);
+
+	return rc;
+}
+/*******************************************************************************
+ * Clearing TX interrupts
+ ******************************************************************************/
+/**
+ *  bnx2x_clear_tx_intr() - This routine is called when a TX interrupt occurs
+ *  @param nic - the nic the interrupt occured on
+ *  @return  0 on success
+ */
+static int bnx2x_clear_tx_intr(nic_t *nic)
+{
+	bnx2x_t *bp = (bnx2x_t *) nic->priv;
+	uint16_t hw_cons = bnx2x_get_tx(bp);
+
+	/* Sanity check: ensure the parameters passed in are valid */
+	if(unlikely(nic == NULL)) {
+		LOG_ERR(PFX "bnx2x_read() nic == NULL");
+		return -EINVAL;
+	}
+
+	if(bp->tx_cons == hw_cons)
+		return 0;
+
+	LOG_DEBUG(PFX "%s: clearing tx interrupt [%d %d]",
+		  nic->log_name,
+		  bp->tx_cons, hw_cons);
+	bp->tx_cons = hw_cons;
+
+	/*  There is a queued TX packet that needs to be sent out.  The usual
+	 *  case is when stack will send an ARP packet out before sending the
+	 *  intended packet */
+	if(nic->tx_packet_queue != NULL)
+	{
+		packet_t *pkt;
+
+		LOG_DEBUG(PFX "%s: sending queued tx packet", nic->log_name);
+		pkt = nic_dequeue_tx_packet(nic);
+
+		/*  Got a TX packet buffer of the TX queue and put it onto
+		 *  the hardware */
+		if(pkt != NULL)
+		{
+			bnx2x_prepare_xmit_packet(nic,
+						  pkt->nic_iface,
+						  pkt);
+
+			bnx2x_start_xmit(nic, pkt->buf_size);
+
+			LOG_DEBUG(PFX "%s: transmitted queued packet %d bytes "
+				      "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
+					  nic->log_name, pkt->buf_size,
+					  bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
+
+			return 0;
+		}
+	}
+
+	pthread_mutex_unlock(&nic->xmit_mutex);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * bnx2x NIC op's table
+ ******************************************************************************/
+struct nic_ops bnx2x_op = {
+	.description	= "bnx2x",
+	.open		= bnx2x_open,
+	.close		= bnx2x_close,
+	.write		= bnx2x_write,
+	.get_tx_pkt	= bnx2x_get_tx_pkt,
+	.start_xmit	= bnx2x_start_xmit,
+	.read		= bnx2x_read,
+	.clear_tx_intr	= bnx2x_clear_tx_intr,
+	.handle_iscsi_path_req = cnic_handle_iscsi_path_req,
+
+	.lib_ops = {
+		.get_library_name	= bnx2x_get_library_name,
+        	.get_pci_table		= bnx2x_get_pci_table,
+	        .get_library_version	= bnx2x_get_library_version,
+		.get_build_date		= bnx2x_get_build_date,
+	        .get_transport_name	= bnx2x_get_transport_name,
+	        .get_uio_name		= bnx2x_get_uio_name,
+	},
+};
diff --git a/brcm_iscsi_uio/src/unix/libs/bnx2x.h b/brcm_iscsi_uio/src/unix/libs/bnx2x.h
new file mode 100644
index 0000000..d711463
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/bnx2x.h
@@ -0,0 +1,365 @@
+/* bnx2x.h: bnx2x user space driver
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __BNX2X_H__
+#define __BNX2X_H__
+
+#include "nic.h"
+
+/******************************************************************************
+ *  Default CNIC values
+ ******************************************************************************/
+#define DEFAULT_BNX2X_NUM_RXBD	15
+#define DEFAULT_BNX2X_RX_LEN	0x400
+
+
+/******************************************************************************
+ *  BNX2X Hardware structures
+ ******************************************************************************/
+#define HC_USTORM_DEF_SB_NUM_INDICES 8
+#define HC_CSTORM_DEF_SB_NUM_INDICES 8
+#define HC_XSTORM_DEF_SB_NUM_INDICES 4
+#define HC_TSTORM_DEF_SB_NUM_INDICES 4
+
+struct atten_def_status_block {
+	volatile __u32 attn_bits;
+	volatile __u32 attn_bits_ack;
+	volatile __u8 status_block_id;
+	volatile __u8 reserved0;
+	volatile __u16 attn_bits_index;
+	volatile __u32 reserved1;
+};
+
+struct cstorm_def_status_block_u {
+	volatile __u16 index_values[HC_USTORM_DEF_SB_NUM_INDICES];
+	volatile __u16 status_block_index;
+	volatile __u8 func;
+	volatile __u8 status_block_id;
+	volatile __u32 __flags;
+};
+
+struct cstorm_def_status_block_c {
+	volatile __u16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES];
+	volatile __u16 status_block_index;
+	volatile __u8 func;
+	volatile __u8 status_block_id;
+	volatile __u32 __flags;
+};
+
+struct xstorm_def_status_block {
+	volatile __u16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES];
+	volatile __u16 status_block_index;
+	volatile __u8 func;
+	volatile __u8 status_block_id;
+	volatile __u32 __flags;
+};
+
+struct tstorm_def_status_block {
+	volatile __u16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES];
+	volatile __u16 status_block_index;
+	volatile __u8 func;
+	volatile __u8 status_block_id;
+	volatile __u32 __flags;
+};
+
+struct host_def_status_block {
+	struct atten_def_status_block atten_status_block;
+	struct cstorm_def_status_block_u u_def_status_block;
+	struct cstorm_def_status_block_c c_def_status_block;
+	struct xstorm_def_status_block x_def_status_block;
+	struct tstorm_def_status_block t_def_status_block;
+};
+
+#define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1
+#define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3
+#define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5
+
+/*  TX Buffer descriptor */
+struct eth_tx_bd_flags {
+	__u8 as_bitfield;
+#define ETH_TX_BD_FLAGS_VLAN_TAG (0x1<<0)
+#define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT 0
+#define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<1)
+#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 1
+#define ETH_TX_BD_FLAGS_L4_CSUM (0x1<<2)
+#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT 2
+#define ETH_TX_BD_FLAGS_END_BD (0x1<<3)
+#define ETH_TX_BD_FLAGS_END_BD_SHIFT 3
+#define ETH_TX_BD_FLAGS_START_BD (0x1<<4)
+#define ETH_TX_BD_FLAGS_START_BD_SHIFT 4
+#define ETH_TX_BD_FLAGS_HDR_POOL (0x1<<5)
+#define ETH_TX_BD_FLAGS_HDR_POOL_SHIFT 5
+#define ETH_TX_BD_FLAGS_SW_LSO (0x1<<6)
+#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT 6
+#define ETH_TX_BD_FLAGS_IPV6 (0x1<<7)
+#define ETH_TX_BD_FLAGS_IPV6_SHIFT 7
+};
+
+struct eth_tx_start_bd {
+	__u32 addr_lo;
+	__u32 addr_hi;
+	__u16 nbd;
+	__u16 nbytes;
+	__u16 vlan;
+	struct eth_tx_bd_flags bd_flags;
+	__u8 general_data;
+#define ETH_TX_START_BD_HDR_NBDS (0x3F<<0)
+#define ETH_TX_START_BD_HDR_NBDS_SHIFT 0
+#define ETH_TX_START_BD_ETH_ADDR_TYPE (0x3<<6)
+#define ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT 6
+};
+
+struct eth_tx_bd {
+	__u32 addr_lo;
+	__u32 addr_hi;
+	__u16 total_pkt_bytes;
+	__u16 nbytes;
+	__u8 reserved[4];
+};
+
+/*  RX Buffer descriptor */
+struct eth_rx_bd {
+	__u32 addr_lo;
+	__u32 addr_hi;
+};
+
+struct ramrod_data {
+	volatile __u32 data_lo;
+	volatile __u32 data_hi;
+};
+
+struct common_ramrod_eth_rx_cqe {
+	volatile __u8 ramrod_type;
+#define COMMON_RAMROD_ETH_RX_CQE_TYPE (0x1<<0)
+#define COMMON_RAMROD_ETH_RX_CQE_TYPE_SHIFT 0
+#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x7F<<1)
+#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 1
+	volatile __u8 conn_type;
+	volatile __u16 reserved1;
+	volatile __u32 conn_and_cmd_data;
+#define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0)
+#define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0
+#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24)
+#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24
+	struct ramrod_data protocol_data;
+	__u32 reserved2[4];
+};
+
+struct parsing_flags {
+	volatile __u16 flags;
+};
+
+struct eth_fast_path_rx_cqe {
+	volatile __u8 type_error_flags;
+#define ETH_FAST_PATH_RX_CQE_TYPE (0x1<<0)
+#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT 0
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<1)
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 1
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<2)
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 2
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<3)
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 3
+#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<4)
+#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 4
+#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<5)
+#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 5
+#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6)
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6
+	volatile __u8 status_flags;
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3)
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4)
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5)
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6)
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7)
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7
+	volatile __u8 placement_offset;
+	volatile __u8 queue_index;
+	volatile __u32 rss_hash_result;
+	volatile __u16 vlan_tag;
+	volatile __u16 pkt_len;
+	volatile __u16 len_on_bd;
+	struct parsing_flags pars_flags;
+	volatile __u16 sgl[8];
+};
+
+struct eth_rx_cqe_next_page {
+	__u32 addr_lo;
+	__u32 addr_hi;
+	__u32 reserved[6];
+};
+
+union eth_rx_cqe {
+	struct eth_fast_path_rx_cqe fast_path_cqe;
+	struct common_ramrod_eth_rx_cqe ramrod_cqe;
+	struct eth_rx_cqe_next_page next_page_cqe;
+};
+
+/******************************************************************************
+ *  BNX2X Registers and HSI
+ ******************************************************************************/
+#define BNX2X_BAR_SIZE			0x500000
+#define BNX2X_BAR2_SIZE			0x12000
+
+#define BNX2X_CHIP_ID(bp)		(bp->chip_id & 0xfffffff0)
+
+#define PORT_MAX			2
+
+/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1
+ *    Port. */
+#define BNX2X_MISC_REG_BOND_ID                                         0xa400
+/* [R 8] These bits indicate the metal revision of the chip. This value
+ *    starts at 0x00 for each all-layer tape-out and increments by one for each
+ *       tape-out. */
+#define BNX2X_MISC_REG_CHIP_METAL                                      0xa404
+/* [R 16] These bits indicate the part number for the chip. */
+#define BNX2X_MISC_REG_CHIP_NUM                                        0xa408
+/* [R 4] These bits indicate the base revision of the chip. This value
+ *    starts at 0x0 for the A0 tape-out and increments by one for each
+ *       all-layer tape-out. */
+#define BNX2X_MISC_REG_CHIP_REV                                        0xa40c
+
+#define BNX2X_CHIP_NUM(bp)		(bp->chip_id >> 16)
+#define CHIP_NUM_57710			0x164e
+#define CHIP_NUM_57711			0x164f
+#define CHIP_NUM_57711E			0x1650
+#define CHIP_IS_E1(bp)			(BNX2X_CHIP_NUM(bp) == CHIP_NUM_57710)
+#define CHIP_IS_57711(bp)		(BNX2X_CHIP_NUM(bp) == CHIP_NUM_57711)
+#define CHIP_IS_57711E(bp)		(BNX2X_CHIP_NUM(bp) == CHIP_NUM_57711E)
+#define CHIP_IS_E1H(bp)			(CHIP_IS_57711(bp) || \
+					 CHIP_IS_57711E(bp))
+#define IS_E1H_OFFSET			CHIP_IS_E1H(bp)
+
+#define MISC_REG_SHARED_MEM_ADDR			0xa2b4
+
+#define MISC_REG_BOND_ID				0xa400
+#define MISC_REG_CHIP_METAL				0xa404
+#define MISC_REG_CHIP_NUM				0xa408
+#define MISC_REG_CHIP_REV				0xa40c
+
+#define BAR_USTRORM_INTMEM				0x400000
+#define BAR_CSTRORM_INTMEM				0x410000
+#define BAR_XSTRORM_INTMEM				0x420000
+#define BAR_TSTRORM_INTMEM				0x430000
+
+#define USTORM_RX_PRODS_OFFSET(port, client_id) \
+	(IS_E1H_OFFSET ? (0x1000 + (port * 0x680) + (client_id * 0x40)) \
+	: (0x4000 + (port * 0x360) + (client_id * 0x30)))
+
+#define	SHMEM_P0_ISCSI_MAC_UPPER	0x4c
+#define	SHMEM_P0_ISCSI_MAC_LOWER	0x50
+#define	SHMEM_P1_ISCSI_MAC_UPPER	0x1dc
+#define	SHMEM_P1_ISCSI_MAC_LOWER	0x1e0
+
+#define SHMEM_ISCSI_MAC_UPPER(bp)	\
+	(((bp)->port == 0) ? SHMEM_P0_ISCSI_MAC_UPPER : SHMEM_P1_ISCSI_MAC_UPPER)
+
+#define SHMEM_ISCSI_MAC_LOWER(bp)	\
+	(((bp)->port == 0) ? SHMEM_P0_ISCSI_MAC_LOWER : SHMEM_P1_ISCSI_MAC_LOWER)
+
+#define BNX2X_RCQ_DESC_CNT	(4096 / sizeof(union eth_rx_cqe))
+#define BNX2X_MAX_RCQ_DESC_CNT		(BNX2X_RCQ_DESC_CNT - 1)
+
+#define BNX2X_RX_DESC_CNT	(4096 / sizeof(struct eth_rx_bd))
+#define BNX2X_MAX_RX_DESC_CNT		(BNX2X_RX_DESC_CNT - 2)
+
+#define BNX2X_TX_DESC_CNT	(4096 / sizeof(struct eth_tx_start_bd))
+#define BNX2X_MAX_TX_DESC_CNT		(BNX2X_TX_DESC_CNT - 1)
+
+#define BNX2X_NEXT_RX_IDX(x)	((((x) & (BNX2X_RX_DESC_CNT - 1)) == \
+				  (BNX2X_MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1)
+
+#define BNX2X_NEXT_RCQ_IDX(x)	((((x) & BNX2X_MAX_RCQ_DESC_CNT) == \
+				  (BNX2X_MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+
+#define BNX2X_NEXT_TX_BD(x) (((x) & (BNX2X_MAX_TX_DESC_CNT - 1)) ==	\
+		(BNX2X_MAX_TX_DESC_CNT - 1)) ?				\
+	(x) + 2 : (x) + 1
+
+#define BNX2X_TX_RING_IDX(x) ((x) & BNX2X_MAX_TX_DESC_CNT)
+
+struct ustorm_eth_rx_producers {
+	__u16 cqe_prod;
+	__u16 bd_prod;
+	__u16 sge_prod;
+	__u16 reserved;
+};
+
+typedef struct bnx2x {
+	nic_t	*parent;
+
+	uint16_t   flags;
+#define CNIC_UIO_UNITIALIZED		0x0001
+#define CNIC_UIO_INITIALIZED		0x0002
+#define CNIC_UIO_ENABLED		0x0004
+#define CNIC_UIO_DISABLED		0x0008
+#define CNIC_UIO_IPv6_ENABLED		0x0010
+#define CNIC_UIO_ADDED_MULICAST		0x0020
+#define CNIC_UIO_MSIX_ENABLED		0x0200
+#define CNIC_UIO_TX_HAS_SENT		0x0400
+
+	void *reg;		/* Pointer to the BAR1 mapped registers	*/
+	void *reg2;		/* Pointer to the BAR2 mapped registers	*/
+
+	int mem_fd;
+
+	__u32 chip_id;
+	__u32 shmem_base;
+	int func;
+	int port;
+
+	__u32 tx_doorbell;
+
+	__u16 tx_prod;
+	__u16 tx_bd_prod;
+	__u16 tx_cons;
+
+	__u32 rx_prod_io;
+
+	__u16 rx_prod;
+	__u16 rx_bd_prod;
+	__u16 rx_cons;
+	__u16 rx_bd_cons;
+
+	/*  RX ring parameters */
+	uint32_t rx_ring_size;
+	uint32_t rx_buffer_size;
+
+	void *bufs;		/* Pointer to the mapped buffer space	*/
+
+	/*  Hardware Status Block locations */
+	void *sblk_map;
+	struct host_def_status_block *status_blk;
+
+	uint16_t rx_index;
+	union eth_rx_cqe *rx_comp_ring;
+	void **rx_pkt_ring;
+
+	struct eth_tx_start_bd *tx_ring;
+	void *tx_pkt;
+
+} bnx2x_t;
+
+/******************************************************************************
+ *  bnx2x Function Declarations
+ ******************************************************************************/
+void bnx2x_start_xmit(nic_t *nic, size_t len);
+
+//struct nic_interface * bnx2x_find_nic_iface(nic_t * nic,
+//                                           uint16_t vlan_id);
+
+struct nic_ops * bnx2x_get_ops();
+#endif /* __BNX2X_H__*/
diff --git a/brcm_iscsi_uio/src/unix/libs/cnic.c b/brcm_iscsi_uio/src/unix/libs/cnic.c
new file mode 100644
index 0000000..11b64a9
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/cnic.c
@@ -0,0 +1,238 @@
+/* cnic_nl.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <linux/limits.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+
+#include "uip_arp.h"
+#include "nic.h"
+#include "logger.h"
+#include "options.h"
+#include "uevent.h"
+
+#include "cnic.h"
+#include "iscsi_if.h"
+
+/*******************************************************************************
+ * Constants
+ ******************************************************************************/
+#define PFX "CNIC "
+
+/*******************************************************************************
+ * Constants shared between the bnx2 and bnx2x modules
+ ******************************************************************************/
+const char bnx2i_library_transport_name[] = "bnx2i";
+const size_t bnx2i_library_transport_name_size = 
+	sizeof(bnx2i_library_transport_name);
+
+/******************************************************************************
+ * Netlink Functions
+ ******************************************************************************/
+
+static int cnic_arp_send(nic_t *nic, nic_interface_t *nic_iface, int fd,
+			 __u8 * mac_addr, __u32 ip_addr, __u16 op)
+{
+	struct ether_header *eth;
+	struct ether_arp *arp;
+	__u32 dst_ip = ip_addr;
+	int pkt_size = sizeof(*eth) + sizeof(*arp);
+	int rc;
+
+	rc = pthread_mutex_trylock(&nic->xmit_mutex);
+
+	eth = (*nic->ops->get_tx_pkt)(nic);
+	arp = (struct ether_arp *)(eth + 1);
+
+	if(rc != 0) {
+		LOG_DEBUG(PFX "%s: could not get xmit_mutex", nic->log_name);
+		return -EAGAIN;
+	}
+
+	if (op == ARPOP_REQUEST) {
+		int i;
+
+		for (i = 0; i < 6; i++)
+			eth->ether_dhost[i] = 0xff;
+	} else
+		memcpy(eth->ether_dhost, mac_addr, 6);
+
+	memcpy(eth->ether_shost, nic->mac_addr, ETH_ALEN);
+	eth->ether_type = htons(ETHERTYPE_ARP);
+	arp->arp_hrd = htons(ARPHRD_ETHER);
+	arp->arp_pro = htons(ETHERTYPE_IP);
+	arp->arp_hln = ETH_ALEN;
+	arp->arp_pln = 4;
+	arp->arp_op = htons(op);
+	memcpy(arp->arp_sha, nic->mac_addr, ETH_ALEN);
+
+	/*  Copy the IP address's into the ARP response */
+	memcpy(arp->arp_spa, nic_iface->ustack.hostaddr, 4);
+	memcpy(arp->arp_tpa, &dst_ip, 4);
+
+	(*nic->nic_library->ops->start_xmit)(nic, pkt_size);
+
+	LOG_DEBUG(PFX "%s: Sent cnic arp request", nic->log_name);
+
+	return 0;
+}
+
+static int cnic_nl_neigh_rsp(nic_t *nic, int fd,
+			     struct iscsi_uevent *ev,
+			     struct iscsi_path *path_req,
+			     __u8 *mac_addr,
+			     nic_interface_t *nic_iface,
+			     int status)
+
+{
+	int rc;
+	uint8_t *ret_buf;
+	struct iscsi_uevent *ret_ev;
+	struct iscsi_path *path_rsp;
+	struct sockaddr_nl dest_addr;
+
+        memset(&dest_addr, 0, sizeof(dest_addr));
+        dest_addr.nl_family = AF_NETLINK;
+        dest_addr.nl_pid = 0;
+        dest_addr.nl_groups = 0; /* unicast */
+
+	ret_buf = calloc(1, NLMSG_SPACE(sizeof(struct iscsi_uevent) + 256));
+
+        memset(ret_buf, 0, NLMSG_SPACE(sizeof(struct iscsi_uevent) + 256));
+
+	/*  prepare the iscsi_uevent buffer */
+	ret_ev = (struct iscsi_uevent *)ret_buf;
+	ret_ev->type = ISCSI_UEVENT_PATH_UPDATE;
+	ret_ev->transport_handle = ev->transport_handle;
+	ret_ev->u.set_path.host_no = ev->r.req_path.host_no;
+
+	/*  Prepare the iscsi_path buffer */
+	path_rsp = ret_buf + sizeof(*ret_ev);
+	path_rsp->handle = path_req->handle;
+	path_rsp->ip_addr_len = 4;
+	memcpy(&path_rsp->src.v4_addr, &nic_iface->ustack.hostaddr,
+	       sizeof(nic_iface->ustack.hostaddr));
+	memcpy(path_rsp->mac_addr, mac_addr, 6);
+	path_rsp->vlan_id = path_req->vlan_id;
+	path_rsp->pmtu    = path_req->pmtu;
+
+        rc = __kipc_call(fd, ret_ev, sizeof(*ret_ev) + sizeof(*path_rsp));
+        if (rc > 0) {
+                LOG_ERR(PFX "neighbor reply sent back to kernel");
+	} else {
+                LOG_ERR(PFX "send neighbor reply failed: %d", rc);
+	}
+
+	free(ret_buf);
+
+	return rc;
+}
+
+/**
+ * cnic_handle_iscsi_path_req() - This function will handle the path req calls 
+ *                                the bnx2i kernel module
+ * @param nic - The nic the message is directed towards
+ * @param fd  - The file descriptor to be used to extract the private data
+ * @param ev  - The iscsi_uevent
+ * @param buf - The private message buffer
+ * @param buf_len - The private message buffer length
+ */
+int cnic_handle_iscsi_path_req(nic_t *nic, int fd, struct iscsi_uevent *ev,
+			       struct iscsi_path *path, size_t buf_len) 
+{
+	nic_interface_t *nic_iface;
+	struct in_addr addr;
+	__u8 mac_addr[6];
+	int rc;
+	uint16_t arp_retry;
+	int status = 0;
+
+	LOG_DEBUG(PFX "%s: Netlink message with VLAN ID: %d, path MTU: %d "
+		      "minor: %d",
+		   nic->log_name, path->vlan_id, path->pmtu, 0/* TODO FIX */);
+
+	pthread_mutex_lock(&nic_list_mutex);
+
+	/*  Find the proper interface via VLAN id */
+	nic_iface = nic_find_nic_iface(nic, path->vlan_id);
+//	nic_iface = cnic_find_nic_iface(nic, path->vlan_id);
+	if (nic_iface == NULL) {
+		pthread_mutex_unlock(&nic_list_mutex);
+		LOG_ERR(PFX "%s: Couldn't find net_iface vlan_id: %d",
+			nic->log_name, path->vlan_id);
+		return -EINVAL;
+	}
+
+	memcpy(&addr, &path->dst.v4_addr, sizeof(addr));
+
+#define MAX_ARP_RETRY 4
+	arp_retry = 0;
+
+	rc = uip_lookup_arp_entry(addr.s_addr, mac_addr);
+	if (rc != 0) {
+		while ((arp_retry < MAX_ARP_RETRY) && (event_loop_stop == 0)) {
+			char *addr_str;
+			int count;
+
+			addr_str = inet_ntoa(addr);
+			LOG_INFO(PFX "%s: Didn't find ip: %s\n",
+				 nic->log_name, addr_str);
+			rc = cnic_arp_send(nic, nic_iface, fd,
+					   mac_addr, addr.s_addr,
+					   ARPOP_REQUEST);
+			if(rc != 0) {
+				status = -EIO;
+				goto done;
+			}
+
+			for(count=0; count<4; count++) {
+				usleep(250000);
+
+				rc = uip_lookup_arp_entry(addr.s_addr,
+							  mac_addr);
+				if (rc == 0)
+					goto done;
+			}
+
+			arp_retry++;
+		}
+	}
+
+done:
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	if(arp_retry >= MAX_ARP_RETRY) {
+		status = -EIO;
+		rc = -EIO;
+	}
+
+	if(status != 0 || rc != 0)
+		pthread_mutex_unlock(&nic->xmit_mutex);
+
+	cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr,
+			  nic_iface, status);
+
+
+	return rc;
+}
diff --git a/brcm_iscsi_uio/src/unix/libs/cnic.h b/brcm_iscsi_uio/src/unix/libs/cnic.h
new file mode 100644
index 0000000..af53b24
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/libs/cnic.h
@@ -0,0 +1,27 @@
+/* cnic.h: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __CNIC_NL_H__
+#define __CNIC_NL_H__
+
+/*******************************************************************************
+ * Constants shared between the bnx2 and bnx2x modules
+ ******************************************************************************/
+extern const char bnx2i_library_transport_name[];
+extern const size_t bnx2i_library_transport_name_size;
+
+int cnic_nl_open();
+void cnic_nl_close();
+
+int cnic_handle_iscsi_path_req(nic_t *nic, int, struct iscsi_uevent *,
+			       struct iscsi_path *path, size_t len);
+
+#endif /* __CNIC_NL_H__ */
diff --git a/brcm_iscsi_uio/src/unix/logger.c b/brcm_iscsi_uio/src/unix/logger.c
new file mode 100644
index 0000000..af15925
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/logger.c
@@ -0,0 +1,175 @@
+/* logger.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "options.h"
+#include "logger.h"
+
+/******************************************************************************
+ * Default logger values
+ ******************************************************************************/
+static const char default_logger_filename[] = "/var/log/brcm-iscsi.log";
+
+struct logger main_log = {
+	.enabled	= LOGGER_ENABLED,
+	.fp		= NULL,
+	.log_file	= (char *) default_logger_filename,
+	.level		= LOG_LEVEL_INFO,
+	.lock		= PTHREAD_MUTEX_INITIALIZER,
+
+	.stats		= {
+		.debug	= 0,
+		.info	= 0,
+		.warn	= 0,
+		.error	= 0,
+
+		.last_log_time = 0,
+	},
+};
+
+/******************************************************************************
+ * Logger Functions
+ ******************************************************************************/
+/**
+ *  log_stream() - Main logging function
+ *  @param fp  - FILE stream to write the log to
+ *  @param level_str - log level string
+ *  @param fmt - log format
+ *  @param ap  - variable argument lists
+ */
+void log_stream(FILE *fp, char *level_str, char *fmt, va_list ap) 
+{
+	char time_buf[32];
+	va_list va_cp;
+
+	va_copy(va_cp, ap);
+
+	pthread_mutex_lock(&main_log.lock);
+	main_log.stats.last_log_time = time(NULL);
+	strftime(time_buf, 26, "%a %b %d %T %Y",	
+		 localtime(&main_log.stats.last_log_time));
+	fprintf(fp, "%s [%s]", level_str, time_buf);
+	vfprintf(fp, fmt, va_cp);
+	fprintf(fp, "\n");
+	pthread_mutex_unlock(&main_log.lock);
+}
+
+
+void log_uip(char *level_str, char *fmt, ...)
+{
+	va_list ap, va_cp;
+
+	va_start(ap, fmt);
+	va_copy(va_cp, ap);
+
+	if(main_log.fp == NULL)
+		return;
+
+	if(main_log.enabled == LOGGER_ENABLED)
+		log_stream(main_log.fp, level_str, fmt, va_cp);
+
+	if(opt.debug == DEBUG_ON) {
+		log_stream(stdout, level_str, fmt, va_cp);
+
+		/* Force the printing of the log file */
+		fflush(main_log.fp);
+
+		/* Force the printing of the log out to standard output */
+		fflush(stdout);
+	}
+	va_end(ap);
+}
+
+int backup_logger_settings(struct logger *src, struct logger *dest)
+{
+	dest->level = src->level;
+
+	dest->log_file = malloc(strlen(src->log_file) + 1);
+	if(dest->log_file == NULL) {
+		LOG_ERR("Could not allocate memory for log file path for backup");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int restore_backup(struct logger *src, struct logger *dest)
+{
+	if(dest->log_file != NULL)
+	{
+		free(dest->log_file);
+	}
+	dest->log_file = src->log_file;
+
+	return 0;
+}
+
+
+
+/******************************************************************************
+ *  Initialize/Clean up routines
+ ******************************************************************************/
+/**
+ *  init_logger() - Prepare the logger
+ *  @param filename - path to where the log will be written to
+ *  @return 0 on success, <0 on failure
+ */
+int init_logger(char *filename)
+{
+	int rc = 0;
+
+	pthread_mutex_lock(&main_log.lock);
+
+	main_log.fp = fopen( filename, "a");
+	if( main_log.fp == NULL) {
+		printf("Could not create log file: %s <%s>\n",
+		       filename, strerror(errno));
+		rc = -EIO;
+	}
+
+	pthread_mutex_unlock(&main_log.lock);
+
+	LOG_INFO("Initialize logger using log file: %s", filename);
+
+	return rc;
+}
+
+void fini_logger(int type)
+{
+	pthread_mutex_lock(&main_log.lock);
+
+	if ( main_log.fp != NULL ) {
+		fclose(main_log.fp);
+		main_log.fp = NULL;
+
+		if(opt.debug == DEBUG_ON) {
+			printf("Closed logger\n");
+			fflush(stdout);
+		}
+	}
+
+	if(type == SHUTDOWN_LOGGER) {
+		if ( (main_log.log_file != NULL) && 
+		     (main_log.log_file != default_logger_filename)) {	   
+			free (main_log.log_file );
+			main_log.log_file = NULL;
+		}
+	}
+
+	main_log.enabled = LOGGER_DISABLED;
+
+	pthread_mutex_unlock(&main_log.lock);
+}
diff --git a/brcm_iscsi_uio/src/unix/logger.h b/brcm_iscsi_uio/src/unix/logger.h
new file mode 100644
index 0000000..7035526
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/logger.h
@@ -0,0 +1,83 @@
+#ifndef __LOGGER_H__
+#define __LOGGER_H__
+
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+/*******************************************************************************
+ * Logger Levels
+ ******************************************************************************/
+#define LOG_LEVEL_DEBUG		4
+#define LOG_LEVEL_INFO		3
+#define LOG_LEVEL_WARN		2
+#define LOG_LEVEL_ERR		1
+#define LOG_LEVEL_UNKNOWN	0
+
+#define LOG_LEVEL_DEBUG_STR	"DBG  "
+#define LOG_LEVEL_INFO_STR	"INFO "
+#define LOG_LEVEL_WARN_STR	"WARN "
+#define LOG_LEVEL_ERR_STR	"ERR  "
+#define LOG_LEVEL_UNKNOWN_STR	"?    "
+
+/*******************************************************************************
+ * Logging Macro's
+ ******************************************************************************/
+#define LOG_DEBUG(fmt, args...) { if (LOG_LEVEL_DEBUG <= main_log.level) { \
+					log_uip(LOG_LEVEL_DEBUG_STR, fmt, ##args);\
+				} }
+
+#define LOG_INFO(fmt, args...)  { if (LOG_LEVEL_INFO <= main_log.level) { \
+					log_uip(LOG_LEVEL_INFO_STR, fmt, ##args); \
+				} }
+#define LOG_WARN(fmt, args...)  { if (LOG_LEVEL_WARN <= main_log.level) { \
+					log_uip(LOG_LEVEL_WARN_STR, fmt, ##args); \
+				} }
+#define LOG_ERR(fmt, args...)   { if (LOG_LEVEL_ERR <= main_log.level) { \
+					log_uip(LOG_LEVEL_ERR_STR, fmt, ##args); \
+				} }
+
+/*******************************************************************************
+ * Logging Statistics
+ ******************************************************************************/
+struct logger_stats {
+	uint64_t debug;
+	uint64_t info;
+	uint64_t warn;
+	uint64_t error;
+
+	time_t   last_log_time;
+};
+
+/*******************************************************************************
+ * Logger Structure
+ ******************************************************************************/
+struct logger {
+	FILE *fp;
+	char *log_file;
+	int8_t   level;
+
+#define LOGGER_ENABLED	0x01
+#define LOGGER_DISABLED	0x02
+	int8_t   enabled;
+
+	pthread_mutex_t lock;
+
+	struct logger_stats stats;
+};
+
+extern struct logger main_log;
+
+int init_logger(char *);
+void log_uip(char *level_str, char *fmt, ...);
+void fini_logger();
+
+int backup_logger_settings(struct logger *src, struct logger *dest);
+int restore_backup(struct logger *src, struct logger *dest);
+
+#define CLOSE_LOGGER    0x01
+#define SHUTDOWN_LOGGER 0x02
+
+#endif
diff --git a/brcm_iscsi_uio/src/unix/main.c b/brcm_iscsi_uio/src/unix/main.c
new file mode 100644
index 0000000..bf307ff
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/main.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: main.c,v 1.16 2006/06/11 21:55:03 adam Exp $
+ *
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <net/ethernet.h>
+#include <arpa/inet.h>
+
+#include "uip.h"
+#include "uip_arp.h"
+#include "uip_eth.h"
+
+#include "timer.h"
+
+#include "build_date.h"
+#include "config.h"
+#include "logger.h"
+#include "nic.h"
+#include "nic_id.h"
+#include "nic_nl.h"
+#include "nic_utils.h"
+#include "options.h"
+#include "packet.h"
+#include "uevent.h"
+
+#include "dhcpc.h"
+
+#include "iscsid_ipc.h"
+#include "brcm_iscsi.h"
+
+/*******************************************************************************
+ *  Constants
+ ******************************************************************************/
+#define PFX "main "
+
+static char default_pid_filepath[]    = "/var/run/brcm_iscsiuio.pid";
+
+/*******************************************************************************
+ *  Global Variables
+ ******************************************************************************/
+static const struct option long_options[] = {
+	{"debug", 0, 0, 0},
+	{"version", 0, 0, 0},
+	{"help", 0, 0, 0},
+	{0, 0, 0, 0}
+};
+
+struct options opt = {
+	.debug = DEBUG_OFF,
+};
+
+int event_loop_stop = 0;
+
+/**
+ *  cleanup() - This function is called when this program is to be closed
+ *              This function will clean up all the cnic uio interfaces and
+ *              flush/close the logger
+ */
+static void cleanup()
+{
+	iscsid_cleanup();
+
+	cleanup_uevent_netlink_sock();
+
+	nic_close_all();
+
+	unload_all_nic_libraries();
+
+	LOG_INFO("Done waiting for cnic's/stacks to gracefully close");
+
+	fini_logger(SHUTDOWN_LOGGER);
+}
+
+/**
+ *  signal_handle_thread() - This is the signal handling thread of this program
+ *                           This is the only thread which will handle signals.
+ *                           All signals are routed here and handled here to
+ *                           provide consistant handling.
+ */
+static pthread_t signal_thread;
+static void * signal_handle_thread(void *arg)
+{
+	sigset_t set;
+	int rc;
+	int signal;
+
+	sigfillset(&set);
+
+	LOG_INFO("signal handling thread ready");
+
+	rc = sigwait(&set, &signal);
+
+	event_loop_stop = 1;
+	switch(signal)
+	{
+		case SIGINT:
+			LOG_INFO("Caught SIGINT signal");
+			break;
+	}
+
+	LOG_INFO("terminating...");
+
+	cleanup();
+	exit(EXIT_SUCCESS);
+}
+
+static void show_version()
+{
+	printf("%s: Version '%s', Build Date: '%s'\n",
+	       APP_NAME, PACKAGE_VERSION, build_date);
+}
+
+static void main_usage()
+{
+	show_version();
+
+	printf("\nUsage: %s [OPTION]\n", APP_NAME);
+	printf("\
+Open-iSCSI initiator daemon.\n\
+  -f, --foreground        make the program run in the foreground\n\
+  -d, --debug debuglevel  print debugging information\n\
+  -p, --pid=pidfile       use pid file (default  %s ).\n\
+  -h, --help              display this help and exit\n\
+  -v, --version           display version and exit\n\
+", default_pid_filepath);
+}
+
+static void daemon_init()
+{
+	int fd;
+
+	fd = open("/dev/null", O_RDWR);
+	if (fd == -1) {
+		exit(-1);
+	}
+
+	dup2(fd, 0);
+	dup2(fd, 1);
+	dup2(fd, 2);
+	setsid();
+	chdir("/");
+}
+
+/*******************************************************************************
+ * Main routine
+ ******************************************************************************/
+int main(int argc, char *argv[])
+{
+	int rc;
+	nic_t *nic;
+	sigset_t set;
+	char *pid_file = default_pid_filepath;
+	int fd;
+	int foreground=0;
+	pid_t pid;
+
+	/*  Record the start time for the user space daemon */
+	opt.start_time = time(NULL);
+
+	/*  parse the parameters */
+	while (1) {
+		int c, option_index;
+
+		c = getopt_long(argc, argv, "fd:p:vh",
+				long_options, &option_index);
+
+		if (c == -1)
+			break;
+
+		switch (c) {
+
+		case 'f':
+			foreground = 1;
+			break;
+
+		/* Enable debugging mode */
+		case 'd':
+			main_log.level = atoi(optarg);
+			opt.debug = DEBUG_ON;
+			break;
+		case 'p':
+			pid_file = optarg;
+			break;
+		case 'v':
+			show_version();
+			exit(EXIT_SUCCESS);
+		case 'h':
+		default:
+			main_usage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	if(!foreground) {
+		char buf[64];
+
+		fd = open(pid_file, O_WRONLY|O_CREAT, 0644);
+		if (fd < 0) {
+			printf("Unable to create pid file: %s", pid_file);
+			exit(1);
+		}
+
+		pid = fork();
+		if (pid < 0) {
+			printf("Starting daemon failed");
+			exit(1);
+		} else if (pid) {
+			exit(0);
+		}
+
+		chdir("/");
+		if (lockf(fd, F_TLOCK, 0) < 0) {
+			printf("Unable to lock pid file: %s [%s]",
+				pid_file, strerror(errno));
+			exit(1);
+		}
+
+		ftruncate(fd, 0);
+		sprintf(buf, "%d\n", getpid());
+		write(fd, buf, strlen(buf));
+
+		daemon_init();
+	}
+
+	if(main_log.enabled == LOGGER_ENABLED) {
+		/*  initialize the logger */
+		rc = init_logger(main_log.log_file);
+		if (rc != 0) {
+			printf("Could not initialize the logger\n");
+			goto error;
+		}
+	}
+
+	LOG_INFO("Started BRCM iSCSI stack: Ver " PACKAGE_VERSION);
+	LOG_INFO("Build date: %s", build_date);
+
+	if (opt.debug == DEBUG_ON) {
+		LOG_INFO("Debug mode enabled");
+	}
+
+	/*  Load the NIC libraries */
+	rc = load_all_nic_libraries();
+	if(rc != 0) {
+		goto error;
+	}
+
+	/*  Initialze the iscsid listener */
+	rc = iscsid_init();
+	if (rc != 0) {
+		goto error;
+	}
+
+	/*  Setup the watching of uio devices */
+	rc = init_uevent_netlink_sock();
+	if(rc != 0) {
+		goto error;
+	}
+
+	brcm_iscsi_init();
+
+	/*  ensure we don't see any signals */
+	sigemptyset(&set);
+	sigaddset(&set, SIGINT);
+	sigaddset(&set, SIGQUIT);
+	sigaddset(&set, SIGTERM);
+	rc = pthread_sigmask(SIG_SETMASK, &set, NULL);
+
+	/*  Spin off the signal handling thread */
+	rc = pthread_create(&signal_thread, NULL, signal_handle_thread, NULL);
+	if (rc != 0) {
+		LOG_ERR("Could not create singal handling thread");
+	}
+
+	pthread_mutex_lock(&nic_list_mutex);
+	/*  Start to spin off the nic threads */
+	nic = nic_list;
+	while(nic != NULL) {
+		prepare_nic(nic);
+		nic = nic->next;
+	}
+
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	/* Using sysfs to discover iSCSI hosts */
+	nic_discover_iscsi_hosts();
+
+	/*  NetLink connection to listen to NETLINK_ISCSI private messages */
+	nic_nl_open();
+
+      error:
+	cleanup();
+	exit(EXIT_FAILURE);
+}
diff --git a/brcm_iscsi_uio/src/unix/nic.c b/brcm_iscsi_uio/src/unix/nic.c
new file mode 100644
index 0000000..af1b5fd
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic.c
@@ -0,0 +1,1128 @@
+/* nic.c: Generic NIC management/utility functions
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "dhcpc.h"
+
+#include "logger.h"
+#include "nic.h"
+#include "nic_utils.h"
+#include "options.h"
+
+#include "uip.h"
+#include "uip_arp.h"
+#include "uip_eth.h"
+#include "uip-neighbor.h"
+
+#include "bnx2.h"
+#include "bnx2x.h"
+
+/******************************************************************************
+ *  Constants
+ *****************************************************************************/
+#define PFX "nic "
+
+/******************************************************************************
+ *  Global variables
+ *****************************************************************************/
+/*  Used to store a list of NIC libraries */
+pthread_mutex_t nic_lib_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+nic_lib_handle_t *nic_lib_list;
+
+/*  Used to store a list of active cnic devices */
+pthread_mutex_t nic_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+nic_t *nic_list = NULL;
+
+/******************************************************************************
+ *  Functions to handle NIC libraries
+ *****************************************************************************/
+/**
+ *  alloc_nic_library_handle() - Used to allocate a NIC library handle
+ *  @return NULL if memory couldn't be allocated, pointer to the handle
+ *    to the NIC library handle 
+ */
+static nic_lib_handle_t * alloc_nic_library_handle()
+{
+	nic_lib_handle_t *handle;
+
+	handle = malloc(sizeof(*handle));
+	if(handle == NULL)
+		return NULL;
+
+	memset(handle, 0, sizeof(*handle));
+	handle->ops	  = NULL;
+
+	pthread_mutex_init(&handle->mutex, NULL);
+
+	return handle;
+}
+
+static void free_nic_library_handle(nic_lib_handle_t *handle)
+{
+	free(handle);
+}
+
+/**
+ *  load_nic_library() - This function is used to load a NIC library
+ *  @param handle - This is the library handle to load
+ *  @return 0 = Success; <0 = failure
+ */
+static int load_nic_library(nic_lib_handle_t *handle)
+{
+	int rc;
+	char *library_name;
+	size_t library_name_size;
+	char *library_version;
+	size_t library_version_size;
+	char *build_date_str;
+	size_t build_date_str_size;
+
+	pthread_mutex_lock(&handle->mutex);
+
+	/* Validate the NIC ops table ensure that all the fields are not NULL */
+	if((handle->ops->open)  == NULL ||
+	   (handle->ops->close) == NULL ||
+	   (handle->ops->read)  == NULL ||
+	   (handle->ops->write) == NULL ||
+	   (handle->ops->clear_tx_intr == NULL)) {
+		LOG_ERR("Invalid NIC ops table: open: 0x%x, close: 0x%x,"
+			"read: 0x%x, write: 0x%x clear_tx_intr: 0x%x "
+			"lib_ops: 0x%x",
+			handle->ops->open, handle->ops->close,
+			handle->ops->read, handle->ops->write,
+			handle->ops->clear_tx_intr,
+			handle->ops->lib_ops);
+		rc = -EINVAL;
+		handle->ops = NULL;
+		goto error;
+	}
+
+	/*  Validate the NIC library ops table to ensure that all the proper
+	 *  fields are filled */
+	if((handle->ops->lib_ops.get_library_name == NULL) ||
+           (handle->ops->lib_ops.get_pci_table == NULL)    || 
+           (handle->ops->lib_ops.get_library_version == NULL) ||
+           (handle->ops->lib_ops.get_build_date == NULL)   ||
+           (handle->ops->lib_ops.get_transport_name == NULL)) {
+		rc =-EINVAL;
+		goto error;
+	}
+
+	(*handle->ops->lib_ops.get_library_name)(&library_name,
+				  		 &library_name_size);
+	(*handle->ops->lib_ops.get_library_version)(&library_version,
+						    &library_version_size);
+	(*handle->ops->lib_ops.get_build_date)(&build_date_str,
+					       &build_date_str_size);
+
+	LOG_DEBUG("Loaded nic library '%s' Version: '%s' build on %s'",
+		  library_name, library_version, build_date_str);
+	
+	pthread_mutex_unlock(&handle->mutex);
+
+	return 0;
+
+error:
+	pthread_mutex_unlock(&handle->mutex);
+
+	return rc;
+}
+
+static struct nic_ops * (*nic_get_ops[])() = {
+	bnx2_get_ops,
+	bnx2x_get_ops,
+};
+
+int load_all_nic_libraries()
+{
+	int rc, i = 0;
+	nic_lib_handle_t *handle;
+
+	for(i=0; i < sizeof(nic_get_ops) / sizeof(nic_get_ops[0]); i++) {
+		/*  Add the CNIC library */
+		handle = alloc_nic_library_handle();
+		if(handle == NULL) {
+			LOG_ERR("Could not allocate memory for CNIC nic lib");
+			return -ENOMEM;
+		}
+
+		handle->ops = (*nic_get_ops[i])();
+
+		rc = load_nic_library(handle);
+		if(rc != 0)
+			return rc;
+
+		/*  Add the CNIC library to the list of library handles */
+		pthread_mutex_lock(&nic_lib_list_mutex);
+	
+		/*  Add this library to the list of nic libraries we
+		 *  know about */
+		if(nic_lib_list == NULL) {
+			nic_lib_list = handle;
+		} else {
+			nic_lib_handle_t *current = nic_lib_list;
+
+			while(current->next != NULL) {
+				current = current->next;
+			}
+
+			current->next = handle;
+		}
+		pthread_mutex_unlock(&nic_lib_list_mutex);
+
+		LOG_DEBUG("Added '%s' nic library", handle->ops->description);
+	}
+
+	return rc;
+}
+
+int unload_all_nic_libraries() {
+	nic_lib_handle_t *current, *next;
+
+	pthread_mutex_lock(&nic_lib_list_mutex);
+	current = nic_lib_list;
+	
+	while(current != NULL) {
+		next = current->next;
+		free_nic_library_handle(current);
+
+		current = next;
+	}
+
+	pthread_mutex_unlock(&nic_lib_list_mutex);
+
+	nic_lib_list = NULL;
+
+	return 0;
+}
+
+NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name)
+{
+	NIC_LIBRARY_EXIST_T rc;
+	nic_lib_handle_t *current;
+
+	pthread_mutex_lock(&nic_lib_list_mutex);
+	current = nic_lib_list;
+	
+	while(current != NULL) {
+		char *uio_name;
+		size_t uio_name_size;
+
+		(*current->ops->lib_ops.get_uio_name)(&uio_name,
+						      &uio_name_size);
+
+		if(strncmp(name, uio_name, uio_name_size) == 0) {
+			rc = NIC_LIBRARY_EXSITS;
+			goto done;
+		}
+
+		current = current->next;
+	}
+
+	rc = NIC_LIBRARY_DOESNT_EXIST;
+
+done:
+	pthread_mutex_unlock(&nic_lib_list_mutex);
+	return rc;
+}
+
+NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name)
+{
+	NIC_LIBRARY_EXIST_T rc;
+	nic_lib_handle_t *current;
+
+	pthread_mutex_lock(&nic_lib_list_mutex);
+	current = nic_lib_list;
+	
+	while(current != NULL) {
+		char *library_name;
+		size_t library_name_size;
+
+		(*current->ops->lib_ops.get_library_name)(&library_name,
+						 	  &library_name_size);
+
+		if(strncmp(name, library_name, library_name_size) == 0) {
+			rc = NIC_LIBRARY_EXSITS;
+			goto done;
+		}
+
+		current = current->next;
+	}
+
+	rc = NIC_LIBRARY_DOESNT_EXIST;
+
+done:
+	pthread_mutex_unlock(&nic_lib_list_mutex);
+	return rc;
+}
+
+/**
+ *  find_nic_lib_using_pci_id() - Find the proper NIC library using the 
+ *     PCI ID's
+ *  @param vendor - PCI vendor ID to search on
+ *  @param device - PCI device ID to search on
+ *  @param subvendor - PCI subvendor ID to search on
+ *  @param subdevice - PCI subdevice ID to search on
+ *  @param handle - This function will return the nic lib handle if found
+ *  @return 0 if found, <0 not found
+ */
+int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device,
+			      uint32_t subvendor, uint32_t subdevice,
+	 		      nic_lib_handle_t **handle,
+			      struct pci_device_id **pci_entry)
+{
+	int rc;
+	nic_lib_handle_t *current;
+
+	pthread_mutex_lock(&nic_lib_list_mutex);
+	current = nic_lib_list;
+	
+	while(current != NULL) {
+		struct pci_device_id *pci_table;
+		uint32_t entries;
+		int i;
+
+		current->ops->lib_ops.get_pci_table(&pci_table, &entries);
+
+		/*  Sanity check the the pci table coming from the 
+		 *  hardware library */
+		if(entries > MAX_PCI_DEVICE_ENTRIES) {
+			LOG_WARN(PFX "Too many pci_table entries(%d) skipping",
+				 entries);
+			continue;
+		}
+
+		for(i=0; i<entries; i++) {
+			LOG_DEBUG(PFX "Checking against: "
+				      "vendor: 0x%x device:0x%x "
+				      "subvendor:0x%x subdevice:0x%x",
+				      pci_table[i].vendor, pci_table[i].device,
+				      pci_table[i].subvendor,
+				      pci_table[i].subdevice);
+
+			if(((vendor & pci_table[i].vendor) == vendor) &&
+			   ((device & pci_table[i].device) == device) &&
+			   ((subvendor & pci_table[i].subvendor) == subvendor) &&
+			   ((subdevice & pci_table[i].subdevice) == subdevice)) {
+				*handle = current;
+				*pci_entry = &pci_table[i];
+				rc = 0;
+				goto done;
+			}
+		}
+
+		current = current->next;
+	}
+	rc = -EINVAL;
+
+done:
+	pthread_mutex_unlock(&nic_lib_list_mutex);
+	
+	return rc;
+}
+
+/**
+ * nic_init() - This will properly initialize a struct cnic_uio device
+ * @return NULL is there is a failure and pointer to an allocated/initialized
+ *         struct cnic_uio on success
+ */
+nic_t *nic_init()
+{
+	nic_t *nic;
+
+	nic = malloc(sizeof(*nic));
+	if (nic == NULL) {
+		LOG_ERR("Coudln't malloc space for nic");
+		return NULL;
+	}
+
+	memset(nic, 0, sizeof(*nic));
+	nic->uio_minor = -1;
+	nic->fd   = INVALID_FD;
+	nic->next = NULL;
+	nic->thread = INVALID_THREAD;
+	nic->flags |= NIC_UNITIALIZED | NIC_DISABLED;
+	nic->state |= NIC_STOPPED;
+	nic->free_packet_queue = NULL;
+	nic->tx_packet_queue = NULL;
+	nic->nic_library = NULL;
+	nic->pci_id	 = NULL;
+	
+	pthread_mutex_init(&nic->uio_wait_mutex, NULL);
+	pthread_cond_init(&nic->uio_wait_cond, NULL);
+
+	pthread_mutex_init(&nic->enable_wait_mutex, NULL);
+	pthread_cond_init(&nic->enable_wait_cond, NULL);
+
+	pthread_mutex_init(&nic->enable_done_mutex, NULL);
+	pthread_cond_init(&nic->enable_done_cond, NULL);
+
+	pthread_mutex_init(&nic->nic_loop_started_mutex, NULL);
+	pthread_cond_init(&nic->nic_loop_started_cond, NULL);
+
+	pthread_mutex_init(&nic->disable_wait_mutex, NULL);
+	pthread_cond_init(&nic->disable_wait_cond, NULL);
+
+	pthread_mutex_init(&nic->xmit_mutex, NULL);
+	pthread_mutex_init(&nic->nic_iface_mutex, NULL);
+
+	pthread_mutex_init(&nic->free_packet_queue_mutex, NULL);
+
+	nic->rx_poll_usec = DEFAULT_RX_POLL_USEC;
+
+	/*  Add this device to our list of nics */
+	pthread_mutex_lock(&nic_list_mutex);
+	if(nic_list == NULL) {
+		nic_list = nic;
+	} else {
+		nic_t *current = nic_list;
+
+		while (current->next != NULL) {
+			current = current->next;
+		}
+
+		current->next = nic;
+	}
+
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	return nic;
+}
+
+int nic_remove(nic_t *nic, int locked)
+{
+	int rc;
+	nic_t *prev, *current;
+
+	if(nic->ops)
+		nic->ops->close(nic, 0);
+
+	nic->state = NIC_EXIT;
+	rc = pthread_cancel(nic->thread);
+	if(rc != 0)
+		LOG_ERR(PFX "%s: Coudln't send cancel to nic", nic->log_name);
+
+	rc = pthread_join(nic->thread, NULL);
+	if(rc != 0)
+		LOG_ERR(PFX "%s: Coudln't join to canceled nic thread",
+			nic->log_name);
+
+	nic->thread == INVALID_THREAD;
+
+	if(!locked)
+		pthread_mutex_lock(&nic_list_mutex);
+
+	current = prev = nic_list;
+	while(current != NULL) {
+		if(current == nic)
+			break;
+
+		prev = current;
+		current = current->next;
+	}
+
+	if (current != NULL) {
+		if (current == nic_list)
+			nic_list = current->next;
+		else
+			prev->next = current->next;
+
+		free(nic);
+	} else {
+		LOG_ERR(PFX "%s: Coudln't find nic", nic->log_name);
+	}
+
+	if(!locked)
+		pthread_mutex_unlock(&nic_list_mutex);
+}
+
+/** 
+ *  nic_close() - Used to indicate to a NIC that it should close
+ *  @param nic - the nic to close
+ *  @param graceful -  ALLOW_GRACEFUL_SHUTDOWN will check the nic state
+ *                     before proceeding to close()
+ *                     FORCE_SHUTDOWN will force the nic to close()
+ *                     reguardless of the state
+ */
+void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+	int rc;
+	nic_interface_t *nic_iface;
+
+	if((nic->flags & NIC_DISABLED) &&
+	   (graceful == ALLOW_GRACEFUL_SHUTDOWN))
+		return;
+
+	/*  The NIC could be configured by the uIP config file
+	 *  but not assoicated with a hardware library just yet
+	 *  we will need to check for this */
+	if(nic->ops == NULL) {
+		LOG_WARN(PFX "%s: when closing nic->ops == NULL",
+			 nic->log_name);
+		return;
+	}
+
+	rc = (*nic->ops->close)(nic, graceful);
+	if(rc != 0) {
+		LOG_ERR(PFX "%s: Could not close nic", nic->log_name);
+	} else  {
+		nic->state = NIC_STOPPED;
+		nic->flags &= ~NIC_ENABLED;
+		nic->flags |= NIC_DISABLED;
+	}
+
+	pthread_mutex_lock(&nic->nic_iface_mutex);
+
+	nic_iface = nic->nic_iface;
+	while(nic_iface != NULL)
+	{
+		uip_reset(&nic_iface->ustack);
+		nic_iface = nic_iface->next;
+	}
+	pthread_mutex_unlock(&nic->nic_iface_mutex);
+}
+
+
+/**
+ *  net_iface_init() - This function is used to add an interface to the 
+ *                     structure cnic_uio
+ *  @return 0 on success, <0 on failure
+ */
+nic_interface_t * nic_iface_init()
+{
+	nic_interface_t *nic_iface = malloc(sizeof(*nic_iface));
+	if(nic_iface == NULL)
+	{
+		LOG_ERR("Could not allocate space for nic iface");
+		return NULL;
+	}
+
+	memset(nic_iface, 0, sizeof(*nic_iface));
+	nic_iface->next = NULL;
+
+	return nic_iface;
+}
+
+/**
+ *  nic_add_net_iface() - This function is used to add an interface to the 
+ *                        nic structure
+ *  @param nic - struct nic device to add the interface to
+ *  @param nic_iface - network interface used to add to the nic
+ *  @return 0 on success, <0 on failure
+ */
+int nic_add_nic_iface(nic_t *nic, 
+		      nic_interface_t *nic_iface)
+{
+
+	pthread_mutex_lock(&nic->nic_iface_mutex);
+
+	/*  Add the nic_interface */
+	if(nic->nic_iface == NULL) {
+		nic->nic_iface = nic_iface;
+	} else {
+		nic_interface_t *current = nic->nic_iface;
+
+		while(current->next != NULL)
+		{
+			current = current->next;
+		}
+
+		current->next = nic_iface;
+	}
+
+	/* Set nic_interface common fields */
+	nic_iface->parent = nic;
+	nic->num_of_nic_iface++;
+
+	pthread_mutex_unlock(&nic->nic_iface_mutex);
+
+	return 0;
+}
+
+/******************************************************************************
+ * Routine to process interrupts from the NIC device
+ ******************************************************************************/
+/**
+ *  nic_process_intr() - Routine used to process interrupts from the hardware
+ *  @param nic - NIC hardware to process the interrupt on
+ *  @return 0 on success, <0 on failure
+ */
+int nic_process_intr(nic_t *nic, int discard_check)
+{
+	fd_set fdset;
+	int ret;
+	int count;
+	struct timeval tv;
+
+	/*  Simple sanity checks */
+	if ((discard_check != 1) &&
+	    (nic->state & NIC_RUNNING) != NIC_RUNNING) {
+		LOG_ERR(PFX "%s: Couldn't process interupt NIC not running",
+			nic->log_name);
+		return -EBUSY;
+	}
+
+	if((discard_check != 1) &&
+	   (nic->fd == INVALID_FD)) {
+		LOG_ERR(PFX "%s: NIC fd not valid", nic->log_name);
+		return -EIO;
+	}
+
+	FD_ZERO(&fdset);
+	FD_SET(nic->fd, &fdset);
+
+	tv.tv_sec = 0;
+	if(nic->state & NIC_LONG_SLEEP) {
+		tv.tv_usec = 1000;
+	} else {
+		tv.tv_usec = nic->rx_poll_usec;
+	}
+
+	/*  Wait for an interrupt to come in or timeout */
+	ret = select(nic->fd + 1, &fdset, NULL, NULL, &tv);
+	switch(ret)
+	{
+	case 1:
+		/* Usually there should only be one file descriptor ready
+		 * to read */
+		break;
+	case 0:
+		return ret;
+	case -1:
+		LOG_ERR(PFX "%s: error waiting for interrupt: %s",
+			nic->log_name, strerror(errno));
+		return 0;
+	default:
+		LOG_ERR(PFX "%s: unknown number of FD's, ignoring: %d ret",
+			nic->log_name, ret);
+		return 0;
+	}
+
+	ret = read(nic->fd, &count, sizeof(count));
+	if (ret > 0) {
+		nic->stats.interrupts++;
+		LOG_DEBUG(PFX "%s: interrupt count: %d prev: %d", 
+			  nic->log_name, count, nic->intr_count);
+
+		if(count == nic->intr_count) {
+			LOG_ERR(PFX "%s: got interrupt but count still the "
+				    "same", 
+				     nic->log_name, count);
+			return 0;
+		}
+
+		/*  Check if we missed an interrupt.  With UIO, 
+		 *  the count should be incremental */
+		if(count != nic->intr_count + 1) {
+			nic->stats.missed_interrupts++;
+			LOG_ERR(PFX "%s: Missed interrupt! on %d not %d", 
+				nic->log_name, count, nic->intr_count);
+		}
+
+		nic->intr_count = count;
+
+		(*nic->ops->clear_tx_intr)(nic);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static void prepare_ipv4_packet(nic_t *nic,
+				nic_interface_t *nic_iface,
+				struct uip_stack *ustack,
+				packet_t *pkt)
+{
+	u16_t ipaddr[2];
+	arp_table_query_t arp_query;
+	dest_ipv4_addr_t  dest_ipv4_addr;
+	struct arp_entry *tabptr;
+	int queue_rc;
+
+	dest_ipv4_addr = uip_determine_dest_ipv4_addr(ustack, ipaddr);
+	if(dest_ipv4_addr == LOCAL_BROADCAST)
+	{
+		uip_build_eth_header(ustack, ipaddr, NULL, pkt);
+		return;
+	}
+
+	arp_query = is_in_arp_table(ipaddr, &tabptr);
+
+	switch(arp_query) {
+		case IS_IN_ARP_TABLE:
+			uip_build_eth_header(ustack,
+					     ipaddr,
+					     tabptr,
+					     pkt);
+			break;
+		case NOT_IN_ARP_TABLE:
+			queue_rc = nic_queue_tx_packet(nic,
+						       nic_iface,
+						       pkt);
+			uip_build_arp_request(ustack, ipaddr);
+			break;
+		default:
+			LOG_ERR("Unknown arp state");
+			break;
+	}
+}
+
+static void prepare_ustack(nic_t *nic,
+		    nic_interface_t *nic_iface,
+		    struct uip_stack *ustack,
+		    struct packet * pkt)
+{
+	ustack->uip_buf = pkt->buf;
+	ustack->uip_len = pkt->buf_size;
+
+	pkt->nic = nic;
+	pkt->nic_iface = nic_iface;
+
+	ustack->data_link_layer = pkt->buf;
+	/*  Adjust the network layer pointer depending if
+	 *  there is a VLAN tag or not, or if the hardware 
+	 *  has stripped out the
+	 *  VLAN tag */
+	if((nic_iface->vlan_id == 0) ||
+	   (NIC_VLAN_STRIP_ENABLED & nic->flags)) {
+		ustack->network_layer = ustack->data_link_layer +
+				    sizeof(struct uip_eth_hdr);
+	} else {
+		ustack->network_layer = ustack->data_link_layer +
+				    sizeof(struct uip_vlan_eth_hdr);
+	}
+}
+
+static int check_timers(nic_t *nic,
+			struct timer *periodic_timer,
+			struct timer *arp_timer,
+			uint8_t take_iface_mutex)
+{
+	if (timer_expired(periodic_timer)) {
+		int i;
+		nic_interface_t *current;
+
+		timer_reset(periodic_timer);
+
+		if(take_iface_mutex)
+			pthread_mutex_lock(&nic->nic_iface_mutex);
+
+		current = nic->nic_iface;
+		while(current != NULL)
+		{
+			packet_t *pkt;
+			struct uip_stack *ustack = &current->ustack;
+
+			pkt = get_next_free_packet(nic);
+			if(pkt == NULL)
+			{
+				continue;
+			}
+
+
+			for (i = 0; i < UIP_CONNS; i++) {
+				prepare_ustack(nic,
+					       current,
+					       ustack,
+					       pkt);
+
+				uip_periodic(ustack, i);
+				/* If the above function invocation resulted
+				 * in data that should be sent out on the 
+				 * network, the global variable uip_len 
+				 * is set to a value > 0. */
+				if (ustack->uip_len > 0) {
+					pkt->buf_size = ustack->uip_len;
+
+					prepare_ipv4_packet(nic,
+							    current,
+							    ustack,
+							    pkt);
+
+					(*nic->ops->write)(nic, current, pkt);
+				}
+			}
+
+			for (i = 0; i < UIP_UDP_CONNS; i++) {
+				prepare_ustack(nic,
+					       current,
+					       ustack,
+					       pkt);
+
+				uip_udp_periodic(ustack, i);
+				/* If the above function invocation resulted
+				 * in data that should be sent out on the 
+				 * network, the global variable uip_len is 
+				 * set to a value > 0. */
+				if (ustack->uip_len > 0) {
+					pkt->buf_size = ustack->uip_len;
+
+					prepare_ipv4_packet(nic,
+							    current,
+							    ustack,
+							    pkt);
+
+					(*nic->ops->write)(nic, current, pkt);
+				}
+			}
+
+			/* Call the ARP timer function every 10 seconds. */
+			if (timer_expired(arp_timer)) {
+				timer_reset(arp_timer);
+				uip_arp_timer();
+			}
+
+			put_packet_in_free_queue(pkt, nic);
+
+ 	               current = current->next;
+	        }
+
+		if(take_iface_mutex)
+	        	pthread_mutex_unlock(&nic->nic_iface_mutex);
+	}
+
+	return 0;
+}
+
+int process_packets(nic_t *nic,
+		    struct timer *periodic_timer, 
+		    struct timer *arp_timer,
+		    nic_interface_t *nic_iface)
+{
+	int rc;
+	packet_t *pkt;
+
+	pkt = get_next_free_packet(nic);
+	if(pkt == NULL)
+		return -ENOMEM;
+
+	rc = (*nic->ops->read)(nic, pkt);
+	if (rc != 0) {
+		uint16_t type;
+		struct uip_stack *ustack;
+
+		/*  check if we have the given VLAN interface */
+		if(nic_iface == NULL) {
+			nic_iface = nic_find_nic_iface(nic, pkt->vlan_tag);
+			if(nic_iface == NULL)
+			{
+				LOG_ERR(PFX "%s: Couldn't find interface for "
+					    "VLAN: %d",
+					nic->log_name, pkt->vlan_tag);
+				rc =0;
+				goto done;
+			}
+		}
+
+		pkt->nic_iface = nic_iface;
+
+		ustack = &nic_iface->ustack;
+
+		ustack->uip_buf = pkt->buf;
+		ustack->uip_len = pkt->buf_size;
+		ustack->data_link_layer = pkt->buf;
+
+		pkt->data_link_layer = pkt->buf;
+
+		/*  Adjust the network layer pointer depending if there is a
+		 *  VLAN tag or not, or if the hardware has stripped out the
+		 *  VLAN tag */
+		if((pkt->vlan_tag == 0) || 
+		   (NIC_VLAN_STRIP_ENABLED & nic->flags)) {
+			ustack->network_layer = ustack->data_link_layer +
+					    sizeof(struct uip_eth_hdr);
+			pkt->network_layer = pkt->data_link_layer +
+					     sizeof(struct uip_eth_hdr);
+			type = ntohs(ETH_BUF(pkt->buf)->type);
+		} else {
+			ustack->network_layer = ustack->data_link_layer +
+					    sizeof(struct uip_vlan_eth_hdr);
+			pkt->network_layer = pkt->data_link_layer +
+					     sizeof(struct uip_vlan_eth_hdr);
+			type = ntohs(VLAN_ETH_BUF(pkt->buf)->type);
+		}
+		
+		/*  determine how we should process this packet based on the
+		 *  ethernet type */
+		switch(type) {
+		case UIP_ETHTYPE_IPv6:
+		case UIP_ETHTYPE_IPv4:
+			uip_arp_ipin();
+			uip_input(ustack);
+			/* If the above function invocation resulted 
+			 * in data that should be sent out on the 
+			 * network, the global variable uip_len is 
+			 * set to a value > 0. */
+			if (ustack->uip_len > 0) {
+				if(is_ipv6(ustack))
+					uip_neighbor_out(ustack);
+				else 
+					prepare_ipv4_packet(nic,
+							    nic_iface,
+							    ustack,
+							    pkt);
+
+				(*nic->ops->write)(nic, nic_iface, pkt);
+			}
+			break;
+		case UIP_ETHTYPE_ARP:
+			uip_arp_arpin(ustack, pkt);
+
+			/* If the above function invocation resulted 
+			 * in data that should be sent out on the 
+			 * network, the global variable uip_len 
+			 * is set to a value > 0. */
+			if (pkt->buf_size > 0) {
+
+				(*nic->ops->write)(nic, nic_iface, pkt);
+			}
+			break;
+		}
+	}
+
+done:
+	put_packet_in_free_queue(pkt, nic);
+
+	return rc;
+}
+
+static int process_dhcp_loop(nic_t *nic,
+			     nic_interface_t *nic_iface,
+			     struct timer *periodic_timer,
+			     struct timer *arp_timer)
+{
+	struct dhcpc_state *s;
+	int rc;
+
+	s = nic_iface->ustack.dhcpc;
+
+	while ((event_loop_stop == 0) &&
+	       (s->state != STATE_CONFIG_RECEIVED) &&
+	       (nic->flags & NIC_ENABLED)) {
+		/*  Check the periodic and ARP timer */
+		check_timers(nic, periodic_timer, arp_timer, 0);
+
+		rc = nic_process_intr(nic, 1);
+
+		while(rc > 0) {
+			rc = process_packets(nic,
+					     periodic_timer,
+					     arp_timer,
+					     nic_iface);
+		}
+
+		sleep(1);
+	}
+
+	return 0;
+}
+
+
+static void nic_loop_close(void *arg)
+{
+	nic_t *nic = (nic_t *) arg;
+
+	(*nic->ops->close)(nic, 0);
+}
+
+void *nic_loop(void *arg)
+{
+	nic_t *nic = (nic_t *) arg;
+	int rc = -1;
+	struct timer periodic_timer, arp_timer;
+	sigset_t set;
+
+	sigfillset(&set);
+	rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
+	if (rc != 0 )
+	{
+		/* TODO: determine if we need to exit this thread if we fail
+		 * to set the signal mask */
+		LOG_ERR(PFX "%s: Couldn't set signal mask", nic->log_name);
+	}
+
+	pthread_cleanup_push(nic_loop_close, arg);
+
+	/*  Signal the device to enable itself */
+	pthread_mutex_lock(&nic->nic_loop_started_mutex);
+	pthread_cond_signal(&nic->nic_loop_started_cond);
+	pthread_mutex_unlock(&nic->nic_loop_started_mutex);
+
+	while(event_loop_stop == 0) {
+		nic_interface_t *nic_iface;
+
+		if(nic->flags & NIC_DISABLED)
+		{
+			LOG_DEBUG(PFX "%s: Waiting to be enabled",
+				  nic->log_name);
+
+			/*  Wait for the device to be enabled */
+			pthread_mutex_lock(&nic->enable_wait_mutex);
+			pthread_cond_wait(&nic->enable_wait_cond,
+					  &nic->enable_wait_mutex);
+			pthread_mutex_unlock(&nic->enable_wait_mutex);
+
+			if (nic->state == NIC_EXIT)
+				pthread_exit(NULL);	
+
+			LOG_DEBUG(PFX "%s: is now enabled", nic->log_name);
+		}
+
+		/*  initialize the device to send/rec data */
+		rc = (*nic->ops->open)(nic);
+		if(rc != 0)
+		{
+			LOG_ERR(PFX "%s: Could not initialize CNIC UIO device",
+				nic->log_name);
+		}
+
+		add_vlan_interfaces(nic);
+		nic_set_all_nic_iface_mac_to_parent(nic);
+
+		rc = alloc_free_queue(nic, 5);
+		if(rc != 5)
+		{
+			LOG_WARN(PFX "%s: Allocated %d packets instead of %d",
+				 nic->log_name, rc, 5);
+		}
+
+		/*  Initialize the system clocks */
+		timer_set(&periodic_timer, CLOCK_SECOND / 2);
+		timer_set(&arp_timer, CLOCK_SECOND * 10);
+
+		/*  Prepare the stack for each of the VLAN interfaces */
+		pthread_mutex_lock(&nic->nic_iface_mutex);
+
+		nic_iface = nic->nic_iface;
+		while(nic_iface != NULL)
+		{
+			uip_init(&nic_iface->ustack,
+				 nic->flags & NIC_IPv6_ENABLED);
+
+			LOG_INFO(PFX "%s: Initialized ip stack: VLAN: %d",
+				 nic->log_name, nic_iface->vlan_id);
+
+			LOG_INFO(PFX "%s: mac: %02x:%02x:%02x:%02x:%02x:%02x",
+				 nic->log_name,
+				 nic_iface->mac_addr[0],
+				 nic_iface->mac_addr[1],
+				 nic_iface->mac_addr[2],
+				 nic_iface->mac_addr[3],
+				 nic_iface->mac_addr[4],
+				 nic_iface->mac_addr[5]);
+
+			if( nic_iface->ustack.ip_config == IP_CONFIG_STATIC ) {
+				struct in_addr addr;
+				uip_ip4addr_t tmp = { 0, 0};
+
+				memcpy(&addr.s_addr, nic_iface->ustack.hostaddr,
+				       sizeof(addr.s_addr));
+
+				LOG_INFO(PFX "%s: Using IP address: %s",
+					 nic->log_name,
+					 inet_ntoa(addr));
+
+				memcpy(&addr.s_addr, nic_iface->ustack.netmask,
+				       sizeof(addr.s_addr));
+
+				LOG_INFO(PFX "%s: Using netmask: %s",
+					 nic->log_name,
+					 inet_ntoa(addr));
+
+				set_uip_stack(&nic_iface->ustack, 
+					      &nic_iface->ustack.hostaddr,
+					      &nic_iface->ustack.netmask,
+					      &tmp,
+					      nic_iface->mac_addr);
+
+			} else {
+				struct uip_stack *ustack = &nic_iface->ustack;
+				uip_ip4addr_t tmp = { 0, 0};
+				
+
+				set_uip_stack(&nic_iface->ustack, 
+					      &nic_iface->ustack.hostaddr,
+					      &nic_iface->ustack.netmask,
+					      &tmp,
+					      nic_iface->mac_addr);
+
+				dhcpc_init(nic, ustack,
+					   nic_iface->mac_addr, ETH_ALEN);
+				rc = process_dhcp_loop(nic, nic_iface,
+						       &periodic_timer,
+						       &arp_timer);
+
+				if(nic->flags & NIC_DISABLED)
+					break;
+
+				LOG_INFO(PFX "%s: Initialized dhcp client",
+					 nic->log_name);
+			}
+
+			nic_iface = nic_iface->next;
+		}
+
+                if(nic->flags & NIC_DISABLED)
+                        goto dev_close;
+
+		pthread_mutex_unlock(&nic->nic_iface_mutex);
+
+		/*  This is when we start the processing of packets */
+		nic->start_time = time(NULL);
+		nic->flags &= ~NIC_UNITIALIZED;
+		nic->flags |= NIC_INITIALIZED;
+		nic->state |= NIC_RUNNING;
+
+                /*  Signal that the device enable is done */
+		pthread_mutex_lock(&nic->enable_done_mutex);
+		pthread_cond_broadcast(&nic->enable_done_cond);
+		pthread_mutex_unlock(&nic->enable_done_mutex);
+
+		while ((nic->state & NIC_RUNNING) && (event_loop_stop == 0)) {
+			/*  Check the periodic and ARP timer */
+			check_timers(nic,
+				     &periodic_timer,
+				     &arp_timer,
+				     1);
+
+			rc = nic_process_intr(nic, 0);
+			while((rc > 0) && (nic->state & NIC_RUNNING)) {
+				rc = process_packets(nic,
+						     &periodic_timer,
+						     &arp_timer,
+						     NULL);
+			}
+		}
+
+dev_close:
+		nic->state = NIC_STOPPED;
+		nic_close(nic, 1);
+
+		/*  Signal we are done closing CNIC/UIO device */
+		pthread_mutex_lock(&nic->disable_wait_mutex);
+		pthread_cond_broadcast(&nic->disable_wait_cond);
+		pthread_mutex_unlock(&nic->disable_wait_mutex);
+	}
+
+	pthread_cleanup_pop(0);
+
+	pthread_exit(NULL);
+}
diff --git a/brcm_iscsi_uio/src/unix/nic.h b/brcm_iscsi_uio/src/unix/nic.h
new file mode 100644
index 0000000..d20e9d1
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic.h
@@ -0,0 +1,319 @@
+/* nic.h:  NIC header file
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+
+#ifndef __NIC_H__
+#define __NIC_H__
+
+#include <stdint.h>
+#include <netinet/if_ether.h>
+#include <linux/if.h>
+#include <linux/limits.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "packet.h"
+#include "uip.h"
+
+#include "iscsi_if.h"
+
+/*  Foward declarations */
+struct nic_ops;
+struct nic_lib_handle;
+struct packet;
+struct nic_op;
+
+extern pthread_mutex_t nic_lib_list_mutex;
+extern struct nic_lib_handle *nic_lib_list;
+
+/*  Used to store a list of active cnic devices */
+extern pthread_mutex_t nic_list_mutex;
+extern struct nic *nic_list;
+
+/*******************************************************************************
+ *  Constants
+ ******************************************************************************/
+#define MAX_PCI_DEVICE_ENTRIES	64	/* Maxium number of pci_device_id
+					   entries a hw library may contain */
+
+/*******************************************************************************
+ * Structure used to hold PCI vendor, device, subvendor and subdevice ID's
+ ******************************************************************************/
+struct pci_device_id {
+	const uint32_t vendor, device;  /* Vendor and device ID or PCI_ANY_ID */
+	const uint32_t subvendor, subdevice;  /* Subsystem ID's or PCI_ANY_ID */
+	const char *device_name;        /* Data private to the driver */
+};
+
+/******************************************************************************
+ * NIC statistics structure
+ ******************************************************************************/
+struct nic_stats {
+	uint64_t        interrupts;
+	uint64_t        missed_interrupts;
+
+	struct {
+		uint64_t        packets;
+		uint64_t        bytes;
+	} tx;
+
+	struct {
+		uint64_t        packets;
+		uint64_t        bytes;
+	} rx;
+};
+
+/******************************************************************************
+ * NIC interface structure
+ ******************************************************************************/
+typedef struct nic_interface {
+	struct nic_interface *next;
+	struct nic *parent;
+
+	uint16_t	flags;
+	uint8_t		mac_addr[ETH_ALEN];
+	uint8_t		vlan_priority;
+	uint16_t	vlan_id;
+
+	time_t		start_time;
+
+	struct uip_stack ustack;
+} nic_interface_t;
+
+/******************************************************************************
+ * NIC lib operations structure
+ ******************************************************************************/
+struct nic_lib_ops {
+	/*  Used to get the NIC library name */
+	void (*get_library_name)(char **library_name,
+				 size_t *library_name_size);
+
+	/*  Used to get to the PCI table supported by the NIC library */
+	void (*get_pci_table)(struct pci_device_id **table,
+			      uint32_t *entries);
+
+	/*  Used to get the version of this NIC library */
+	void (*get_library_version)(char **version_string,
+				    size_t *version_string_size);
+
+	/*  Used to get the NIC library build date*/
+	void (*get_build_date)(char **build_date_string,
+			       size_t *build_date_string_size);
+
+	/*  Used to get the transport name assoicated with this library */
+	void (*get_transport_name)(char **transport_name,
+				   size_t *transport_name_size);
+
+	/*  Used to get the uio name assoicated with this library */
+	void (*get_uio_name)(char **uio_name,
+			     size_t *uio_name_size);
+
+};
+
+/*******************************************************************************
+ * NIC op table definition
+ ******************************************************************************/
+typedef struct nic_ops {
+	struct nic_lib_ops	lib_ops;
+
+	char *description;
+	int (*open)(struct nic *);
+	int (*close)(struct nic *, int);
+	int (*read)(struct nic *, struct packet *);
+	int (*write)(struct nic *, nic_interface_t *,
+		     struct packet *);
+	void * (*get_tx_pkt)(struct nic *);
+	void (*start_xmit)(struct nic *, size_t);
+	int (*clear_tx_intr)(struct nic *);
+	int (*handle_iscsi_path_req)(struct nic *,
+				     int,
+				     struct iscsi_uevent *ev,
+				     struct iscsi_path *path,
+				     size_t len);
+} net_ops_t;
+
+typedef struct nic_lib_handle {
+	struct nic_lib_handle *next;
+
+	pthread_mutex_t		mutex;
+	struct nic_ops		*ops;
+} nic_lib_handle_t;
+
+typedef struct nic {
+	struct nic *next;
+
+	uint16_t   flags;
+#define NIC_UNITIALIZED		0x0001
+#define NIC_INITIALIZED		0x0002
+#define NIC_ENABLED		0x0004
+#define NIC_DISABLED		0x0008
+#define NIC_IPv6_ENABLED	0x0010
+#define NIC_ADDED_MULICAST	0x0020
+#define NIC_VLAN_STRIP_ENABLED	0x0100
+#define NIC_MSIX_ENABLED	0x0200
+#define NIC_TX_HAS_SENT		0x0400
+
+#define NIC_UIO_NAME_MALLOC	0x1000
+#define NIC_CONFIG_NAME_MALLOC	0x2000
+
+	uint16_t state;
+#define NIC_STOPPED	0x0001
+#define NIC_RUNNING	0x0002
+#define NIC_LONG_SLEEP	0x0004
+#define NIC_EXIT	0x0008
+
+	int fd;			/* Holds the file descriptor to UIO */
+	uint16_t uio_minor;	/* Holds the UIO minor number */
+
+	uint32_t host_no;	/* Holds the associated host number */
+
+	char *library_name;	/* Name of the library to assoicate with */
+	char *log_name;		/* Human friendly name used in the log
+				   file					*/
+	char *config_device_name; /* Name read from the XML configuration
+				   file					*/
+	char eth_device_name[IFNAMSIZ];	/* Network interface name	*/
+	char *uio_device_name;	/* UIO device name			*/
+
+	uint32_t   intr_count;	/* Total UIO interrupt count		*/
+
+	/*  iSCSI ring ethernet MAC address */
+	__u8 mac_addr[ETH_ALEN];
+
+	/*  Used to manage the network interfaces of this device */
+	pthread_mutex_t  nic_iface_mutex;
+	__u32 num_of_nic_iface;
+	nic_interface_t *nic_iface;
+
+	/*  Wait for the particular uio device to appear */
+	pthread_mutex_t  uio_wait_mutex;
+	pthread_cond_t   uio_wait_cond;
+
+	/*  Wait for the device to be enabled */
+	pthread_mutex_t  enable_wait_mutex;
+	pthread_cond_t   enable_wait_cond;
+
+	/*  Wait for the device to be finished enabled */
+	pthread_mutex_t  enable_done_mutex;
+	pthread_cond_t   enable_done_cond;
+
+	/*  Wait for the nic loop to start */
+	pthread_mutex_t  nic_loop_started_mutex;
+	pthread_cond_t   nic_loop_started_cond;
+
+	/*  Wait for the device to be disabled */
+	pthread_mutex_t  disable_wait_mutex;
+	pthread_cond_t   disable_wait_cond;
+
+	/* Held when transmitting */
+	pthread_mutex_t xmit_mutex;
+
+	/* The thread this device is running on */
+	pthread_t thread;
+
+	/* Statistical Information on this device */
+	time_t start_time;
+	struct nic_stats	stats;
+
+#define DEFAULT_RX_POLL_USEC	100	/* usec */
+	/* options enabled by the user */
+	uint32_t rx_poll_usec;
+
+	/*  Used to hold hardware specific data */
+	void *priv;
+
+	/*  Used to hold the TX packets that are needed to be sent */
+	struct packet *tx_packet_queue;
+
+	/* Mutex to protect the list of free packets */
+	pthread_mutex_t free_packet_queue_mutex;
+
+	/*  Used to hold the free packets that are needed to be sent */
+	struct packet *free_packet_queue;
+
+	/*  Points to the NIC library */
+	nic_lib_handle_t	*nic_library;
+
+	/*  Points to the PCI table entry */
+	struct pci_device_id	*pci_id;
+
+	/*  Used to process the interrupt */
+	int (*process_intr)(struct nic *nic);
+
+	struct nic_ops	*ops;
+} nic_t;
+
+
+/******************************************************************************
+ * Function Prototypes
+ *****************************************************************************/
+int load_all_nic_libraries();
+
+nic_t *nic_init();
+int nic_remove(nic_t * nic, int locked);
+
+int nic_add_nic_iface(nic_t *nic,
+                      nic_interface_t *nic_iface);
+int nic_process_intr(nic_t *nic, int discard_check);
+
+nic_interface_t * nic_iface_init();
+
+typedef enum {
+	NIC_LIBRARY_EXSITS	= 1,
+	NIC_LIBRARY_DOESNT_EXIST= 2,
+} NIC_LIBRARY_EXIST_T;
+
+NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name);
+NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name);
+
+/*******************************************************************************
+ *  Packet management utility functions
+ ******************************************************************************/
+struct packet * get_next_tx_packet(nic_t *nic);
+struct packet * get_next_free_packet(nic_t *nic);
+void put_packet_in_tx_queue(struct packet *pkt,
+                            nic_t *nic);
+void put_packet_in_free_queue(struct packet *pkt,
+                              nic_t *nic);
+
+
+typedef enum {
+        ALLOW_GRACEFUL_SHUTDOWN	= 1,
+        FORCE_SHUTDOWN		= 2,
+} NIC_SHUTDOWN_T;
+
+int unload_all_nic_libraries();
+void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful);
+
+/*  Use this function to fill in minor number and uio, and eth names */
+int nic_fill_name(nic_t *nic);
+
+int detemine_initial_uio_events();
+
+int enable_multicast(nic_t *nic);
+int disable_multicast(nic_t *nic);
+
+void nic_set_all_nic_iface_mac_to_parent(nic_t *nic);
+struct nic_interface * nic_find_nic_iface(nic_t *nic,
+					  uint16_t vlan_id);
+int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device,
+                              uint32_t subvendor, uint32_t subdevice,
+			      nic_lib_handle_t **handle,
+			      struct pci_device_id **pci_entry);
+
+void *nic_loop(void *arg);
+
+int nic_packet_capture(struct nic *,
+                       struct packet *pkt);
+
+
+#endif /* __NIC_H__ */
diff --git a/brcm_iscsi_uio/src/unix/nic_id.c b/brcm_iscsi_uio/src/unix/nic_id.c
new file mode 100644
index 0000000..49fb4a7
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_id.c
@@ -0,0 +1,359 @@
+/* nic_id.c: Using sysfs to determine the PCI vendor, device, subvendor and
+ *           subdevice ID's
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <linux/if.h>
+
+#include "logger.h"
+#include "nic.h"
+
+#define PFX "nic_id "
+
+/*******************************************************************************
+ * Sysfs constant strings used to get PCI vendor, and device ID's
+ ******************************************************************************/
+const char uio_vendor_id_template[] = "/sys/class/uio/uio%d/device/vendor";
+const char uio_subvendor_id_template[] = "/sys/class/uio/uio%d/device/subsystem_vendor";
+const char uio_device_id_template[] = "/sys/class/uio/uio%d/device/device";
+const char uio_subdevice_id_template[] = "/sys/class/uio/uio%d/device/subsystem_device";
+const char uio_device_symlink_template[] = "/sys/class/uio/uio%d/device";
+
+/**
+ *  get_id() - Utility function to read hex values from sysfs
+ *  @param nic - NIC device to use
+ *  @param sysfs_template - sysfs path template to use
+ *  @param sysfs_template_size - sysfs path template size in bytes
+ *  @parm id - this is the value returned from the sysfs entry
+ *  @return 0 on success <0 on failure
+ */
+static int get_id(nic_t *nic,
+		  const char *sysfs_template,
+		  const size_t sysfs_template_size,
+		  uint32_t *id)
+{
+	int rc = 0;
+	FILE *fp;
+	size_t chars_read;
+	char buf[7];
+	char *path;
+	size_t path_size;
+
+	path_size = sysfs_template_size + 4;
+	path = malloc(path_size);
+	if(path == NULL)
+	{
+		LOG_ERR("Could not allocate memory for %s", sysfs_template);
+		return -ENOMEM;
+	}
+
+	snprintf(path, path_size, sysfs_template, nic->uio_minor);
+
+	fp = fopen(path, "r");
+	if(fp == NULL)
+	{
+		LOG_ERR("Could not open path: %s", path);
+		rc = -EIO;
+		goto error_fopen;
+	}
+
+	chars_read = fread(buf, sizeof(buf), 1, fp); 
+	if(chars_read != 1)
+	{
+		LOG_ERR("Could not read from: %s", path);
+		rc = -EIO;
+		goto error;
+	}
+
+	chars_read = sscanf(buf, "%x", id);
+	if(chars_read != 1)
+	{
+		LOG_ERR("Could interpret value: %s from: %s",
+			buf, path);
+		rc = -EIO;
+		goto error;
+	}
+
+error:
+	fclose(fp);
+
+error_fopen:
+	free(path);
+
+	return rc;
+}
+
+static int get_vendor(nic_t *nic,
+		      uint32_t *id)
+{
+	return get_id(nic,
+		      uio_vendor_id_template, sizeof(uio_vendor_id_template),
+		      id);
+}
+
+static int get_subvendor(nic_t *nic,
+			 uint32_t *id)
+{
+	return get_id(nic,
+		      uio_subvendor_id_template,
+		      sizeof(uio_subvendor_id_template),
+		      id);
+}
+
+static int get_device(nic_t *nic,
+		      uint32_t *id)
+{
+	return get_id(nic,
+		      uio_device_id_template,
+		      sizeof(uio_device_id_template),
+		      id);
+}
+
+static int get_subdevice(nic_t *nic,
+			 uint32_t *id)
+{
+	return get_id(nic,
+		      uio_subdevice_id_template,
+		      sizeof(uio_subdevice_id_template),
+		      id);
+}
+
+int get_bus_slot_func_num(nic_t *nic,
+			  uint32_t *bus,
+			  uint32_t *slot,
+			  uint32_t *func)
+{
+	size_t size;
+	char *path, *tok, *tok2;
+	int path_tokens, i;
+	size_t path_size;
+	char *read_pci_bus_slot_func_str;
+	char pci_bus_slot_func_str[32];
+	int rc;
+	char *saveptr;
+
+	path_size = sizeof(uio_device_symlink_template) + 4;
+	path = malloc(path_size);
+	if(path == NULL)
+	{
+		LOG_ERR("Could not allocate path memory for %s",
+			uio_device_symlink_template);
+		rc = -ENOMEM;
+		goto error_alloc_path;
+	}
+
+	read_pci_bus_slot_func_str = malloc(128);
+	if(read_pci_bus_slot_func_str == NULL)
+	{
+		LOG_ERR(PFX "Could not allocate read pci bus memory for %s",
+			nic->log_name, uio_device_symlink_template);
+		rc = -ENOMEM;
+		goto error_alloc_read_pci_bus;
+	}
+
+	snprintf(path, path_size, uio_device_symlink_template, nic->uio_minor);
+
+	size = readlink(path, read_pci_bus_slot_func_str, 128);
+	if(size == -1) {
+		LOG_ERR(PFX "%s: Error with %s: %s",
+			nic->log_name, path, strerror(errno));
+		rc = errno;
+		goto error;
+	}
+
+	if(size > ((128) - 1)) {
+		read_pci_bus_slot_func_str[128 - 1] = '\0';
+		LOG_ERR(PFX "%s: not enough space (%d) for reading PCI "
+			    "slot:bus.func %s: %s",
+			    nic->log_name, size, path, strerror(errno));
+		rc = -EIO;
+		goto error;
+	}
+
+	/*  readlink() doesn't NULL terminate the string */
+	read_pci_bus_slot_func_str[size] = '\0';
+
+	path_tokens = 0;
+	tok = strtok_r(read_pci_bus_slot_func_str, "/", &saveptr);
+	while (tok != NULL) {
+		path_tokens++;
+		tok = strtok_r(NULL, "/", &saveptr);
+	}
+
+	size = readlink(path, read_pci_bus_slot_func_str, 128);
+	if(size == -1) {
+		LOG_ERR(PFX "%s: Error with %s: %s",
+			nic->log_name, path, strerror(errno));
+		rc = errno;
+		goto error;
+	}
+
+	if(size > ((128) - 1)) {
+		read_pci_bus_slot_func_str[128 - 1] = '\0';
+		LOG_ERR(PFX "%s: not enough space for reading PCI "
+			    "slot:bus.func %s: %s",
+			    nic->log_name, path, strerror(errno));
+		rc = -EIO;
+		goto error;
+	}
+
+	/*  readlink() doesn't NULL terminate the string */
+	read_pci_bus_slot_func_str[size] = '\0';
+
+	tok = strtok_r(read_pci_bus_slot_func_str, "/", &saveptr);
+	for (i=0; i<path_tokens-1; i++) {
+		tok = strtok_r(NULL, "/", &saveptr);
+	}
+	strcpy(pci_bus_slot_func_str, tok);
+
+	tok = strtok_r(pci_bus_slot_func_str, ":", &saveptr);
+	if(tok == NULL) {
+		LOG_ERR(PFX "%s: Error with slot string: %s",
+			nic->log_name, pci_bus_slot_func_str);
+		rc = -EIO;
+		goto error;
+	}
+
+	tok = strtok_r(NULL, ":", &saveptr);
+	if(tok == NULL) {
+		LOG_ERR(PFX "%s: Error parsing slot: %s",
+			nic->log_name, pci_bus_slot_func_str);
+		rc = -EIO;
+		goto error;
+	}
+
+	sscanf(tok, "%x", bus);
+
+	/*  Need to extract the next token "xx.x" */
+	tok = strtok_r(NULL, ":", &saveptr);
+	if(tok == NULL) {
+		LOG_ERR(PFX "%s: Error extracing bus.func: %s",
+			nic->log_name, pci_bus_slot_func_str);
+		rc = -EIO;
+		goto error;
+	}
+
+	tok2 = strtok_r(tok, ".", &saveptr);
+	if(tok2 == NULL) {
+		LOG_ERR(PFX "%s: Error parsing bus: %s",
+			nic->log_name, pci_bus_slot_func_str);
+		rc = -EIO;
+		goto error;
+	}
+
+	sscanf(tok2, "%x", slot);
+
+	tok2 = strtok_r(NULL, ".", &saveptr);
+	if(tok2 == NULL) {
+		LOG_ERR(PFX "%s: Error parsing func: %s",
+			nic->log_name, pci_bus_slot_func_str);
+		rc = -EIO;
+		goto error;
+	}
+
+	sscanf(tok2, "%x", func);
+	LOG_INFO(PFX "%s: is found at %02x:%02x.%02x", nic->log_name,
+		 *bus, *slot, *func);
+
+	free(read_pci_bus_slot_func_str);
+
+	rc = 0;
+
+error:
+error_alloc_read_pci_bus:
+	free(path);
+
+error_alloc_path:
+
+	return rc;
+}
+
+/**
+ *  find_set_nic_lib() - Match the NIC library to the NIC
+ *  @param nic - NIC device to determine which NIC library to use
+ *  @return 0 on success <0 on failure
+ */
+int find_set_nic_lib(nic_t *nic)
+{
+	uint32_t vendor;
+	uint32_t subvendor;
+	uint32_t device;
+	uint32_t subdevice;
+
+	uint32_t pci_bus;
+	uint32_t pci_slot;
+	uint32_t pci_func;
+	int rc = 0;
+
+	nic_lib_handle_t *handle;
+	struct pci_device_id *pci_entry;
+
+	rc = get_vendor(nic, &vendor);
+	if( rc != 0)
+	{
+		LOG_ERR("%s: Could not get vendor id [0x%x]",
+			nic->log_name, rc);
+		return rc;
+	}
+
+	rc = get_subvendor(nic, &subvendor);
+	if( rc != 0)
+	{
+		LOG_ERR("%s: Could not get subvendor id [0x%x]",
+			nic->log_name, rc);
+		return rc;
+	}
+
+	rc = get_device(nic, &device);
+	if( rc != 0)
+	{
+		LOG_ERR("%s: Could not get device id [0x%x]",
+			nic->log_name, rc);
+		return rc;
+	}
+
+	rc = get_subdevice(nic, &subdevice);
+	if( rc != 0)
+	{
+		LOG_ERR("%s: Could not get subdevice id [0x%x]",
+			nic->log_name, rc);
+		return rc;
+	}
+
+	get_bus_slot_func_num(nic, &pci_bus, &pci_slot, &pci_func);
+
+	LOG_DEBUG("%s: Looking for device vendor: "
+		  "0x%x subvendor: 0x%x device: 0x%x subdevice: 0x%x",
+		  nic->log_name, vendor, subvendor, device, subdevice);
+
+	rc = find_nic_lib_using_pci_id(vendor, device, subvendor, subdevice,
+				       &handle, &pci_entry);
+
+	if(rc != 0) {
+		LOG_WARN(PFX "%s: Couldn't find proper NIC library",
+			 nic->log_name);
+		return rc;
+	}
+
+	nic->nic_library = handle;
+	nic->pci_id      = pci_entry;
+
+	/*  Prepare the NIC library op table */
+	nic->ops = handle->ops;
+
+	return 0;
+}
diff --git a/brcm_iscsi_uio/src/unix/nic_id.h b/brcm_iscsi_uio/src/unix/nic_id.h
new file mode 100644
index 0000000..de1a744
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_id.h
@@ -0,0 +1,22 @@
+/* nic_id.h: NIC uIP NetLink user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __NIC_ID_H__
+#define __NIC_ID_H__
+
+int find_set_nic_lib(nic_t *nic);
+
+int get_bus_slot_func_num(nic_t *nic,
+                          uint32_t *bus,
+                          uint32_t *slot,
+                          uint32_t *func);
+
+#endif /* __NIC_ID_H__ */
diff --git a/brcm_iscsi_uio/src/unix/nic_nl.c b/brcm_iscsi_uio/src/unix/nic_nl.c
new file mode 100644
index 0000000..c09cd8e
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_nl.c
@@ -0,0 +1,462 @@
+/* nic_nl.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <linux/limits.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <iscsi_if.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+
+#include "uip_arp.h"
+#include "logger.h"
+#include "options.h"
+#include "uevent.h"
+
+#include "nic.h"
+#include "nic_nl.h"
+#include "nic_utils.h"
+
+/*******************************************************************************
+ * Constants
+ ******************************************************************************/
+#define PFX "NIC_NL "
+
+static void *nlm_recvbuf = NULL;
+static void *nlm_sendbuf = NULL;
+
+static struct sockaddr_nl src_addr;
+
+const static struct sockaddr_nl dest_addr = {
+	.nl_family	= AF_NETLINK,
+	.nl_pid		= 0, /* kernel */
+	.nl_groups	= 0, /* unicast */
+};
+
+#define POLL_NL		0
+#define POLL_MAX        1
+
+/* Netlink */
+int		nl_sock = INVALID_FD;
+
+static int
+nl_read(int ctrl_fd, char *data, int size, int flags)
+{
+	int rc;
+	struct iovec iov;
+	struct msghdr msg;
+
+	iov.iov_base = data;
+	iov.iov_len = size;
+
+	memset(&src_addr, 0, sizeof(src_addr));
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	src_addr.nl_groups = 1;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_name= (void*)&src_addr;
+	msg.msg_namelen = sizeof(src_addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	rc = recvmsg(ctrl_fd, &msg, flags);
+
+	return rc;
+}
+
+static int
+nlpayload_read(int ctrl_fd, char *data, int count, int flags)
+{
+        int rc;
+        struct iovec iov;
+        struct msghdr msg;
+
+	iov.iov_base = nlm_recvbuf;
+	iov.iov_len = NLMSG_SPACE(count);
+	memset(iov.iov_base, 0, iov.iov_len);
+
+	memset(&src_addr, 0, sizeof(src_addr));
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	src_addr.nl_groups = 1;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_name= (void*)&src_addr;
+	msg.msg_namelen = sizeof(src_addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	rc = recvmsg(ctrl_fd, &msg, flags);
+
+	memcpy(data, NLMSG_DATA(iov.iov_base), count);
+
+	return rc;
+}
+
+static int
+kwritev(int fd, enum iscsi_uevent_e type, struct iovec *iovp, int count)
+{
+	int i, rc;
+	struct nlmsghdr *nlh;
+	struct msghdr msg;
+	struct iovec iov;
+	int datalen = 0;
+
+	for (i = 0; i < count; i++) {
+		datalen += iovp[i].iov_len;
+	}
+
+	nlh = nlm_sendbuf;
+	memset(nlh, 0, NLMSG_SPACE(datalen));
+
+	nlh->nlmsg_len = NLMSG_SPACE(datalen);
+	nlh->nlmsg_pid = getpid();
+	nlh->nlmsg_flags = 0;
+	nlh->nlmsg_type = type;
+
+	datalen = 0;
+	for (i = 0; i < count; i++) {
+		memcpy(NLMSG_DATA(nlh) + datalen, iovp[i].iov_base,
+		       iovp[i].iov_len);
+		datalen += iovp[i].iov_len;
+	}
+	iov.iov_base = (void*)nlh;
+	iov.iov_len = nlh->nlmsg_len;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_name= (void*)&dest_addr;
+	msg.msg_namelen = sizeof(dest_addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	do {
+		rc = sendmsg(fd, &msg, 0);
+		if (rc == -ENOMEM) {
+			LOG_ERR(PFX "sendmsg: alloc_skb() failed");
+			sleep(1);
+		} else if (rc < 0) {
+			LOG_ERR(PFX "sendmsg: bug?: on %d %s[0x%x]",
+				fd, strerror(errno), errno);
+			sleep(1);
+		}
+	} while ((rc < 0) && (event_loop_stop == 0));
+
+	return rc;
+}
+
+/*
+ * __kipc_call() should never block. Therefore
+ * Netlink's xmit logic is serialized. This means we do not allocate on
+ * xmit path. Instead we reuse nlm_sendbuf buffer.
+ *
+ * Transport must assure non-blocking operations for:
+ *
+ *	- session_create()
+ *	- conn_create()
+ *	- conn_bind()
+ *	_ set_param()
+ *	- conn_start()
+ *	- conn_stop()
+ *
+ * Its OK to block for cleanup for short period of time in operatations for:
+ *
+ *	- conn_destroy()
+ *	- session_destroy()
+ *
+ * FIXME: interface needs to be extended to allow longer blocking on
+ *        cleanup. (Dima)
+ */
+int
+__kipc_call(int fd, void *iov_base, int iov_len)
+{
+	int rc;
+	struct iovec iov;
+	struct iscsi_uevent *ev = iov_base;
+	enum iscsi_uevent_e type = ev->type;
+	int wait_response;
+
+	/* Sanity check */
+	if(iov_base == NULL)
+		return -EINVAL;
+
+	iov.iov_base = iov_base;
+	iov.iov_len = iov_len;
+
+	rc = kwritev(fd, type, &iov, 1);
+
+	wait_response = 0;
+	do {
+		rc = nlpayload_read(fd, (void*)ev, sizeof(*ev), MSG_PEEK);
+		if (rc < 0) {
+			LOG_ERR(PFX "Error reading resp to reply: %s[%d]",
+				strerror(rc), rc);
+			return rc;
+		}
+
+		if (ev->type != type) {
+			LOG_DEBUG(PFX "expecting event %d, got %d, handling...",
+				  type, ev->type);
+			if (ev->type == ISCSI_KEVENT_IF_ERROR) {
+				if ((rc = nlpayload_read(fd, (void*)ev,
+							 sizeof(*ev), 0)) < 0) {
+					return rc;
+				}
+				if (ev->iferror == -ENOSYS) {
+					/* not fatal so let caller handle log */
+					LOG_DEBUG(PFX "Recieved iferror %d: %s",
+						  ev->iferror,
+						  strerror(ev->iferror));
+				} else if (ev->iferror < 0) {
+					LOG_ERR("Received iferror %d: %s",
+						   ev->iferror,
+						   strerror(ev->iferror));
+				} else {
+					LOG_ERR("Received iferror %d",
+						   ev->iferror);
+				}
+				return ev->iferror;
+			}
+		} else if (ev->type == ISCSI_UEVENT_GET_STATS) {
+			/* kget_stats() will read */
+			return 0;
+		} else {
+			if ((rc = nlpayload_read(fd, (void*)ev,
+						 sizeof(*ev), 0)) < 0) {
+				return rc;
+			}
+			break;
+		}
+
+		wait_response++;
+	} while ((ev->type != type) &&
+		 (event_loop_stop == 0) &&
+		 (wait_response < MAX_COUNT_NIC_NL_RESP));
+
+	return rc;
+}
+
+static int ctldev_handle()
+{
+	nic_t *nic = NULL;
+	int rc;
+	size_t ev_size;
+	struct iscsi_uevent *ev;
+	char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
+	struct nlmsghdr *nlh;
+	char *data;
+	uint8_t *payload;
+	struct iscsi_path *path;
+	char *msg_type_str;
+	uint32_t host_no;
+
+	/*  Take a quick peek at what how much uIP will need to read */
+	if ((rc = nl_read(nl_sock, nlm_ev,
+		NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) {
+		LOG_ERR("can not read nlm_ev, error %d", rc);
+		return rc;
+	}
+	nlh = (struct nlmsghdr *)nlm_ev;
+
+	data = (char *) malloc(nlh->nlmsg_len);
+	if(data == NULL) {
+		LOG_ERR("Couldn't allocate %d bytes for Netlink iSCSI message\n",
+			 nlh->nlmsg_len);
+		return -ENOMEM;
+	}
+
+	memset(data, 0, nlh->nlmsg_len);
+	ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+	if ((rc = nl_read(nl_sock, data, (int) nlh->nlmsg_len, 0)) < 0) {
+		LOG_ERR("can not read nlm_ev, error %d", rc);
+		goto error;
+	}
+
+	ev = (struct iscsi_uevent *)NLMSG_DATA(data);
+	switch (ev->type) {
+	case ISCSI_KEVENT_PATH_REQ:
+		msg_type_str = "path_req";
+
+		if((ev_size - sizeof(ev)) != sizeof(*path))
+			LOG_WARN("Didn't get iscsi_path size(%d) expected %d",
+				 ev_size - sizeof(ev), sizeof(*path));
+		host_no = ev->r.req_path.host_no;
+
+		break;
+	case ISCSI_KEVENT_IF_DOWN:
+		msg_type_str = "if_down";
+
+		host_no = ev->r.notify_if_down.host_no;
+		break;
+	default:
+		/*  We don't care about other iSCSI Netlink messages */
+		LOG_DEBUG(PFX "Received ev->type: 0x%x", ev->type);
+		rc = 0;
+		goto error;
+        }
+
+	/*  This is a message that drivers should be interested in */
+	LOG_INFO("Received: '%s': host_no: %d", msg_type_str,  host_no);
+
+	rc = from_host_no_find_associated_eth_device(host_no, &nic);
+	if(rc != 0) {
+		LOG_ERR(PFX "Dropping msg, couldn't find nic with host no:%d\n",
+			host_no);
+		goto error;
+	}
+
+	/*  Ensure that the NIC is RUNNING */
+	if(((nic->state & NIC_RUNNING) != NIC_RUNNING) &&
+	   (ev->type != ISCSI_KEVENT_IF_DOWN)) {
+		LOG_WARN(PFX "%s: is not running so can't issue neigh req, "
+			     "cmd: 0x%d",
+			 nic->log_name, ev->type);
+		goto error;
+	}
+
+	ev = (struct iscsi_uevent *)NLMSG_DATA(data);
+	payload = (uint8_t *) ((uint8_t *)ev) + sizeof(*ev);
+	path = (struct iscsi_path *)payload;
+
+	if(nic->ops) {
+		switch (ev->type) {
+        	case ISCSI_KEVENT_PATH_REQ:
+			/*  pass the request up to the user space
+			 *  library driver */
+			if(nic->ops->handle_iscsi_path_req) {
+				nic->ops->handle_iscsi_path_req(nic,
+								nl_sock, ev,
+								path, ev_size);
+			}
+			break;
+		case ISCSI_KEVENT_IF_DOWN:
+			nic_remove(nic, 0);
+
+			break;
+		}
+	}
+
+	rc = 0;
+
+error:
+	free(data);
+
+	return rc;
+}
+
+/**
+ *  nic_nl_open() - This is called when opening/creating the Netlink listening
+ *                   thread
+ *  @param dev - CNIC UIO device to create a NetLink listener on
+ *  @return 0 on success, <0 on failure
+ */
+int nic_nl_open()
+{
+	int rc;
+	struct pollfd poll_array[POLL_MAX];
+	memset(poll_array, 0, sizeof(poll_array));
+
+	nlm_sendbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
+	if (!nlm_sendbuf) {
+		LOG_ERR(PFX "can't allocate nlm_sendbuf");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	nlm_recvbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
+	if (!nlm_recvbuf) {
+		LOG_ERR(PFX "can't allocate nlm_recvbuf");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ISCSI);
+	if (nl_sock < 0) {
+		LOG_ERR(PFX "can not create NETLINK_ISCSI socket");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	memset(&src_addr, 0, sizeof(src_addr));
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	src_addr.nl_groups = ISCSI_NL_GRP_UIP;
+
+        while ((!event_loop_stop) && (bnx2i_loaded == 0)) {
+		rc = bind(nl_sock,
+			  (struct sockaddr *)&src_addr, sizeof(src_addr));
+		if (rc == 0)
+			break;
+
+		LOG_ERR(PFX "waiting binding to NETLINK_ISCSI socket");
+
+		pthread_mutex_lock(&bnx2i_module_loaded_mutex);
+		pthread_cond_wait(&bnx2i_module_loaded_cond,
+				  &bnx2i_module_loaded_mutex);
+		pthread_mutex_unlock(&bnx2i_module_loaded_mutex);
+
+		sleep(1);
+	}
+
+	if(event_loop_stop) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	LOG_INFO(PFX "Netlink to CNIC on pid %d is ready", src_addr.nl_pid);
+
+	poll_array[POLL_NL].fd = nl_sock;
+	poll_array[POLL_NL].events = POLLIN;
+
+        while (!event_loop_stop) {
+                int res = poll(poll_array, POLL_MAX, NL_POLL_RESOLUTION);
+                if (res > 0) {
+                        if (poll_array[POLL_NL].revents)
+                                ctldev_handle();
+                } else if (res < 0) {
+                        if (errno == EINTR) {
+                                LOG_DEBUG(PFX "event_loop interrupted");
+                        } else {
+                                LOG_ERR(PFX "got poll() error (%d), errno (%d), "
+                                          "exiting", res, errno);
+                                break;
+                        }
+                }
+        }
+
+	LOG_INFO(PFX "Netlink thread exit'ing");
+	rc = 0;
+
+error:
+	if(nlm_sendbuf) {
+		free(nlm_sendbuf);
+		nlm_sendbuf = NULL;
+	}
+
+	if(nlm_recvbuf) {
+		free(nlm_recvbuf);
+		nlm_recvbuf = NULL;
+	}
+
+	return 0;
+}
diff --git a/brcm_iscsi_uio/src/unix/nic_nl.h b/brcm_iscsi_uio/src/unix/nic_nl.h
new file mode 100644
index 0000000..7325ee2
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_nl.h
@@ -0,0 +1,20 @@
+/* nic_nl.h: NIC uIP NetLink user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __NIC_NL_H__
+#define __NIC_NL_H__
+
+int nic_nl_open();
+void nic_nl_close();
+
+int __kipc_call(int fd, void *iov_base, int iov_len);
+
+#endif /* __NIC_NL_H__ */
diff --git a/brcm_iscsi_uio/src/unix/nic_utils.c b/brcm_iscsi_uio/src/unix/nic_utils.c
new file mode 100644
index 0000000..04b88da
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_utils.c
@@ -0,0 +1,1377 @@
+/* nic_util.c: shared NIC utility functions
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "logger.h"
+#include "nic.h"
+#include "nic_id.h"
+#include "nic_vlan.h"
+#include "nic_utils.h"
+#include "options.h"
+
+#define PFX "nic_utils "
+
+/******************************************************************************
+ *  String constants
+ *****************************************************************************/
+static const char nic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
+static const char cnic_sysfs_uio_event_template[] = "/sys/class/uio/uio%d/event";
+static const char base_uio_sysfs_name[] = "/sys/class/uio/";
+static const char uio_name[] = "uio";
+
+static const char uio_base_dir[] = "/dev/uio";
+static const char uio_udev_path_template[] = "/dev/uio%hd";
+
+
+static const char base_iscsi_host_name[] = "/sys/class/iscsi_host/";
+static const char host_template[] = "host%d";
+static const char iscsi_host_path_template[] = "/sys/class/iscsi_host/host%d";
+static const char iscsi_host_path_netdev_template[] = "/sys/class/iscsi_host/host%d/netdev";
+
+/******************************************************************************
+ *  Autodiscovery of iscsi_hosts
+ *****************************************************************************/
+static int filter_host_name(const struct dirent *entry)
+{
+	if((memcmp(entry->d_name, "host", 4) == 0)) 
+		return 1;
+	else
+		return 0;
+}
+
+int nic_discover_iscsi_hosts()
+{
+	struct dirent **files;
+	int count;
+	int i;
+	int rc;
+
+	count = scandir(base_iscsi_host_name, &files, filter_host_name,
+			alphasort);
+
+	switch(count) { 
+	case 0:
+		/*  Currently there are no iSCSI hosts */
+		rc = 0;
+		break;
+
+	case -1:
+		LOG_WARN(PFX "Error when scanning path: %s[%s]",
+			 base_iscsi_host_name, strerror(errno));
+		rc = -EINVAL;
+		break;
+
+	default:
+		/*  There are iSCSI hosts */
+		for(i=0; i<count; i++) {
+			int host_no;
+ 			char *raw = NULL;
+		        uint32_t raw_size = 0;
+			char temp_path[sizeof(iscsi_host_path_netdev_template) + 8];
+			rc = sscanf(files[i]->d_name, host_template, &host_no);
+			nic_t *nic;
+
+			LOG_INFO(PFX "Found host[%d]: %s",
+				 host_no, files[i]->d_name);
+
+			/*  Build the path to determine netdev name */
+			snprintf(temp_path, sizeof(temp_path),
+				 iscsi_host_path_netdev_template, host_no);
+
+		        rc = capture_file(&raw, &raw_size, temp_path);
+		        if(rc != 0)
+				continue;
+
+			rc = from_host_no_find_associated_eth_device(host_no,
+								     &nic);
+			if(rc != 0) {
+				LOG_INFO(PFX "NIC not found creating an instance for host_no: %d", host_no);
+				nic = nic_init();
+				if(nic == NULL) {
+					LOG_ERR(PFX "%s: Couldn't allocate space for %s",
+						raw);
+
+					return -ENOMEM;
+				}
+				
+				/*  Normalize the string */
+				if(raw[raw_size - 1] == '\n')
+					raw[raw_size - 1] = '\0';
+
+				strncpy(nic->eth_device_name, raw, raw_size);
+				nic->config_device_name = nic->eth_device_name;
+				nic->log_name = nic->eth_device_name;
+			} else {
+				LOG_INFO(PFX "%s: NIC found host_no: %d",
+					 nic->log_name, host_no);
+
+			}
+
+
+			free(raw);
+		}
+
+		/*  Cleanup the scandir() call */
+		for(i=0; i<count; i++)
+			free(files[i]);
+		free(files);
+
+		rc = 0;
+		break;
+	}
+
+	return rc;
+}
+
+/******************************************************************************
+ *  Enable/Disable Multicast on physical interface
+ *****************************************************************************/
+static int nic_util_enable_disable_multicast(nic_t *nic,
+					     uint32_t cmd)
+{
+	int rc = 0;
+	struct uip_eth_addr multicast_addr;
+	int fd;
+	struct ifreq ifr;
+
+	/* adding ethernet multicast address for IPv6*/
+	memcpy(&multicast_addr, nic->mac_addr, ETH_ALEN);
+	multicast_addr.addr[0] = 0x33;
+	multicast_addr.addr[1] = 0x33;
+	multicast_addr.addr[2] = 0xff;
+
+	/* Prepare the request */
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, nic->eth_device_name,
+		sizeof(nic->eth_device_name));
+	memcpy(ifr.ifr_hwaddr.sa_data, multicast_addr.addr, ETH_ALEN);
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		LOG_ERR(PFX "%s: Couldn't create socket to %s "
+		            "multicast address: %s",
+			nic->log_name, 
+			cmd == SIOCADDMULTI ? "added" : "delete",	
+			strerror(errno));
+		return errno;
+	}
+
+	if (ioctl(fd, cmd, (char*)&ifr) != 0) {
+		LOG_ERR("%s: Couldn't issue ioctl socket to %s "
+			"multicast address: %s",
+			nic->log_name,
+			cmd == SIOCADDMULTI ? "add" : "delete",
+			strerror(errno));
+		rc = errno;
+		goto error;
+	}
+
+	LOG_INFO(PFX "%s: %s address %02x:%02x:%02x:%02x:%02x:%02x "
+	             "to multicast list for %s",
+		 nic->log_name,
+		 cmd == SIOCADDMULTI ? "Added" : "Deleted",
+		 multicast_addr.addr[0], multicast_addr.addr[1],
+		 multicast_addr.addr[2], multicast_addr.addr[3],
+		 multicast_addr.addr[4], multicast_addr.addr[5],
+		 nic->eth_device_name);
+
+	if(cmd == SIOCADDMULTI) {
+		nic->flags |= NIC_ADDED_MULICAST;
+	} else {
+		nic->flags &= ~NIC_ADDED_MULICAST;
+	}
+
+error:
+	close(fd);
+
+	return rc;
+}
+
+/**
+ *  enable_multicast() - This fuction is used to enable 
+ *  	the listening of multicast addresses for a given network interface
+ *  @param nic - NIC device to enable multicast on
+ *  @return 0 for success or <0 for failure
+ */
+int enable_multicast(nic_t *nic) 
+{
+	return nic_util_enable_disable_multicast(nic, SIOCADDMULTI);
+}
+
+/**
+ *  disable_multicast() - This fuction is used to disable
+ *  	the listening of multicast addresses for a given network interface
+ *  @param dev - NIC  device to disable multicast on
+ *  @return 0 for success or <0 for failure
+ */
+int disable_multicast(nic_t *nic) 
+{
+	return nic_util_enable_disable_multicast(nic, SIOCDELMULTI);
+}
+
+/*******************************************************************************
+ * Finding associated UIO/physical network interfaces
+ ******************************************************************************/
+static int filter_net_name(const struct dirent *entry)
+{
+	if((memcmp(entry->d_name, "net:", 4) == 0)) 
+		return 1;
+	else
+		return 0;
+}
+
+static char * extract_net_name(struct dirent **files)
+{
+	return strstr(files[0]->d_name, ":");
+}
+
+static int filter_dot_out(const struct dirent *entry)
+{
+	if((memcmp(entry->d_name, ".", 1) == 0)) 
+		return 0;
+	else
+		return 1;
+}
+
+static char * extract_none(struct dirent **files)
+{
+	return (files[0]->d_name);
+}
+
+/**
+ *  from_host_no_find_nic() - Given the host number
+ *      this function will try to find the assoicated nic interface
+ *  @param host_no - minor number of the UIO device
+ *  @param nic - pointer to the NIC will set if successful
+ *  @return 0 on success, <0 on error
+ */
+int from_host_no_find_associated_eth_device(int host_no,
+					    nic_t **nic)
+{
+	nic_t *current_nic = nic_list;
+        char *raw = NULL, *raw_tmp;
+        uint32_t raw_size = 0;
+
+	char temp_path[sizeof(iscsi_host_path_netdev_template) + 8];
+	int rc = -EIO;
+
+	/*  Build the path to determine uio name */
+	snprintf(temp_path, sizeof(temp_path),
+		 iscsi_host_path_netdev_template, host_no);
+
+        rc = capture_file(&raw, &raw_size, temp_path);
+        if(rc != 0)
+        {
+                goto error;
+        }
+
+        /* sanitize name string by replacing newline with null termination */
+        raw_tmp = raw;
+        while(*raw_tmp != '\n')
+                raw_tmp++;
+        *raw_tmp = '\0';
+
+	rc = -EIO;
+
+	pthread_mutex_lock(&nic_list_mutex);
+	current_nic = nic_list;
+	while(current_nic != NULL)
+	{
+		if (strcmp(raw, current_nic->eth_device_name) == 0) {
+			*nic = current_nic;
+			rc = 0;
+			break;
+		}
+
+		current_nic = current_nic->next;
+	}
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	free(raw);
+	
+      error:
+	return rc;
+}
+
+
+/*******************************************************************************
+ *  NIC packet handling functions
+ ******************************************************************************/
+/**
+ *  from_uio_find_associated_eth_device() - Given the uio minor number
+ *      this function will try to find the assoicated phyisical network
+ *      interface
+ *  @param uio_minor - minor number of the UIO device
+ *  @param name - char buffer which will be filled if successful
+ *  @param name_size - size of the name buffer
+ *  @return >0 minor number <0 an error
+ */
+int from_uio_find_associated_eth_device(int uio_minor,
+					char *name,
+					size_t name_size)
+{
+	char *path;
+	int rc;
+	int count;
+	struct dirent **files;
+	char *parsed_name;
+	int i;
+	int path_iterator;
+	char *search_paths[] = { "/sys/class/uio/uio%i/device/",
+				 "/sys/class/uio/uio%i/device/net" };
+	int (*search_filters[])(const struct dirent *) = {
+		filter_net_name,
+		filter_dot_out,
+	};
+	char *(*extract_name[])(struct dirent **files) = {
+		extract_net_name,
+		extract_none,
+	};
+	int extract_name_offset[] = { 1, 0 };
+
+	path = malloc(PATH_MAX);
+	if (path == NULL) {
+		LOG_ERR(PFX "Could not allocate memory for path");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for(path_iterator = 0;
+	    path_iterator < sizeof(search_paths) / sizeof(search_paths[0]);
+	    path_iterator++) {
+		/*  Build the path to determine uio name */
+		rc = sprintf(path, search_paths[path_iterator],
+			     uio_minor);
+		count = scandir(path, &files,
+				search_filters[path_iterator],
+				alphasort);
+
+		switch(count) { 
+		case 1:
+			parsed_name = (*extract_name[path_iterator])(files);
+			if(parsed_name == NULL) {
+				LOG_WARN(PFX "Couldn't find delimiter in: %s",
+					 files[0]->d_name);
+		
+				break;
+			}
+
+			strncpy(name,
+				parsed_name +
+					extract_name_offset[path_iterator],
+				name_size);
+
+			free(files[0]);
+			free(files);
+
+			rc = 0;
+			break;
+
+		case 0:
+			rc = -EINVAL;
+			break;
+
+		case -1:
+			LOG_WARN(PFX "Error when scanning path: %s[%s]",
+				 path, strerror(errno));
+			rc = -EINVAL;
+			break;
+
+		default:
+			LOG_WARN(PFX "Too many entries when looking for device: %s",
+				 path);
+
+			/*  Cleanup the scandir() call */
+			for(i=0; i<count; i++)
+				free(files[i]);
+			free(files);
+
+			rc = -EINVAL;
+			break;
+		}
+
+		if(rc == 0)
+			break;
+	}
+
+error:
+	free(path);
+
+	return rc;
+}
+
+/**
+ *  filter_uio_name() - This is the callback used by scandir when looking for
+ *                      the number of uio entries
+ */
+static int filter_uio_name(const struct dirent *entry)
+{
+	/*  Only return if the name of the file begins with 'uio' */
+	if((memcmp(entry->d_name, uio_name, sizeof(uio_name) -1) == 0)) 
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * from_netdev_name_find_nic() - This is used to find the NIC device given
+ *                               the netdev name
+ * @param interface_name - name of the interface to search on
+ * @param nic - pointer of the pointer to the NIC
+ * @return 0 on success, <0 on failure
+ */
+int from_netdev_name_find_nic(char *interface_name,
+			      nic_t **nic)
+{
+	nic_t *current_nic;
+
+	pthread_mutex_lock(&nic_list_mutex);
+	current_nic = nic_list;
+	while(current_nic != NULL)
+	{
+		if (strcmp(interface_name, current_nic->eth_device_name) == 0) {
+			break;
+		}
+
+		current_nic = current_nic->next;
+	}
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	if(current_nic == NULL)
+		return -EINVAL;
+
+	*nic = current_nic;
+	return 0;
+}
+
+/**
+ *  from_phys_name_find_assoicated_uio_device() - This is used to find the
+ *  						  uio minor
+ *      when given a network interface name
+ *  @param interface_name - network interface name to search for
+ *  @return >0 minor number <0 an error
+ */
+int from_phys_name_find_assoicated_uio_device(nic_t *nic)
+{
+	char *path = NULL;
+	int count;
+	struct dirent **files;
+	int i;
+	int rc;
+	char *interface_name = nic->config_device_name;
+
+	if(interface_name == NULL)
+		interface_name = nic->eth_device_name;
+
+	count = scandir(base_uio_sysfs_name,
+			&files, filter_uio_name, alphasort);
+
+	switch(count) { 
+	case 0:
+		LOG_WARN(PFX "Couldn't find %s to determine uio minor",
+			 interface_name);
+		return-EINVAL;
+
+	case -1:
+		LOG_WARN(PFX "Error when scanning for %s in path: %s [%s]",
+			 interface_name,
+			 base_uio_sysfs_name, strerror(errno));
+		return -EINVAL;
+	}
+
+	path = malloc(PATH_MAX);
+	if (path == NULL) {
+		LOG_ERR(PFX "Could not allocate memory for path");
+		return -ENOMEM;
+	}
+
+	/*  Run through the contents of the filtered files to see if the
+	 *  network interface name matches that of the uio device */
+	for(i=0; i <count; i++)
+	{
+		int uio_minor;
+		char eth_name[IFNAMSIZ];
+
+		rc = sscanf(files[i]->d_name, "uio%d", &uio_minor);
+		if(rc != 1)
+		{
+			LOG_WARN("Could not parse: %s", files[i]->d_name);
+			continue;
+		}
+
+		rc = from_uio_find_associated_eth_device(uio_minor,
+							 eth_name,
+							 sizeof(eth_name));
+		if( rc != 0)
+		{
+			LOG_WARN("uio minor: %d not valid [%d}", uio_minor, rc);
+			continue;
+		}
+
+		if(strncmp(eth_name, interface_name, sizeof(eth_name)) == 0)
+		{
+			memcpy(nic->eth_device_name,
+			       eth_name,
+			       sizeof(nic->eth_device_name));
+
+			LOG_INFO(PFX "%s associated with uio%d",
+				 nic->eth_device_name, uio_minor);
+
+		 	rc = uio_minor;
+			goto done;
+		}
+	}
+
+	LOG_WARN("Could not find assoicate uio device with %s",
+		 interface_name);
+
+	rc = -EINVAL;
+done:
+	if(path != NULL)
+		free(path);
+
+	for(i=0; i<count; i++)
+		free(files[i]);
+	free(files);
+
+	return rc;
+
+}
+
+/**
+ *  nic_verify_uio_sysfs_name() - Using the name entry in sysfs it will try to 
+ *      match the NIC library name
+ *  @param nic - The NIC hardware to check
+ *
+ */
+int nic_verify_uio_sysfs_name(nic_t *nic)
+{
+        char *raw = NULL, *raw_tmp;
+	uint32_t raw_size = 0;
+	char temp_path[sizeof(nic_uio_sysfs_name_tempate) + 8];
+	int rc = 0;
+
+	/*  Build the path to determine uio name */
+	snprintf(temp_path, sizeof(temp_path),
+		 nic_uio_sysfs_name_tempate, nic->uio_minor);
+
+        rc = capture_file(&raw, &raw_size, temp_path);
+        if(rc != 0)
+        {
+                goto error;
+        }
+
+	/* sanitize name string by replacing newline with null termination */
+	raw_tmp = raw;
+	while(*raw_tmp != '\n')
+		raw_tmp++;
+	*raw_tmp = '\0';
+
+	/*  If the nic library is not set then check if there is a library
+	 *  which matches the library name */ 
+	if(nic->nic_library == NULL) {
+		NIC_LIBRARY_EXIST_T exist;
+
+		exist = does_nic_uio_name_exist(raw);
+		if (exist == NIC_LIBRARY_DOESNT_EXIST) {
+			LOG_ERR(PFX "%s: could not find library: %s ",
+				nic->log_name, raw);
+			rc = -EIO;
+		} 
+	} else {
+		char *library_name;
+		size_t library_name_size;
+
+		/*  Get the string name from the NIC library */
+		(*nic->ops->lib_ops.get_library_name)(&library_name,
+						      &library_name_size);
+
+		if (strcmp(raw, library_name) != 0) {
+			LOG_ERR(PFX "%s: uio names not equal: "
+				    "expecting %s got %s from %s",
+				nic->log_name, library_name, raw, temp_path);
+			rc = -EIO;
+		}
+	}
+
+	free(raw);
+
+	LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
+
+      error:
+	return rc;
+}
+
+
+/**
+ * nic_fill_name() - This will initialize all the hardware resources underneath
+ *                   a struct cnic_uio device
+ * @param nic - The nic device to attach the hardware with
+ * @return 0 on success, on failure a errno will be returned
+ */
+int nic_fill_name(nic_t *nic)
+{
+	int rc;
+
+	if((nic->config_device_name != NULL) &&
+	   (memcmp(uio_base_dir, nic->config_device_name,
+		  sizeof(uio_base_dir) - 1) == 0)) {
+		uint16_t uio_minor;
+		char eth_name[sizeof(nic->eth_device_name)];
+
+		/*  Determine the minor number for the UIO device */
+		rc = sscanf(nic->config_device_name, uio_udev_path_template,
+			    &uio_minor);
+		if(rc != 1)
+		{
+			LOG_WARN(PFX "%s: Could not parse for minor number",
+				 nic->uio_device_name);
+			return -EINVAL;
+		} else {
+			nic->uio_minor = uio_minor;
+		}
+
+		nic->uio_device_name = nic->config_device_name;
+
+		/*  Determine the assoicated physical network interface */
+		rc = from_uio_find_associated_eth_device(nic->uio_minor,
+						 	 eth_name,
+							 sizeof(eth_name));
+		if(rc != 0) {
+			LOG_WARN(PFX "%s: Couldn't find associated eth device",
+				 nic->uio_device_name);
+		} else {
+			memcpy(nic->eth_device_name,
+			       eth_name, sizeof(eth_name));
+		}
+
+		LOG_INFO(PFX "%s: configured for uio device for %s",
+			 nic->log_name,
+			 nic->uio_device_name);
+
+	} else {
+		LOG_INFO(PFX "looking for uio device for %s",
+			 nic->config_device_name);
+
+		rc = from_phys_name_find_assoicated_uio_device(nic);
+		if(rc < 0) {
+			/*  TODO wait for ethernet interface to appear */
+			LOG_ERR(PFX "Could not determine UIO name");
+		}
+
+		nic->uio_minor = rc;
+
+		nic->uio_device_name = malloc(sizeof(uio_udev_path_template) + 8);
+		if(nic->uio_device_name == NULL)
+		{
+			LOG_INFO(PFX "%s: Couldn't malloc space for uio name",
+				 nic->log_name);
+			return -ENOMEM;
+		}
+			
+		snprintf(nic->uio_device_name,
+			 sizeof(uio_udev_path_template) + 8,
+			 uio_udev_path_template, nic->uio_minor);
+
+		nic->flags |= NIC_UIO_NAME_MALLOC;
+	}
+
+	return 0;
+}
+
+void prepare_nic(nic_t *nic)
+{
+	int rc;
+	NIC_LIBRARY_EXIST_T exist;
+
+	nic_fill_name(nic);
+
+	/* No assoicated library, we can skip it */
+	if(nic->library_name != NULL) {
+		/*  Check that we have the proper NIC library loaded */
+		exist = does_nic_library_exist(nic->library_name);
+		if(exist == NIC_LIBRARY_DOESNT_EXIST) {
+			LOG_ERR(PFX "NIC library doesn't exists: %s",
+				nic->library_name);
+			goto error;
+		}
+	}
+
+	/*  Determine the NIC library to use based on the PCI Id */
+	rc = find_set_nic_lib(nic);
+	if (rc != 0) {
+		LOG_ERR(PFX "%s: Couldn't find NIC library",
+			nic->log_name);
+		goto error;
+	}
+
+	LOG_INFO("%s: found NIC '%s'",
+		 nic->log_name,
+		 nic->pci_id->device_name);
+
+	if(nic->thread == INVALID_THREAD) {
+		struct timespec   ts;
+		struct timeval    tp;
+
+		/*  Try to spin up the nic thread */
+		rc = pthread_create(&nic->thread, NULL, nic_loop, nic);
+		if (rc != 0) {
+			LOG_ERR(PFX "%s: Couldn't create thread for nic",
+				nic->log_name);
+			goto error;
+		}
+
+		/* Convert from timeval to timespec */
+		rc =  gettimeofday(&tp, NULL);
+		ts.tv_sec  = tp.tv_sec;
+		ts.tv_nsec = tp.tv_usec * 1000;
+		ts.tv_sec += 5; /*  TODO: hardcoded wait for 5 seconds */
+
+		/*  Wait for the device to be disabled */
+		pthread_mutex_lock(&nic->nic_loop_started_mutex);
+		rc = pthread_cond_timedwait(&nic->nic_loop_started_cond,
+					    &nic->nic_loop_started_mutex, &ts);
+		pthread_mutex_unlock(&nic->nic_loop_started_mutex);
+	}
+
+	LOG_INFO("Created nic thread: %s", nic->log_name);
+
+error:
+	return;
+}
+
+/*******************************************************************************
+ * Functions used to enable/disable the NIC
+ ******************************************************************************/
+/**
+ *  nic_enable() - Function used to enable the NIC
+ *  @param nic - NIC to enable
+ *  @return 0 on success, <0 on failure
+ */
+int nic_enable(nic_t *nic)
+{
+	if( (nic->flags & NIC_DISABLED) &&
+	    (nic->state & NIC_STOPPED))
+	{
+		struct timespec   ts;
+		struct timeval    tp;
+		int rc;
+
+		/*  Signal the device to enable itself */
+		pthread_mutex_lock(&nic->enable_wait_mutex);
+		pthread_cond_signal(&nic->enable_wait_cond);
+		pthread_mutex_unlock(&nic->enable_wait_mutex);
+
+		nic->flags &= ~NIC_DISABLED;
+		nic->flags |= NIC_ENABLED;
+
+		/* Convert from timeval to timespec */
+		rc =  gettimeofday(&tp, NULL);
+		ts.tv_sec  = tp.tv_sec;
+		ts.tv_nsec = tp.tv_usec * 1000;
+		ts.tv_sec += 5; /*  TODO: hardcoded wait for 5 seconds */
+
+		/*  Wait for the device to be disabled */
+		pthread_mutex_lock(&nic->enable_done_mutex);
+		rc = pthread_cond_timedwait(&nic->enable_done_cond,
+					    &nic->enable_done_mutex, &ts);
+		pthread_mutex_unlock(&nic->enable_done_mutex);
+
+		if(rc == 0) {
+			LOG_DEBUG(PFX "%s: device enabled", nic->log_name);
+
+			return 0;
+		} else {
+			LOG_ERR(PFX "%s: waiting to finish nic_enable err:%s",
+				 nic->log_name, strerror(rc));
+			return rc;
+		}
+	}
+	else
+	{
+		LOG_INFO(PFX "%s: device already enabled: flag: "
+			     "0x%x state: 0x%x",
+			 nic->log_name, nic->flags, nic->state);
+		return -EALREADY;
+	}
+}
+
+/**
+ *  nic_disable() - Function used to disable the NIC
+ *  @param nic - NIC to disble
+ *  @return 0 on success, <0 on failure
+ */
+int nic_disable(nic_t *nic)
+{
+	if( (nic->flags & NIC_ENABLED) &&
+	    (nic->state & NIC_RUNNING))
+	{
+		nic->flags &= ~NIC_ENABLED;
+		nic->flags |= NIC_DISABLED;
+		nic->state &= ~NIC_RUNNING;
+		nic->state |= NIC_STOPPED;
+
+		/*  Wait for the device to be disabled */
+		pthread_mutex_lock(&nic->disable_wait_mutex);
+		pthread_cond_wait(&nic->disable_wait_cond,
+				  &nic->disable_wait_mutex);
+		pthread_mutex_unlock(&nic->disable_wait_mutex);
+
+		LOG_DEBUG(PFX "%s: device disabled", nic->log_name);
+
+		return 0;
+	}
+	else
+	{
+		LOG_WARN(PFX "%s: device already disabled: ",
+			 nic->log_name, nic->flags, nic->state);
+		return -EALREADY;
+	}
+}
+
+void nic_close_all()
+{
+	nic_t *nic;
+
+	pthread_mutex_lock(&nic_list_mutex);
+
+	/*  Start the shutdown process */
+	nic = nic_list;
+	while (nic != NULL) {
+		nic_close(nic, 1);
+		nic = nic->next;
+	}
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	LOG_INFO(PFX "All CNIC threads have exited");
+}
+
+
+/******************************************************************************
+ *  Routines to read initialized UIO values from sysfs
+ *****************************************************************************/
+/**
+ * determine_initial_uio_events() - This utility function will
+ *    determine the number of uio events that have occured on the 
+ *    given device.  This value is read from the UIO sysfs entry
+ * @param dev - device to read from
+ * @param num_of_event - number of UIO events
+ * @return 0 is success, <0 failure
+ */
+int detemine_initial_uio_events(nic_t *nic,
+			        uint32_t *num_of_events)
+{
+        char *raw = NULL;
+	uint32_t raw_size = 0;
+	ssize_t elements_read;
+	char temp_path[sizeof(cnic_sysfs_uio_event_template) + 8];
+	int rc;
+
+	/*  Capture RX buffer size */
+	snprintf(temp_path, sizeof(temp_path), 
+		 cnic_sysfs_uio_event_template, nic->uio_minor);
+
+        rc = capture_file(&raw, &raw_size, temp_path);
+        if(rc != 0)
+        {
+                goto error;
+        }
+
+	elements_read = sscanf(raw, "%d", num_of_events);
+	if(elements_read != 1)
+	{
+		LOG_ERR(PFX "%s: Couldn't parse UIO events size from %s",
+			nic->log_name, temp_path);
+		rc =-EIO;
+		goto error;
+	}
+
+	rc = 0;
+error:
+	if(raw != NULL)
+		free(raw);
+
+	return rc;
+}
+
+
+
+
+/**
+ *  add_vlan_interfaces() - Using the associated ethernet device name, this
+ *                      function will traverse through the local VLAN table
+ *                      determine if the associated interface is a VLAN
+ *                      then will create network interfaces for all VLAN ID
+ *  @param dev - struct cnic_uio device to assign the VLAN ID
+ *  @return 0 on success, <0 on failure
+ */
+int add_vlan_interfaces(nic_t *nic)
+{
+	int rc;
+	struct vlan_handle handle;
+	struct vlan_found_handle found_handle;
+
+        init_vlan_table(&handle);
+	rc = capture_vlan_table(&handle);
+	if(rc != 0) {
+		LOG_ERR(PFX "Failed to capture VLAN table");
+		rc = -EIO;
+		goto error_vlan_handle;
+	}
+
+        rc = init_vlan_found_handle(&found_handle, &handle);
+	if(rc != 0) {
+		LOG_ERR(PFX "Failed to init VLAN found handle");
+		goto error_vlan_found_handle;
+	}
+
+	rc = find_vlans_using_phy_interface(&handle,
+					    &found_handle,
+					    nic->eth_device_name);
+	if(rc > 0)
+	{
+		int i;
+
+		for(i=0; i<rc; i++)
+		{
+			struct vlan_found_entry *found_entry;
+			nic_interface_t *nic_iface;
+
+			found_entry = &found_handle.entries[i];
+
+			if(found_entry->found == VLAN_ENTRY_FOUND)
+			{
+	                        nic_iface = nic_iface_init(nic);
+				if(nic_iface == NULL)
+				{
+					LOG_ERR("Couldn't allocate space for net_iface");
+					continue;
+				}
+
+				nic_iface->vlan_id = found_handle.handle->entries->vlan_id;
+
+				rc = nic_add_nic_iface(nic, nic_iface);
+			}
+		}
+	}
+
+	release_vlan_found_handle(&found_handle);
+
+error_vlan_found_handle:
+
+	release_vlan_table(&handle);
+
+error_vlan_handle:
+
+	return rc;
+}
+
+/**
+ *  nic_set_all_nic_iface_mac_to_parent() - This is a utility function used to 
+ *      intialize all the MAC addresses of the network interfaces for a given
+ *      CNIC UIO device
+ *  @param dev - CNIC UIO device to initialize
+ */
+void nic_set_all_nic_iface_mac_to_parent(nic_t *nic)
+{
+	nic_interface_t *current;
+
+	pthread_mutex_lock(&nic->nic_iface_mutex);
+
+	current = nic->nic_iface;
+	while(current != NULL)
+	{
+		/*  Set the initial MAC address of this interface to the parent
+		 *  adapter */
+		memcpy(current->mac_addr, nic->mac_addr, 6);
+
+		current = current->next;
+	}
+
+	pthread_mutex_unlock(&nic->nic_iface_mutex);
+}
+
+/*******************************************************************************
+ *  NIC packet handling functions
+ ******************************************************************************/
+/**
+ *  nic_alloc_packet_buffer() - Used to allocate a packet buffer used to
+ *      send a TX packet later
+ *  @param nic - nic device to send the packet on
+ *  @param nic_iface - nic interface to send out on
+ *  @param buf - pointer to the buffer to send
+ *  @param buf_size - size in bytes of the buffer to send
+ *  @return pointer to the allocated packet buffer
+ *          NULL if memory could not be allocated
+ */
+static packet_t * nic_alloc_packet_buffer(nic_t *nic,
+					  nic_interface_t *nic_iface,
+					  uint8_t *buf,
+					  size_t  buf_size)
+{
+	packet_t *pkt;
+
+	pkt = malloc(sizeof(*pkt) + buf_size);
+	if(pkt == NULL) {
+		LOG_ERR(PFX "%s: Couldn't allocate space for packet buffer\n");
+		return NULL;
+	}
+
+	pkt->next = NULL;
+	pkt->nic = nic;
+	pkt->nic_iface = nic_iface;
+	pkt->buf_size = buf_size;
+	memcpy(pkt->buf, buf, buf_size);
+
+	return pkt;
+}
+
+/**
+ *  nic_queue_tx_packet() - Used to queue a TX packet buffer to send later
+ *  @param nic - NIC device to send the packet on
+ *  @param nic_iface - NIC interface to send on the packet on
+ *  @param pkt - packet to queue
+ *  @return 0 if successful or <0 if unsuccessful
+ */
+int nic_queue_tx_packet(nic_t *nic,
+			nic_interface_t *nic_iface,
+			packet_t *pkt)
+{
+	packet_t *queued_pkt;
+
+	queued_pkt = nic_alloc_packet_buffer(nic, nic_iface,
+					     pkt->buf, pkt->buf_size);
+	if(queued_pkt == NULL)
+	{
+		LOG_ERR(PFX "%s: Couldn't allocate tx packet to queue");
+		return -ENOMEM;
+	}
+
+	if(nic->tx_packet_queue == NULL) {
+		nic->tx_packet_queue = queued_pkt;
+	} else {
+		packet_t *current_pkt;
+
+		current_pkt = nic->tx_packet_queue;
+		while(current_pkt->next != NULL)
+		{
+			current_pkt = current_pkt->next;
+		}
+	
+		current_pkt->next = queued_pkt;
+	}
+
+	LOG_DEBUG(PFX "%s: tx packet queued", nic->log_name);
+
+	return 0;
+}
+
+
+/**
+ *  nic_dequeue_tx_packet() - Used pop a TX packet buffer of the TX 
+ *  @param dev - cnic_uio device to send the packet on
+ *  @param buf - pointer to the buffer to send
+ *  @param buf_size - size in bytes of the buffer to send
+ *  @return NULL if there are no more TX packet buffers to send
+ *  	    pointer to the packet buffer which is detached from the device
+ */
+packet_t * nic_dequeue_tx_packet(nic_t *nic)
+{
+	packet_t *pkt;
+
+	pkt = nic->tx_packet_queue;
+
+	/* There is a packet buffer to send, time to detach it from the 
+	 * cnic_uio device */
+	if(pkt != NULL) {
+		nic->tx_packet_queue = pkt->next;
+		pkt->next = NULL;
+	}
+
+	return pkt;
+}
+
+
+/*******************************************************************************
+ *  NIC interface management utility functions
+ ******************************************************************************/
+/**
+ *  nic_find_nic_iface() - This function is used to find an interface from the 
+ *                         NIC
+ *  @param vlan_id - VLAN id to look for
+ *  @return nic_iface - if found network interface with the given VLAN ID
+ *                      if not found a NULL is returned
+ */
+nic_interface_t * nic_find_nic_iface(nic_t *nic,
+				     uint16_t vlan_id)
+{
+	nic_interface_t *current;
+
+	pthread_mutex_lock(&nic->nic_iface_mutex);
+
+	current = nic->nic_iface;
+	while(current != NULL)
+	{
+		if(current->vlan_id == vlan_id)
+		{
+			pthread_mutex_unlock(&nic->nic_iface_mutex);
+			return current;
+		}
+
+		current = current->next;
+	}
+
+	pthread_mutex_unlock(&nic->nic_iface_mutex);
+
+	return NULL;
+}
+
+
+/*******************************************************************************
+ *  Packet management utility functions
+ ******************************************************************************/
+/**
+ *  get_next_packet_in_queue() - This function will return the next packet in 
+ *    the queue
+ *  @param queue - the queue to pull the packet from
+ *  @return the packet in the queue
+ */
+static packet_t * get_next_packet_in_queue(packet_t **queue)
+{
+	packet_t *pkt;
+
+	if(*queue == NULL)
+		return NULL;
+
+	pkt = *queue;
+	*queue = pkt->next;
+
+	return pkt;
+}
+
+/**
+ *  get_next_tx_packet() - This function will return the next packet in 
+ *    the TX queue
+ *  @param nic - NIC to pull the TX packet from
+ *  @return the packet in hte queue
+ */
+packet_t * get_next_tx_packet(nic_t *nic)
+{
+	return get_next_packet_in_queue(&nic->tx_packet_queue);
+}
+
+/**
+ *  get_next_free_packet() - This function will return the next packet in 
+ *    the free queue
+ *  @param nic - NIC to pull the RX packet from
+ *  @return the packet in hte queue
+ */
+packet_t * get_next_free_packet(nic_t *nic)
+{
+	packet_t *pkt;
+	pthread_mutex_lock(&nic->free_packet_queue_mutex);
+	pkt = get_next_packet_in_queue(&nic->free_packet_queue);
+	pthread_mutex_unlock(&nic->free_packet_queue_mutex);
+
+	if(pkt != NULL)
+		reset_packet(pkt);
+
+	return pkt;
+}
+
+/**
+ *  put_packet_in_queue() - This function will place the packet in the given
+ *    queue
+ *  @param pkt   - the packet to place
+ *  @param queue - the queue to place the packet
+ *  @return the packet in the queue
+ */
+static void put_packet_in_queue(packet_t *pkt,
+				packet_t **queue)
+{
+	if(*queue == NULL) {
+		*queue = pkt;
+	} else {
+		pkt->next = *queue;
+		*queue = pkt;
+	}
+}
+
+/**
+ *  put_packet_in_tx_queue() - This function will place the packet in
+ *    the TX queue
+ *  @param pkt - packet to place
+ *  @param nic - NIC to pull the TX packet from
+ *  @return the packet in hte queue
+ */
+void put_packet_in_tx_queue(packet_t *pkt,
+			    nic_t *nic)
+{
+	return put_packet_in_queue(pkt,
+				   &nic->tx_packet_queue);
+}
+
+/**
+ *  put_packet_in_free_queue() - This function will place the packet in 
+ *    the RX queue
+ *  @param pkt - packet to place
+ *  @param nic - NIC to pull the RX packet from
+ *  @return the packet in hte queue
+ */
+void put_packet_in_free_queue(packet_t *pkt,
+			    nic_t *nic)
+{
+	pthread_mutex_lock(&nic->free_packet_queue_mutex);
+	put_packet_in_queue(pkt,
+			     &nic->free_packet_queue);
+	pthread_mutex_unlock(&nic->free_packet_queue_mutex);
+}
+
+
+uint32_t calculate_default_netmask(uint32_t ip_addr)
+{ 
+	uint32_t netmask;
+
+	if (IN_CLASSA(ntohl(ip_addr)))
+		netmask = htonl(IN_CLASSA_NET);
+	else if (IN_CLASSB(ntohl(ip_addr)))
+		netmask = htonl(IN_CLASSB_NET);
+	else if (IN_CLASSC(ntohl(ip_addr)))
+		netmask = htonl(IN_CLASSC_NET);
+	else {
+		LOG_ERR("Unable to guess netmask for address %x\n",
+                                &ip_addr);
+                        return -1;
+        }
+
+	return netmask;
+}
+
+
+
+/*******************************************************************************
+ *  File Management
+ ******************************************************************************/
+ /**
+  * determine_file_size_read() - when fstat doesn't work on filepath
+  *     within the /proc filesytem, we need to read/count the size of the file
+  *     until we hit a EOF
+  * @parm filepath - path of the file in which to determine the filesize in 
+  *                  bytes
+  * @return file size in bytes, <0 on failure
+  */
+int determine_file_size_read(const char *filepath) 
+{
+	size_t total_size = 0;
+	ssize_t size = 1;
+	int fd;
+	char buf[1024];
+
+	fd = open(filepath, O_RDONLY);
+	if(fd == -1) {
+		LOG_ERR("Could not open file: %s", filepath);
+		return -1;
+	}
+
+	while(size > 0)
+	{
+		size = read(fd, buf, sizeof(buf));
+
+		switch(size) {
+		case 0:
+			break;
+		case -1:
+			LOG_ERR("Error reading file to determine size: %s",
+				strerror(errno));
+			total_size = -1;
+			break;
+		default:
+			total_size += size;
+			break;
+		}
+	}
+
+	close(fd);
+
+	return total_size;
+}
+
+/**
+ *  capture_file() - Used to capture a file into a buffer
+ *  @param raw - This pointer will be set to the buffer which will hold the 
+ *         file contents
+ *  @param raw_size - This is the size of the buffer returned
+ *  @param path - The file path to capture the data from
+ *  @return 0 is returned on success, <0 is returned on failure
+ */
+int capture_file(char **raw, uint32_t *raw_size, const char *path)
+{
+	FILE *fp;
+	size_t read_size;
+	int rc = 0;
+	int file_size;
+
+	file_size = determine_file_size_read(path);
+	if(file_size < 0)
+	{
+		LOG_ERR("Could not determine size %s",
+			path);
+		return -EIO;
+	}
+
+	fp = fopen(path, "r");
+	if(fp == NULL) {
+		LOG_ERR("Could not open path %s",
+			path);
+		return -EIO;
+	}
+
+	*raw = malloc(file_size);
+	if(*raw == NULL) {
+		LOG_ERR("Could not malloc space for capture %s",
+			path);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	read_size = fread(*raw, file_size, 1, fp);
+	if(read_size < 0) {
+		LOG_ERR("Could not read capture, path: %s len: %d",
+			path, file_size);
+		free(*raw);
+		*raw = NULL;
+		rc = errno;
+	}
+	else
+	{
+		*raw_size = file_size;
+	}
+error:
+	fclose(fp);
+
+	LOG_INFO("Done capturing %s", path);
+
+	return rc;
+}
diff --git a/brcm_iscsi_uio/src/unix/nic_utils.h b/brcm_iscsi_uio/src/unix/nic_utils.h
new file mode 100644
index 0000000..a36457a
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_utils.h
@@ -0,0 +1,55 @@
+/* nic_util.h: NIC utility functions
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+#ifndef __NIC_UTILS_H__
+#define __NIC_UTILS_H__
+
+#include "nic.h"
+
+/******************************************************************************
+ * Function Prototype
+ ******************************************************************************/
+int nic_discover_iscsi_hosts();
+
+int enable_mutlicast(nic_t *nic);
+int disable_mutlicast(nic_t *nic);
+
+int from_netdev_name_find_nic(char *interface_name,
+			      nic_t **nic);
+
+int from_host_no_find_associated_eth_device(int host_no,
+                                            nic_t **nic);
+
+int from_phys_name_find_assoicated_uio_device(nic_t *nic);
+
+int nic_queue_tx_packet(nic_t *nic,
+			nic_interface_t *nic_iface,
+			packet_t *pkt);
+
+packet_t * nic_dequeue_tx_packet(nic_t *nic);
+nic_interface_t * nic_find_nic_iface(nic_t *nic,
+                                     uint16_t vlan_id);
+int add_vlan_interfaces(nic_t *nic);
+
+int nic_verify_uio_sysfs_name(nic_t *nic);
+void nic_close_all();
+
+uint32_t calculate_default_netmask(uint32_t ip_addr);
+
+void prepare_nic(nic_t *nic);
+
+int nic_enable(nic_t *nic);
+int nic_disable(nic_t *nic);
+
+int determine_file_size_read(const char *filepath);
+int capture_file(char **raw, uint32_t *raw_size, const char *path);
+
+
+#endif /* __NIC_UTILS_H__ */
diff --git a/brcm_iscsi_uio/src/unix/nic_vlan.c b/brcm_iscsi_uio/src/unix/nic_vlan.c
new file mode 100644
index 0000000..4f28f22
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_vlan.c
@@ -0,0 +1,311 @@
+/* nic_vlan.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <linux/if.h>
+
+#include "logger.h"
+#include "nic.h"
+#include "nic_utils.h"
+#include "nic_vlan.h"
+
+/*******************************************************************************
+ * Constants
+ ******************************************************************************/
+#define PFX "vlan"
+
+static const char proc_vlan_config_path[] = "/proc/net/vlan/config";
+
+/*******************************************************************************
+ * Resolving Found VLAN's for CNIC
+ ******************************************************************************/
+int init_vlan_found_handle(struct vlan_found_handle *found_handle,
+			   struct vlan_handle *handle)
+{
+	memset(found_handle, 0, sizeof(*found_handle));
+
+	found_handle->entries = malloc(found_handle->num_of_entries *
+				       sizeof(struct vlan_found_entry));
+	if(found_handle->entries == NULL)
+	{
+		LOG_ERR("Could not allocate space for found entries");
+		return -ENOMEM;
+	}
+
+	found_handle->handle = handle;
+	found_handle->num_of_entries = handle->num_of_entries;
+
+	memset(found_handle->entries, 0, found_handle->num_of_entries *
+	                                       sizeof(struct vlan_found_entry));
+
+	handle->outstanding_found_handles++;
+
+	return 0;
+}
+
+void release_vlan_found_handle(struct vlan_found_handle *found_handle)
+{
+	if(found_handle->entries != NULL) {
+		free(found_handle->entries);
+		found_handle->entries = NULL;
+	}
+
+	found_handle->num_of_entries = 0;
+
+	found_handle->handle->outstanding_found_handles--;
+
+	found_handle->handle = NULL;
+
+}
+
+/*******************************************************************************
+ * Resolving VLAN's for CNIC
+ ******************************************************************************/
+/**
+ *  init_vlan_handle() - Used to initialize struct ipv4_route_handle so
+ *                            that is can be used
+ *  @param handle - Pointer to struct ipv4_route_handle to initialize
+ *  @return 0 on success and <0 on failure
+ */
+void init_vlan_table(struct vlan_handle *handle)
+{
+	handle->entries = NULL;
+	handle->num_of_entries = 0;
+}
+
+/**
+ *  parse_vlan_table() - Given the raw dump of a Linux vlan table, this
+ *                       function will parse the into entries held by
+ *                       struct vlan_handle
+ *  @param handle - struct vlan_handle used to hold the parsed contents
+ *  @param raw    - buffer to parse the contents from
+ *  @param raw_size  - size of the buffer in bytes
+ *  @return 0 on success, <0 on failure
+ */
+int parse_vlan_table(struct vlan_handle *handle,
+		     char *raw, uint32_t raw_size)
+{
+	FILE *fp;
+	int i;
+	char *token;
+	size_t size;
+	int rc;
+
+	token = raw;
+
+	/*  determine the number of entries */
+	while(*token != '\0')
+	{
+		if(*token == '\n')
+			handle->num_of_entries++;
+
+		token++;
+	}
+
+	/*  There are 2 lines which describe the vlan table 
+	 *  This lines need to be skipped with counting */
+	handle->num_of_entries -= 2;	
+
+	LOG_INFO("Number of vlan entries: %d", handle->num_of_entries);
+
+	size = handle->num_of_entries * sizeof(struct vlan_entry);
+	handle->entries = malloc(size);
+	if(handle->entries == NULL) {
+		LOG_ERR("Couldn't malloc space to parse vlan table. entires: %d size: %d",
+			handle->num_of_entries, size);
+		return -ENOMEM;
+	}
+
+	fp = fmemopen(raw, raw_size, "r");
+	if(fp == NULL) {
+		LOG_ERR("Could not open raw dump of vlan table");
+		rc = errno;
+		goto fmemopen_error;
+	}
+
+        if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */
+		LOG_ERR("Empty or missing line, or read error");
+		rc = -EIO;
+		goto error;
+	}
+
+        if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the second line. */
+		LOG_ERR("Empty or missing line, or read error");
+		rc = -EIO;
+		goto error;
+	}
+
+	i = 0;
+	/*  Time to parse the routing table */
+	while(1)
+	{
+		struct vlan_entry *entry = &handle->entries[i];
+		int r;
+
+		r = fscanf(fp, "%15s |%hu |%15s",
+				entry->vlan_iface_name, 
+				&entry->vlan_id,
+				entry->phy_iface_name);
+		if (r != 3) {
+			if (feof(fp)) { /* EOF with no (nonspace) chars read. */
+				break;
+			}
+
+			LOG_WARN("Parsing error: parsed %d elements",
+				 r);
+			break;
+		}
+
+		i++;
+
+		LOG_DEBUG("Vlan %d: vlan iface:%s vlan id:%d phys iface:%s",
+			  i,
+			  entry->vlan_iface_name,
+			  entry->vlan_id,
+			  entry->phy_iface_name);
+	}
+
+	fclose(fp);
+
+	return 0;
+
+error:
+	fclose(fp);
+
+fmemopen_error:
+	if(handle->entries != NULL)
+		free(handle->entries);
+
+	return rc;
+}
+
+/**
+ *  capture_vlan_table() - This function will snapshot the Linux vlan
+ *                         routing table for further processing
+ *  @param handle - struct vlan_handle used to hold the routing context
+ *  @return 0 on success, <0 on failure
+ */
+int capture_vlan_table(struct vlan_handle *handle)
+{
+	char *raw = NULL;
+	uint32_t raw_size = 0;
+	int rc;
+
+	rc = capture_file(&raw, &raw_size, proc_vlan_config_path);
+	if(rc != 0)
+	{
+		goto error;	
+	}
+
+	rc = parse_vlan_table(handle, raw, raw_size);
+	if(rc != 0)
+	{
+		goto error;	
+	}
+
+error:
+	if(raw != NULL)
+		free(raw);
+
+	return rc;
+}
+
+/**
+ *  release_vlan_table() - This function will free all resources used by
+ *                         the handle
+ *  @param handle -  struct vlan_handle used to hold the routing context
+ */
+void release_vlan_table(struct vlan_handle *handle)
+{
+	if(handle->entries != NULL) {
+		free(handle->entries);
+		handle->entries = NULL;
+	}
+
+	handle->num_of_entries = 0;
+}
+
+/**
+ *  find_phy_using_vlan_interface() - Given the interface name determine VLAN
+ *      tag ID to match either the physical or VLAN interface name
+ *  @param vlan_iface_name - VLAN interface used to find the physical
+ *                           interface 
+ *  @param phy_iface_name - returned value is the physical interface name
+ *  @param vlan_id - returned value is the VLAN id
+ *  @return 1 is returned if the interface is a VLAN, 0 if the interface is not
+ *          <0 is returned if there is an error
+ */
+int find_phy_using_vlan_interface(struct vlan_handle *handle,
+				  char *vlan_iface_name,
+				  char **phy_iface_name, uint16_t *vlan_id)
+{
+	int i, rc = 0;
+		
+	for(i=0; i < handle->num_of_entries; i++)
+	{
+		struct vlan_entry *entry = &handle->entries[i];
+
+		/*  Compare VLAN interface names to find a match */
+		if(strcmp(entry->vlan_iface_name, vlan_iface_name) == 0)
+		{
+			*phy_iface_name = entry->phy_iface_name;
+			*vlan_id = entry->vlan_id;
+			rc = 1;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/**
+ *  find_vlans_using_phy_interface() - Given the physical interface name this 
+ *      function will determine the VLAN interface name and VLAN ID
+ *  @param iface_name - physical interface used to find the vlan interface 
+ *  @param vlan_iface_name - returned value is the VLAN interface name
+ *  @return The number of VLAN interfaces found
+ */
+int find_vlans_using_phy_interface(struct vlan_handle *handle,
+		 	 	   struct vlan_found_handle *found_handle,
+				   char *phy_iface_name)
+{
+	int i, num_found = 0;
+		
+	for(i=0; i < handle->num_of_entries; i++)
+	{
+		struct vlan_entry *entry = &handle->entries[i];
+
+		/*  Compare interface names to find a match */
+		if(strcmp(entry->phy_iface_name, phy_iface_name) == 0)
+		{
+			found_handle->entries[i].found = VLAN_ENTRY_FOUND;
+			num_found++;
+		}
+	}
+
+	return num_found;
+}
diff --git a/brcm_iscsi_uio/src/unix/nic_vlan.h b/brcm_iscsi_uio/src/unix/nic_vlan.h
new file mode 100644
index 0000000..b586f19
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/nic_vlan.h
@@ -0,0 +1,65 @@
+/* nic_vlan.h: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __NIC_VLAN_H__
+#define __NIC_VLAN_H__
+
+#include <sys/types.h>
+
+
+/*  Used to hold entries in the vlan table */
+struct vlan_entry {
+	char vlan_iface_name[16];
+	char phy_iface_name[16];
+	uint16_t vlan_id; 
+};
+
+struct vlan_handle
+{
+	struct vlan_entry *entries;
+	uint32_t          num_of_entries;
+
+	uint32_t outstanding_found_handles;
+};
+
+struct vlan_found_entry
+{
+#define VLAN_ENTRY_FOUND	1
+#define VLAN_ENTRY_NOT_FOUND	0
+	uint8_t found;
+};
+
+struct vlan_found_handle
+{
+	struct vlan_handle *handle;
+	uint32_t          num_of_entries;
+	struct vlan_found_entry *entries;
+};
+
+/*******************************************************************************
+ * Function Prototypes
+ ******************************************************************************/
+void init_vlan_table(struct vlan_handle *handle);
+int capture_vlan_table(struct vlan_handle *handle);
+void release_vlan_table(struct vlan_handle *handle);
+
+int find_phy_using_vlan_interface(struct vlan_handle *handle,
+				  char *vlan_iface_name,
+				  char **phy_iface_name, uint16_t *vlan_id);
+int find_vlans_using_phy_interface(struct vlan_handle *handle,
+				   struct vlan_found_handle *found_handle,
+				   char *phy_iface_name);
+
+int init_vlan_found_handle(struct vlan_found_handle *found_handle,
+                           struct vlan_handle *handle);
+void release_vlan_found_handle(struct vlan_found_handle *found_handle);
+
+#endif /* __NIC_VLAN_H__ */
diff --git a/brcm_iscsi_uio/src/unix/options.h b/brcm_iscsi_uio/src/unix/options.h
new file mode 100644
index 0000000..876391c
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/options.h
@@ -0,0 +1,88 @@
+/* options.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+#ifndef __OPTIONS_H__
+#define __OPTIONS_H__
+
+#include <byteswap.h>
+#include <time.h>
+#include <sys/types.h>
+
+/******************************************************************************
+ * Constants which are tuned at compile time by the user
+ *****************************************************************************/
+
+/**
+ * MAX_COUNT_NIC_NL_RESP - This is the maximum number of polls uIP will
+ *                         try for a kernel response after a PATH_REQ
+ */
+#define MAX_COUNT_NIC_NL_RESP 5
+
+/**
+ * ENABLE_LOG_UEVENT - By defining ENABLE_LOG_UEVENT this will log all the
+ *                     uevents from the kernel that the uIP application 
+ *                     sees.  This is useful for debugging purposes
+ */
+#undef ENABLE_LOG_UEVENT
+
+/**
+ * NLM_BUF_DEFAULT_MAX - This is the buffer size allocated for the send/receive
+ *                       buffers used by the uIP Netlink subsystem.  This
+ *                       value is in bytes.
+ */
+#define NLM_BUF_DEFAULT_MAX	8192	/* bytes */
+
+/**
+ *  NL_POLL_RESOLUTION - This defines the number of milliseconds between
+ *                       each polling of the Netlink socket.
+ */
+#define NL_POLL_RESOLUTION	250	/* milliseconds */
+
+/******************************************************************************
+ * Non adjustable constants
+ *****************************************************************************/
+
+#define APP_NAME "uIP"
+/* BUILD_DATE is automatically generated from the Makefile */
+
+
+#define DEBUG_OFF	0x1
+#define DEBUG_ON	0x2
+
+#define INVALID_FD	-1
+#define INVALID_THREAD	-1
+
+struct options {
+	char debug;
+
+	/*  Time the userspace daemon was started */
+	time_t	start_time;
+};
+
+extern int event_loop_stop;
+extern struct options opt;
+
+#ifdef WORDS_BIGENDIAN
+#define ntohll(x)  (x)
+#define htonll(x)  (x)
+#else
+#define ntohll(x)  bswap_64(x)
+#define htonll(x)  bswap_64(x)
+#endif
+
+# define likely(x)      __builtin_expect(!!(x), 1)
+# define unlikely(x)    __builtin_expect(!!(x), 0)
+
+/*  taken from Linux kernel, include/linux/compiler-gcc.h */
+/* Optimization barrier */
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#endif
diff --git a/brcm_iscsi_uio/src/unix/packet.c b/brcm_iscsi_uio/src/unix/packet.c
new file mode 100644
index 0000000..53f3a6b
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/packet.c
@@ -0,0 +1,106 @@
+/* packet.c: packet management
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "logger.h"
+#include "packet.h"
+#include "nic.h"
+
+/**
+ * alloc_packet() - Function used to allocate memory for a packet
+ * @param max_buf_size - max packet size
+ * @param priv_size    - size of the assoicated private data
+ * @return NULL if failed, on success return a pointer to the packet
+ */
+struct packet * alloc_packet(size_t max_buf_size,
+			     size_t priv_size)
+{
+	struct packet *pkt;
+	void *priv;
+
+	pkt = malloc(max_buf_size + sizeof(struct packet));
+	if(pkt == NULL) {
+		LOG_ERR("Could not allocate any memory for packet");
+		return NULL;
+	}
+
+	priv = malloc(priv_size);
+	if(priv == NULL) {
+		LOG_ERR("Could not allocate any memory for private structure");
+		goto free_pkt;
+	}
+	
+	pkt->max_buf_size = max_buf_size;
+	pkt->priv = priv;
+
+	return pkt;
+
+free_pkt:
+	free(pkt);
+
+	return NULL;
+}
+
+void free_packet(struct packet *pkt)
+{
+	if(pkt->priv != NULL)
+		free(pkt->priv);
+
+	free(pkt);
+}
+
+/**
+ *  reset_packet() - This will reset the packet fields to default values
+ *  @param pkt - the packet to reset
+ */
+void reset_packet(packet_t *pkt)
+{
+	pkt->next = NULL;
+
+	pkt->flags = 0;
+	pkt->vlan_tag = 0;
+
+	pkt->buf_size = 0;
+
+	pkt->data_link_layer = NULL;
+	pkt->network_layer   = NULL;
+}
+
+int alloc_free_queue(nic_t *nic,
+		     size_t num_of_packets)
+{
+	int rc, i;
+
+	pthread_mutex_lock(&nic->free_packet_queue_mutex);
+	for(i=0; i<num_of_packets; i++) {
+		packet_t *pkt;
+
+		pkt = alloc_packet(1500, 1500);
+		if(pkt == NULL) {
+			rc = i;
+			goto done;
+		}
+
+		reset_packet(pkt);
+
+		pkt->next = nic->free_packet_queue;
+		nic->free_packet_queue = pkt;
+	}
+
+	rc = num_of_packets;
+
+done:	
+	pthread_mutex_unlock(&nic->free_packet_queue_mutex);
+
+	return i;
+}
diff --git a/brcm_iscsi_uio/src/unix/packet.h b/brcm_iscsi_uio/src/unix/packet.h
new file mode 100644
index 0000000..4c98b62
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/packet.h
@@ -0,0 +1,48 @@
+/* packet.h: packet definitions
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+
+#ifndef __PACKET_H__
+#define __PACKET_H__
+
+#include "nic.h"
+
+struct nic;
+struct nic_interface;
+
+typedef struct packet {
+	struct packet *next;
+
+	uint32_t flags;
+#define VLAN_TAGGED	0x0001
+	uint16_t vlan_tag;
+
+	size_t  max_buf_size;
+	size_t  buf_size;
+
+	uint8_t *data_link_layer;
+	uint8_t *network_layer;
+
+	struct nic *nic;
+	struct nic_interface *nic_iface;
+
+	void   *priv;
+	uint8_t	buf[];
+} packet_t;
+
+/******************************************************************************
+ *  Packet Function Declarations
+ *****************************************************************************/
+int alloc_free_queue(struct nic *, size_t num_of_packets);
+void reset_packet(packet_t *pkt);
+
+#endif /*  __PACKET_H__ */
diff --git a/brcm_iscsi_uio/src/unix/uevent.c b/brcm_iscsi_uio/src/unix/uevent.c
new file mode 100644
index 0000000..7d76f79
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/uevent.c
@@ -0,0 +1,579 @@
+/* uevent.c: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <linux/limits.h>
+#include <linux/netlink.h>
+
+#include "nic.h"
+#include "nic_vlan.h"
+#include "nic_utils.h"
+#include "logger.h"
+#include "options.h"
+#include "uevent.h"
+
+/******************************************************************************
+ *  Listening for uevents for cnic and bnx2i 
+ ******************************************************************************/
+static int uevent_netlink_sock = -1;
+static pthread_t uevent_watch_thread = INVALID_THREAD;
+
+/*  Used to notify when the cnic module is loaded */
+pthread_mutex_t cnic_module_loaded_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cnic_module_loaded_cond = PTHREAD_COND_INITIALIZER;
+int cnic_loaded = 0;
+
+/*  Used to notify when the bnx2i module is loaded */
+pthread_mutex_t bnx2i_module_loaded_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t bnx2i_module_loaded_cond = PTHREAD_COND_INITIALIZER;
+int bnx2i_loaded = 0;
+
+/******************************************************************************
+ *  uevent Contants
+ ******************************************************************************/
+#define PFX "uevent "
+
+static const char add_cnic_module_str[] = "add@/module/cnic";
+static const char remove_cnic_module_str[] = "remove@/module/cnic";
+static const char add_uio_module_str[] = "add@/class/uio/uio";
+static const char sscanf_uio_module_str[] = "add@/class/uio/uio%d";
+
+static const char uevent_action_key[] = "ACTION=";
+static const char uevent_devpath_key[] = "DEVPATH=";
+static const char uevent_subsystem_key[] = "SUBSYSTEM=";
+static const char uevent_driver_key[] = "DRIVER=";
+static const char uevent_seqnum_key[] = "SEQNUM=";
+static const char uevent_devpath_old_key[] = "DEVPATH_OLD=";
+static const char uevent_physdevpath_key[] = "PHYSDEVPATH=";
+static const char uevent_physdevbus_key[] = "PHYSDEVBUS=";
+static const char uevent_physdevdriver_key[] = "PHYSDEVDRIVER=";
+static const char uevent_major_key[] = "MAJOR=";
+static const char uevent_minor_key[] = "MINOR=";
+static const char uevent_timeout_key[] = "TIMEOUT=";
+static const char uevent_interface_key[] = "INTERFACE=";
+static const char uevent_ifindex_key[] = "IFINDEX=";
+
+static const char uevent_add[] = "add";
+static const char uevent_remove[] = "remove";
+static const char uevent_uio[] = "uio";
+static const char uevent_bnx2i[] = "bnx2i";
+
+static const char uevent_cnic_devpath[] = "/module/cnic";
+static const char uevent_cnic_subsystem[] = "module";
+
+static const char uevent_bnx2i_devpath[]   = "/module/bnx2i";
+static const char uevent_bnx2i_subsystem[] = "module";
+
+static const char uevent_net_devpath[]		= "/class/net";
+static const char uevent_net_subsystem[]	= "net";
+
+static const char uio_udev_path_template[] = "/dev/uio%d";
+
+/******************************************************************************
+ *  uevent Functions
+ ******************************************************************************/
+static void parse_uevent(char *buf, int buf_len, struct parsed_uevent *event)
+{
+	int i;
+	int bufpos;
+
+	bufpos = 0;
+
+	event->init = buf;
+
+	for (i = 0; (bufpos < buf_len); i++) {
+		char *key = &buf[bufpos];
+
+		if (memcmp(key,
+			   uevent_action_key,
+			   sizeof(uevent_action_key) - 1) == 0) {
+			event->action = &key[sizeof(uevent_action_key) - 1];
+			LOG_UEVENT("%s%s", uevent_action_key, event->action);
+		} else if (memcmp(key,
+				  uevent_devpath_key,
+				  sizeof(uevent_devpath_key) - 1) == 0) {
+			event->devpath = &key[sizeof(uevent_devpath_key) - 1];
+			LOG_UEVENT("%s%s", uevent_devpath_key, event->devpath);
+
+		} else if (memcmp(key,
+				  uevent_subsystem_key,
+				  sizeof(uevent_subsystem_key) - 1) == 0) {
+			event->subsystem =
+			    &key[sizeof(uevent_subsystem_key) - 1];
+			LOG_UEVENT("%s%s", uevent_subsystem_key,
+				   event->subsystem);
+		} else
+		    if (memcmp
+			(key, uevent_driver_key,
+			 sizeof(uevent_driver_key) - 1) == 0) {
+			event->driver = &key[sizeof(uevent_driver_key) - 1];
+			LOG_UEVENT("%s%s", uevent_driver_key, event->driver);
+		} else if (memcmp(key,
+				  uevent_seqnum_key,
+				  sizeof(uevent_seqnum_key) - 1) == 0) {
+			event->seqnum = &key[sizeof(uevent_seqnum_key) - 1];
+			LOG_UEVENT("%s%s", uevent_seqnum_key, event->seqnum);
+		} else if (memcmp(key,
+				  uevent_devpath_old_key,
+				  sizeof(uevent_devpath_old_key) - 1) == 0) {
+			event->devpath_old =
+			    &key[sizeof(uevent_devpath_old_key)] - 1;
+			LOG_UEVENT("%s%s", uevent_devpath_old_key,
+				  event->devpath_old);
+		} else
+		    if (memcmp
+			(key, uevent_physdevpath_key,
+			 sizeof(uevent_physdevpath_key) - 1) == 0) {
+			event->physdevpath =
+			    &key[sizeof(uevent_physdevpath_key) - 1];
+			LOG_UEVENT("%s%s", uevent_physdevpath_key,
+				  event->physdevpath);
+		} else
+		    if (memcmp
+			(key, uevent_physdevbus_key,
+			 sizeof(uevent_physdevbus_key) - 1) == 0) {
+			event->physdevbus =
+			    &key[sizeof(uevent_physdevbus_key) - 1];
+			LOG_UEVENT("%s%s", uevent_physdevbus_key,
+				  event->physdevbus);
+		} else
+		    if (memcmp
+			(key, uevent_physdevdriver_key,
+			 sizeof(uevent_physdevdriver_key) - 1) == 0) {
+			event->physdevdriver =
+			    &key[sizeof(uevent_physdevdriver_key) - 1];
+			LOG_UEVENT("%s%s", uevent_physdevdriver_key,
+				  event->physdevdriver);
+		} else
+		    if (memcmp
+			(key, uevent_major_key,
+			 sizeof(uevent_major_key) - 1) == 0) {
+			event->major = &key[sizeof(uevent_major_key) - 1];
+			LOG_UEVENT("%s%s", uevent_major_key, event->major);
+		} else if (memcmp(key,
+				  uevent_minor_key,
+				  sizeof(uevent_minor_key) - 1) == 0) {
+			event->minor = &key[sizeof(uevent_minor_key) - 1];
+			LOG_UEVENT("%s%s", uevent_minor_key, event->minor);
+		} else if (memcmp(key,
+				  uevent_timeout_key,
+				  sizeof(uevent_timeout_key) - 1) == 0) {
+			event->timeout = &key[sizeof(uevent_timeout_key) - 1];
+			LOG_UEVENT("%s%s", uevent_timeout_key, event->timeout);
+		} else if (memcmp(key,
+				  uevent_interface_key,
+				  sizeof(uevent_interface_key) - 1) == 0) {
+			event->interface = &key[sizeof(uevent_interface_key) - 1];
+			LOG_UEVENT("%s%s", uevent_interface_key,
+					  event->interface);
+		} else if (memcmp(key,
+				  uevent_ifindex_key,
+				  sizeof(uevent_ifindex_key) - 1) == 0) {
+			event->ifindex = &key[sizeof(uevent_ifindex_key) - 1];
+			LOG_UEVENT("%s%s", uevent_ifindex_key, event->ifindex);
+		} else {
+			LOG_INFO(PFX "Unknown: %s", key);
+		}
+
+		bufpos += strlen(key) + 1;
+	}
+}
+
+/******************************************************************************
+ *  wakeup_cnic_dev() - This function will notify all those waiting on the 
+ *                      uio_wait_event conditionial.  This should trigger
+ *                      all threads waiting on this event.
+ *  @param event  - The uevent which comes from the kernel
+ *  @param return - 0 on success, <0 on failure
+ *****************************************************************************/
+static int wakeup_cnic_dev(struct parsed_uevent *event)
+{
+	int minor;
+	nic_t *nic;
+	int rc;
+
+	rc = sscanf(event->minor, "%d", &minor);
+	if(rc == 1) {
+		LOG_INFO(PFX "New uio device registered: minor: %d", minor);
+	} else {
+		LOG_INFO(PFX "Couldn't parse minor number: %s", event->minor);
+		return -EIO;
+	}
+
+	pthread_mutex_lock(&nic_list_mutex);
+	nic = nic_list;
+	while (nic != NULL) {
+		if (nic->uio_minor == minor) {
+			/* TODO:  we need to wait for all the UIO entries to
+			 * appear in sysfs.  Need to determine a discrete way
+			 * to determine if this entry extsts */
+			struct timespec sleep_req, sleep_rem;
+
+			sleep_req.tv_sec  = 1;
+			sleep_req.tv_nsec = 5000000;
+
+			nanosleep(&sleep_req, &sleep_rem);
+
+			/*  Ensure that this is still a bnx2_cnic device */
+			rc = nic_verify_uio_sysfs_name(nic);
+			if (rc != 0) {
+				LOG_WARN(PFX "%s: Could not verify device",
+					 nic->log_name);
+			}
+
+			nic->log_name = nic->eth_device_name;
+
+			/*  Ensure all the NIC fields are initialized */
+			prepare_nic(nic);
+
+			if (nic->flags & NIC_UNITIALIZED) {
+				LOG_INFO(PFX "toggling cnic: %s to start",
+					 nic->log_name);
+				pthread_mutex_lock(&nic->uio_wait_mutex);
+				pthread_cond_broadcast(&nic->uio_wait_cond);
+				pthread_mutex_unlock(&nic->uio_wait_mutex);
+			}
+
+			break;
+		}
+
+		nic = nic->next;
+	}
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	if (nic == NULL) {
+                int uio_minor;
+                char eth_name[IFNAMSIZ];
+
+		/*  time to alloc a new cnic/uio device */
+		LOG_INFO(PFX "Couldn't find dev instance");
+
+		nic = nic_init();
+		if(nic == NULL)
+		{
+			LOG_ERR(PFX "Could not allocate memory for device");
+
+			rc =-ENOMEM;
+			goto error;
+		}
+
+		nic->uio_minor = minor;
+
+		/*  Malloc space for the uio name */
+		nic->uio_device_name = malloc(sizeof(uio_udev_path_template) + 8);
+		if(nic->uio_device_name == NULL)
+		{
+			LOG_ERR(PFX "Could not allocate space for device name");
+
+			rc = -ENOMEM;
+			goto error;
+		}
+
+		snprintf(nic->uio_device_name,
+			 sizeof(uio_udev_path_template) + 8,
+			 uio_udev_path_template, minor);
+
+		nic->flags |= NIC_UIO_NAME_MALLOC;
+
+                rc = from_uio_find_associated_eth_device(uio_minor,
+						nic->eth_device_name,
+						sizeof(nic->eth_device_name));
+
+		nic->config_device_name = nic->eth_device_name;
+		nic->log_name = nic->eth_device_name;
+
+		/*  Ensure all the NIC fields are initialized */
+		prepare_nic(nic);
+	}
+
+	rc = 0;
+
+error:
+	return rc;
+}
+
+/******************************************************************************
+ *  close_cnic_dev() - This function will notify all those waiting on the 
+ *                     uio_wait_event conditionial.  This should trigger
+ *                     all threads waiting on this event.
+ *  @param event  - The uevent which comes from the kernel
+ *  @param return - 0 on success, <0 on failure
+ *****************************************************************************/
+static int close_cnic_dev(struct parsed_uevent *event)
+{
+	int minor;
+	nic_t *nic;
+	int rc;
+
+	rc = sscanf(event->minor, "%d", &minor);
+	if(rc == 1) {
+		LOG_INFO(PFX "Removing uio device: minor: %d", minor);
+	} else {
+		LOG_INFO(PFX "Couldn't parse minor number: %s", event->minor);
+		return -EIO;
+	}
+
+	pthread_mutex_lock(&nic_list_mutex);
+	nic = nic_list;
+	while (nic != NULL) {
+		if (nic->uio_minor == minor) {
+			nic_remove(nic, 1);
+
+			rc = 0;
+			break;
+		}
+
+		nic = nic->next;
+	}
+	pthread_mutex_unlock(&nic_list_mutex);
+
+	if(nic == NULL)
+	{
+		LOG_INFO(PFX "Couldn't find nic to close");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+/**
+ *  uevent_close() -  This function is called when exiting the uevent watch
+ *  		      loop.   This function will clean up the Netlink socket
+ *  		      watching for uevents from the kernel.
+ */
+static void uevent_close(void *arg)
+{
+	if (uevent_netlink_sock != -1)
+		close(uevent_netlink_sock);
+}
+
+/**
+ *  uevent_watch_loop() - This function will use Netlink to watch for uevents
+ *                        coming from the kernel.  This operates much like
+ *                        udev.
+ */
+static void *uevent_watch_loop(void *arg)
+{
+	int rc;
+	sigset_t set;
+
+	pthread_cleanup_push(uevent_close, NULL);
+
+	sigfillset(&set);
+	rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
+	if (rc != 0) {
+		LOG_ERR(PFX "Couldn't set signal mask for the uevent thread");
+	}
+
+	while (1) {
+		ssize_t size;
+		char buffer[1024];
+		struct parsed_uevent event;
+
+		size = recv(uevent_netlink_sock, &buffer, sizeof(buffer), 0);
+
+		if ((size_t) size > sizeof(buffer) - 1)
+			size = sizeof(buffer) - 1;
+		buffer[size] = '\0';
+
+		memset(&event, 0, sizeof(event));
+		parse_uevent(buffer, size, &event);
+
+		/* check if a uio device has been added */
+		if ((memcmp(event.action,
+			    uevent_add, sizeof(uevent_add)) == 0) &&
+		    (memcmp(event.subsystem,
+			    uevent_uio, sizeof(uevent_uio)) == 0)) {
+			/*  Found a cnic device */
+			wakeup_cnic_dev(&event);
+
+		/* check if a uio device has been removed */
+		} else if ((memcmp(event.action,
+				   uevent_remove, sizeof(uevent_remove)) == 0)&&
+			   (memcmp(event.subsystem,
+			   	   uevent_uio, sizeof(uevent_uio)) == 0)) {
+			/*  Found a cnic device */
+			close_cnic_dev(&event);
+
+		/* check if a bnx2i device has been added */
+		} else if ((memcmp(event.action,
+			    uevent_add, sizeof(uevent_add)) == 0) &&
+		    (memcmp(event.subsystem,
+			    uevent_bnx2i, sizeof(uevent_bnx2i)) == 0)) {
+			/*  Found a bnx2i device */
+			pthread_mutex_lock(&bnx2i_module_loaded_mutex);
+			bnx2i_loaded = 1;
+
+			pthread_cond_broadcast(&bnx2i_module_loaded_cond);
+			pthread_mutex_unlock(&bnx2i_module_loaded_mutex);
+
+		/* check if a bnx2i device has been removed */
+		} else if ((memcmp(event.action,
+				   uevent_remove, sizeof(uevent_remove)) == 0)&&
+			   (memcmp(event.subsystem,
+			   	   uevent_uio, sizeof(uevent_bnx2i)) == 0)) {
+			/*  Found a cnic device */
+			pthread_mutex_lock(&bnx2i_module_loaded_mutex);
+			bnx2i_loaded = 0;
+
+			pthread_cond_broadcast(&bnx2i_module_loaded_cond);
+			pthread_mutex_unlock(&bnx2i_module_loaded_mutex);
+
+		} else if ((memcmp(event.action,
+				   uevent_add, sizeof(uevent_add)) == 0) &&
+			   (memcmp(event.devpath,
+				   uevent_cnic_devpath,
+				   sizeof(uevent_cnic_devpath)) == 0) &&
+			   (memcmp(event.subsystem,
+				   uevent_cnic_subsystem,
+				   sizeof(uevent_cnic_subsystem)) == 0)) {
+
+			LOG_INFO("CNIC module has been loaded");
+			pthread_mutex_lock(&cnic_module_loaded_mutex);
+			pthread_cond_broadcast(&cnic_module_loaded_cond);
+			cnic_loaded = 1;
+			pthread_mutex_unlock(&cnic_module_loaded_mutex);
+		} else if ((memcmp(event.action,
+				   uevent_add, sizeof(uevent_add)) == 0) &&
+			   (memcmp(event.devpath,
+				   uevent_net_devpath,
+				   sizeof(uevent_net_devpath) -1 ) == 0) &&
+			   (memcmp(event.subsystem,
+				   uevent_net_subsystem,
+				   sizeof(uevent_net_subsystem)) == 0)) {
+			uint16_t vlan_id;
+			int rc;
+			char *vlan_iface_name;
+			struct vlan_handle handle;
+
+			LOG_DEBUG("New NIC interface %s has been discovered",
+				  event.interface);
+
+			init_vlan_table(&handle);
+			rc = capture_vlan_table(&handle);
+			if(rc != 0) {
+				LOG_ERR(PFX "Failed to capture VLAN table");
+			}
+
+			rc = find_phy_using_vlan_interface(&handle,
+							   event.interface,
+							   &vlan_iface_name,
+							   &vlan_id);
+			if(rc == 1)
+			{
+				LOG_DEBUG("Interface %s is a vlan",
+					  event.interface);
+			}
+
+			release_vlan_table(&handle);
+		}
+	}
+
+	pthread_cleanup_pop(0);
+
+	pthread_exit(NULL);
+}
+
+/*******************************************************************************
+ *  Public Functions
+ ******************************************************************************/
+/**
+ *  init_uevent_netlink_sock() - This is used to initialize the NetLink
+ *  				 connection to the kernel to listen for uevents
+ *  @return 0 on success, <0 on failure
+ */
+int init_uevent_netlink_sock()
+{
+	struct sockaddr_nl snl;
+	const int buffersize = 16 * 1024 * 1024;
+	int rc;
+
+	memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+	snl.nl_family = AF_NETLINK;
+	snl.nl_pid = getpid();
+	snl.nl_groups = 1;
+
+	uevent_netlink_sock = socket(PF_NETLINK,
+				     SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+	if (uevent_netlink_sock == -1) {
+		LOG_ERR(PFX "error getting socket: %s", strerror(errno));
+		return -EIO;
+	}
+
+	/* set receive buffersize */
+	setsockopt(uevent_netlink_sock,
+		   SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
+
+	rc = bind(uevent_netlink_sock,
+		  (struct sockaddr *)&snl, sizeof(struct sockaddr_nl));
+	if (rc < 0) {
+		LOG_ERR(PFX "bind failed: %s", strerror(errno));
+		goto error;
+	}
+
+	/*  Spin up the thread used to watch */
+	rc = pthread_create(&uevent_watch_thread, NULL,
+			    uevent_watch_loop, NULL);
+	if (rc != 0) {
+		LOG_ERR(PFX "Could not create thread for watching uevents");
+		goto error;
+	}
+
+	LOG_INFO(PFX "Listening for uevents");
+
+	return 0;
+
+      error:
+	close(uevent_netlink_sock);
+	uevent_netlink_sock = -1;
+	return rc;
+}
+
+/**
+ *  cleanup_uevent_netlink_sock() - This is used to close the NetLink
+ *  				    connection to the kernel listening for 
+ *  				    uevents
+ *  @return 0 on success, <0 on failure
+ */
+int cleanup_uevent_netlink_sock()
+{
+	if (uevent_watch_thread != INVALID_THREAD) {
+		int rc;
+
+		/*  Notify that the uevent thread needs to stop */
+		rc = pthread_cancel(uevent_watch_thread);
+		if (rc != 0) {
+			LOG_ERR(PFX "Could not cancel uevent thread: %s",
+				strerror(rc));
+		}
+
+		/*  Wait for the uevent thread to stop */
+		rc = pthread_join(uevent_watch_thread, NULL);
+		if (rc != 0) {
+			LOG_ERR(PFX "Could not kill uevent thread");
+		}
+
+		uevent_watch_thread = INVALID_THREAD;
+	}
+
+	LOG_INFO(PFX "uevent thread closed");
+
+	return 0;
+}
diff --git a/brcm_iscsi_uio/src/unix/uevent.h b/brcm_iscsi_uio/src/unix/uevent.h
new file mode 100644
index 0000000..98484e4
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/uevent.h
@@ -0,0 +1,54 @@
+/* uevent.h: CNIC UIO uIP user space stack
+ *
+ * Copyright (c) 2004-2008 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Benjamin Li  (benli@broadcom.com)
+ */
+
+#ifndef __UEVENT_H__
+#define __UEVENT_H__
+
+#include <pthread.h>
+
+#ifdef ENABLE_LOG_UEVENT
+#define LOG_UEVENT	LOG_DEBUG
+#else
+#define LOG_UEVENT(fmt, args...)
+#endif
+
+extern pthread_mutex_t cnic_module_loaded_mutex;
+extern pthread_cond_t  cnic_module_loaded_cond;
+extern int cnic_loaded;
+
+extern pthread_mutex_t bnx2i_module_loaded_mutex;
+extern pthread_cond_t bnx2i_module_loaded_cond;
+extern int bnx2i_loaded;
+
+struct parsed_uevent {
+	char *init;
+	char *action;
+	char *devpath;
+	char *subsystem;
+	char *driver;
+	char *seqnum;
+	char *devpath_old;
+	char *physdevpath;
+	char *physdevbus;
+	char *physdevdriver;
+	char *major;
+	char *minor;
+	char *timeout;
+
+	/*  Seen when network interfaces appear */
+	char *interface;
+	char *ifindex;
+};
+
+int init_uevent_netlink_sock();
+int cleanup_uevent_netlink_sock();
+
+#endif /* __UEVENT_H__ */
diff --git a/brcm_iscsi_uio/src/unix/uip-conf.h b/brcm_iscsi_uio/src/unix/uip-conf.h
new file mode 100644
index 0000000..a277fe3
--- /dev/null
+++ b/brcm_iscsi_uio/src/unix/uip-conf.h
@@ -0,0 +1,159 @@
+/**
+ * \addtogroup uipopt
+ * @{
+ */
+
+/**
+ * \name Project-specific configuration options
+ * @{
+ *
+ * uIP has a number of configuration options that can be overridden
+ * for each project. These are kept in a project-specific uip-conf.h
+ * file and all configuration names have the prefix UIP_CONF.
+ */
+
+/*
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ * $Id: uip-conf.h,v 1.6 2006/06/12 08:00:31 adam Exp $
+ */
+
+/**
+ * \file
+ *         An example uIP configuration file
+ * \author
+ *         Adam Dunkels <adam@sics.se>
+ */
+
+#ifndef __UIP_CONF_H__
+#define __UIP_CONF_H__
+
+#include <inttypes.h>
+
+/**
+ * 8 bit datatype
+ *
+ * This typedef defines the 8-bit type used throughout uIP.
+ *
+ * \hideinitializer
+ */
+typedef uint8_t u8_t;
+
+/**
+ * 16 bit datatype
+ *
+ * This typedef defines the 16-bit type used throughout uIP.
+ *
+ * \hideinitializer
+ */
+typedef uint16_t u16_t;
+
+/**
+ * 32 bit datatype
+ *
+ * This typedef defines the 16-bit type used throughout uIP.
+ *
+ * \hideinitializer
+ */
+typedef uint32_t u32_t;
+
+/**
+ * Statistics datatype
+ *
+ * This typedef defines the dataype used for keeping statistics in
+ * uIP.
+ *
+ * \hideinitializer
+ */
+typedef uint64_t uip_stats_t;
+
+/**
+ * Maximum number of TCP connections.
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_MAX_CONNECTIONS 40
+
+/**
+ * Maximum number of listening TCP ports.
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_MAX_LISTENPORTS 40
+
+/**
+ * uIP buffer size.
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_BUFFER_SIZE     420
+
+/**
+ * CPU byte order.
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_BYTE_ORDER      LITTLE_ENDIAN
+
+/**
+ * Logging on or off
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_LOGGING         1
+
+/**
+ * UDP support on or off
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_UDP             1
+
+/**
+ * UDP checksums on or off
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_UDP_CHECKSUMS   1
+
+/**
+ * uIP statistics on or off
+ *
+ * \hideinitializer
+ */
+#define UIP_CONF_STATISTICS      1
+
+
+#define UIP_CONF_IPV6 0
+
+#endif /* __UIP_CONF_H__ */
+
+/** @} */
+/** @} */
diff --git a/usr/Makefile b/usr/Makefile
index 4d3c71f..3d1a1d6 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -41,7 +41,7 @@ ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iface.o idbm.o sy
 COMMON_SRCS =  $(ISCSI_LIB_SRCS)
 # core initiator files
 INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o isns.o \
-		cxgb3i.o be2iscsi.o transport.o
+		cxgb3i.o be2iscsi.o transport.o uip_mgmt_ipc.o
 # fw boot files
 FW_BOOT_SRCS = $(wildcard ../utils/fwparam_ibft/*.o)
 
diff --git a/usr/initiator.c b/usr/initiator.c
index 8735af9..52008ca 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -45,6 +45,7 @@
 #include "iscsi_sysfs.h"
 #include "iscsi_settings.h"
 #include "iface.h"
+#include "host.h"
 #include "sysdeps.h"
 
 #define ISCSI_CONN_ERR_REOPEN_DELAY	3
@@ -713,6 +714,37 @@ static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
 	return 0;
 }
 
+static int __set_net_config(struct iscsi_transport *t,
+			    iscsi_session_t *session,
+			    struct iface_rec *iface)
+{
+	if (t->template->set_net_config) {
+		/* uip needs the netdev name */
+		struct host_info hinfo;
+		int hostno, rc;
+
+		/* this assumes that the netdev or hw address is going to be
+		   set */
+		hostno = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
+		if (rc) {
+			log_debug(4, "Couldn't get host no.\n");
+			return rc;
+		}
+
+		/* uip needs the netdev name */
+		if (!strlen(iface->netdev)) {
+			memset(&hinfo, 0, sizeof(hinfo));
+			hinfo.host_no = hostno;
+			iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
+			strcpy(iface->netdev, hinfo.iface.netdev);
+		}
+
+		return t->template->set_net_config(t, iface, session);
+	}
+
+	return 0;
+}
+
 static void
 __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
 		      int redirected)
@@ -754,6 +786,11 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
 	if (!redirected)
 		session->reopen_cnt++;
 
+	/* uIP will needs to be re-triggered on the connection re-open */
+	if (__set_net_config(conn->session->t, conn->session,
+			      &conn->session->nrec.iface) != 0)
+		goto queue_reopen;
+
 	if (iscsi_conn_connect(conn, qtask)) {
 		delay = ISCSI_CONN_ERR_REOPEN_DELAY;
 		goto queue_reopen;
@@ -2103,6 +2140,10 @@ static int iface_set_param(struct iscsi_transport *t, struct iface_rec *iface,
 	session->conn[0].bind_ep = 1;
 	session->hostno = hostno;
 
+	rc = __set_net_config(t, session, iface);
+	if (rc != 0)
+		return rc;
+
 	rc = __iscsi_host_set_param(t, session->hostno,
 				    ISCSI_HOST_PARAM_IPADDRESS,
 				    iface->ipaddress, ISCSI_STRING);
diff --git a/usr/transport.c b/usr/transport.c
index ebdfb1b..ad4ac52 100644
--- a/usr/transport.c
+++ b/usr/transport.c
@@ -25,6 +25,7 @@
 #include "log.h"
 #include "util.h"
 #include "iscsi_sysfs.h"
+#include "uip_mgmt_ipc.h"
 #include "cxgb3i.h"
 #include "be2iscsi.h"
 
@@ -58,6 +59,7 @@ struct iscsi_transport_template bnx2i = {
 	.ep_connect	= ktransport_ep_connect,
 	.ep_poll	= ktransport_ep_poll,
 	.ep_disconnect	= ktransport_ep_disconnect,
+	.set_net_config = uip_broadcast_params,
 };
 
 struct iscsi_transport_template be2iscsi = {
diff --git a/usr/transport.h b/usr/transport.h
index 5ceedb3..2ec903c 100644
--- a/usr/transport.h
+++ b/usr/transport.h
@@ -35,6 +35,9 @@ struct iscsi_transport_template {
 	int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms);
 	void (*ep_disconnect) (struct iscsi_conn *conn);
 	void (*create_conn) (struct iscsi_conn *conn);
+	int (*set_net_config) (struct iscsi_transport *t,
+			       struct iface_rec *iface,
+			       struct iscsi_session *session);
 };
 
 /* represents data path provider */
diff --git a/usr/uip_mgmt_ipc.c b/usr/uip_mgmt_ipc.c
new file mode 100644
index 0000000..a34a943
--- /dev/null
+++ b/usr/uip_mgmt_ipc.c
@@ -0,0 +1,41 @@
+/*
+ * uIP iSCSI Daemon/Admin Management IPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <string.h>
+
+#include "log.h"
+#include "uip_mgmt_ipc.h"
+#include "util.h"
+
+int uip_broadcast_params(struct iscsi_transport *t,
+			 struct iface_rec *iface,
+			 struct iscsi_session *session)
+{
+	struct iscsid_uip_broadcast broadcast;
+
+        log_debug(3, "broadcasting to uip\n");
+
+	memset(&broadcast, 0, sizeof(broadcast));
+
+	broadcast.header.command = ISCSID_UIP_IPC_GET_IFACE;
+	broadcast.header.payload_len = sizeof(*iface);
+
+	memcpy(&broadcast.u.iface_rec, iface, sizeof(*iface));
+
+	return uip_broadcast(&broadcast,
+			     sizeof(iscsid_uip_broadcast_header_t) +
+			     sizeof(*iface));
+}
diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h
new file mode 100644
index 0000000..dd49c0b
--- /dev/null
+++ b/usr/uip_mgmt_ipc.h
@@ -0,0 +1,71 @@
+/*
+ * uIP iSCSI Daemon/Admin Management IPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#ifndef UIP_MGMT_IPC_H
+#define UIP_MGMT_IPC_H
+
+#include "types.h"
+#include "iscsi_if.h"
+#include "config.h"
+#include "mgmt_ipc.h"
+
+#include "initiator.h"
+#include "transport.h"
+
+#define ISCSID_UIP_NAMESPACE	"ISCSID_UIP_ABSTRACT_NAMESPACE"
+
+typedef enum iscsid_uip_cmd {
+	ISCSID_UIP_IPC_UNKNOWN			= 0,
+	ISCSID_UIP_IPC_GET_IFACE		= 1,
+
+        __ISCSID_UIP_IPC_MAX_COMMAND
+} iscsid_uip_cmd_e;
+
+typedef struct iscsid_uip_broadcast_header {
+	iscsid_uip_cmd_e command;
+	uint32_t payload_len;
+} iscsid_uip_broadcast_header_t;
+
+/* IPC Request */
+typedef struct iscsid_uip_broadcast {
+	struct iscsid_uip_broadcast_header header;
+
+	union {
+		/* messages */
+		struct ipc_broadcast_iface_rec {
+			struct iface_rec rec;
+		} iface_rec;
+	} u;
+} iscsid_uip_broadcast_t;
+
+typedef enum iscsid_uip_mgmt_ipc_err {
+	ISCSID_UIP_MGMT_IPC_OK                     = 0,
+        ISCISD_UIP_MGMT_IPC_ERR                    = 1,
+        ISCISD_UIP_MGMT_IPC_ERR_NOT_FOUND          = 2,
+        ISCISD_UIP_MGMT_IPC_ERR_NOMEM              = 3,
+} iscsid_uip_mgmt_ipc_err_e;
+
+/* IPC Response */
+typedef struct iscsid_uip_mgmt_rsp {
+	iscsid_uip_cmd_e command;
+	iscsid_uip_mgmt_ipc_err_e err;
+} iscsid_uip_rsp_t;
+
+extern int uip_broadcast_params(struct iscsi_transport *t,
+				struct iface_rec *iface,
+				struct iscsi_session *session);
+
+
+#endif /* UIP_MGMT_IPC_H */
diff --git a/usr/util.c b/usr/util.c
index e72ed15..390c895 100644
--- a/usr/util.c
+++ b/usr/util.c
@@ -23,6 +23,7 @@
 #include "idbm.h"
 #include "iface.h"
 #include "session_info.h"
+#include "uip_mgmt_ipc.h"
 
 void daemon_init(void)
 {
@@ -201,6 +202,44 @@ static void iscsid_startup(void)
 
 #define MAXSLEEP 128
 
+static mgmt_ipc_err_e ipc_connect(int *fd, char *unix_sock_name)
+{
+	int nsec;
+	struct sockaddr_un addr;
+
+	*fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (*fd < 0) {
+		log_error("can not create IPC socket (%d)!", errno);
+		return MGMT_IPC_ERR_ISCSID_NOTCONN;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_LOCAL;
+	memcpy((char *) &addr.sun_path + 1, unix_sock_name,
+		strlen(unix_sock_name));
+	/*
+	 * Trying to connect with exponential backoff
+	 */
+	for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
+		if (connect(*fd, (struct sockaddr *) &addr, sizeof(addr)) == 0)
+			/* Connection established */
+			return MGMT_IPC_OK;
+
+		/* If iscsid isn't there, there's no sense
+		 * in retrying. */
+		if (errno == ECONNREFUSED)
+			break;
+
+		/*
+		 * Delay before trying again
+		 */
+		if (nsec <= MAXSLEEP/2)
+			sleep(nsec);
+	}
+	log_error("can not connect to iSCSI daemon (%d)!", errno);
+	return MGMT_IPC_ERR_ISCSID_NOTCONN;
+}
+
 static mgmt_ipc_err_e iscsid_connect(int *fd, int start_iscsid)
 {
 	int nsec;
@@ -340,6 +379,72 @@ int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
 	return iscsid_req_wait(cmd, fd);
 }
 
+static mgmt_ipc_err_e uip_connect(int *fd)
+{
+	return ipc_connect(fd, ISCSID_UIP_NAMESPACE);
+}
+
+int uip_broadcast(void *buf, size_t buf_len)
+{
+	int err;
+	int fd;
+	iscsid_uip_rsp_t rsp;
+	int flags;
+	int count;
+
+	err = uip_connect(&fd);
+	if (err) {
+		log_warning("uIP daemon is not up");
+		return err;
+	}
+
+	/*  Send the data to uIP */
+	if ((err = write(fd, buf, buf_len)) != buf_len) {
+		log_error("got write error (%d/%d), daemon died?",
+			err, errno);
+		close(fd);
+		return -EIO;
+	}
+
+	/*  Set the socket to a non-blocking read, this way if there are
+	 *  problems waiting for uIP, iscsid can bailout early */
+	flags = fcntl(fd, F_GETFL, 0);
+	if (flags == -1)
+	        flags = 0;
+	err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+	if(err != 0) {
+		log_error("could not set uip broadcast to non-blocking: %d",
+			  errno);
+		close(fd);
+		return -EIO;
+	}
+
+#define MAX_UIP_BROADCAST_READ_TRIES 3
+	for(count = 0; count < MAX_UIP_BROADCAST_READ_TRIES; count++) {
+		/*  Wait for the response */
+		err = read(fd, &rsp, sizeof(rsp));
+		if (err == sizeof(rsp)) {
+			log_debug(3, "Broadcasted to uIP with length: %ld\n",
+				  buf_len);
+			break;
+		} else if((err == -1) && (errno == EAGAIN)) {
+			usleep(250000);
+			continue;
+		} else {
+			log_error("Could not read response (%d/%d), daemon died?",
+				  err, errno);
+			break;
+		}
+	}
+
+	if(count == MAX_UIP_BROADCAST_READ_TRIES)
+		log_error("Could not broadcast to uIP");
+
+	close(fd);
+
+	return 0;
+}
+
 void idbm_node_setup_defaults(node_rec_t *rec)
 {
 	int i;
diff --git a/usr/util.h b/usr/util.h
index 1d94496..d69d6c4 100644
--- a/usr/util.h
+++ b/usr/util.h
@@ -35,5 +35,6 @@ extern int __iscsi_match_session(struct node_rec *rec, char *targetname,
 
 extern char *strstrip(char *s);
 extern char *get_global_string_param(char *pathname, const char *key);
+extern int uip_broadcast(void *buf, size_t buf_len);
 
 #endif
