1*46e419f0Sho$OpenBSD: DESIGN-NOTES,v 1.20 2002/06/10 18:11:11 ho Exp $ 29d4c2f25Sniklas$EOM: DESIGN-NOTES,v 1.48 1999/08/12 22:34:25 niklas Exp $ 32040585eSniklas 42040585eSniklasGeneral coding conventions 52040585eSniklas-------------------------- 62040585eSniklasGNU indentation, Max 80 characters per line, KNF comments, mem* instead of b*, 7002a8f41SniklasBSD copyright, one header per module specifying the API. 82040585eSniklasMultiple inclusion protection like this: 92040585eSniklas 102040585eSniklas#ifndef _HEADERNAME_H_ 112040585eSniklas#define _HEADERNAME_H_ 122040585eSniklas 132040585eSniklas... Here comes the bulk of the header ... 142040585eSniklas 152040585eSniklas#endif /* _HEADERNAME_H_ */ 162040585eSniklas 172b81057dSniklasStart all files with RCS ID tags. 182040585eSniklas 192040585eSniklasGCC -Wall clean, ANSI prototypes. System dependent facilities should be 201bd1ea20Sniklasnamed sysdep_* and be placed in sysdep.c. Every C file should include 211bd1ea20Sniklassysdep.h as the first isakmpd include file. Primary target systems are OpenBSD 222040585eSniklasand Linux, but porting to Microsoft Windows variants should not be made 232040585eSniklasoverly difficult. 242040585eSniklas 25c6bfb327SniklasNote places which need reconsiderations with comments starting with the 262040585eSniklasstring "XXX", e.g. 272040585eSniklas 282040585eSniklas/* XXX Not implemented yet. */ 292040585eSniklas 302040585eSniklasTOC 312040585eSniklas--- 322040585eSniklasapp.c Application support. 334a3d04dbShoattribute.c Attribute handling. 342040585eSniklascert.c Dispatching certificate related functions to the according 352040585eSniklas module based on the encoding. 362040585eSniklasconf.c Interface to isakmpd configuration. 37b393bef8Sniklasconnection.c Handle the high-level connection concept. 381f98d23fSniklasconstants.c Value to name map of constants. 392040585eSniklascookie.c Cookie generation. 402040585eSniklascrypto.c Generic cryptography. 412040585eSniklasdh.c Diffie-Hellman exchange logic. 424a3d04dbShodnssec.c IKE authentication using signed DNS KEY RRs. 432040585eSniklasdoi.c Generic handling of different DOIs. 442040585eSniklasexchange.c Exchange state machinery. 452040585eSniklasexchange_num.cst 462040585eSniklas Some constants used for exhange scripts. 472040585eSniklasfield.c Generic handling of fields. 482040585eSniklasgenconstants.sh 492040585eSniklas Generate constant files from .cst source. 502040585eSniklasgenfields.sh Generate field description files from .fld source. 512040585eSniklasgmp_util.c Utilities to ease interfaceing to GMP. 522040585eSniklashash.c Generic hash handling. 532040585eSniklasif.c Network interface details. 54c8b8b55eSniklasike_aggressive.c 551f98d23fSniklas IKE's aggressive mode exchange logic. 564a3d04dbShoike_auth.c IKE authentication method abstraction. 572040585eSniklasike_main_mode.c IKE's main mode exchange logic. 58c8b8b55eSniklasike_phase_1.c Common parts IKE's main & aggressive modes' exchange logic. 592040585eSniklasike_quick_mode.c 602040585eSniklas IKE's quick mode logic. 612040585eSniklasinit.c Initialization of all modules (might be autogenned in the 622040585eSniklas future). 6361d575f0Sangelosipsec.c The IPsec DOI. 6461d575f0Sangelosipsec_fld.fld Description of IPsec DOI-specific packet layouts. 6561d575f0Sangelosipsec_num.cst Constants defined by the IPsec DOI. 662040585eSniklasisakmp_doi.c The ISAKMP pseudo-DOI. 672040585eSniklasisakmp_fld.fld Generic packet layout. 682040585eSniklasisakmp_num.cst ISAKMP constants. 692040585eSniklasisakmpd.c Main loop. 704a3d04dbShokey.c Generic key handling. 71*46e419f0Sholibcrypto.c Initialize crypto (OpenSSL). 722040585eSniklaslog.c Logging of exceptional or informational messages. 732040585eSniklasmath_2n.c Polynomial math. 742040585eSniklasmath_ec2n.c Elliptic curve math. 752040585eSniklasmath_group.c Group math. 762040585eSniklasmessage.c Generic message handling. 7761d575f0Sangelospf_key_v2.c Interface with PF_KEY sockets (for use with IPsec). 78556701c4Sniklaspolicy.c Keynote glue. 792040585eSniklasprf.c Pseudo random functions. 802040585eSniklassa.c Handling of Security Associations (SAs). 81c6bfb327Sniklassysdep/*/sysdep.c 82c6bfb327Sniklas System dependent stuff. 832040585eSniklastimer.c Timed events. 842040585eSniklastransport.c Generic transport handling. 852040585eSniklasudp.c The UDP transport. 862040585eSniklasui.c The "User Interface", i.e. the FIFO command handler. 872040585eSniklasutil.c Miscellaneous utility functions. 882040585eSniklasx509.c Encoding/Decoding X509 Certificates and related structures. 892040585eSniklas 902040585eSniklasCentral datatypes 912040585eSniklas----------------- 922040585eSniklas 93b393bef8Sniklasstruct connection Persistent connections. 942040585eSniklasstruct constant_map A map from constants to their ASCII names. 952040585eSniklasstruct crypto_xf A crypto class 962040585eSniklasstruct doi The DOI function switch 972040585eSniklasstruct event An event that is to happen at some point in time. 982040585eSniklasstruct exchange A description of an exchange while it is performed. 992040585eSniklasstruct field A description of an ISAKMP field. 1002040585eSniklasstruct group A class abstracting out Oakley group operations 1012040585eSniklasstruct hash A hashing class 10261d575f0Sangelosstruct ipsec_exch IPsec-specific exchange fields. 10361d575f0Sangelosstruct ipsec_proto IPsec-specific protocol attributes. 10461d575f0Sangelosstruct ipsec_sa IPsec-specific SA stuff. 1052040585eSniklasstruct message A generic ISAKMP message. 1062040585eSniklasstruct payload A "fat" payload reference pointing into message buffers 1072040585eSniklasstruct prf A pseudo random function class 1082040585eSniklasstruct proto Per-protocol attributes. 1092040585eSniklasstruct post_send Post-send function chain node. 1102040585eSniklasstruct sa A security association. 1112040585eSniklasstruct transport An ISAKMP transport, i.e. a channel where ISAKMP 1122040585eSniklas messages are passed (not necessarily connection- 1132040585eSniklas oriented). This is an abstract class, serving as 1142040585eSniklas a superclass to the different specific transports. 1152040585eSniklas 1162040585eSniklasSAs & exchanges 1172040585eSniklas--------------- 1182040585eSniklas 1192040585eSniklasstruct exchange Have all fields belonging to a simple exchange 1202040585eSniklas + a list of all the SAs being negotiated. 1212040585eSniklas Short-lived. 1222040585eSniklasstruct sa Only hold SA-specific stuff. Lives longer. 1232040585eSniklas 1242040585eSniklasIn order to recognize exchanges and SAs it is good to know what constitutes 1252040585eSniklastheir identities: 1262040585eSniklas 1272040585eSniklasPhase 1 exchange Cookie pair (apart from the first message of course, 1282040585eSniklas where the responder cookie is zero. 1292040585eSniklas 1302040585eSniklasISAKMP SA Cookie pair. I.e. there exists a one-to-one 1312040585eSniklas mapping to the negotiation in this case. 1322040585eSniklas 1332040585eSniklasPhase 2 exchange Cookie pair + message ID. 1342040585eSniklas 1352040585eSniklasGeneric SA Cookie pair + message ID + SPI. 1362040585eSniklas 1372040585eSniklasHowever it would be really nice to have a name of any SA that is natural 1381f98d23fSniklasto use for human beings, for things like deleting SAs manually. The simplest 1392040585eSniklasID would be the struct sa address. Another idea would be some kind of sequence 1402b81057dSniklasnumber, either global or per-destination. Right now I have introduced a name 1412b81057dSniklasfor SAs, non-unique, that binds together SAs and their configuration 1422b81057dSniklasparameters. This means both manual exchange runs and rekeying are simpler. 143c6bfb327SniklasBoth struct exchange and struct sa does hold a reference count, but this is 144c6bfb327Sniklasnot entirely like a reference count in the traditional meaning where 145c6bfb327Sniklasevery reference gets counted. Perhaps it will be in the future, but for now 146c6bfb327Sniklaswe increment the count at allocation time and at times we schedule events 147c6bfb327Sniklastha might happen sometime in the future where we will need the structure. 148c6bfb327SniklasThese events then realeases its reference when done. This way intermediate 149c6bfb327Sniklasdeallocation of these structures are OK. 1502040585eSniklas 1512040585eSniklasThe basic idea of control flow 1522040585eSniklas------------------------------ 1532040585eSniklas 1542040585eSniklasThe main loop just waits for events of any kind. Supposedly a message 1552040585eSniklascomes in, then the daemon looks to see if the cookies describes an 1562040585eSniklasexisting ISAKMP SA, if they don't and the rcookie is zero, it triggers a 1572040585eSniklassetup of a new ISAKMP SA. An exhaustive validation phase of the message 1582040585eSniklasis gone through at this stage. If anything goes wrong, we drop the packet 1592040585eSniklasand probably send some notification back. After the SA is found we try to 1602040585eSniklaslocate the exchange object and advance its state, else we try to create a 1612040585eSniklasnew exchange. 1622040585eSniklas 1632040585eSniklasNeed exchanges be an abstraction visible in the code? If so an exchange is 1642040585eSniklasroughly a very simple FSM (only timeouts and retransmissions are events that 1652040585eSniklasdoes not just advance the state through a sequential single path). The 1662040585eSniklasinformational exchange is such a special case, I am not sure it's interesting 1672040585eSniklasto treat as an exchange in the logic of the implementation. The only reason 1682040585eSniklasto do so would be to keep the implementation tightly coupled to the 169c6bfb327Sniklasspecification for ease of understanding. As the code looks now, exchanges 170c6bfb327Sniklas*are* an abstraction in the code, and it has proven to be a rather nice 171c6bfb327Sniklasway of having things. 1722040585eSniklas 1732040585eSniklasWhen the exchange has been found the exchange engine "runs" a script which 174c6bfb327Sniklassteps forward for each incoming message, and on each reply to them. 1752040585eSniklas 1762040585eSniklasPayload parsing details 1772040585eSniklas----------------------- 1782040585eSniklas 1792040585eSniklasAfter the generic header has been validated, we do a generic payload 1802040585eSniklasparsing pass over the message and sort out the payloads into buckets indexed 1812040585eSniklasby the payload type. Note that proposals and transforms are part of the SA 1822040585eSniklaspayloads. We then pass over them once more validating each payload 1832040585eSniklasin numeric payload type order. This makes SA payloads come naturally first. 1842040585eSniklas 1852040585eSniklasMessages 1862040585eSniklas-------- 1872040585eSniklas 1882040585eSniklasI am not sure there is any use in sharing the message structure for both 1892040585eSniklasincoming and outgoing messages but I do it anyhow. Specifically there are 1902040585eSniklascertain fields which only makes sense in one direction. Incoming messages 1912040585eSniklasonly use one segment in the iovec vector, while outgoing has one segment per 1922040585eSniklaspayload as well as one for the ISAKMP header. The iovec vector is 1932040585eSniklasreallocated for each payload added, maybe we should do it in chunks of a 1942040585eSniklasnumber of payloads instead, like 10 or so. 1952040585eSniklas 1962040585eSniklasDesign "errors" 1972040585eSniklas--------------- 1982040585eSniklas 1992040585eSniklasCurrently there are two "errors" in our design. The first one is that the 20061d575f0Sangeloscoupling between the IPsec DOI and IKE is tight. It should be separated by 2012040585eSniklasa clean interface letting other key exchange models fit in instead of IKE. 2022040585eSniklasThe second problem is that we need a protocol-specific opaque SA part 20361d575f0Sangelosin the DOI specific one. Now both IPsec ESP attributes takes place even 2042040585eSniklasin ISAKMP SA structures. 2052040585eSniklas 2062040585eSniklasUser control 2072040585eSniklas------------ 2082040585eSniklas 2092040585eSniklasIn order to control the daemon you send commands through a FIFO called 2102040585eSniklasisakmpd.fifo. The commands are one-letter codes followed by arguments. 2114a3d04dbShoFor now, eleven such commands are implemented: 2122040585eSniklas 213b393bef8Sniklasc connect Establish a connection with a peer 2144a3d04dbShoC configure Add or remove configuration entries 215b393bef8Sniklasd delete Delete an SA given cookies and message-IDs 2161f98d23fSniklasD debug Change logging level for a debug class 2174a3d04dbShop packet capture Enable/disable packet capture feature 2182040585eSniklasr report Report status information of the daemon 219b393bef8Sniklast teardown Teardown a connection 2200c6a08f2SangelosQ quit Quit the isakmpd process 2210c6a08f2SangelosR reinitialize Reinitialize isakmpd (re-read configuration file) 2220c6a08f2SangelosS report SA Report SA information to file /var/run/isakmp_sa 2230c6a08f2SangelosT teardown all Teardown all Phase 2 connections 2242040585eSniklas 2252040585eSniklasFor example you can do: 2262040585eSniklas 227fc127296Sniklasc ISAKMP-peer 2282040585eSniklas 2292040585eSniklasIn order to delete an SA you use the 'd' command. However this is not yet 2302040585eSniklassupported. 2312040585eSniklas 2322040585eSniklasTo alter the level of debugging in the "LOG_MISC" logging class to 99 you do: 2332040585eSniklas 2342040585eSniklasD 0 99 2352040585eSniklas 2362040585eSniklasThe report command is just an "r", and results in a list of active exchanges 2372040585eSniklasand security associations. 2382040585eSniklas 239f8f1e192SniklasThe "C" command takes 3 subcommands: set, rm and rms, for adding and removing 240f8f1e192Sniklasentries + remove complete sections respectively. Examples: 241f8f1e192Sniklas 242f8f1e192SniklasC set [Net-A]:Address=192.168.0.0 243f8f1e192SniklasC rm [Net-A]:Address 244f8f1e192SniklasC rms [Net-A] 245f8f1e192Sniklas 246f8f1e192SniklasAll these commands are atomic, i.e. they are not collected into larger 247f8f1e192Sniklastransactions, which there should be a way to do, but currently isn't. 248f8f1e192Sniklas 2494a3d04dbShoThe FIFO UI is also described in the isakmpd(8) man page. 2502b81057dSniklas 2511f98d23fSniklasIn addition to giving commands over the FIFO, you may send signals to the 2521f98d23fSniklasdaemon. Currently two such signals are implemented: 2531f98d23fSniklas 2541f98d23fSniklasSIGHUP Re-initialize isakmpd (not fully implemented yet) 2551f98d23fSniklasSIGUSR1 Generate a report, much as the "r" FIFO command. 2561f98d23fSniklas 2571f98d23fSniklasFor example, to generate a report, you do: 2581f98d23fSniklas 2591f98d23fSniklasunix# kill -USR1 <PID of isakmpd process> 2601f98d23fSniklas 2612040585eSniklasThe constant descriptions 2622040585eSniklas------------------------- 2632040585eSniklas 2642040585eSniklasWe have invented a simple constant description language, for the sake 2652040585eSniklasof easily getting textual representations of manifest constants. 2662040585eSniklasThe syntax is best described by an example: 2672040585eSniklas 2682040585eSniklasGROUP 2692040585eSniklas CONSTANT_A 1 2702040585eSniklas CONSTANT_B 2 2712040585eSniklas. 2722040585eSniklas 2732040585eSniklasThis defines a constant map "group" with the following two defines: 2742040585eSniklas 2752040585eSniklas#define GROUP_CONSTANT_A 1 2762040585eSniklas#define GROUP_CONSTANT_B 2 2772040585eSniklas 2782040585eSniklasWe can now get the textual representation by: 2792040585eSniklas 2802040585eSniklas cp = constant_name (group, foo); 2812040585eSniklas 2822040585eSniklasHere foo is an integer with either of the two constants as a value. 2832040585eSniklas 2842040585eSniklasThe field descriptions 2852040585eSniklas---------------------- 2862040585eSniklas 2872040585eSniklasThere is language for describing header and payload layouts too, 2882040585eSniklassimilar to the constant descriptions. Here too I just show an example: 2892040585eSniklas 2902040585eSniklasRECORD_A 2912040585eSniklas FIELD_A raw 4 2922040585eSniklas FIELD_B num 2 2932040585eSniklas FIELD_C mask 1 group_c_cst 2942040585eSniklas FIELD_D ign 1 2952040585eSniklas FIELD_E cst 2 group_e1_cst,group_e2_cst 2962040585eSniklas. 2972040585eSniklas 2982040585eSniklasRECORD_B : RECORD_A 2992040585eSniklas FIELD_F raw 3002040585eSniklas. 3012040585eSniklas 3022040585eSniklasThis creates some utility constants like RECORD_A_SZ, RECORD_A_FIELD_A_LEN, 3032040585eSniklasRECORD_A_FIELD_A_OFF, RECORD_A_FIELD_B_LEN etc. The *_OFF contains the 3042040585eSniklasoctet offset into the record and the *_LEN constants are the lenghts. 3052040585eSniklasThe type fields can be: raw, num, mask, ign & cst. Raw are used for 3062040585eSniklasoctet buffers, num for (unsigned) numbers of 1, 2 or 4 octet's length 3072040585eSniklasin network byteorder, mask is a bitmask where the bit values have symbols 3082040585eSniklascoupled to them via the constant maps given after the length in octets 3092040585eSniklas(also 1, 2 or 4). Ign is just a filler type, ot padding and lastly cst 3102040585eSniklasdenotes constants whose values can be found in the given constant map(s). 3112040585eSniklasThe last field in a record can be a raw, without a length, then just an 3122040585eSniklas_OFF symbol will be generated. You can offset the first symbol to the 3132040585eSniklassize of another record, like is done above for RECORD_B, i.e. in that 3142040585eSniklascase RECORD_A_SZ == RECORD_B_FIELD_F_OFF. All this data are collected 3152040585eSniklasin struct field arrays which makes it possible to symbolically print out 3162040585eSniklasentire payloads in readable form via field_dump_payload. 3172040585eSniklas 318f8f1e192SniklasConfiguration 319f8f1e192Sniklas------------- 320f8f1e192Sniklas 321f8f1e192SniklasInternally isakmpd uses a section-tag-value triplet database for 322f8f1e192Sniklasconfiguration. Currently this happen to map really well to the 323f8f1e192Sniklasconfiguration file format, which on the other hand does not map 324f8f1e192Sniklasequally well to humans. It is envisioned that the configuration 325f8f1e192Sniklasdatabase should be dynamically modifiable, and through a lot of 326f8f1e192Sniklasdiffernet mechanisms. Therefore we have designed an API for this 327f8f1e192Sniklaspurpose. 328f8f1e192Sniklas 329f8f1e192Sniklasint conf_begin (); 330f8f1e192Sniklasint conf_set (int transaction, char *section, char *tag, char *value, 331f8f1e192Sniklas int override); 332f8f1e192Sniklasint conf_remove (int transaction, char *section, char *tag); 333f8f1e192Sniklasint conf_remove_section (int transaction, char *section); 334f8f1e192Sniklasint conf_end (int transaction, int commit); 335f8f1e192Sniklas 336f8f1e192SniklasThe caller will always be responsible for the memory management of the 337f8f1e192Sniklaspassed strings, conf_set will copy the values, and not use the original 338f8f1e192Sniklasstrings after it has returned. Return value will be zero on success and 339f8f1e192Sniklasnon-zero otherwise. Note that the conf_remove* functions consider not 340f8f1e192Sniklasfinding anything to remove as failure. 341f8f1e192Sniklas 3422040585eSniklasIdentification 3432040585eSniklas-------------- 3442040585eSniklas 3452040585eSniklasISAKMP supports a lot of identity types, and we should too of course. 3462040585eSniklas 3471f98d23fSniklas* Phase 1, Main mode or Aggressive mode 3482040585eSniklas 3492040585eSniklasToday when we connect we do it based on the peer's IP address. That does not 3502040585eSniklasautomatically mean we should do policy decision based on IPs, rather we should 3512040585eSniklaslook at the ID the peer provide and get policy info keyed on that. 3522040585eSniklas 3532040585eSniklasPerhaps we get an ID saying the peer is FQDN niklas.hallqvist.se, then our 3542040585eSniklaspolicy rules might look like: 3552040585eSniklas 3562040585eSniklas[IQ_FQDN] 3572040585eSniklas# If commented, internal verification is used 3582040585eSniklas#Verificator= verify_fqdn 3592040585eSniklasAccept= no 3602040585eSniklas 3612040585eSniklas[ID_FQDN niklas.hallqvist.se] 3622040585eSniklasPolicy= MY_POLICY_001 3632040585eSniklas 3642040585eSniklas[MY_POLICY_001] 3652040585eSniklas# Whatever policy rules we might have. 3662040585eSniklasAccept= yes 3672040585eSniklas 3682040585eSniklasWhich means niklas.hallqvist.se is allowed to negotiate SAs with us, but 3692040585eSniklasnoone else. 3702040585eSniklas 3711f98d23fSniklas* Phase 2, Quick mode 3722040585eSniklas 3732040585eSniklasIn quick mode the identities are implicitly the IP addresses of the peers, 3742040585eSniklaswhich must mean the IP addresses actually used for the ISAKMP tunnel. 3752b81057dSniklasOtherwise we today support IPV4_ADDR & IPV4_ADDR_SUBNET as ID types. 3762040585eSniklas 377fb1921ccSniklasX509-Certificates 378fb1921ccSniklas----------------- 379fb1921ccSniklasTo use RSA Signature mode you are required to generate certificates. 380fb1921ccSniklasThis can be done with ssleay, see man ssl. But the X509 certificates 381fb1921ccSniklasrequire a subjectAltname extension that can either be an IPV4 address, 382fb1921ccSniklasa User-FQDN or just FQDN. ssleay can not create those extension, 383fb1921ccSniklasinsead use the x509test program in regress/x509 to modify an existing 384fb1921ccSniklascertificate. It will insert the subjectAltname extension and sign it 385fb1921ccSniklaswith the provided private Key. The resulting certificate then needs 386fb1921ccSniklasto be stored in the directory pointed to by "Certs-directory" in 387fb1921ccSniklassection "X509-certificates". 388fb1921ccSniklas 3892040585eSniklasLicense to use 3902040585eSniklas-------------- 3912040585eSniklas/* 392c6bfb327Sniklas * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. 3932040585eSniklas * 3942040585eSniklas * Redistribution and use in source and binary forms, with or without 3952040585eSniklas * modification, are permitted provided that the following conditions 3962040585eSniklas * are met: 3972040585eSniklas * 1. Redistributions of source code must retain the above copyright 3982040585eSniklas * notice, this list of conditions and the following disclaimer. 3992040585eSniklas * 2. Redistributions in binary form must reproduce the above copyright 4002040585eSniklas * notice, this list of conditions and the following disclaimer in the 4012040585eSniklas * documentation and/or other materials provided with the distribution. 4022040585eSniklas * 3. All advertising materials mentioning features or use of this software 4032040585eSniklas * must display the following acknowledgement: 4042040585eSniklas * This product includes software developed by Ericsson Radio Systems. 4052040585eSniklas * 4. The name of the author may not be used to endorse or promote products 4062040585eSniklas * derived from this software without specific prior written permission. 4072040585eSniklas * 4082040585eSniklas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4092040585eSniklas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4102040585eSniklas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4112040585eSniklas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4122040585eSniklas * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4132040585eSniklas * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4142040585eSniklas * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 4152040585eSniklas * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 4162040585eSniklas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 4172040585eSniklas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4182040585eSniklas */ 4192040585eSniklas 4202040585eSniklas/* 4212040585eSniklas * This code was written under funding by Ericsson Radio Systems. 4222040585eSniklas */ 4232040585eSniklas 4242040585eSniklasMaybe we should skip clause 3? Or redo it to mention the development was not 4252040585eSniklas"by" but rather "funded by"? I think the comment about funding after the 426002a8f41Sniklaslicense might also mention the actual author(s). 427