diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 1998-08-19 21:32:28 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 1998-08-19 21:32:28 +0000 |
commit | 39e6e65a2c5a3312f365d59f23c469641e049c82 (patch) | |
tree | c0d6000a18918db140589a84596a8dfc215a4ced /cpukit/libnetworking | |
parent | First version produced. (diff) | |
download | rtems-39e6e65a2c5a3312f365d59f23c469641e049c82.tar.bz2 |
Base files
Diffstat (limited to 'cpukit/libnetworking')
209 files changed, 59313 insertions, 0 deletions
diff --git a/cpukit/libnetworking/README b/cpukit/libnetworking/README new file mode 100644 index 0000000000..0a5c7ad49d --- /dev/null +++ b/cpukit/libnetworking/README @@ -0,0 +1,14 @@ +This is a snapshot of my attempt to fit the FreeBSD networking code into +RTEMS. Things seem to be working! + +Things that need to be done: + 1) More documentation! + 2) Figure out what's still not working :-) + 3) Rationalize the include files. Right now I have a special + hack in the Makefile to ensure that I pick up the FreeBSD versions + of the include files that are duplicated between RTEMS + and FreeBSD. + The network device driver source should move to the BSP source tree. + 4) Have a look at all the FIXME comments. + 5) Go through and make sure that all the source files are + free of undesired copyright restrictions. diff --git a/cpukit/libnetworking/arpa/ftp.h b/cpukit/libnetworking/arpa/ftp.h new file mode 100644 index 0000000000..9a36488540 --- /dev/null +++ b/cpukit/libnetworking/arpa/ftp.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ftp.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _ARPA_FTP_H_ +#define _ARPA_FTP_H_ + +/* Definitions for FTP; see RFC-765. */ + +/* + * Reply codes. + */ +#define PRELIM 1 /* positive preliminary */ +#define COMPLETE 2 /* positive completion */ +#define CONTINUE 3 /* positive intermediate */ +#define TRANSIENT 4 /* transient negative completion */ +#define ERROR 5 /* permanent negative completion */ + +/* + * Type codes + */ +#define TYPE_A 1 /* ASCII */ +#define TYPE_E 2 /* EBCDIC */ +#define TYPE_I 3 /* image */ +#define TYPE_L 4 /* local byte size */ + +#ifdef FTP_NAMES +char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" }; +#endif + +/* + * Form codes + */ +#define FORM_N 1 /* non-print */ +#define FORM_T 2 /* telnet format effectors */ +#define FORM_C 3 /* carriage control (ASA) */ +#ifdef FTP_NAMES +char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" }; +#endif + +/* + * Structure codes + */ +#define STRU_F 1 /* file (no record structure) */ +#define STRU_R 2 /* record structure */ +#define STRU_P 3 /* page structure */ +#ifdef FTP_NAMES +char *strunames[] = {"0", "File", "Record", "Page" }; +#endif + +/* + * Mode types + */ +#define MODE_S 1 /* stream */ +#define MODE_B 2 /* block */ +#define MODE_C 3 /* compressed */ +#ifdef FTP_NAMES +char *modenames[] = {"0", "Stream", "Block", "Compressed" }; +#endif + +/* + * Record Tokens + */ +#define REC_ESC '\377' /* Record-mode Escape */ +#define REC_EOR '\001' /* Record-mode End-of-Record */ +#define REC_EOF '\002' /* Record-mode End-of-File */ + +/* + * Block Header + */ +#define BLK_EOR 0x80 /* Block is End-of-Record */ +#define BLK_EOF 0x40 /* Block is End-of-File */ +#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */ +#define BLK_RESTART 0x10 /* Block is Restart Marker */ + +#define BLK_BYTECOUNT 2 /* Bytes in this block */ + +#endif /* !_FTP_H_ */ diff --git a/cpukit/libnetworking/arpa/inet.h b/cpukit/libnetworking/arpa/inet.h new file mode 100644 index 0000000000..fb95ee288a --- /dev/null +++ b/cpukit/libnetworking/arpa/inet.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * @(#)inet.h 8.1 (Berkeley) 6/2/93 + * From: Id: inet.h,v 8.5 1997/01/29 08:48:09 vixie Exp $ + * $Id$ + */ + +#ifndef _ARPA_INET_H_ +#define _ARPA_INET_H_ + +/* External definitions for functions in inet(3), addr2ascii(3) */ + +#include <sys/types.h> +#include <sys/cdefs.h> + +struct in_addr; + +/* XXX all new diversions!! argh!! */ +#define inet_addr __inet_addr +#define inet_aton __inet_aton +#define inet_lnaof __inet_lnaof +#define inet_makeaddr __inet_makeaddr +#define inet_neta __inet_neta +#define inet_netof __inet_netof +#define inet_network __inet_network +#define inet_net_ntop __inet_net_ntop +#define inet_net_pton __inet_net_pton +#define inet_ntoa __inet_ntoa +#define inet_pton __inet_pton +#define inet_ntop __inet_ntop +#define inet_nsap_addr __inet_nsap_addr +#define inet_nsap_ntoa __inet_nsap_ntoa + +__BEGIN_DECLS +int ascii2addr __P((int, const char *, void *)); +char *addr2ascii __P((int, const void *, int, char *)); +unsigned long inet_addr __P((const char *)); +int inet_aton __P((const char *, struct in_addr *)); +unsigned long inet_lnaof __P((struct in_addr)); +struct in_addr inet_makeaddr __P((u_long , u_long)); +char * inet_neta __P((u_long, char *, size_t)); +unsigned long inet_netof __P((struct in_addr)); +unsigned long inet_network __P((const char *)); +char *inet_net_ntop __P((int, const void *, int, char *, size_t)); +int inet_net_pton __P((int, const char *, void *, size_t)); +char *inet_ntoa __P((struct in_addr)); +int inet_pton __P((int, const char *, void *)); +const char *inet_ntop __P((int, const void *, char *, size_t)); +u_int inet_nsap_addr __P((const char *, u_char *, int)); +char *inet_nsap_ntoa __P((int, const u_char *, char *)); +__END_DECLS + +#endif /* !_INET_H_ */ diff --git a/cpukit/libnetworking/arpa/nameser.h b/cpukit/libnetworking/arpa/nameser.h new file mode 100644 index 0000000000..634dece37b --- /dev/null +++ b/cpukit/libnetworking/arpa/nameser.h @@ -0,0 +1,448 @@ +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * From: Id: nameser.h,v 8.16 1998/02/06 00:35:58 halley Exp + * $Id$ + */ + +#ifndef _ARPA_NAMESER_H_ +#define _ARPA_NAMESER_H_ + +#define BIND_4_COMPAT + +#include <sys/types.h> +#include <sys/cdefs.h> + +/* + * revision information. this is the release date in YYYYMMDD format. + * it can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__NAMESER > 19931104)". do not + * compare for equality; rather, use it to determine whether your libnameser.a + * is new enough to contain a certain feature. + */ + +/* XXXRTH I made this bigger than __BIND in 4.9.5 T6B */ +#define __NAMESER 19961001 /* New interface version stamp. */ + +/* + * Define constants based on RFC 883, RFC 1034, RFC 1035 + */ +#define NS_PACKETSZ 512 /* maximum packet size */ +#define NS_MAXDNAME 1025 /* maximum domain name */ +#define NS_MAXCDNAME 255 /* maximum compressed domain name */ +#define NS_MAXLABEL 63 /* maximum length of domain label */ +#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ +#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ +#define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ +#define NS_INADDRSZ 4 /* IPv4 T_A */ +#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ +#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ + +/* + * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() + * in synch with it. + */ +typedef enum __ns_sect { + ns_s_qd = 0, /* Query: Question. */ + ns_s_zn = 0, /* Update: Zone. */ + ns_s_an = 1, /* Query: Answer. */ + ns_s_pr = 1, /* Update: Prerequisites. */ + ns_s_ns = 2, /* Query: Name servers. */ + ns_s_ud = 2, /* Update: Update. */ + ns_s_ar = 3, /* Query|Update: Additional records. */ + ns_s_max = 4 +} ns_sect; + +/* + * This is a message handle. It is caller allocated and has no dynamic data. + * This structure is intended to be opaque to all but ns_parse.c, thus the + * leading _'s on the member names. Use the accessor functions, not the _'s. + */ +typedef struct __ns_msg { + const u_char *_msg, *_eom; + u_int16_t _id, _flags, _counts[ns_s_max]; + const u_char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const u_char *_ptr; +} ns_msg; + +/* Private data structure - do not use from outside library. */ +struct _ns_flagdata { int mask, shift; }; +extern struct _ns_flagdata _ns_flagdata[]; + +/* Accessor macros - this is part of the public interface. */ +#define ns_msg_getflag(handle, flag) ( \ + ((handle)._flags & _ns_flagdata[flag].mask) \ + >> _ns_flagdata[flag].shift \ + ) +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +/* + * This is a parsed record. It is caller allocated and has no dynamic data. + */ +typedef struct __ns_rr { + char name[NS_MAXDNAME]; /* XXX need to malloc */ + u_int16_t type; + u_int16_t class; + u_int32_t ttl; + u_int16_t rdlength; + const u_char *rdata; +} ns_rr; + +/* Accessor macros - this is part of the public interface. */ +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((rr).type + 0) +#define ns_rr_class(rr) ((rr).class + 0) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +/* + * These don't have to be in the same order as in the packet flags word, + * and they can even overlap in some cases, but they will need to be kept + * in synch with ns_parse.c:ns_flagdata[]. + */ +typedef enum __ns_flag { + ns_f_qr, /* Question/Response. */ + ns_f_opcode, /* Operation code. */ + ns_f_aa, /* Authoritative Answer. */ + ns_f_tc, /* Truncation occurred. */ + ns_f_rd, /* Recursion Desired. */ + ns_f_ra, /* Recursion Available. */ + ns_f_z, /* MBZ. */ + ns_f_ad, /* Authentic Data (DNSSEC). */ + ns_f_cd, /* Checking Disabled (DNSSEC). */ + ns_f_rcode, /* Response code. */ + ns_f_max +} ns_flag; + +/* + * Currently defined opcodes. + */ +typedef enum __ns_opcode { + ns_o_query = 0, /* Standard query. */ + ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ + ns_o_status = 2, /* Name server status query (unsupported). */ + /* Opcode 3 is undefined/reserved. */ + ns_o_notify = 4, /* Zone change notification. */ + ns_o_update = 5, /* Zone update message. */ + ns_o_max = 6 +} ns_opcode; + +/* + * Currently defined response codes. + */ +typedef enum __ns_rcode { + ns_r_noerror = 0, /* No error occurred. */ + ns_r_formerr = 1, /* Format error. */ + ns_r_servfail = 2, /* Server failure. */ + ns_r_nxdomain = 3, /* Name error. */ + ns_r_notimpl = 4, /* Unimplemented. */ + ns_r_refused = 5, /* Operation refused. */ + /* these are for BIND_UPDATE */ + ns_r_yxdomain = 6, /* Name exists */ + ns_r_yxrrset = 7, /* RRset exists */ + ns_r_nxrrset = 8, /* RRset does not exist */ + ns_r_notauth = 9, /* Not authoritative for zone */ + ns_r_notzone = 10, /* Zone of record different from zone section */ + ns_r_max = 11 +} ns_rcode; + +/* BIND_UPDATE */ +typedef enum __ns_update_operation { + ns_uop_delete = 0, + ns_uop_add = 1, + ns_uop_max = 2 +} ns_update_operation; + +/* + * This RR-like structure is particular to UPDATE. + */ +struct ns_updrec { + struct ns_updrec *r_prev; /* prev record */ + struct ns_updrec *r_next; /* next record */ + u_int8_t r_section; /* ZONE/PREREQUISITE/UPDATE */ + char * r_dname; /* owner of the RR */ + u_int16_t r_class; /* class number */ + u_int16_t r_type; /* type number */ + u_int32_t r_ttl; /* time to live */ + u_char * r_data; /* rdata fields as text string */ + u_int16_t r_size; /* size of r_data field */ + int r_opcode; /* type of operation */ + /* following fields for private use by the resolver/server routines */ + struct ns_updrec *r_grpnext; /* next record when grouped */ + struct databuf *r_dp; /* databuf to process */ + struct databuf *r_deldp; /* databuf's deleted/overwritten */ + u_int16_t r_zone; /* zone number on server */ +}; +typedef struct ns_updrec ns_updrec; + +/* + * Currently defined type values for resources and queries. + */ +typedef enum __ns_type { + ns_t_a = 1, /* Host address. */ + ns_t_ns = 2, /* Authoritative server. */ + ns_t_md = 3, /* Mail destination. */ + ns_t_mf = 4, /* Mail forwarder. */ + ns_t_cname = 5, /* Canonical name. */ + ns_t_soa = 6, /* Start of authority zone. */ + ns_t_mb = 7, /* Mailbox domain name. */ + ns_t_mg = 8, /* Mail group member. */ + ns_t_mr = 9, /* Mail rename name. */ + ns_t_null = 10, /* Null resource record. */ + ns_t_wks = 11, /* Well known service. */ + ns_t_ptr = 12, /* Domain name pointer. */ + ns_t_hinfo = 13, /* Host information. */ + ns_t_minfo = 14, /* Mailbox information. */ + ns_t_mx = 15, /* Mail routing information. */ + ns_t_txt = 16, /* Text strings. */ + ns_t_rp = 17, /* Responsible person. */ + ns_t_afsdb = 18, /* AFS cell database. */ + ns_t_x25 = 19, /* X_25 calling address. */ + ns_t_isdn = 20, /* ISDN calling address. */ + ns_t_rt = 21, /* Router. */ + ns_t_nsap = 22, /* NSAP address. */ + ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /* Security signature. */ + ns_t_key = 25, /* Security key. */ + ns_t_px = 26, /* X.400 mail mapping. */ + ns_t_gpos = 27, /* Geographical position (withdrawn). */ + ns_t_aaaa = 28, /* Ip6 Address. */ + ns_t_loc = 29, /* Location Information. */ + ns_t_nxt = 30, /* Next domain (security). */ + ns_t_eid = 31, /* Endpoint identifier. */ + ns_t_nimloc = 32, /* Nimrod Locator. */ + ns_t_srv = 33, /* Server Selection. */ + ns_t_atma = 34, /* ATM Address */ + ns_t_naptr = 35, /* Naming Authority PoinTeR */ + /* Query type values which do not appear in resource records. */ + ns_t_ixfr = 251, /* Incremental zone transfer. */ + ns_t_axfr = 252, /* Transfer zone of authority. */ + ns_t_mailb = 253, /* Transfer mailbox records. */ + ns_t_maila = 254, /* Transfer mail agent records. */ + ns_t_any = 255, /* Wildcard match. */ + ns_t_max = 65536 +} ns_type; + +/* + * Values for class field + */ +typedef enum __ns_class { + ns_c_in = 1, /* Internet. */ + /* Class 2 unallocated/unsupported. */ + ns_c_chaos = 3, /* MIT Chaos-net. */ + ns_c_hs = 4, /* MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /* for prereq. sections in update requests */ + ns_c_any = 255, /* Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +/* + * Flags field of the KEY RR rdata + */ +#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */ +#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ +#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ +#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ +#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ +/* The type bits can also be interpreted independently, as single bits: */ +#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */ +#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */ +#define NS_KEY_EXPERIMENTAL 0x2000 /* Security is *mandatory* if bit=0 */ +#define NS_KEY_RESERVED3 0x1000 /* reserved - must be zero */ +#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */ +#define NS_KEY_USERACCOUNT 0x0400 /* key is assoc. with a user acct */ +#define NS_KEY_ENTITY 0x0200 /* key is assoc. with entity eg host */ +#define NS_KEY_ZONEKEY 0x0100 /* key is zone key */ +#define NS_KEY_IPSEC 0x0080 /* key is for IPSEC (host or user)*/ +#define NS_KEY_EMAIL 0x0040 /* key is for email (MIME security) */ +#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */ +#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */ +#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */ + +#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED3 | \ + NS_KEY_RESERVED4 | \ + NS_KEY_RESERVED10 | \ + NS_KEY_RESERVED11 ) + +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define NS_ALG_MD5RSA 1 /* MD5 with RSA */ +#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */ +#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */ + +/* Signatures */ +#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */ +#define NS_MD5RSA_MAX_BITS 2552 + /* Total of binary mod and exp */ +#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) + /* Max length of text sig block */ +#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) + +/* Offsets into SIG record rdata to find various values */ +#define NS_SIG_TYPE 0 /* Type flags */ +#define NS_SIG_ALG 2 /* Algorithm */ +#define NS_SIG_LABELS 3 /* How many labels in name */ +#define NS_SIG_OTTL 4 /* Original TTL */ +#define NS_SIG_EXPIR 8 /* Expiration time */ +#define NS_SIG_SIGNED 12 /* Signature time */ +#define NS_SIG_FOOT 16 /* Key footprint */ +#define NS_SIG_SIGNER 18 /* Domain name of who signed it */ + +/* How RR types are represented as bit-flags in NXT records */ +#define NS_NXT_BITS 8 +#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) + + +/* + * Inline versions of get/put short/long. Pointer is advanced. + */ +#define NS_GET16(s, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += NS_INT16SZ; \ +} + +#define NS_GET32(l, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += NS_INT32SZ; \ +} + +#define NS_PUT16(s, cp) { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += NS_INT16SZ; \ +} + +#define NS_PUT32(l, cp) { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += NS_INT32SZ; \ +} + +/* + * ANSI C identifier hiding. + */ +#define ns_get16 __ns_get16 +#define ns_get32 __ns_get32 +#define ns_put16 __ns_put16 +#define ns_put32 __ns_put32 +#define ns_initparse __ns_initparse +#define ns_parserr __ns_parserr +#define ns_sprintrr __ns_sprintrr +#define ns_sprintrrf __ns_sprintrrf +#define ns_format_ttl __ns_format_ttl +#define ns_parse_ttl __ns_parse_ttl +#define ns_name_ntop __ns_name_ntop +#define ns_name_pton __ns_name_pton +#define ns_name_unpack __ns_name_unpack +#define ns_name_pack __ns_name_pack +#define ns_name_compress __ns_name_compress +#define ns_name_uncompress __ns_name_uncompress + +__BEGIN_DECLS +u_int ns_get16 __P((const u_char *)); +u_long ns_get32 __P((const u_char *)); +void ns_put16 __P((u_int, u_char *)); +void ns_put32 __P((u_long, u_char *)); +int ns_initparse __P((const u_char *, int, ns_msg *)); +int ns_parserr __P((ns_msg *, ns_sect, int, ns_rr *)); +int ns_sprintrr __P((const ns_msg *, const ns_rr *, + const char *, const char *, char *, size_t)); +int ns_sprintrrf __P((const u_char *, size_t, const char *, + ns_class, ns_type, u_long, const u_char *, + size_t, const char *, const char *, + char *, size_t)); +int ns_format_ttl __P((u_long, char *, size_t)); +int ns_parse_ttl __P((const char *, u_long *)); +int ns_name_ntop __P((const u_char *, char *, size_t)); +int ns_name_pton __P((const char *, u_char *, size_t)); +int ns_name_unpack __P((const u_char *, const u_char *, + const u_char *, u_char *, size_t)); +int ns_name_pack __P((const u_char *, u_char *, int, + const u_char **, const u_char **)); +int ns_name_uncompress __P((const u_char *, const u_char *, + const u_char *, char *, size_t)); +int ns_name_compress __P((const char *, u_char *, size_t, + const u_char **, const u_char **)); +int ns_name_skip __P((const u_char **, const u_char *)); +__END_DECLS + +#ifdef BIND_4_COMPAT +#include <arpa/nameser_compat.h> +#endif + +#endif /* !_ARPA_NAMESER_H_ */ diff --git a/cpukit/libnetworking/arpa/nameser_compat.h b/cpukit/libnetworking/arpa/nameser_compat.h new file mode 100644 index 0000000000..2ab5b47386 --- /dev/null +++ b/cpukit/libnetworking/arpa/nameser_compat.h @@ -0,0 +1,194 @@ +/* Copyright (c) 1983, 1989 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * from nameser.h 8.1 (Berkeley) 6/2/93 + * From: Id: nameser_compat.h,v 8.9 1998/03/20 23:25:10 halley Exp + * $Id$ + */ + +#ifndef _ARPA_NAMESER_COMPAT_ +#define _ARPA_NAMESER_COMPAT_ + +#define __BIND 19950621 /* (DEAD) interface version stamp. */ + +#include <machine/endian.h> + +#if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \ + BYTE_ORDER != PDP_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ + error "Undefined or invalid BYTE_ORDER"; +#endif + +/* + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INT32SZ NS_INT32SZ +#define INT16SZ NS_INT16SZ +#define INADDRSZ NS_INADDRSZ +#define IN6ADDRSZ NS_IN6ADDRSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define S_ZONE ns_s_zn +#define S_PREREQ ns_s_pr +#define S_UPDATE ns_s_ud +#define S_ADDT ns_s_ar + +#define QUERY ns_o_query +#define IQUERY ns_o_iquery +#define STATUS ns_o_status +#define NS_NOTIFY_OP ns_o_notify +#define NS_UPDATE_OP ns_o_update + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone + +#define DELETE ns_uop_delete +#define ADD ns_uop_add + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +/* BIND_UPDATE */ +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#endif /* _ARPA_NAMESER_COMPAT_ */ diff --git a/cpukit/libnetworking/arpa/telnet.h b/cpukit/libnetworking/arpa/telnet.h new file mode 100644 index 0000000000..a9527e0381 --- /dev/null +++ b/cpukit/libnetworking/arpa/telnet.h @@ -0,0 +1,340 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)telnet.h 8.2 (Berkeley) 12/15/93 + */ + +#ifndef _ARPA_TELNET_H_ +#define _ARPA_TELNET_H_ + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = { + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", + 0 +}; +#else +extern char *telcmds[]; +#endif + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ + (unsigned int)(x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + + +#define NTELOPTS (1+TELOPT_NEW_ENVIRON) +#ifdef TELOPTS +char *telopts[NTELOPTS+1] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", + 0 +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_NEW_ENVIRON +#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ +#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ +#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ +#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ + +#define LFLOW_OFF 0 /* Disable remote flow control */ +#define LFLOW_ON 1 /* Enable remote flow control */ +#define LFLOW_RESTART_ANY 2 /* Restart output on any char */ +#define LFLOW_RESTART_XON 3 /* Restart output only on XON */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 +#define SLC_MCL 19 +#define SLC_MCR 20 +#define SLC_MCWL 21 +#define SLC_MCWR 22 +#define SLC_MCBOL 23 +#define SLC_MCEOL 24 +#define SLC_INSRT 25 +#define SLC_OVER 26 +#define SLC_ECR 27 +#define SLC_EWR 28 +#define SLC_EBOL 29 +#define SLC_EEOL 30 + +#define NSLC 30 + +/* + * For backwards compatability, we define SLC_NAMES to be the + * list of names if SLC_NAMES is not defined. + */ +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", \ + "MCL", "MCR", "MCWL", "MCWR", "MCBOL", \ + "MCEOL", "INSRT", "OVER", "ECR", "EWR", \ + "EBOL", "EEOL", \ + 0 + +#ifdef SLC_NAMES +char *slc_names[] = { + SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define OLD_ENV_VAR 1 +#define OLD_ENV_VALUE 0 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define ENV_ESC 2 +#define ENV_USERVAR 3 + +/* + * AUTHENTICATION suboptions + */ + +/* + * Who is authenticating who ... + */ +#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ +#define AUTH_WHO_SERVER 1 /* Server authenticating client */ +#define AUTH_WHO_MASK 1 + +/* + * amount of authentication done + */ +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_CNT 5 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +char *authtype_names[] = { + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", + 0 +}; +#else +extern char *authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +/* + * ENCRYPTion suboptions + */ +#define ENCRYPT_IS 0 /* I pick encryption type ... */ +#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ +#define ENCRYPT_REPLY 2 /* Initial setup response */ +#define ENCRYPT_START 3 /* Am starting to send encrypted */ +#define ENCRYPT_END 4 /* Am ending encrypted */ +#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ +#define ENCRYPT_REQEND 6 /* Request you end encrypting */ +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +char *encrypt_names[] = { + "IS", "SUPPORT", "REPLY", "START", "END", + "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", + 0 +}; +char *enctype_names[] = { + "ANY", "DES_CFB64", "DES_OFB64", + 0 +}; +#else +extern char *encrypt_names[]; +extern char *enctype_names[]; +#endif + + +#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] + +#endif /* !_TELNET_H_ */ diff --git a/cpukit/libnetworking/bpfilter.h b/cpukit/libnetworking/bpfilter.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/cpukit/libnetworking/bpfilter.h diff --git a/cpukit/libnetworking/kern/kern_subr.c b/cpukit/libnetworking/kern/kern_subr.c new file mode 100644 index 0000000000..71e51fc442 --- /dev/null +++ b/cpukit/libnetworking/kern/kern_subr.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1982, 1986, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/queue.h> + +int +uiomove(cp, n, uio) + register caddr_t cp; + register int n; + register struct uio *uio; +{ + register struct iovec *iov; + u_int cnt; + int error; + +#ifdef DIAGNOSTIC + if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) + panic("uiomove: mode"); +#endif + while (n > 0 && uio->uio_resid) { + iov = uio->uio_iov; + cnt = iov->iov_len; + if (cnt == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + continue; + } + if (cnt > n) + cnt = n; + + switch (uio->uio_segflg) { + + case UIO_USERSPACE: + case UIO_USERISPACE: + if (uio->uio_rw == UIO_READ) + error = copyout(cp, iov->iov_base, cnt); + else + error = copyin(iov->iov_base, cp, cnt); + if (error) + return (error); + break; + + case UIO_SYSSPACE: + if (uio->uio_rw == UIO_READ) + bcopy((caddr_t)cp, iov->iov_base, cnt); + else + bcopy(iov->iov_base, (caddr_t)cp, cnt); + break; + case UIO_NOCOPY: + break; + } + iov->iov_base += cnt; + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + cp += cnt; + n -= cnt; + } + return (0); +} + +#ifdef vax /* unused except by ct.c, other oddities XXX */ +/* + * Get next character written in by user from uio. + */ +int +uwritec(uio) + struct uio *uio; +{ + register struct iovec *iov; + register int c; + + if (uio->uio_resid <= 0) + return (-1); +again: + if (uio->uio_iovcnt <= 0) + panic("uwritec"); + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + if (--uio->uio_iovcnt == 0) + return (-1); + goto again; + } + switch (uio->uio_segflg) { + + case UIO_USERSPACE: + c = fubyte(iov->iov_base); + break; + + case UIO_SYSSPACE: + c = *(u_char *) iov->iov_base; + break; + + case UIO_USERISPACE: + c = fuibyte(iov->iov_base); + break; + } + if (c < 0) + return (-1); + iov->iov_base++; + iov->iov_len--; + uio->uio_resid--; + uio->uio_offset++; + return (c); +} +#endif /* vax */ + +/* + * General routine to allocate a hash table. + */ +void * +hashinit(elements, type, hashmask) + int elements, type; + u_long *hashmask; +{ + long hashsize; + LIST_HEAD(generic, generic) *hashtbl; + int i; + + if (elements <= 0) + panic("hashinit: bad elements"); + for (hashsize = 1; hashsize <= elements; hashsize <<= 1) + continue; + hashsize >>= 1; + hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); + for (i = 0; i < hashsize; i++) + LIST_INIT(&hashtbl[i]); + *hashmask = hashsize - 1; + return (hashtbl); +} + +#define NPRIMES 27 +static int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039, + 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653, + 7159, 7673, 8191, 12281, 16381, 24571, 32749 }; + +/* + * General routine to allocate a prime number sized hash table. + */ +void * +phashinit(elements, type, nentries) + int elements, type; + u_long *nentries; +{ + long hashsize; + LIST_HEAD(generic, generic) *hashtbl; + int i; + + if (elements <= 0) + panic("phashinit: bad elements"); + for (i = 1, hashsize = primes[1]; hashsize <= elements;) { + i++; + if (i == NPRIMES) + break; + hashsize = primes[i]; + } + hashsize = primes[i - 1]; + hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); + for (i = 0; i < hashsize; i++) + LIST_INIT(&hashtbl[i]); + *nentries = hashsize; + return (hashtbl); +} diff --git a/cpukit/libnetworking/kern/uipc_domain.c b/cpukit/libnetworking/kern/uipc_domain.c new file mode 100644 index 0000000000..b35c7e6e67 --- /dev/null +++ b/cpukit/libnetworking/kern/uipc_domain.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)uipc_domain.c 8.2 (Berkeley) 10/18/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/domain.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/systm.h> + +/* + * System initialization + * + * Note: domain initialization wants to take place on a per domain basis + * as a result of traversing a linker set. Most likely, each domain + * want to call a registration function rather than being handled here + * in domaininit(). Probably this will look like: + * + * SYSINIT(unique, SI_SUB_PROTO_DOMAI, SI_ORDER_ANY, domain_add, xxx) + * + * Where 'xxx' is replaced by the address of a parameter struct to be + * passed to the doamin_add() function. + */ + +static int x_save_spl; /* used by kludge*/ +static void kludge_splimp __P((void *)); +static void kludge_splx __P((void *)); + void domaininit __P((void *)); +SYSINIT(splimp, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, kludge_splimp, &x_save_spl) +SYSINIT(domain, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, domaininit, NULL) +SYSINIT(splx, SI_SUB_PROTO_END, SI_ORDER_FIRST, kludge_splx, &x_save_spl) + +static void pffasttimo __P((void *)); +static void pfslowtimo __P((void *)); + +struct domain *domains; + +#define ADDDOMAIN(x) { \ + __CONCAT(x,domain.dom_next) = domains; \ + domains = &__CONCAT(x,domain); \ +} + +extern struct linker_set domain_set; + +/* ARGSUSED*/ +void +domaininit(dummy) + void *dummy; +{ + register struct domain *dp, **dpp; + register struct protosw *pr; + +/* - not in our sources +#ifdef ISDN + ADDDOMAIN(isdn); +#endif +*/ + + for (dp = domains; dp; dp = dp->dom_next) { + if (dp->dom_init) + (*dp->dom_init)(); + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++){ +#ifdef PRU_OLDSTYLE + /* See comments in uipc_socket2.c. */ + if (pr->pr_usrreqs == 0 && pr->pr_ousrreq) + pr->pr_usrreqs = &pru_oldstyle; +#endif + if (pr->pr_init) + (*pr->pr_init)(); + } + } + + if (max_linkhdr < 16) /* XXX */ + max_linkhdr = 16; + max_hdr = max_linkhdr + max_protohdr; + max_datalen = MHLEN - max_hdr; + timeout(pffasttimo, (void *)0, 1); + timeout(pfslowtimo, (void *)0, 1); +} + + +/* + * The following two operations are kludge code. Most likely, they should + * be done as a "domainpreinit()" for the first function and then rolled + * in as the last act of "domaininit()" for the second. + * + * In point of fact, it is questionable why other initialization prior + * to this does not also take place at splimp by default. + */ +static void +kludge_splimp(udata) + void *udata; +{ + int *savesplp = udata; + + *savesplp = splimp(); +} + +static void +kludge_splx(udata) + void *udata; +{ + int *savesplp = udata; + + splx( *savesplp); +} + + + +struct protosw * +pffindtype(int family, int type) +{ + register struct domain *dp; + register struct protosw *pr; + + for (dp = domains; dp; dp = dp->dom_next) + if (dp->dom_family == family) + goto found; + return (0); +found: + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) + if (pr->pr_type && pr->pr_type == type) + return (pr); + return (0); +} + +struct protosw * +pffindproto(int family, int protocol, int type) +{ + register struct domain *dp; + register struct protosw *pr; + struct protosw *maybe = 0; + + if (family == 0) + return (0); + for (dp = domains; dp; dp = dp->dom_next) + if (dp->dom_family == family) + goto found; + return (0); +found: + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { + if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) + return (pr); + + if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && + pr->pr_protocol == 0 && maybe == (struct protosw *)0) + maybe = pr; + } + return (maybe); +} + +void +pfctlinput(cmd, sa) + int cmd; + struct sockaddr *sa; +{ + register struct domain *dp; + register struct protosw *pr; + + for (dp = domains; dp; dp = dp->dom_next) + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) + if (pr->pr_ctlinput) + (*pr->pr_ctlinput)(cmd, sa, (void *)0); +} + +static void +pfslowtimo(arg) + void *arg; +{ + register struct domain *dp; + register struct protosw *pr; + + for (dp = domains; dp; dp = dp->dom_next) + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) + if (pr->pr_slowtimo) + (*pr->pr_slowtimo)(); + timeout(pfslowtimo, (void *)0, hz/2); +} + +static void +pffasttimo(arg) + void *arg; +{ + register struct domain *dp; + register struct protosw *pr; + + for (dp = domains; dp; dp = dp->dom_next) + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) + if (pr->pr_fasttimo) + (*pr->pr_fasttimo)(); + timeout(pffasttimo, (void *)0, hz/5); +} diff --git a/cpukit/libnetworking/kern/uipc_mbuf.c b/cpukit/libnetworking/kern/uipc_mbuf.c new file mode 100644 index 0000000000..f682be94a7 --- /dev/null +++ b/cpukit/libnetworking/kern/uipc_mbuf.c @@ -0,0 +1,851 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#define MBTYPES +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/domain.h> +#include <sys/protosw.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_kern.h> +#include <vm/vm_extern.h> + +static void mbinit __P((void *)); +SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) + +struct mbuf *mbutl; +char *mclrefcnt; +struct mbstat mbstat; +struct mbuf *mmbfree; +union mcluster *mclfree; +int max_linkhdr; +int max_protohdr; +int max_hdr; +int max_datalen; + +static void m_reclaim __P((void)); + +/* "number of clusters of pages" */ +#define NCL_INIT 1 + +#define NMB_INIT 16 + +/* ARGSUSED*/ +static void +mbinit(dummy) + void *dummy; +{ + int s; + + mmbfree = NULL; mclfree = NULL; + s = splimp(); + if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0) + goto bad; + if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) + goto bad; + splx(s); + return; +bad: + panic("mbinit"); +} + +/* + * Allocate at least nmb mbufs and place on mbuf free list. + * Must be called at splimp. + */ +/* ARGSUSED */ +int +m_mballoc(nmb, nowait) + register int nmb; + int nowait; +{ + register caddr_t p; + register int i; + int nbytes; + + /* Once we run out of map space, it will be impossible to get + * any more (nothing is ever freed back to the map) (XXX which + * is dumb). (however you are not dead as m_reclaim might + * still be able to free a substantial amount of space). + */ + if (mb_map_full) + return (0); + + nbytes = round_page(nmb * MSIZE); + p = (caddr_t)kmem_malloc(mb_map, nbytes, nowait ? M_NOWAIT : M_WAITOK); + /* + * Either the map is now full, or this is nowait and there + * are no pages left. + */ + if (p == NULL) + return (0); + + nmb = nbytes / MSIZE; + for (i = 0; i < nmb; i++) { + ((struct mbuf *)p)->m_next = mmbfree; + mmbfree = (struct mbuf *)p; + p += MSIZE; + } + mbstat.m_mbufs += nmb; + return (1); +} + +/* + * Allocate some number of mbuf clusters + * and place on cluster free list. + * Must be called at splimp. + */ +/* ARGSUSED */ +int +m_clalloc(ncl, nowait) + register int ncl; + int nowait; +{ + register caddr_t p; + register int i; + + /* + * Once we run out of map space, it will be impossible + * to get any more (nothing is ever freed back to the + * map). + */ + if (mb_map_full) + return (0); + + p = (caddr_t)kmem_malloc(mb_map, ncl*MCLBYTES, + nowait ? M_NOWAIT : M_WAITOK); + /* + * Either the map is now full, or this is nowait and there + * are no pages left. + */ + if (p == NULL) + return (0); + + for (i = 0; i < ncl; i++) { + ((union mcluster *)p)->mcl_next = mclfree; + mclfree = (union mcluster *)p; + p += MCLBYTES; + mbstat.m_clfree++; + } + mbstat.m_clusters += ncl; + return (1); +} + +/* + * When MGET failes, ask protocols to free space when short of memory, + * then re-attempt to allocate an mbuf. + */ +struct mbuf * +m_retry(i, t) + int i, t; +{ + register struct mbuf *m; + + m_reclaim(); +#define m_retry(i, t) (struct mbuf *)0 + MGET(m, i, t); +#undef m_retry + if (m != NULL) + mbstat.m_wait++; + else + mbstat.m_drops++; + return (m); +} + +/* + * As above; retry an MGETHDR. + */ +struct mbuf * +m_retryhdr(i, t) + int i, t; +{ + register struct mbuf *m; + + m_reclaim(); +#define m_retryhdr(i, t) (struct mbuf *)0 + MGETHDR(m, i, t); +#undef m_retryhdr + if (m != NULL) + mbstat.m_wait++; + else + mbstat.m_drops++; + return (m); +} + +static void +m_reclaim() +{ + register struct domain *dp; + register struct protosw *pr; + int s = splimp(); + + for (dp = domains; dp; dp = dp->dom_next) + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) + if (pr->pr_drain) + (*pr->pr_drain)(); + splx(s); + mbstat.m_drain++; +} + +/* + * Space allocation routines. + * These are also available as macros + * for critical paths. + */ +struct mbuf * +m_get(nowait, type) + int nowait, type; +{ + register struct mbuf *m; + + MGET(m, nowait, type); + return (m); +} + +struct mbuf * +m_gethdr(nowait, type) + int nowait, type; +{ + register struct mbuf *m; + + MGETHDR(m, nowait, type); + return (m); +} + +struct mbuf * +m_getclr(nowait, type) + int nowait, type; +{ + register struct mbuf *m; + + MGET(m, nowait, type); + if (m == 0) + return (0); + bzero(mtod(m, caddr_t), MLEN); + return (m); +} + +struct mbuf * +m_free(m) + struct mbuf *m; +{ + register struct mbuf *n; + + MFREE(m, n); + return (n); +} + +void +m_freem(m) + register struct mbuf *m; +{ + register struct mbuf *n; + + if (m == NULL) + return; + do { + MFREE(m, n); + m = n; + } while (m); +} + +/* + * Mbuffer utility routines. + */ + +/* + * Lesser-used path for M_PREPEND: + * allocate new mbuf to prepend to chain, + * copy junk along. + */ +struct mbuf * +m_prepend(m, len, how) + register struct mbuf *m; + int len, how; +{ + struct mbuf *mn; + + MGET(mn, how, m->m_type); + if (mn == (struct mbuf *)NULL) { + m_freem(m); + return ((struct mbuf *)NULL); + } + if (m->m_flags & M_PKTHDR) { + M_COPY_PKTHDR(mn, m); + m->m_flags &= ~M_PKTHDR; + } + mn->m_next = m; + m = mn; + if (len < MHLEN) + MH_ALIGN(m, len); + m->m_len = len; + return (m); +} + +/* + * Make a copy of an mbuf chain starting "off0" bytes from the beginning, + * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. + * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. + */ +static int MCFail; + +struct mbuf * +m_copym(m, off0, len, wait) + register struct mbuf *m; + int off0, wait; + register int len; +{ + register struct mbuf *n, **np; + register int off = off0; + struct mbuf *top; + int copyhdr = 0; + + if (off < 0 || len < 0) + panic("m_copym"); + if (off == 0 && m->m_flags & M_PKTHDR) + copyhdr = 1; + while (off > 0) { + if (m == 0) + panic("m_copym"); + if (off < m->m_len) + break; + off -= m->m_len; + m = m->m_next; + } + np = ⊤ + top = 0; + while (len > 0) { + if (m == 0) { + if (len != M_COPYALL) + panic("m_copym"); + break; + } + MGET(n, wait, m->m_type); + *np = n; + if (n == 0) + goto nospace; + if (copyhdr) { + M_COPY_PKTHDR(n, m); + if (len == M_COPYALL) + n->m_pkthdr.len -= off0; + else + n->m_pkthdr.len = len; + copyhdr = 0; + } + n->m_len = min(len, m->m_len - off); + if (m->m_flags & M_EXT) { + n->m_data = m->m_data + off; + if(!m->m_ext.ext_ref) + mclrefcnt[mtocl(m->m_ext.ext_buf)]++; + else + (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, + m->m_ext.ext_size); + n->m_ext = m->m_ext; + n->m_flags |= M_EXT; + } else + bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), + (unsigned)n->m_len); + if (len != M_COPYALL) + len -= n->m_len; + off = 0; + m = m->m_next; + np = &n->m_next; + } + if (top == 0) + MCFail++; + return (top); +nospace: + m_freem(top); + MCFail++; + return (0); +} + +/* + * Copy an entire packet, including header (which must be present). + * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. + */ +struct mbuf * +m_copypacket(m, how) + struct mbuf *m; + int how; +{ + struct mbuf *top, *n, *o; + + MGET(n, how, m->m_type); + top = n; + if (!n) + goto nospace; + + M_COPY_PKTHDR(n, m); + n->m_len = m->m_len; + if (m->m_flags & M_EXT) { + n->m_data = m->m_data; + mclrefcnt[mtocl(m->m_ext.ext_buf)]++; + n->m_ext = m->m_ext; + n->m_flags |= M_EXT; + } else { + bcopy(mtod(m, char *), mtod(n, char *), n->m_len); + } + + m = m->m_next; + while (m) { + MGET(o, how, m->m_type); + if (!o) + goto nospace; + + n->m_next = o; + n = n->m_next; + + n->m_len = m->m_len; + if (m->m_flags & M_EXT) { + n->m_data = m->m_data; + mclrefcnt[mtocl(m->m_ext.ext_buf)]++; + n->m_ext = m->m_ext; + n->m_flags |= M_EXT; + } else { + bcopy(mtod(m, char *), mtod(n, char *), n->m_len); + } + + m = m->m_next; + } + return top; +nospace: + m_freem(top); + MCFail++; + return 0; +} + +/* + * Copy data from an mbuf chain starting "off" bytes from the beginning, + * continuing for "len" bytes, into the indicated buffer. + */ +void +m_copydata(m, off, len, cp) + register struct mbuf *m; + register int off; + register int len; + caddr_t cp; +{ + register unsigned count; + + if (off < 0 || len < 0) + panic("m_copydata"); + while (off > 0) { + if (m == 0) + panic("m_copydata"); + if (off < m->m_len) + break; + off -= m->m_len; + m = m->m_next; + } + while (len > 0) { + if (m == 0) + panic("m_copydata"); + count = min(m->m_len - off, len); + bcopy(mtod(m, caddr_t) + off, cp, count); + len -= count; + cp += count; + off = 0; + m = m->m_next; + } +} + +/* + * Concatenate mbuf chain n to m. + * Both chains must be of the same type (e.g. MT_DATA). + * Any m_pkthdr is not updated. + */ +void +m_cat(m, n) + register struct mbuf *m, *n; +{ + while (m->m_next) + m = m->m_next; + while (n) { + if (m->m_flags & M_EXT || + m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { + /* just join the two chains */ + m->m_next = n; + return; + } + /* splat the data from one into the other */ + bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, + (u_int)n->m_len); + m->m_len += n->m_len; + n = m_free(n); + } +} + +void +m_adj(mp, req_len) + struct mbuf *mp; + int req_len; +{ + register int len = req_len; + register struct mbuf *m; + register int count; + + if ((m = mp) == NULL) + return; + if (len >= 0) { + /* + * Trim from head. + */ + while (m != NULL && len > 0) { + if (m->m_len <= len) { + len -= m->m_len; + m->m_len = 0; + m = m->m_next; + } else { + m->m_len -= len; + m->m_data += len; + len = 0; + } + } + m = mp; + if (mp->m_flags & M_PKTHDR) + m->m_pkthdr.len -= (req_len - len); + } else { + /* + * Trim from tail. Scan the mbuf chain, + * calculating its length and finding the last mbuf. + * If the adjustment only affects this mbuf, then just + * adjust and return. Otherwise, rescan and truncate + * after the remaining size. + */ + len = -len; + count = 0; + for (;;) { + count += m->m_len; + if (m->m_next == (struct mbuf *)0) + break; + m = m->m_next; + } + if (m->m_len >= len) { + m->m_len -= len; + if (mp->m_flags & M_PKTHDR) + mp->m_pkthdr.len -= len; + return; + } + count -= len; + if (count < 0) + count = 0; + /* + * Correct length for chain is "count". + * Find the mbuf with last data, adjust its length, + * and toss data from remaining mbufs on chain. + */ + m = mp; + if (m->m_flags & M_PKTHDR) + m->m_pkthdr.len = count; + for (; m; m = m->m_next) { + if (m->m_len >= count) { + m->m_len = count; + break; + } + count -= m->m_len; + } + while (m->m_next) + (m = m->m_next) ->m_len = 0; + } +} + +/* + * Rearange an mbuf chain so that len bytes are contiguous + * and in the data area of an mbuf (so that mtod and dtom + * will work for a structure of size len). Returns the resulting + * mbuf chain on success, frees it and returns null on failure. + * If there is room, it will add up to max_protohdr-len extra bytes to the + * contiguous region in an attempt to avoid being called next time. + */ +static int MPFail; + +struct mbuf * +m_pullup(n, len) + register struct mbuf *n; + int len; +{ + register struct mbuf *m; + register int count; + int space; + + /* + * If first mbuf has no cluster, and has room for len bytes + * without shifting current data, pullup into it, + * otherwise allocate a new mbuf to prepend to the chain. + */ + if ((n->m_flags & M_EXT) == 0 && + n->m_data + len < &n->m_dat[MLEN] && n->m_next) { + if (n->m_len >= len) + return (n); + m = n; + n = n->m_next; + len -= m->m_len; + } else { + if (len > MHLEN) + goto bad; + MGET(m, M_DONTWAIT, n->m_type); + if (m == 0) + goto bad; + m->m_len = 0; + if (n->m_flags & M_PKTHDR) { + M_COPY_PKTHDR(m, n); + n->m_flags &= ~M_PKTHDR; + } + } + space = &m->m_dat[MLEN] - (m->m_data + m->m_len); + do { + count = min(min(max(len, max_protohdr), space), n->m_len); + bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, + (unsigned)count); + len -= count; + m->m_len += count; + n->m_len -= count; + space -= count; + if (n->m_len) + n->m_data += count; + else + n = m_free(n); + } while (len > 0 && n); + if (len > 0) { + (void) m_free(m); + goto bad; + } + m->m_next = n; + return (m); +bad: + m_freem(n); + MPFail++; + return (0); +} + +/* + * Partition an mbuf chain in two pieces, returning the tail -- + * all but the first len0 bytes. In case of failure, it returns NULL and + * attempts to restore the chain to its original state. + */ +struct mbuf * +m_split(m0, len0, wait) + register struct mbuf *m0; + int len0, wait; +{ + register struct mbuf *m, *n; + unsigned len = len0, remain; + + for (m = m0; m && len > m->m_len; m = m->m_next) + len -= m->m_len; + if (m == 0) + return (0); + remain = m->m_len - len; + if (m0->m_flags & M_PKTHDR) { + MGETHDR(n, wait, m0->m_type); + if (n == 0) + return (0); + n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; + n->m_pkthdr.len = m0->m_pkthdr.len - len0; + m0->m_pkthdr.len = len0; + if (m->m_flags & M_EXT) + goto extpacket; + if (remain > MHLEN) { + /* m can't be the lead packet */ + MH_ALIGN(n, 0); + n->m_next = m_split(m, len, wait); + if (n->m_next == 0) { + (void) m_free(n); + return (0); + } else + return (n); + } else + MH_ALIGN(n, remain); + } else if (remain == 0) { + n = m->m_next; + m->m_next = 0; + return (n); + } else { + MGET(n, wait, m->m_type); + if (n == 0) + return (0); + M_ALIGN(n, remain); + } +extpacket: + if (m->m_flags & M_EXT) { + n->m_flags |= M_EXT; + n->m_ext = m->m_ext; + if(!m->m_ext.ext_ref) + mclrefcnt[mtocl(m->m_ext.ext_buf)]++; + else + (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, + m->m_ext.ext_size); + m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ + n->m_data = m->m_data + len; + } else { + bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); + } + n->m_len = remain; + m->m_len = len; + n->m_next = m->m_next; + m->m_next = 0; + return (n); +} +/* + * Routine to copy from device local memory into mbufs. + */ +struct mbuf * +m_devget(buf, totlen, off0, ifp, copy) + char *buf; + int totlen, off0; + struct ifnet *ifp; + void (*copy) __P((char *from, caddr_t to, u_int len)); +{ + register struct mbuf *m; + struct mbuf *top = 0, **mp = ⊤ + register int off = off0, len; + register char *cp; + char *epkt; + + cp = buf; + epkt = cp + totlen; + if (off) { + cp += off + 2 * sizeof(u_short); + totlen -= 2 * sizeof(u_short); + } + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = totlen; + m->m_len = MHLEN; + + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + m->m_len = MLEN; + } + len = min(totlen, epkt - cp); + if (len >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = len = min(len, MCLBYTES); + else + len = m->m_len; + } else { + /* + * Place initial small packet/header at end of mbuf. + */ + if (len < m->m_len) { + if (top == 0 && len + max_linkhdr <= m->m_len) + m->m_data += max_linkhdr; + m->m_len = len; + } else + len = m->m_len; + } + if (copy) + copy(cp, mtod(m, caddr_t), (unsigned)len); + else + bcopy(cp, mtod(m, caddr_t), (unsigned)len); + cp += len; + *mp = m; + mp = &m->m_next; + totlen -= len; + if (cp == epkt) + cp = buf; + } + return (top); +} + +/* + * Copy data from a buffer back into the indicated mbuf chain, + * starting "off" bytes from the beginning, extending the mbuf + * chain if necessary. + */ +void +m_copyback(m0, off, len, cp) + struct mbuf *m0; + register int off; + register int len; + caddr_t cp; +{ + register int mlen; + register struct mbuf *m = m0, *n; + int totlen = 0; + + if (m0 == 0) + return; + while (off > (mlen = m->m_len)) { + off -= mlen; + totlen += mlen; + if (m->m_next == 0) { + n = m_getclr(M_DONTWAIT, m->m_type); + if (n == 0) + goto out; + n->m_len = min(MLEN, len + off); + m->m_next = n; + } + m = m->m_next; + } + while (len > 0) { + mlen = min (m->m_len - off, len); + bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); + cp += mlen; + len -= mlen; + mlen += off; + off = 0; + totlen += mlen; + if (len == 0) + break; + if (m->m_next == 0) { + n = m_get(M_DONTWAIT, m->m_type); + if (n == 0) + break; + n->m_len = min(MLEN, len); + m->m_next = n; + } + m = m->m_next; + } +out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) + m->m_pkthdr.len = totlen; +} diff --git a/cpukit/libnetworking/kern/uipc_socket.c b/cpukit/libnetworking/kern/uipc_socket.c new file mode 100644 index 0000000000..0933fea50a --- /dev/null +++ b/cpukit/libnetworking/kern/uipc_socket.c @@ -0,0 +1,1100 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/file.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/kernel.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/resourcevar.h> +#include <sys/signalvar.h> +#include <sys/sysctl.h> + +static int somaxconn = SOMAXCONN; +SYSCTL_INT(_kern, KERN_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, 0, ""); + +/* + * Socket operation routines. + * These routines are called by the routines in + * sys_socket.c or from a system process, and + * implement the semantics of socket operations by + * switching out to the protocol specific routines. + */ +/*ARGSUSED*/ +int +socreate(dom, aso, type, proto, p) + int dom; + struct socket **aso; + register int type; + int proto; + struct proc *p; +{ + register struct protosw *prp; + register struct socket *so; + register int error; + + if (proto) + prp = pffindproto(dom, proto, type); + else + prp = pffindtype(dom, type); + if (prp == 0 || prp->pr_usrreqs == 0) + return (EPROTONOSUPPORT); + if (prp->pr_type != type) + return (EPROTOTYPE); + MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); + bzero((caddr_t)so, sizeof(*so)); + TAILQ_INIT(&so->so_incomp); + TAILQ_INIT(&so->so_comp); + so->so_type = type; + so->so_state = SS_PRIV; + so->so_uid = 0; + so->so_proto = prp; + error = (*prp->pr_usrreqs->pru_attach)(so, proto); + if (error) { + so->so_state |= SS_NOFDREF; + sofree(so); + return (error); + } + *aso = so; + return (0); +} + +int +sobind(so, nam) + struct socket *so; + struct mbuf *nam; +{ + int s = splnet(); + int error; + + error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam); + splx(s); + return (error); +} + +int +solisten(so, backlog) + register struct socket *so; + int backlog; +{ + int s = splnet(), error; + + error = (*so->so_proto->pr_usrreqs->pru_listen)(so); + if (error) { + splx(s); + return (error); + } + if (so->so_comp.tqh_first == NULL) + so->so_options |= SO_ACCEPTCONN; + if (backlog < 0 || backlog > somaxconn) + backlog = somaxconn; + so->so_qlimit = backlog; + splx(s); + return (0); +} + +void +sofree(so) + register struct socket *so; +{ + struct socket *head = so->so_head; + + if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) + return; + if (head != NULL) { + if (so->so_state & SS_INCOMP) { + TAILQ_REMOVE(&head->so_incomp, so, so_list); + head->so_incqlen--; + } else if (so->so_state & SS_COMP) { + TAILQ_REMOVE(&head->so_comp, so, so_list); + } else { + panic("sofree: not queued"); + } + head->so_qlen--; + so->so_state &= ~(SS_INCOMP|SS_COMP); + so->so_head = NULL; + } + sbrelease(&so->so_snd); + sorflush(so); + FREE(so, M_SOCKET); +} + +/* + * Close a socket on last file table reference removal. + * Initiate disconnect if connected. + * Free socket when disconnect complete. + */ +int +soclose(so) + register struct socket *so; +{ + int s = splnet(); /* conservative */ + int error = 0; + + if (so->so_options & SO_ACCEPTCONN) { + struct socket *sp, *sonext; + + for (sp = so->so_incomp.tqh_first; sp != NULL; sp = sonext) { + sonext = sp->so_list.tqe_next; + (void) soabort(sp); + } + for (sp = so->so_comp.tqh_first; sp != NULL; sp = sonext) { + sonext = sp->so_list.tqe_next; + (void) soabort(sp); + } + } + if (so->so_pcb == 0) + goto discard; + if (so->so_state & SS_ISCONNECTED) { + if ((so->so_state & SS_ISDISCONNECTING) == 0) { + error = sodisconnect(so); + if (error) + goto drop; + } + if (so->so_options & SO_LINGER) { + if ((so->so_state & SS_ISDISCONNECTING) && + (so->so_state & SS_NBIO)) + goto drop; + while (so->so_state & SS_ISCONNECTED) { + soconnsleep (so); + } + } + } +drop: + if (so->so_pcb) { + int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so); + if (error == 0) + error = error2; + } +discard: + if (so->so_state & SS_NOFDREF) + panic("soclose: NOFDREF"); + so->so_state |= SS_NOFDREF; + sofree(so); + splx(s); + return (error); +} + +/* + * Must be called at splnet... + */ +int +soabort(so) + struct socket *so; +{ + + return (*so->so_proto->pr_usrreqs->pru_abort)(so); +} + +int +soaccept(so, nam) + register struct socket *so; + struct mbuf *nam; +{ + int s = splnet(); + int error; + + if ((so->so_state & SS_NOFDREF) == 0) + panic("soaccept: !NOFDREF"); + so->so_state &= ~SS_NOFDREF; + error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam); + splx(s); + return (error); +} + +int +soconnect(so, nam) + register struct socket *so; + struct mbuf *nam; +{ + int s; + int error; + + if (so->so_options & SO_ACCEPTCONN) + return (EOPNOTSUPP); + s = splnet(); + /* + * If protocol is connection-based, can only connect once. + * Otherwise, if connected, try to disconnect first. + * This allows user to disconnect by connecting to, e.g., + * a null address. + */ + if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && + ((so->so_proto->pr_flags & PR_CONNREQUIRED) || + (error = sodisconnect(so)))) + error = EISCONN; + else + error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam); + splx(s); + return (error); +} + +int +soconnect2(so1, so2) + register struct socket *so1; + struct socket *so2; +{ + int s = splnet(); + int error; + + error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2); + splx(s); + return (error); +} + +int +sodisconnect(so) + register struct socket *so; +{ + int s = splnet(); + int error; + + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + goto bad; + } + if (so->so_state & SS_ISDISCONNECTING) { + error = EALREADY; + goto bad; + } + error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so); +bad: + splx(s); + return (error); +} + +#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) +/* + * Send on a socket. + * If send must go all at once and message is larger than + * send buffering, then hard error. + * Lock against other senders. + * If must go all at once and not enough room now, then + * inform user that this would block and do nothing. + * Otherwise, if nonblocking, send as much as possible. + * The data to be sent is described by "uio" if nonzero, + * otherwise by the mbuf chain "top" (which must be null + * if uio is not). Data provided in mbuf chain must be small + * enough to send all at once. + * + * Returns nonzero on error, timeout or signal; callers + * must check for short counts if EINTR/ERESTART are returned. + * Data and control buffers are freed on return. + */ +int +sosend(so, addr, uio, top, control, flags) + register struct socket *so; + struct mbuf *addr; + struct uio *uio; + struct mbuf *top; + struct mbuf *control; + int flags; +{ + struct mbuf **mp; + register struct mbuf *m; + register long space, len, resid; + int clen = 0, error, s, dontroute, mlen; + int atomic = sosendallatonce(so) || top; + + if (uio) + resid = uio->uio_resid; + else + resid = top->m_pkthdr.len; + /* + * In theory resid should be unsigned. + * However, space must be signed, as it might be less than 0 + * if we over-committed, and we must use a signed comparison + * of space and resid. On the other hand, a negative resid + * causes us to loop sending 0-length segments to the protocol. + * + * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM + * type sockets since that's an error. + */ + if (resid < 0 || so->so_type == SOCK_STREAM && (flags & MSG_EOR)) { + error = EINVAL; + goto out; + } + + dontroute = + (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && + (so->so_proto->pr_flags & PR_ATOMIC); + if (control) + clen = control->m_len; +#define snderr(errno) { error = errno; splx(s); goto release; } + +restart: + error = sblock(&so->so_snd, SBLOCKWAIT(flags)); + if (error) + goto out; + do { + s = splnet(); + if (so->so_state & SS_CANTSENDMORE) + snderr(EPIPE); + if (so->so_error) { + error = so->so_error; + so->so_error = 0; + splx(s); + goto release; + } + if ((so->so_state & SS_ISCONNECTED) == 0) { + /* + * `sendto' and `sendmsg' is allowed on a connection- + * based socket if it supports implied connect. + * Return ENOTCONN if not connected and no address is + * supplied. + */ + if ((so->so_proto->pr_flags & PR_CONNREQUIRED) && + (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) { + if ((so->so_state & SS_ISCONFIRMING) == 0 && + !(resid == 0 && clen != 0)) + snderr(ENOTCONN); + } else if (addr == 0) + snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? + ENOTCONN : EDESTADDRREQ); + } + space = sbspace(&so->so_snd); + if (flags & MSG_OOB) + space += 1024; + if ((atomic && resid > so->so_snd.sb_hiwat) || + clen > so->so_snd.sb_hiwat) + snderr(EMSGSIZE); + if (space < resid + clen && uio && + (atomic || space < so->so_snd.sb_lowat || space < clen)) { + if (so->so_state & SS_NBIO) + snderr(EWOULDBLOCK); + sbunlock(&so->so_snd); + error = sbwait(&so->so_snd); + splx(s); + if (error) + goto out; + goto restart; + } + splx(s); + mp = ⊤ + space -= clen; + do { + if (uio == NULL) { + /* + * Data is prepackaged in "top". + */ + resid = 0; + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + } else do { + if (top == 0) { + MGETHDR(m, M_WAIT, MT_DATA); + mlen = MHLEN; + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *)0; + } else { + MGET(m, M_WAIT, MT_DATA); + mlen = MLEN; + } + if (resid >= MINCLSIZE) { + MCLGET(m, M_WAIT); + if ((m->m_flags & M_EXT) == 0) + goto nopages; + mlen = MCLBYTES; + len = min(min(mlen, resid), space); + } else { +nopages: + len = min(min(mlen, resid), space); + /* + * For datagram protocols, leave room + * for protocol headers in first mbuf. + */ + if (atomic && top == 0 && len < mlen) + MH_ALIGN(m, len); + } + space -= len; + error = uiomove(mtod(m, caddr_t), (int)len, uio); + resid = uio->uio_resid; + m->m_len = len; + *mp = m; + top->m_pkthdr.len += len; + if (error) + goto release; + mp = &m->m_next; + if (resid <= 0) { + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + break; + } + } while (space > 0 && atomic); + if (dontroute) + so->so_options |= SO_DONTROUTE; + s = splnet(); /* XXX */ + error = (*so->so_proto->pr_usrreqs->pru_send)(so, + (flags & MSG_OOB) ? PRUS_OOB : + /* + * If the user set MSG_EOF, the protocol + * understands this flag and nothing left to + * send then use PRU_SEND_EOF instead of PRU_SEND. + */ + ((flags & MSG_EOF) && + (so->so_proto->pr_flags & PR_IMPLOPCL) && + (resid <= 0)) ? + PRUS_EOF : 0, + top, addr, control); + splx(s); + if (dontroute) + so->so_options &= ~SO_DONTROUTE; + clen = 0; + control = 0; + top = 0; + mp = ⊤ + if (error) + goto release; + } while (resid && space > 0); + } while (resid); + +release: + sbunlock(&so->so_snd); +out: + if (top) + m_freem(top); + if (control) + m_freem(control); + return (error); +} + +/* + * Implement receive operations on a socket. + * We depend on the way that records are added to the sockbuf + * by sbappend*. In particular, each record (mbufs linked through m_next) + * must begin with an address if the protocol so specifies, + * followed by an optional mbuf or mbufs containing ancillary data, + * and then zero or more mbufs of data. + * In order to avoid blocking network interrupts for the entire time here, + * we splx() while doing the actual copy to user space. + * Although the sockbuf is locked, new data may still be appended, + * and thus we must maintain consistency of the sockbuf during that time. + * + * The caller may receive the data as a single mbuf chain by supplying + * an mbuf **mp0 for use in returning the chain. The uio is then used + * only for the count in uio_resid. + */ +int +soreceive(so, paddr, uio, mp0, controlp, flagsp) + register struct socket *so; + struct mbuf **paddr; + struct uio *uio; + struct mbuf **mp0; + struct mbuf **controlp; + int *flagsp; +{ + register struct mbuf *m, **mp; + register int flags, len, error, s, offset; + struct protosw *pr = so->so_proto; + struct mbuf *nextrecord; + int moff, type = 0; + int orig_resid = uio->uio_resid; + + mp = mp0; + if (paddr) + *paddr = 0; + if (controlp) + *controlp = 0; + if (flagsp) + flags = *flagsp &~ MSG_EOR; + else + flags = 0; + if (flags & MSG_OOB) { + m = m_get(M_WAIT, MT_DATA); + error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK); + if (error) + goto bad; + do { + error = uiomove(mtod(m, caddr_t), + (int) min(uio->uio_resid, m->m_len), uio); + m = m_free(m); + } while (uio->uio_resid && error == 0 && m); +bad: + if (m) + m_freem(m); + return (error); + } + if (mp) + *mp = (struct mbuf *)0; + if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) + (*pr->pr_usrreqs->pru_rcvd)(so, 0); + +restart: + error = sblock(&so->so_rcv, SBLOCKWAIT(flags)); + if (error) + return (error); + s = splnet(); + + m = so->so_rcv.sb_mb; + /* + * If we have less data than requested, block awaiting more + * (subject to any timeout) if: + * 1. the current count is less than the low water mark, or + * 2. MSG_WAITALL is set, and it is possible to do the entire + * receive operation at once if we block (resid <= hiwat). + * 3. MSG_DONTWAIT is not set + * If MSG_WAITALL is set but resid is larger than the receive buffer, + * we have to do the receive in sections, and thus risk returning + * a short count if a timeout or signal occurs after we start. + */ + if (m == 0 || (((flags & MSG_DONTWAIT) == 0 && + so->so_rcv.sb_cc < uio->uio_resid) && + (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || + ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && + m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { +#ifdef DIAGNOSTIC + if (m == 0 && so->so_rcv.sb_cc) + panic("receive 1"); +#endif + if (so->so_error) { + if (m) + goto dontblock; + error = so->so_error; + if ((flags & MSG_PEEK) == 0) + so->so_error = 0; + goto release; + } + if (so->so_state & SS_CANTRCVMORE) { + if (m) + goto dontblock; + else + goto release; + } + for (; m; m = m->m_next) + if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { + m = so->so_rcv.sb_mb; + goto dontblock; + } + if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && + (so->so_proto->pr_flags & PR_CONNREQUIRED)) { + error = ENOTCONN; + goto release; + } + if (uio->uio_resid == 0) + goto release; + if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { + error = EWOULDBLOCK; + goto release; + } + sbunlock(&so->so_rcv); + error = sbwait(&so->so_rcv); + splx(s); + if (error) + return (error); + goto restart; + } +dontblock: + nextrecord = m->m_nextpkt; + if (pr->pr_flags & PR_ADDR) { +#ifdef DIAGNOSTIC + if (m->m_type != MT_SONAME) + panic("receive 1a"); +#endif + orig_resid = 0; + if (flags & MSG_PEEK) { + if (paddr) + *paddr = m_copy(m, 0, m->m_len); + m = m->m_next; + } else { + sbfree(&so->so_rcv, m); + if (paddr) { + *paddr = m; + so->so_rcv.sb_mb = m->m_next; + m->m_next = 0; + m = so->so_rcv.sb_mb; + } else { + MFREE(m, so->so_rcv.sb_mb); + m = so->so_rcv.sb_mb; + } + } + } + while (m && m->m_type == MT_CONTROL && error == 0) { + if (flags & MSG_PEEK) { + if (controlp) + *controlp = m_copy(m, 0, m->m_len); + m = m->m_next; + } else { + sbfree(&so->so_rcv, m); + if (controlp) { + if (pr->pr_domain->dom_externalize && + mtod(m, struct cmsghdr *)->cmsg_type == + SCM_RIGHTS) + error = (*pr->pr_domain->dom_externalize)(m); + *controlp = m; + so->so_rcv.sb_mb = m->m_next; + m->m_next = 0; + m = so->so_rcv.sb_mb; + } else { + MFREE(m, so->so_rcv.sb_mb); + m = so->so_rcv.sb_mb; + } + } + if (controlp) { + orig_resid = 0; + controlp = &(*controlp)->m_next; + } + } + if (m) { + if ((flags & MSG_PEEK) == 0) + m->m_nextpkt = nextrecord; + type = m->m_type; + if (type == MT_OOBDATA) + flags |= MSG_OOB; + } + moff = 0; + offset = 0; + while (m && uio->uio_resid > 0 && error == 0) { + if (m->m_type == MT_OOBDATA) { + if (type != MT_OOBDATA) + break; + } else if (type == MT_OOBDATA) + break; +#ifdef DIAGNOSTIC + else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) + panic("receive 3"); +#endif + so->so_state &= ~SS_RCVATMARK; + len = uio->uio_resid; + if (so->so_oobmark && len > so->so_oobmark - offset) + len = so->so_oobmark - offset; + if (len > m->m_len - moff) + len = m->m_len - moff; + /* + * If mp is set, just pass back the mbufs. + * Otherwise copy them out via the uio, then free. + * Sockbuf must be consistent here (points to current mbuf, + * it points to next record) when we drop priority; + * we must note any additions to the sockbuf when we + * block interrupts again. + */ + if (mp == 0) { + splx(s); + error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); + s = splnet(); + if (error) + goto release; + } else + uio->uio_resid -= len; + if (len == m->m_len - moff) { + if (m->m_flags & M_EOR) + flags |= MSG_EOR; + if (flags & MSG_PEEK) { + m = m->m_next; + moff = 0; + } else { + nextrecord = m->m_nextpkt; + sbfree(&so->so_rcv, m); + if (mp) { + *mp = m; + mp = &m->m_next; + so->so_rcv.sb_mb = m = m->m_next; + *mp = (struct mbuf *)0; + } else { + MFREE(m, so->so_rcv.sb_mb); + m = so->so_rcv.sb_mb; + } + if (m) + m->m_nextpkt = nextrecord; + } + } else { + if (flags & MSG_PEEK) + moff += len; + else { + if (mp) + *mp = m_copym(m, 0, len, M_WAIT); + m->m_data += len; + m->m_len -= len; + so->so_rcv.sb_cc -= len; + } + } + if (so->so_oobmark) { + if ((flags & MSG_PEEK) == 0) { + so->so_oobmark -= len; + if (so->so_oobmark == 0) { + so->so_state |= SS_RCVATMARK; + break; + } + } else { + offset += len; + if (offset == so->so_oobmark) + break; + } + } + if (flags & MSG_EOR) + break; + /* + * If the MSG_WAITALL flag is set (for non-atomic socket), + * we must not quit until "uio->uio_resid == 0" or an error + * termination. If a signal/timeout occurs, return + * with a short count but without error. + * Keep sockbuf locked against other readers. + */ + while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && + !sosendallatonce(so) && !nextrecord) { + if (so->so_error || so->so_state & SS_CANTRCVMORE) + break; + error = sbwait(&so->so_rcv); + if (error) { + sbunlock(&so->so_rcv); + splx(s); + return (0); + } + m = so->so_rcv.sb_mb; + if (m) + nextrecord = m->m_nextpkt; + } + } + + if (m && pr->pr_flags & PR_ATOMIC) { + flags |= MSG_TRUNC; + if ((flags & MSG_PEEK) == 0) + (void) sbdroprecord(&so->so_rcv); + } + if ((flags & MSG_PEEK) == 0) { + if (m == 0) + so->so_rcv.sb_mb = nextrecord; + if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) + (*pr->pr_usrreqs->pru_rcvd)(so, flags); + } + if (orig_resid == uio->uio_resid && orig_resid && + (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { + sbunlock(&so->so_rcv); + splx(s); + goto restart; + } + + if (flagsp) + *flagsp |= flags; +release: + sbunlock(&so->so_rcv); + splx(s); + return (error); +} + +int +soshutdown(so, how) + register struct socket *so; + register int how; +{ + register struct protosw *pr = so->so_proto; + + how++; + if (how & FREAD) + sorflush(so); + if (how & FWRITE) + return ((*pr->pr_usrreqs->pru_shutdown)(so)); + return (0); +} + +void +sorflush(so) + register struct socket *so; +{ + register struct sockbuf *sb = &so->so_rcv; + register struct protosw *pr = so->so_proto; + register int s; + struct sockbuf asb; + + sb->sb_flags |= SB_NOINTR; + (void) sblock(sb, M_WAITOK); + s = splimp(); + socantrcvmore(so); + sbunlock(sb); + asb = *sb; + bzero((caddr_t)sb, sizeof (*sb)); + splx(s); + if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) + (*pr->pr_domain->dom_dispose)(asb.sb_mb); + sbrelease(&asb); +} + +int +sosetopt(so, level, optname, m0) + register struct socket *so; + int level, optname; + struct mbuf *m0; +{ + int error = 0; + register struct mbuf *m = m0; + + if (level != SOL_SOCKET) { + if (so->so_proto && so->so_proto->pr_ctloutput) + return ((*so->so_proto->pr_ctloutput) + (PRCO_SETOPT, so, level, optname, &m0)); + error = ENOPROTOOPT; + } else { + switch (optname) { + + case SO_LINGER: + if (m == NULL || m->m_len != sizeof (struct linger)) { + error = EINVAL; + goto bad; + } + so->so_linger = mtod(m, struct linger *)->l_linger; + /* fall thru... */ + + case SO_DEBUG: + case SO_KEEPALIVE: + case SO_DONTROUTE: + case SO_USELOOPBACK: + case SO_BROADCAST: + case SO_REUSEADDR: + case SO_REUSEPORT: + case SO_OOBINLINE: + case SO_TIMESTAMP: + if (m == NULL || m->m_len < sizeof (int)) { + error = EINVAL; + goto bad; + } + if (*mtod(m, int *)) + so->so_options |= optname; + else + so->so_options &= ~optname; + break; + + case SO_SNDBUF: + case SO_RCVBUF: + case SO_SNDLOWAT: + case SO_RCVLOWAT: + { + int optval; + + if (m == NULL || m->m_len < sizeof (int)) { + error = EINVAL; + goto bad; + } + + /* + * Values < 1 make no sense for any of these + * options, so disallow them. + */ + optval = *mtod(m, int *); + if (optval < 1) { + error = EINVAL; + goto bad; + } + + switch (optname) { + + case SO_SNDBUF: + case SO_RCVBUF: + if (sbreserve(optname == SO_SNDBUF ? + &so->so_snd : &so->so_rcv, + (u_long) optval) == 0) { + error = ENOBUFS; + goto bad; + } + break; + + /* + * Make sure the low-water is never greater than + * the high-water. + */ + case SO_SNDLOWAT: + so->so_snd.sb_lowat = + (optval > so->so_snd.sb_hiwat) ? + so->so_snd.sb_hiwat : optval; + break; + case SO_RCVLOWAT: + so->so_rcv.sb_lowat = + (optval > so->so_rcv.sb_hiwat) ? + so->so_rcv.sb_hiwat : optval; + break; + } + break; + } + + case SO_SNDTIMEO: + case SO_RCVTIMEO: + { + struct timeval *tv; + short val; + + if (m == NULL || m->m_len < sizeof (*tv)) { + error = EINVAL; + goto bad; + } + tv = mtod(m, struct timeval *); + if (tv->tv_sec > SHRT_MAX / hz - hz) { + error = EDOM; + goto bad; + } + val = tv->tv_sec * hz + tv->tv_usec / tick; + + switch (optname) { + + case SO_SNDTIMEO: + so->so_snd.sb_timeo = val; + break; + case SO_RCVTIMEO: + so->so_rcv.sb_timeo = val; + break; + } + break; + } + + case SO_PRIVSTATE: + /* we don't care what the parameter is... */ + so->so_state &= ~SS_PRIV; + break; + + default: + error = ENOPROTOOPT; + break; + } + if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { + (void) ((*so->so_proto->pr_ctloutput) + (PRCO_SETOPT, so, level, optname, &m0)); + m = NULL; /* freed by protocol */ + } + } +bad: + if (m) + (void) m_free(m); + return (error); +} + +int +sogetopt(so, level, optname, mp) + register struct socket *so; + int level, optname; + struct mbuf **mp; +{ + register struct mbuf *m; + + if (level != SOL_SOCKET) { + if (so->so_proto && so->so_proto->pr_ctloutput) { + return ((*so->so_proto->pr_ctloutput) + (PRCO_GETOPT, so, level, optname, mp)); + } else + return (ENOPROTOOPT); + } else { + m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof (int); + + switch (optname) { + + case SO_LINGER: + m->m_len = sizeof (struct linger); + mtod(m, struct linger *)->l_onoff = + so->so_options & SO_LINGER; + mtod(m, struct linger *)->l_linger = so->so_linger; + break; + + case SO_USELOOPBACK: + case SO_DONTROUTE: + case SO_DEBUG: + case SO_KEEPALIVE: + case SO_REUSEADDR: + case SO_REUSEPORT: + case SO_BROADCAST: + case SO_OOBINLINE: + case SO_TIMESTAMP: + *mtod(m, int *) = so->so_options & optname; + break; + + case SO_PRIVSTATE: + *mtod(m, int *) = so->so_state & SS_PRIV; + break; + + case SO_TYPE: + *mtod(m, int *) = so->so_type; + break; + + case SO_ERROR: + *mtod(m, int *) = so->so_error; + so->so_error = 0; + break; + + case SO_SNDBUF: + *mtod(m, int *) = so->so_snd.sb_hiwat; + break; + + case SO_RCVBUF: + *mtod(m, int *) = so->so_rcv.sb_hiwat; + break; + + case SO_SNDLOWAT: + *mtod(m, int *) = so->so_snd.sb_lowat; + break; + + case SO_RCVLOWAT: + *mtod(m, int *) = so->so_rcv.sb_lowat; + break; + + case SO_SNDTIMEO: + case SO_RCVTIMEO: + { + int val = (optname == SO_SNDTIMEO ? + so->so_snd.sb_timeo : so->so_rcv.sb_timeo); + + m->m_len = sizeof(struct timeval); + mtod(m, struct timeval *)->tv_sec = val / hz; + mtod(m, struct timeval *)->tv_usec = + (val % hz) * tick; + break; + } + + default: + (void)m_free(m); + return (ENOPROTOOPT); + } + *mp = m; + return (0); + } +} + +void +sohasoutofband(so) + register struct socket *so; +{ +#if 0 /* FIXME: For now we just ignore out of band data */ + struct proc *p; + + if (so->so_pgid < 0) + gsignal(-so->so_pgid, SIGURG); + else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) + psignal(p, SIGURG); + selwakeup(&so->so_rcv.sb_sel); +#endif +} diff --git a/cpukit/libnetworking/kern/uipc_socket2.c b/cpukit/libnetworking/kern/uipc_socket2.c new file mode 100644 index 0000000000..0539d2c5f3 --- /dev/null +++ b/cpukit/libnetworking/kern/uipc_socket2.c @@ -0,0 +1,965 @@ +/* + * This file has undergone several changes to reflect the + * differences between the RTEMS and FreeBSD kernels. + */ + +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/file.h> +#include <sys/buf.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/signalvar.h> +#include <sys/sysctl.h> + +/* + * Primitive routines for operating on sockets and socket buffers + */ + +u_long sb_max = SB_MAX; /* XXX should be static */ +SYSCTL_INT(_kern, KERN_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, "") + +static u_long sb_efficiency = 8; /* parameter for sbreserve() */ +SYSCTL_INT(_kern, OID_AUTO, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency, + 0, ""); + +/* + * Procedures to manipulate state flags of socket + * and do appropriate wakeups. Normal sequence from the + * active (originating) side is that soisconnecting() is + * called during processing of connect() call, + * resulting in an eventual call to soisconnected() if/when the + * connection is established. When the connection is torn down + * soisdisconnecting() is called during processing of disconnect() call, + * and soisdisconnected() is called when the connection to the peer + * is totally severed. The semantics of these routines are such that + * connectionless protocols can call soisconnected() and soisdisconnected() + * only, bypassing the in-progress calls when setting up a ``connection'' + * takes no time. + * + * From the passive side, a socket is created with + * two queues of sockets: so_q0 for connections in progress + * and so_q for connections already made and awaiting user acceptance. + * As a protocol is preparing incoming connections, it creates a socket + * structure queued on so_q0 by calling sonewconn(). When the connection + * is established, soisconnected() is called, and transfers the + * socket structure to so_q, making it available to accept(). + * + * If a socket is closed with sockets on either + * so_q0 or so_q, these sockets are dropped. + * + * If higher level protocols are implemented in + * the kernel, the wakeups done here will sometimes + * cause software-interrupt process scheduling. + */ + +void +soisconnecting(so) + register struct socket *so; +{ + + so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); + so->so_state |= SS_ISCONNECTING; +} + +void +soisconnected(so) + register struct socket *so; +{ + register struct socket *head = so->so_head; + + so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); + so->so_state |= SS_ISCONNECTED; + if (head && (so->so_state & SS_INCOMP)) { + TAILQ_REMOVE(&head->so_incomp, so, so_list); + head->so_incqlen--; + so->so_state &= ~SS_INCOMP; + TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); + so->so_state |= SS_COMP; + sorwakeup(head); + soconnwakeup(head); + } else { + soconnwakeup(so); + sorwakeup(so); + sowwakeup(so); + } +} + +void +soisdisconnecting(so) + register struct socket *so; +{ + + so->so_state &= ~SS_ISCONNECTING; + so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); + soconnwakeup(so); + sowwakeup(so); + sorwakeup(so); +} + +void +soisdisconnected(so) + register struct socket *so; +{ + + so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); + so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); + soconnwakeup(so); + sowwakeup(so); + sorwakeup(so); +} + +/* + * Return a random connection that hasn't been serviced yet and + * is eligible for discard. There is a one in qlen chance that + * we will return a null, saying that there are no dropable + * requests. In this case, the protocol specific code should drop + * the new request. This insures fairness. + * + * This may be used in conjunction with protocol specific queue + * congestion routines. + */ +struct socket * +sodropablereq(head) + register struct socket *head; +{ + register struct socket *so; + unsigned int i, j, qlen, m; + + static int rnd; + static long old_mono_secs; + static unsigned int cur_cnt, old_cnt; + + if ((i = (m = rtems_bsdnet_seconds_since_boot()) - old_mono_secs) != 0) { + old_mono_secs = m; + old_cnt = cur_cnt / i; + cur_cnt = 0; + } + + so = TAILQ_FIRST(&head->so_incomp); + if (!so) + return (so); + + qlen = head->so_incqlen; + if (++cur_cnt > qlen || old_cnt > qlen) { + rnd = (314159 * rnd + 66329) & 0xffff; + j = ((qlen + 1) * rnd) >> 16; + + while (j-- && so) + so = TAILQ_NEXT(so, so_list); + } + + return (so); +} + +/* + * When an attempt at a new connection is noted on a socket + * which accepts connections, sonewconn is called. If the + * connection is possible (subject to space constraints, etc.) + * then we allocate a new structure, propoerly linked into the + * data structure of the original socket, and return this. + * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED. + * + * Currently, sonewconn() is defined as sonewconn1() in socketvar.h + * to catch calls that are missing the (new) second parameter. + */ +struct socket * +sonewconn1(head, connstatus) + register struct socket *head; + int connstatus; +{ + register struct socket *so; + + if (head->so_qlen > 3 * head->so_qlimit / 2) + return ((struct socket *)0); + MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT); + if (so == NULL) + return ((struct socket *)0); + bzero((caddr_t)so, sizeof(*so)); + so->so_head = head; + so->so_type = head->so_type; + so->so_options = head->so_options &~ SO_ACCEPTCONN; + so->so_linger = head->so_linger; + so->so_state = head->so_state | SS_NOFDREF; + so->so_proto = head->so_proto; + so->so_timeo = head->so_timeo; + so->so_pgid = head->so_pgid; + so->so_uid = head->so_uid; + (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); + if (connstatus) { + TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); + so->so_state |= SS_COMP; + } else { + TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list); + so->so_state |= SS_INCOMP; + head->so_incqlen++; + } + head->so_qlen++; + if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0)) { + if (so->so_state & SS_COMP) { + TAILQ_REMOVE(&head->so_comp, so, so_list); + } else { + TAILQ_REMOVE(&head->so_incomp, so, so_list); + head->so_incqlen--; + } + head->so_qlen--; + (void) free((caddr_t)so, M_SOCKET); + return ((struct socket *)0); + } + if (connstatus) { + sorwakeup(head); + soconnwakeup(head); + so->so_state |= connstatus; + } + return (so); +} + +/* + * Socantsendmore indicates that no more data will be sent on the + * socket; it would normally be applied to a socket when the user + * informs the system that no more data is to be sent, by the protocol + * code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data + * will be received, and will normally be applied to the socket by a + * protocol when it detects that the peer will send no more data. + * Data queued for reading in the socket may yet be read. + */ + +void +socantsendmore(so) + struct socket *so; +{ + + so->so_state |= SS_CANTSENDMORE; + sowwakeup(so); +} + +void +socantrcvmore(so) + struct socket *so; +{ + + so->so_state |= SS_CANTRCVMORE; + sorwakeup(so); +} + +/* + * Socket buffer (struct sockbuf) utility routines. + * + * Each socket contains two socket buffers: one for sending data and + * one for receiving data. Each buffer contains a queue of mbufs, + * information about the number of mbufs and amount of data in the + * queue, and other fields allowing select() statements and notification + * on data availability to be implemented. + * + * Data stored in a socket buffer is maintained as a list of records. + * Each record is a list of mbufs chained together with the m_next + * field. Records are chained together with the m_nextpkt field. The upper + * level routine soreceive() expects the following conventions to be + * observed when placing information in the receive buffer: + * + * 1. If the protocol requires each message be preceded by the sender's + * name, then a record containing that name must be present before + * any associated data (mbuf's must be of type MT_SONAME). + * 2. If the protocol supports the exchange of ``access rights'' (really + * just additional data associated with the message), and there are + * ``rights'' to be received, then a record containing this data + * should be present (mbuf's must be of type MT_RIGHTS). + * 3. If a name or rights record exists, then it must be followed by + * a data record, perhaps of zero length. + * + * Before using a new socket structure it is first necessary to reserve + * buffer space to the socket, by calling sbreserve(). This should commit + * some of the available buffer space in the system buffer pool for the + * socket (currently, it does nothing but enforce limits). The space + * should be released by calling sbrelease() when the socket is destroyed. + */ + +int +soreserve(so, sndcc, rcvcc) + register struct socket *so; + u_long sndcc, rcvcc; +{ + + if (sbreserve(&so->so_snd, sndcc) == 0) + goto bad; + if (sbreserve(&so->so_rcv, rcvcc) == 0) + goto bad2; + if (so->so_rcv.sb_lowat == 0) + so->so_rcv.sb_lowat = 1; + if (so->so_snd.sb_lowat == 0) + so->so_snd.sb_lowat = MCLBYTES; + if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) + so->so_snd.sb_lowat = so->so_snd.sb_hiwat; + return (0); +bad2: + sbrelease(&so->so_snd); +bad: + return (ENOBUFS); +} + +/* + * Allot mbufs to a sockbuf. + * Attempt to scale mbmax so that mbcnt doesn't become limiting + * if buffering efficiency is near the normal case. + */ +int +sbreserve(sb, cc) + struct sockbuf *sb; + u_long cc; +{ + + if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES)) + return (0); + sb->sb_hiwat = cc; + sb->sb_mbmax = min(cc * sb_efficiency, sb_max); + if (sb->sb_lowat > sb->sb_hiwat) + sb->sb_lowat = sb->sb_hiwat; + return (1); +} + +/* + * Free mbufs held by a socket, and reserved mbuf space. + */ +void +sbrelease(sb) + struct sockbuf *sb; +{ + + sbflush(sb); + sb->sb_hiwat = sb->sb_mbmax = 0; +} + +/* + * Routines to add and remove + * data from an mbuf queue. + * + * The routines sbappend() or sbappendrecord() are normally called to + * append new mbufs to a socket buffer, after checking that adequate + * space is available, comparing the function sbspace() with the amount + * of data to be added. sbappendrecord() differs from sbappend() in + * that data supplied is treated as the beginning of a new record. + * To place a sender's address, optional access rights, and data in a + * socket receive buffer, sbappendaddr() should be used. To place + * access rights and data in a socket receive buffer, sbappendrights() + * should be used. In either case, the new data begins a new record. + * Note that unlike sbappend() and sbappendrecord(), these routines check + * for the caller that there will be enough space to store the data. + * Each fails if there is not enough space, or if it cannot find mbufs + * to store additional information in. + * + * Reliable protocols may use the socket send buffer to hold data + * awaiting acknowledgement. Data is normally copied from a socket + * send buffer in a protocol with m_copy for output to a peer, + * and then removing the data from the socket buffer with sbdrop() + * or sbdroprecord() when the data is acknowledged by the peer. + */ + +/* + * Append mbuf chain m to the last record in the + * socket buffer sb. The additional space associated + * the mbuf chain is recorded in sb. Empty mbufs are + * discarded and mbufs are compacted where possible. + */ +void +sbappend(sb, m) + struct sockbuf *sb; + struct mbuf *m; +{ + register struct mbuf *n; + + if (m == 0) + return; + n = sb->sb_mb; + if (n) { + while (n->m_nextpkt) + n = n->m_nextpkt; + do { + if (n->m_flags & M_EOR) { + sbappendrecord(sb, m); /* XXXXXX!!!! */ + return; + } + } while (n->m_next && (n = n->m_next)); + } + sbcompress(sb, m, n); +} + +#ifdef SOCKBUF_DEBUG +void +sbcheck(sb) + register struct sockbuf *sb; +{ + register struct mbuf *m; + register int len = 0, mbcnt = 0; + + for (m = sb->sb_mb; m; m = m->m_next) { + len += m->m_len; + mbcnt += MSIZE; + if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ + mbcnt += m->m_ext.ext_size; + if (m->m_nextpkt) + panic("sbcheck nextpkt"); + } + if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { + printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc, + mbcnt, sb->sb_mbcnt); + panic("sbcheck"); + } +} +#endif + +/* + * As above, except the mbuf chain + * begins a new record. + */ +void +sbappendrecord(sb, m0) + register struct sockbuf *sb; + register struct mbuf *m0; +{ + register struct mbuf *m; + + if (m0 == 0) + return; + m = sb->sb_mb; + if (m) + while (m->m_nextpkt) + m = m->m_nextpkt; + /* + * Put the first mbuf on the queue. + * Note this permits zero length records. + */ + sballoc(sb, m0); + if (m) + m->m_nextpkt = m0; + else + sb->sb_mb = m0; + m = m0->m_next; + m0->m_next = 0; + if (m && (m0->m_flags & M_EOR)) { + m0->m_flags &= ~M_EOR; + m->m_flags |= M_EOR; + } + sbcompress(sb, m, m0); +} + +/* + * As above except that OOB data + * is inserted at the beginning of the sockbuf, + * but after any other OOB data. + */ +void +sbinsertoob(sb, m0) + register struct sockbuf *sb; + register struct mbuf *m0; +{ + register struct mbuf *m; + register struct mbuf **mp; + + if (m0 == 0) + return; + for (mp = &sb->sb_mb; *mp ; mp = &((*mp)->m_nextpkt)) { + m = *mp; + again: + switch (m->m_type) { + + case MT_OOBDATA: + continue; /* WANT next train */ + + case MT_CONTROL: + m = m->m_next; + if (m) + goto again; /* inspect THIS train further */ + } + break; + } + /* + * Put the first mbuf on the queue. + * Note this permits zero length records. + */ + sballoc(sb, m0); + m0->m_nextpkt = *mp; + *mp = m0; + m = m0->m_next; + m0->m_next = 0; + if (m && (m0->m_flags & M_EOR)) { + m0->m_flags &= ~M_EOR; + m->m_flags |= M_EOR; + } + sbcompress(sb, m, m0); +} + +/* + * Append address and data, and optionally, control (ancillary) data + * to the receive queue of a socket. If present, + * m0 must include a packet header with total length. + * Returns 0 if no space in sockbuf or insufficient mbufs. + */ +int +sbappendaddr(sb, asa, m0, control) + register struct sockbuf *sb; + struct sockaddr *asa; + struct mbuf *m0, *control; +{ + register struct mbuf *m, *n; + int space = asa->sa_len; + +if (m0 && (m0->m_flags & M_PKTHDR) == 0) +panic("sbappendaddr"); + if (m0) + space += m0->m_pkthdr.len; + for (n = control; n; n = n->m_next) { + space += n->m_len; + if (n->m_next == 0) /* keep pointer to last control buf */ + break; + } + if (space > sbspace(sb)) + return (0); + if (asa->sa_len > MLEN) + return (0); + MGET(m, M_DONTWAIT, MT_SONAME); + if (m == 0) + return (0); + m->m_len = asa->sa_len; + bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); + if (n) + n->m_next = m0; /* concatenate data to control */ + else + control = m0; + m->m_next = control; + for (n = m; n; n = n->m_next) + sballoc(sb, n); + n = sb->sb_mb; + if (n) { + while (n->m_nextpkt) + n = n->m_nextpkt; + n->m_nextpkt = m; + } else + sb->sb_mb = m; + return (1); +} + +int +sbappendcontrol(sb, m0, control) + struct sockbuf *sb; + struct mbuf *control, *m0; +{ + register struct mbuf *m, *n; + int space = 0; + + if (control == 0) + panic("sbappendcontrol"); + for (m = control; ; m = m->m_next) { + space += m->m_len; + if (m->m_next == 0) + break; + } + n = m; /* save pointer to last control buffer */ + for (m = m0; m; m = m->m_next) + space += m->m_len; + if (space > sbspace(sb)) + return (0); + n->m_next = m0; /* concatenate data to control */ + for (m = control; m; m = m->m_next) + sballoc(sb, m); + n = sb->sb_mb; + if (n) { + while (n->m_nextpkt) + n = n->m_nextpkt; + n->m_nextpkt = control; + } else + sb->sb_mb = control; + return (1); +} + +/* + * Compress mbuf chain m into the socket + * buffer sb following mbuf n. If n + * is null, the buffer is presumed empty. + */ +void +sbcompress(sb, m, n) + register struct sockbuf *sb; + register struct mbuf *m, *n; +{ + register int eor = 0; + register struct mbuf *o; + + while (m) { + eor |= m->m_flags & M_EOR; + if (m->m_len == 0 && + (eor == 0 || + (((o = m->m_next) || (o = n)) && + o->m_type == m->m_type))) { + m = m_free(m); + continue; + } + if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && + (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && + n->m_type == m->m_type) { + bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, + (unsigned)m->m_len); + n->m_len += m->m_len; + sb->sb_cc += m->m_len; + m = m_free(m); + continue; + } + if (n) + n->m_next = m; + else + sb->sb_mb = m; + sballoc(sb, m); + n = m; + m->m_flags &= ~M_EOR; + m = m->m_next; + n->m_next = 0; + } + if (eor) { + if (n) + n->m_flags |= eor; + else + printf("semi-panic: sbcompress\n"); + } +} + +/* + * Free all mbufs in a sockbuf. + * Check that all resources are reclaimed. + */ +void +sbflush(sb) + register struct sockbuf *sb; +{ + + if (sb->sb_flags & SB_LOCK) + panic("sbflush"); + while (sb->sb_mbcnt) + sbdrop(sb, (int)sb->sb_cc); + if (sb->sb_cc || sb->sb_mb) + panic("sbflush 2"); +} + +/* + * Drop data from (the front of) a sockbuf. + */ +void +sbdrop(sb, len) + register struct sockbuf *sb; + register int len; +{ + register struct mbuf *m, *mn; + struct mbuf *next; + + next = (m = sb->sb_mb) ? m->m_nextpkt : 0; + while (len > 0) { + if (m == 0) { + if (next == 0) + panic("sbdrop"); + m = next; + next = m->m_nextpkt; + continue; + } + if (m->m_len > len) { + m->m_len -= len; + m->m_data += len; + sb->sb_cc -= len; + break; + } + len -= m->m_len; + sbfree(sb, m); + MFREE(m, mn); + m = mn; + } + while (m && m->m_len == 0) { + sbfree(sb, m); + MFREE(m, mn); + m = mn; + } + if (m) { + sb->sb_mb = m; + m->m_nextpkt = next; + } else + sb->sb_mb = next; +} + +/* + * Drop a record off the front of a sockbuf + * and move the next record to the front. + */ +void +sbdroprecord(sb) + register struct sockbuf *sb; +{ + register struct mbuf *m, *mn; + + m = sb->sb_mb; + if (m) { + sb->sb_mb = m->m_nextpkt; + do { + sbfree(sb, m); + MFREE(m, mn); + m = mn; + } while (m); + } +} + +/* + * Create a "control" mbuf containing the specified data + * with the specified type for presentation on a socket buffer. + */ +struct mbuf * +sbcreatecontrol(p, size, type, level) + caddr_t p; + register int size; + int type, level; +{ + register struct cmsghdr *cp; + struct mbuf *m; + + if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) + return ((struct mbuf *) NULL); + cp = mtod(m, struct cmsghdr *); + /* XXX check size? */ + (void)memcpy(CMSG_DATA(cp), p, size); + size += sizeof(*cp); + m->m_len = size; + cp->cmsg_len = size; + cp->cmsg_level = level; + cp->cmsg_type = type; + return (m); +} + +#ifdef PRU_OLDSTYLE +/* + * The following routines mediate between the old-style `pr_usrreq' + * protocol implementations and the new-style `struct pr_usrreqs' + * calling convention. + */ + +/* syntactic sugar */ +#define nomb (struct mbuf *)0 + +static int +old_abort(struct socket *so) +{ + return so->so_proto->pr_ousrreq(so, PRU_ABORT, nomb, nomb, nomb); +} + +static int +old_accept(struct socket *so, struct mbuf *nam) +{ + return so->so_proto->pr_ousrreq(so, PRU_ACCEPT, nomb, nam, nomb); +} + +static int +old_attach(struct socket *so, int proto) +{ + return so->so_proto->pr_ousrreq(so, PRU_ATTACH, nomb, + (struct mbuf *)proto, /* XXX */ + nomb); +} + +static int +old_bind(struct socket *so, struct mbuf *nam) +{ + return so->so_proto->pr_ousrreq(so, PRU_BIND, nomb, nam, nomb); +} + +static int +old_connect(struct socket *so, struct mbuf *nam) +{ + return so->so_proto->pr_ousrreq(so, PRU_CONNECT, nomb, nam, nomb); +} + +static int +old_connect2(struct socket *so1, struct socket *so2) +{ + return so1->so_proto->pr_ousrreq(so1, PRU_CONNECT2, nomb, + (struct mbuf *)so2, nomb); +} + +static int +old_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp) +{ + return so->so_proto->pr_ousrreq(so, PRU_CONTROL, (struct mbuf *)cmd, + (struct mbuf *)data, + (struct mbuf *)ifp); +} + +static int +old_detach(struct socket *so) +{ + return so->so_proto->pr_ousrreq(so, PRU_DETACH, nomb, nomb, nomb); +} + +static int +old_disconnect(struct socket *so) +{ + return so->so_proto->pr_ousrreq(so, PRU_DISCONNECT, nomb, nomb, nomb); +} + +static int +old_listen(struct socket *so) +{ + return so->so_proto->pr_ousrreq(so, PRU_LISTEN, nomb, nomb, nomb); +} + +static int +old_peeraddr(struct socket *so, struct mbuf *nam) +{ + return so->so_proto->pr_ousrreq(so, PRU_PEERADDR, nomb, nam, nomb); +} + +static int +old_rcvd(struct socket *so, int flags) +{ + return so->so_proto->pr_ousrreq(so, PRU_RCVD, nomb, + (struct mbuf *)flags, /* XXX */ + nomb); +} + +static int +old_rcvoob(struct socket *so, struct mbuf *m, int flags) +{ + return so->so_proto->pr_ousrreq(so, PRU_RCVOOB, m, + (struct mbuf *)flags, /* XXX */ + nomb); +} + +static int +old_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *addr, + struct mbuf *control) +{ + int req; + + if (flags & PRUS_OOB) { + req = PRU_SENDOOB; + } else if(flags & PRUS_EOF) { + req = PRU_SEND_EOF; + } else { + req = PRU_SEND; + } + return so->so_proto->pr_ousrreq(so, req, m, addr, control); +} + +static int +old_sense(struct socket *so, struct stat *sb) +{ + return so->so_proto->pr_ousrreq(so, PRU_SENSE, (struct mbuf *)sb, + nomb, nomb); +} + +static int +old_shutdown(struct socket *so) +{ + return so->so_proto->pr_ousrreq(so, PRU_SHUTDOWN, nomb, nomb, nomb); +} + +static int +old_sockaddr(struct socket *so, struct mbuf *nam) +{ + return so->so_proto->pr_ousrreq(so, PRU_SOCKADDR, nomb, nam, nomb); +} + +struct pr_usrreqs pru_oldstyle = { + old_abort, old_accept, old_attach, old_bind, old_connect, + old_connect2, old_control, old_detach, old_disconnect, + old_listen, old_peeraddr, old_rcvd, old_rcvoob, old_send, + old_sense, old_shutdown, old_sockaddr +}; + +#endif /* PRU_OLDSTYLE */ + +/* + * Some routines that return EOPNOTSUPP for entry points that are not + * supported by a protocol. Fill in as needed. + */ +int +pru_accept_notsupp(struct socket *so, struct mbuf *nam) +{ + return EOPNOTSUPP; +} + +int +pru_connect2_notsupp(struct socket *so1, struct socket *so2) +{ + return EOPNOTSUPP; +} + +int +pru_control_notsupp(struct socket *so, int cmd, caddr_t data, + struct ifnet *ifp) +{ + return EOPNOTSUPP; +} + +int +pru_listen_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + +int +pru_rcvd_notsupp(struct socket *so, int flags) +{ + return EOPNOTSUPP; +} + +int +pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags) +{ + return EOPNOTSUPP; +} + +/* + * This isn't really a ``null'' operation, but it's the default one + * and doesn't do anything destructive. + */ +int +pru_sense_null(struct socket *so, struct stat *sb) +{ + sb->st_blksize = so->so_snd.sb_hiwat; + return 0; +} + diff --git a/cpukit/libnetworking/lib/README b/cpukit/libnetworking/lib/README new file mode 100644 index 0000000000..787c24c012 --- /dev/null +++ b/cpukit/libnetworking/lib/README @@ -0,0 +1 @@ +Sources from application-level (as opposed to kernel-level) libraries. diff --git a/cpukit/libnetworking/lib/getprotoby.c b/cpukit/libnetworking/lib/getprotoby.c new file mode 100644 index 0000000000..b90c247a54 --- /dev/null +++ b/cpukit/libnetworking/lib/getprotoby.c @@ -0,0 +1,42 @@ +#include <netdb.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +static const struct protoent prototab[] = { + { "ip", NULL, IPPROTO_IP }, + { "icmp", NULL, IPPROTO_ICMP }, + { "tcp", NULL, IPPROTO_TCP }, + { "udp", NULL, IPPROTO_UDP }, + }; + +/* + * Dummy version of BSD getprotobyname() + */ +struct protoent * +getprotobyname (const char *name) +{ + int i; + + for (i = 0 ; i < (sizeof prototab / sizeof prototab[0]) ; i++) { + if (strcmp (name, prototab[i].p_name) == 0) + return &prototab[i]; + } + return NULL; +} + +/* + * Dummy version of BSD getprotobynumber() + */ +struct protoent * +getprotobynumber (int proto) +{ + int i; + + for (i = 0 ; i < (sizeof prototab / sizeof prototab[0]) ; i++) { + if (proto == prototab[i].p_proto) + return &prototab[i]; + } + return NULL; +} diff --git a/cpukit/libnetworking/lib/syslog.c b/cpukit/libnetworking/lib/syslog.c new file mode 100644 index 0000000000..7f468c81e6 --- /dev/null +++ b/cpukit/libnetworking/lib/syslog.c @@ -0,0 +1,187 @@ +/* + * RTEMS version of syslog and associated routines + * + * $Id$ + */ + +#include <rtems.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +static int LogStatus = LOG_CONS; +static const char *LogTag = "syslog"; +static int LogFacility = LOG_USER; +static int LogMask = 0xff; + +static int LogFd = -1; +static rtems_id LogSemaphore; +extern struct in_addr rtems_bsdnet_log_host_address; + +#define SYSLOG_PORT 514 + +void +syslog (int pri, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vsyslog (pri, fmt, ap); + va_end (ap); +} + +/* + * FIXME: Should cbuf be static? It could be if we put the mutex + * around the entire body of this routine. Then we wouldn't + * have to worry about blowing stacks with a local variable + * that large. Could make cbuf bigger, too. + */ +void +vsyslog (int pri, const char *fmt, va_list ap) +{ + int cnt; + char *cp; + char *msgp, cbuf[200]; + int sent; + + if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { + syslog (LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID, + "syslog: unknown facility/priority: %#x", pri); + pri &= LOG_PRIMASK|LOG_FACMASK; + } + + if (!LOG_MASK(LOG_PRI(pri)) & LogMask) + return; + + if ((pri & LOG_FACMASK) == 0) + pri |= LogFacility; + + cnt = sprintf (cbuf, "<%d>", pri); + cp = msgp = cbuf + cnt; + if (LogTag) { + const char *lp = LogTag; + while ((*cp = *lp++) != '\0') + cp++; + } + if (LogStatus & LOG_PID) { + rtems_id tid; + rtems_task_ident (RTEMS_SELF, 0, &tid); + cnt = sprintf (cp, "[%#lx]", (unsigned long)tid); + cp += cnt; + } + if (LogTag) { + *cp++ = ':'; + *cp++ = ' '; + } + cnt = vsprintf (cp, fmt, ap); + cnt += cp - cbuf; + if (cbuf[cnt-1] == '\n') + cbuf[--cnt] = '\0'; + + if (LogStatus & LOG_PERROR) + printf ("%s\n", cbuf); + + /* + * Grab the mutex + */ + sent = 0; + if ((rtems_bsdnet_log_host_address.s_addr != INADDR_ANY) + && (LogFd >= 0) + && (rtems_semaphore_obtain (LogSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT) == RTEMS_SUCCESSFUL)) { + /* + * Set the destination address/port + */ + struct sockaddr_in farAddress; + farAddress.sin_family = AF_INET; + farAddress.sin_port = htons (SYSLOG_PORT); + farAddress.sin_addr = rtems_bsdnet_log_host_address; + memset (farAddress.sin_zero, '\0', sizeof farAddress.sin_zero); + + /* + * Send the message + */ + if (sendto (LogFd, cbuf, cnt, 0, (struct sockaddr *)&farAddress, sizeof farAddress) >= 0) + sent = 1; + rtems_semaphore_release (LogSemaphore); + } + if (!sent && (LogStatus & LOG_CONS) && !(LogStatus & LOG_PERROR)) + printf ("%s\n", msgp); +} + +void +openlog (const char *ident, int logstat, int logfac) +{ + rtems_status_code sc; + struct sockaddr_in myAddress; + + if (ident != NULL) + LogTag = ident; + LogStatus = logstat; + if (logfac != 0 && (logfac & ~LOG_FACMASK) == 0) + LogFacility = logfac; + + /* + * Create the socket + */ + if ((LogFd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + printf ("Can't create syslog socket: %d\n", errno); + return; + } + + /* + * Bind socket to name + */ + myAddress.sin_family = AF_INET; + myAddress.sin_addr.s_addr = INADDR_ANY; + myAddress.sin_port = 0; + memset (myAddress.sin_zero, '\0', sizeof myAddress.sin_zero); + if (bind (LogFd, (struct sockaddr *)&myAddress, sizeof (myAddress)) < 0) { + close (LogFd); + LogFd = -1; + printf ("Can't bind syslog socket: %d\n", errno); + return; + } + + /* + * Create the mutex + */ + sc = rtems_semaphore_create (rtems_build_name('s', 'L', 'o', 'g'), + 1, + RTEMS_PRIORITY | + RTEMS_BINARY_SEMAPHORE | + RTEMS_INHERIT_PRIORITY | + RTEMS_NO_PRIORITY_CEILING | + RTEMS_LOCAL, + 0, + &LogSemaphore); + if (sc != RTEMS_SUCCESSFUL) { + printf ("Can't create syslog seamphore: %d\n", sc); + close (LogFd); + LogFd = -1; + } +} + +void +closelog(void) +{ + if (LogFd >= 0) { + close (LogFd); + LogFd = -1; + rtems_semaphore_delete (LogSemaphore); + } +} + +int +setlogmask (int pmask) +{ + int omask; + + omask = LogMask; + if (pmask != 0) + LogMask = pmask; + return (omask); +} diff --git a/cpukit/libnetworking/lib/tftpDriver.c b/cpukit/libnetworking/lib/tftpDriver.c new file mode 100644 index 0000000000..cf75623580 --- /dev/null +++ b/cpukit/libnetworking/lib/tftpDriver.c @@ -0,0 +1,609 @@ +/* + * Trivial File Transfer Protocol (RFC 1350) + * + * Transfer file to/from remote host + * + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + * + * $Id$ + */ + +#include <stdio.h> +#include <errno.h> +#include <malloc.h> +#include <string.h> +#include <unistd.h> +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/rtems_bsdnet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* + * Range of UDP ports to try + */ +#define UDP_PORT_BASE 3180 + +/* + * Pathname prefix + */ +#define TFTP_PATHNAME_PREFIX "/TFTP/" + +/* + * Default limits + */ +#define PACKET_REPLY_MILLISECONDS 6000 +#define OPEN_RETRY_LIMIT 10 +#define IO_RETRY_LIMIT 10 + +/* + * TFTP opcodes + */ +#define TFTP_OPCODE_RRQ 1 +#define TFTP_OPCODE_WRQ 2 +#define TFTP_OPCODE_DATA 3 +#define TFTP_OPCODE_ACK 4 +#define TFTP_OPCODE_ERROR 5 + +/* + * Largest data transfer + */ +#define TFTP_BUFSIZE 512 + +/* + * Packets transferred between machines + */ +union tftpPacket { + /* + * RRQ/WRQ packet + */ + struct tftpRWRQ { + rtems_unsigned16 opcode; + char filename_mode[TFTP_BUFSIZE]; + } tftpRWRQ; + + /* + * DATA packet + */ + struct tftpDATA { + rtems_unsigned16 opcode; + rtems_unsigned16 blocknum; + rtems_unsigned8 data[TFTP_BUFSIZE]; + } tftpDATA; + + /* + * ACK packet + */ + struct tftpACK { + rtems_unsigned16 opcode; + rtems_unsigned16 blocknum; + } tftpACK; + + /* + * ERROR packet + */ + struct tftpERROR { + rtems_unsigned16 opcode; + rtems_unsigned16 errorCode; + char errorMessage[TFTP_BUFSIZE]; + } tftpERROR; +}; + +/* + * State of each TFTP stream + */ +struct tftpStream { + /* + * Buffer for storing most recently-received packet + */ + union tftpPacket pkbuf; + + /* + * Last block number received + */ + rtems_unsigned16 blocknum; + + /* + * Data transfer socket + */ + int socket; + struct sockaddr_in myAddress; + struct sockaddr_in farAddress; + + /* + * Indices into buffer + */ + int nleft; + int nused; + + /* + * Flags + */ + int firstReply; + int eof; +}; + +/* + * Number of streams open at the same time + */ +static rtems_id tftp_mutex; +static int nStreams; +static struct tftpStream ** volatile tftpStreams; + +/* + * Initialize the TFTP driver + */ +rtems_device_driver rtems_tftp_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + rtems_status_code sc; + + sc = rtems_semaphore_create (rtems_build_name('T', 'F', 'T', 'P'), + 1, + RTEMS_FIFO | + RTEMS_BINARY_SEMAPHORE | + RTEMS_NO_INHERIT_PRIORITY | + RTEMS_NO_PRIORITY_CEILING | + RTEMS_LOCAL, + 0, + &tftp_mutex); + if (sc != RTEMS_SUCCESSFUL) + return sc; + rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor); + return RTEMS_SUCCESSFUL; +} + +/* + * Set error message + * This RTEMS/UNIX error mapping needs to be fixed! + */ +static void +tftpSetErrno (struct tftpStream *tp) +{ + unsigned int tftpError; + static const int errorMap[] = { + 0, + ENOENT, + EPERM, + ENOSPC, + EINVAL, + ENXIO, + EEXIST, + ESRCH, + 0, + }; + + tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode); + if (tftpError < (sizeof errorMap / sizeof errorMap[0])) + errno = errorMap[tftpError]; + else + errno = 1000 + tftpError; +} + +/* + * Send a message to make the other end shut up + */ +static void +sendStifle (struct tftpStream *tp, struct sockaddr_in *to) +{ + int len; + + /* + * Create the error packet (Unknown transfer ID). + */ + tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR); + tp->pkbuf.tftpERROR.errorCode = htons (5); + len = sizeof tp->pkbuf.tftpERROR.opcode + + sizeof tp->pkbuf.tftpERROR.errorCode + 1; + len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY"); + + /* + * Send it + */ + sendto (tp->socket, (char *)&tp->pkbuf, len, 0, + (struct sockaddr *)to, sizeof *to); +} + +/* + * Wait for a data packet + */ +static int +getPacket (struct tftpStream *tp) +{ + int len; + struct timeval tv; + + tv.tv_sec = 6; + tv.tv_usec = 0; + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); + for (;;) { + union { + struct sockaddr s; + struct sockaddr_in i; + } from; + int fromlen = sizeof from; + len = recvfrom (tp->socket, (char *)&tp->pkbuf, + sizeof tp->pkbuf, 0, + &from.s, &fromlen); + if (len < 0) + break; + if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) { + if (tp->firstReply) { + tp->firstReply = 0; + tp->farAddress.sin_port = from.i.sin_port; + } + if (tp->farAddress.sin_port == from.i.sin_port) + break; + } + + /* + * Packet is from someone with whom we are + * not interested. Tell them to go away. + */ + sendStifle (tp, &from.i); + } + tv.tv_sec = 0; + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); + return len; +} + +/* + * Send an acknowledgement + */ +static int +sendAck (struct tftpStream *tp) +{ + /* + * Create the acknowledgement + */ + tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK); + tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum); + + /* + * Send it + */ + if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0, + (struct sockaddr *)&tp->farAddress, + sizeof tp->farAddress) < 0) + return errno; + return 0; +} + +/* + * Release a stream and clear the pointer to it + */ +static void +releaseStream (int s) +{ + rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + free (tftpStreams[s]); + tftpStreams[s] = NULL; + rtems_semaphore_release (tftp_mutex); +} + +/* + * Open a TFTP stream + */ +rtems_device_driver rtems_tftp_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + rtems_libio_open_close_args_t *ap = pargp; + struct tftpStream *tp; + int retryCount; + rtems_unsigned32 farAddress; + int s; + int len; + char *cp1, *cp2; + char *remoteFilename; + rtems_interval now; + rtems_status_code sc; + + /* + * Read-only for now + */ + if (ap->flags & LIBIO_FLAGS_WRITE) + return RTEMS_NOT_IMPLEMENTED; + + /* + * Pick apart the name into a host:pathname pair + */ + if (strlen (ap->iop->pathname) <= strlen (TFTP_PATHNAME_PREFIX)) + return RTEMS_INVALID_NAME; + cp2 = ap->iop->pathname + strlen (TFTP_PATHNAME_PREFIX); + if (*cp2 == '/') { + farAddress = rtems_bsdnet_bootp_server_address.s_addr; + } + else { + char *hostname; + + cp1 = cp2; + while (*cp2 != '/') { + if (*cp2 == '\0') + return RTEMS_INVALID_NAME; + cp2++; + } + len = cp2 - cp1; + hostname = malloc (len + 1); + if (hostname == NULL) + return RTEMS_NO_MEMORY; + strncpy (hostname, cp1, len); + hostname[len] = '\0'; + farAddress = inet_addr (hostname); + free (hostname); + } + if ((farAddress == 0) || (farAddress == ~0)) + return RTEMS_INVALID_NAME; + if (*++cp2 == '\0') + return RTEMS_INVALID_NAME; + remoteFilename = cp2; + if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10)) + return RTEMS_INVALID_NAME; + + /* + * Find a free stream + */ + sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + return sc; + for (s = 0 ; s < nStreams ; s++) { + if (tftpStreams[s] == NULL) + break; + } + if (s == nStreams) { + /* + * Reallocate stream pointers + * Guard against the case where realloc() returns NULL. + */ + struct tftpStream **np; + + np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams); + if (np == NULL) { + rtems_semaphore_release (tftp_mutex); + return RTEMS_NO_MEMORY; + } + tftpStreams = np; + } + tp = tftpStreams[s] = malloc (sizeof (struct tftpStream)); + rtems_semaphore_release (tftp_mutex); + if (tp == NULL) + return RTEMS_NO_MEMORY; + ap->iop->data0 = s; + ap->iop->data1 = tp; + + /* + * Create the socket + */ + if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + releaseStream (s); + return RTEMS_TOO_MANY; + } + + /* + * Bind the socket to a local address + */ + retryCount = 0; + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + for (;;) { + int try = (now + retryCount) % 10; + + tp->myAddress.sin_family = AF_INET; + tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor); + tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0) + break; + if (++retryCount == 10) { + close (tp->socket); + releaseStream (minor); + return RTEMS_RESOURCE_IN_USE; + } + } + + /* + * Set the UDP destination to the TFTP server + * port on the remote machine. + */ + tp->farAddress.sin_family = AF_INET; + tp->farAddress.sin_addr.s_addr = farAddress; + tp->farAddress.sin_port = htons (69); + + /* + * Start the transfer + */ + tp->firstReply = 1; + for (;;) { + /* + * Create the request + */ + tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ); + cp1 = tp->pkbuf.tftpRWRQ.filename_mode; + cp2 = remoteFilename; + while ((*cp1++ = *cp2++) != '\0') + continue; + cp2 = "octet"; + while ((*cp1++ = *cp2++) != '\0') + continue; + len = cp1 - (char *)&tp->pkbuf.tftpRWRQ; + + /* + * Send the request + */ + if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0, + (struct sockaddr *)&tp->farAddress, + sizeof tp->farAddress) < 0) { + close (tp->socket); + releaseStream (minor); + return RTEMS_UNSATISFIED; + } + + /* + * Get reply + */ + len = getPacket (tp); + if (len >= (int) sizeof tp->pkbuf.tftpACK) { + int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); + if ((opcode == TFTP_OPCODE_DATA) + && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) { + tp->nused = 0; + tp->blocknum = 1; + tp->nleft = len - 2 * sizeof (rtems_unsigned16); + tp->eof = (tp->nleft < TFTP_BUFSIZE); + if (sendAck (tp) != 0) { + close (tp->socket); + releaseStream (minor); + return RTEMS_UNSATISFIED; + } + break; + } + if (opcode == TFTP_OPCODE_ERROR) { + tftpSetErrno (tp); + close (tp->socket); + releaseStream (ap->iop->data0); + return RTEMS_INTERNAL_ERROR; + } + } + + /* + * Keep trying + */ + if (++retryCount >= OPEN_RETRY_LIMIT) { + close (tp->socket); + releaseStream (minor); + return RTEMS_UNSATISFIED; + } + } + return RTEMS_SUCCESSFUL; +} + +/* + * Read from a TFTP stream + */ +rtems_device_driver rtems_tftp_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + rtems_libio_rw_args_t *ap = pargp; + char *bp; + struct tftpStream *tp; + int retryCount; + int nwant; + + tp = ap->iop->data1; + + /* + * Read till user request is satisfied or EOF is reached + */ + bp = ap->buffer; + nwant = ap->count; + while (nwant) { + if (tp->nleft) { + int count; + if (nwant < tp->nleft) + count = nwant; + else + count = tp->nleft; + memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count); + tp->nused += count; + tp->nleft -= count; + bp += count; + nwant -= count; + if (nwant == 0) + break; + } + if (tp->eof) + break; + + /* + * Wait for the next packet + */ + retryCount = 0; + for (;;) { + int len = getPacket (tp); + if (len >= (int)sizeof tp->pkbuf.tftpACK) { + int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); + rtems_unsigned16 nextBlock = tp->blocknum + 1; + if ((opcode == TFTP_OPCODE_DATA) + && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) { + tp->nused = 0; + tp->nleft = len - 2 * sizeof (rtems_unsigned16); + tp->eof = (tp->nleft < TFTP_BUFSIZE); + tp->blocknum++; + if (sendAck (tp) != 0) + return RTEMS_IO_ERROR; + break; + } + if (opcode == TFTP_OPCODE_ERROR) { + tftpSetErrno (tp); + return RTEMS_INTERNAL_ERROR; + } + } + + /* + * Keep trying? + */ + if (++retryCount == IO_RETRY_LIMIT) + return RTEMS_IO_ERROR; + if (sendAck (tp) != 0) + return RTEMS_IO_ERROR; + } + } + ap->bytes_moved = ap->count - nwant; + return RTEMS_SUCCESSFUL; +} + +/* + * Close a TFTP stream + */ +rtems_device_driver rtems_tftp_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + rtems_libio_open_close_args_t *ap = pargp; + struct tftpStream *tp = ap->iop->data1;; + + if (!tp->eof && !tp->firstReply) { + /* + * Tell the other end to stop + */ + rtems_interval ticksPerSecond; + sendStifle (tp, &tp->farAddress); + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond); + rtems_task_wake_after (1 + ticksPerSecond / 10); + } + close (tp->socket); + releaseStream (ap->iop->data0); + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver rtems_tftp_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + return RTEMS_NOT_CONFIGURED; +} + +rtems_device_driver rtems_tftp_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + return RTEMS_NOT_CONFIGURED; +} diff --git a/cpukit/libnetworking/libc/addr2ascii.3 b/cpukit/libnetworking/libc/addr2ascii.3 new file mode 100644 index 0000000000..21ebe2a22f --- /dev/null +++ b/cpukit/libnetworking/libc/addr2ascii.3 @@ -0,0 +1,216 @@ +.\" +.\" Copyright 1996 Massachusetts Institute of Technology +.\" +.\" Permission to use, copy, modify, and distribute this software and +.\" its documentation for any purpose and without fee is hereby +.\" granted, provided that both the above copyright notice and this +.\" permission notice appear in all copies, that both the above +.\" copyright notice and this permission notice appear in all +.\" supporting documentation, and that the name of M.I.T. not be used +.\" in advertising or publicity pertaining to distribution of the +.\" software without specific, written prior permission. M.I.T. makes +.\" no representations about the suitability of this software for any +.\" purpose. It is provided "as is" without express or implied +.\" warranty. +.\" +.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS +.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT +.\" SHALL M.I.T. 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. +.\" +.\" $ANA: addr2ascii.3,v 1.1 1996/06/13 18:41:46 wollman Exp $ +.\" +.Dd June 13, 1996 +.Dt ADDR2ASCII 3 +.Os +.Sh NAME +.Nm addr2ascii , +.Nm ascii2addr +.Nd Generic address formatting routines +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <netinet/in.h> +.Fd #include <arpa/inet.h> +.Ft "char *" +.Fn addr2ascii "int af" "const void *addrp" "int len" "char *buf" +.Ft int +.Fn ascii2addr "int af" "const char *ascii" "void *result" +.Sh DESCRIPTION +The routines +.Fn addr2ascii +and +.Fn ascii2addr +are used to convert network addresses between binary form and a +printable form appropriate to the address family. Both functions take +an +.Fa af +argument, specifying the address family to be used in the conversion +process. +(Currently, only the +.Dv AF_INET +and +.Dv AF_LINK +address families are supported.) +.Pp +The +.Fn addr2ascii +function +is used to convert binary, network-format addresses into printable +form. In addition to +.Fa af , +there are three other arguments. The +.Fa addrp +argument is a pointer to the network address to be converted. +The +.Fa len +argument is the length of the address. The +.Fa buf +argument is an optional pointer to a caller-allocated buffer to hold +the result; if a null pointer is passed, +.Fn addr2ascii +uses a statically-allocated buffer. +.Pp +The +.Fn ascii2addr +function performs the inverse operation to +.Fn addr2ascii . +In addition to +.Fa af , +it takes two parameters, +.Fa ascii +and +.Fa result . +The +.Fa ascii +parameter is a pointer to the string which is to be converted into +binary. The +.Fa result +parameter is a pointer to an appropriate network address structure for +the specified family. +.Pp +The following gives the appropriate structure to use for binary +addresses in the specified family: +.Pp +.Bl -tag -width AF_INETxxxx -compact +.It Dv AF_INET +.Li struct in_addr +.Pq in Aq Pa netinet/in.h +.It Dv AF_LINK +.Li struct sockaddr_dl +.Pq in Aq Pa net/if_dl.h +.\" .It Dv AF_INET6 +.\" .Li struct in6_addr +.\" .Pq in Aq Pa netinet6/in6.h +.El +.Sh RETURN VALUES +The +.Fn addr2ascii +function returns the address of the buffer it was passed, or a static +buffer if the a null pointer was passed; on failure, it returns a null +pointer. +The +.Fn ascii2addr +function returns the length of the binary address in bytes, or -1 on +failure. +.Sh EXAMPLES +The +.Xr inet 3 +functions +.Fn inet_ntoa +and +.Fn inet_aton +could be implemented thusly: +.Bd -literal -offset indent +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +char * +inet_ntoa(struct in_addr addr) +{ + return addr2ascii(AF_INET, &addr, sizeof addr, 0); +} + +int +inet_aton(const char *ascii, struct in_addr *addr) +{ + return (ascii2addr(AF_INET, ascii, addr) + == sizeof(*addr)); +} +.Ed +.Pp +In actuality, this cannot be done because +.Fn addr2ascii +and +.Fn ascii2addr +are implemented in terms of the +.Xr inet 3 +functions, rather than the other way around. +.Sh ERRORS +When a failure is returned, +.Li errno +is set to one of the following values: +.Bl -tag -width [EPROTONOSUPPORT] +.It Bq Er ENAMETOOLONG +The +.Fn addr2ascii +routine was passed a +.Fa len +parameter which was inappropriate for the address family given by +.Fa af . +.It Bq Er EPROTONOSUPPORT +Either routine was passed an +.Fa af +parameter other than +.Dv AF_INET +or +.Dv AF_LINK . +.It Bq Er EINVAL +The string passed to +.Fn ascii2addr +was improperly formatted for address family +.Fa af . +.El +.Sh SEE ALSO +.Xr inet 3 , +.Xr linkaddr 3 , +.Xr inet 4 +.Sh HISTORY +An interface close to this one was originally suggested by Craig +Partridge. This particular interface originally appeared in the +.Tn INRIA +.Tn IPv6 +implementation. +.Sh AUTHORS +Code and documentation by +.An Garrett A. Wollman , +MIT Laboratory for Computer Science. +.Sh BUGS +The original implementations supported IPv6. This support should +eventually be resurrected. The +.Tn NRL +implementation also included support for the +.Dv AF_ISO +and +.Dv AF_NS +address families. +.Pp +The genericity of this interface is somewhat questionable. A truly +generic interface would provide a means for determining the length of +the buffer to be used so that it could be dynamically allocated, and +would always require a +.Dq Li "struct sockaddr" +to hold the binary address. Unfortunately, this is incompatible with existing +practice. This limitation means that a routine for printing network +addresses from arbitrary address families must still have internal +knowledge of the maximum buffer length needed and the appropriate part +of the address to use as the binary address. diff --git a/cpukit/libnetworking/libc/addr2ascii.c b/cpukit/libnetworking/libc/addr2ascii.c new file mode 100644 index 0000000000..5bee3ea40e --- /dev/null +++ b/cpukit/libnetworking/libc/addr2ascii.c @@ -0,0 +1,92 @@ +/* + * Copyright 1996 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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. + * + * $ANA: addr2ascii.c,v 1.1 1996/06/13 18:41:46 wollman Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <errno.h> +#include <string.h> + +#include <net/if_dl.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/*- + * Convert a network address from binary to printable numeric format. + * This API is copied from INRIA's IPv6 implementation, but it is a + * bit bogus in two ways: + * + * 1) There is no value in passing both an address family and + * an address length; either one should imply the other, + * or we should be passing sockaddrs instead. + * 2) There should by contrast be /added/ a length for the buffer + * that we pass in, so that programmers are spared the need to + * manually calculate (read: ``guess'') the maximum length. + * + * Flash: the API is also the same in the NRL implementation, and seems to + * be some sort of standard, so we appear to be stuck with both the bad + * naming and the poor choice of arguments. + */ +char * +addr2ascii(af, addrp, len, buf) + int af; + const void *addrp; + int len; /* should be size_t XXX */ + char *buf; /* XXX should pass length of buffer */ +{ + static char staticbuf[64]; /* 64 for AF_LINK > 16 for AF_INET */ + + if (!buf) + buf = staticbuf; + + switch(af) { + case AF_INET: + if (len != sizeof(struct in_addr)) { + errno = ENAMETOOLONG; + return 0; + } + strcpy(buf, inet_ntoa(*(const struct in_addr *)addrp)); + break; + + case AF_LINK: + if (len != sizeof(struct sockaddr_dl)) { + errno = ENAMETOOLONG; + return 0; + } + strcpy(buf, link_ntoa((const struct sockaddr_dl *)addrp)); + break; + + default: + errno = EPROTONOSUPPORT; + return 0; + } + return buf; +} diff --git a/cpukit/libnetworking/libc/ascii2addr.c b/cpukit/libnetworking/libc/ascii2addr.c new file mode 100644 index 0000000000..0b5bab427f --- /dev/null +++ b/cpukit/libnetworking/libc/ascii2addr.c @@ -0,0 +1,72 @@ +/* + * Copyright 1996 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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. + * + * $ANA: ascii2addr.c,v 1.2 1996/06/13 18:46:02 wollman Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <errno.h> +#include <string.h> + +#include <net/if_dl.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +int +ascii2addr(af, ascii, result) + int af; + const char *ascii; + void *result; +{ + struct in_addr *ina; + char strbuf[4*sizeof("123")]; /* long enough for V4 only */ + + switch(af) { + case AF_INET: + ina = result; + strbuf[0] = '\0'; + strncat(strbuf, ascii, (sizeof strbuf)-1); + if (inet_aton(strbuf, ina)) + return sizeof(struct in_addr); + errno = EINVAL; + break; + + case AF_LINK: + link_addr(ascii, result); + /* oops... no way to detect failure */ + return sizeof(struct sockaddr_dl); + + default: + errno = EPROTONOSUPPORT; + break; + } + + return -1; +} diff --git a/cpukit/libnetworking/libc/base64.c b/cpukit/libnetworking/libc/base64.c new file mode 100644 index 0000000000..c9518ca730 --- /dev/null +++ b/cpukit/libnetworking/libc/base64.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static char rcsid[] = "$Id$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) { + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + size_t i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/cpukit/libnetworking/libc/byteorder.3 b/cpukit/libnetworking/libc/byteorder.3 new file mode 100644 index 0000000000..666521bec3 --- /dev/null +++ b/cpukit/libnetworking/libc/byteorder.3 @@ -0,0 +1,76 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" @(#)byteorder.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt BYTEORDER 3 +.Os BSD 4.2 +.Sh NAME +.Nm htonl , +.Nm htons , +.Nm ntohl , +.Nm ntohs +.Nd convert values between host and network byte order +.Sh SYNOPSIS +.Fd #include <sys/param.h> +.Ft u_long +.Fn htonl "u_long hostlong" +.Ft u_short +.Fn htons "u_short hostshort" +.Ft u_long +.Fn ntohl "u_long netlong" +.Ft u_short +.Fn ntohs "u_short netshort" +.Sh DESCRIPTION +These routines convert 16 and 32 bit quantities between network +byte order and host byte order. +On machines which have a byte order which is the same as the network +order, routines are defined as null macros. +.Pp +These routines are most often used in conjunction with Internet +addresses and ports as returned by +.Xr gethostbyname 3 +and +.Xr getservent 3 . +.Sh SEE ALSO +.Xr gethostbyname 3 , +.Xr getservent 3 +.Sh HISTORY +The +.Nm byteorder +functions appeared in +.Bx 4.2 . +.Sh BUGS +On the +.Tn VAX +bytes are handled backwards from most everyone else in +the world. This is not expected to be fixed in the near future. diff --git a/cpukit/libnetworking/libc/ether_addr.c b/cpukit/libnetworking/libc/ether_addr.c new file mode 100644 index 0000000000..9b7a9abf44 --- /dev/null +++ b/cpukit/libnetworking/libc/ether_addr.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1995 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 REGENTS 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. + * + * ethernet address conversion and lookup routines + * + * Written by Bill Paul <wpaul@ctr.columbia.edu> + * Center for Telecommunications Research + * Columbia University, New York City + * + * $Id$ + */ + + +#include <stdio.h> +#include <paths.h> +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <net/ethernet.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +#ifndef _PATH_ETHERS +#define _PATH_ETHERS "/etc/ethers" +#endif + +/* + * Parse a string of text containing an ethernet address and hostname + * and separate it into its component parts. + */ +int ether_line(l, e, hostname) + char *l; + struct ether_addr *e; + char *hostname; +{ + int i, o[6]; + + i = sscanf(l, "%x:%x:%x:%x:%x:%x %s", &o[0], &o[1], &o[2], + &o[3], &o[4], &o[5], + hostname); + if (i != 7) + return (i); + + for (i=0; i<6; i++) + e->octet[i] = o[i]; + return (0); +} + +/* + * Convert an ASCII representation of an ethernet address to + * binary form. + */ +struct ether_addr *ether_aton(a) + char *a; +{ + int i; + static struct ether_addr o; + unsigned int o0, o1, o2, o3, o4, o5; + + i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); + + if (i != 6) + return (NULL); + + o.octet[0]=o0; + o.octet[1]=o1; + o.octet[2]=o2; + o.octet[3]=o3; + o.octet[4]=o4; + o.octet[5]=o5; + + return ((struct ether_addr *)&o); +} + +/* + * Convert a binary representation of an ethernet address to + * an ASCII string. + */ +char *ether_ntoa(n) + struct ether_addr *n; +{ + int i; + static char a[18]; + + i = sprintf(a,"%x:%x:%x:%x:%x:%x",n->octet[0],n->octet[1],n->octet[2], + n->octet[3],n->octet[4],n->octet[5]); + if (i < 11) + return (NULL); + return ((char *)&a); +} + +/* + * Map an ethernet address to a hostname. Use either /etc/ethers or + * NIS/YP. + */ + +int ether_ntohost(hostname, e) + char *hostname; + struct ether_addr *e; +{ + FILE *fp; + char buf[BUFSIZ + 2]; + struct ether_addr local_ether; + char local_host[MAXHOSTNAMELEN]; +#ifdef YP + char *result; + int resultlen; + char *ether_a; + char *yp_domain; +#endif + if ((fp = fopen(_PATH_ETHERS, "r")) == NULL) + return (1); + + while (fgets(buf,BUFSIZ,fp)) { + if (buf[0] == '#') + continue; +#ifdef YP + if (buf[0] == '+') { + if (yp_get_default_domain(&yp_domain)) + continue; + ether_a = ether_ntoa(e); + if (yp_match(yp_domain, "ethers.byaddr", ether_a, + strlen(ether_a), &result, &resultlen)) { + continue; + } + strncpy(buf, result, resultlen); + buf[resultlen] = '\0'; + free(result); + } +#endif + if (!ether_line(buf, &local_ether, local_host)) { + if (!bcmp((char *)&local_ether.octet[0], + (char *)&e->octet[0], 6)) { + /* We have a match */ + strcpy(hostname, local_host); + fclose(fp); + return(0); + } + } + } + fclose(fp); + return (1); +} + +/* + * Map a hostname to an ethernet address using /etc/ethers or + * NIS/YP. + */ +int ether_hostton(hostname, e) + char *hostname; + struct ether_addr *e; +{ + FILE *fp; + char buf[BUFSIZ + 2]; + struct ether_addr local_ether; + char local_host[MAXHOSTNAMELEN]; +#ifdef YP + char *result; + int resultlen; + char *yp_domain; +#endif + if ((fp = fopen(_PATH_ETHERS, "r")) == NULL) + return (1); + + while (fgets(buf,BUFSIZ,fp)) { + if (buf[0] == '#') + continue; +#ifdef YP + if (buf[0] == '+') { + if (yp_get_default_domain(&yp_domain)) + continue; + if (yp_match(yp_domain, "ethers.byname", hostname, + strlen(hostname), &result, &resultlen)) { + continue; + } + strncpy(buf, result, resultlen); + buf[resultlen] = '\0'; + free(result); + } +#endif + if (!ether_line(buf, &local_ether, local_host)) { + if (!strcmp(hostname, local_host)) { + /* We have a match */ + bcopy((char *)&local_ether.octet[0], + (char *)&e->octet[0], 6); + fclose(fp); + return(0); + } + } + } + fclose(fp); + return (1); +} diff --git a/cpukit/libnetworking/libc/ethers.3 b/cpukit/libnetworking/libc/ethers.3 new file mode 100644 index 0000000000..afea48320a --- /dev/null +++ b/cpukit/libnetworking/libc/ethers.3 @@ -0,0 +1,193 @@ +.\" Copyright (c) 1995 +.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 REGENTS 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. +.\" +.\" $Id$ +.\" +.Dd April 12, 1995 +.Dt ETHERS 3 +.Os FreeBSD 2.1 +.Sh NAME +.Nm ethers , +.Nm ether_line , +.Nm ether_aton , +.Nm ether_ntoa , +.Nm ether_ntohost , +.Nm ether_hostton +.Nd Ethernet address conversion and lookup routines +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <sys/socket.h> +.Fd #include <net/ethernet.h> +.Ft int +.Fn ether_line "char *l" "struct ether_addr *e" "char *hostname" +.Ft struct ether_addr * +.Fn ether_aton "char *a" +.Ft char * +.Fn ether_ntoa "struct ether_addr *n" +.Ft int +.Fn ether_ntohost "char *hostname" "struct ether_addr *e" +.Ft int +.Fn ether_hostton "char *hostname" "struct ether_addr *e" +.Sh DESCRIPTION +These functions operate on ethernet addresses using an +.Ar ether_addr +structure, which is defined in the header file +.Aq Pa netinet/if_ether.h : +.Bd -literal -offset indent +/* + * The number of bytes in an ethernet (MAC) address. + */ +#define ETHER_ADDR_LEN 6 + +/* + * Structure of a 48-bit Ethernet address. + */ +struct ether_addr { + u_char octet[ETHER_ADDR_LEN]; +}; +.Ed +.Pp +The function +.Fn ether_line +scans +.Ar l , +an +.Tn ASCII +string in +.Xr ethers 5 +format and sets +.Ar e +to the ethernet address specified in the string and +.Ar h +to the hostname. This function is used to parse lines from +.Pa /etc/ethers +into their component parts. +.Pp +The +.Fn ether_aton +function converts an +.Tn ASCII +representation of an ethernet address into an +.Ar ether_addr +structure. Likewise, +.Fn ether_ntoa +converts an ethernet address specified as an +.Ar ether_addr +structure into an +.Tn ASCII +string. +.Pp +The +.Fn ether_ntohost +and +.Fn ether_hostton +functions map ethernet addresses to their corresponding hostnames +as specified in the +.Pa /etc/ethers +database. +.Fn ether_ntohost +converts from ethernet address to hostname, and +.Fn ether_hostton +converts from hostname to ethernet address. +.Sh RETURN VALUES +.Fn ether_line +returns zero on success and non-zero if it was unable to parse +any part of the supplied line +.Ar l . +It returns the extracted ethernet address in the supplied +.Ar ether_addr +structure +.Ar e +and the hostname in the supplied string +.Ar h . +.Pp +On success, +.Fn ether_ntoa +returns a pointer to a string containing an +.Tn ASCII +representation of an ethernet address. If it is unable to convert +the supplied +.Ar ether_addr +structure, it returns a +.Dv NULL +pointer. Likewise, +.Fn ether_aton +returns a pointer to an +.Ar ether_addr +structure on success and a +.Dv NULL +pointer on failure. +.Pp +The +.Fn ether_ntohost +and +.Fn ether_hostton +functions both return zero on success or non-zero if they were +unable to find a match in the +.Pa /etc/ethers +database. +.Sh NOTES +The user must insure that the hostname strings passed to the +the +.Fn ether_line , +.Fn ether_ntohost +and +.Fn ether_hostton +functions are large enough to contain the returned hostnames. +.Sh NIS INTERACTION +If the +.Pa /etc/ethers +contains a line with a single + in it, the +.Fn ether_ntohost +and +.Fn ether_hostton +functions will attempt to consult the NIS +.Pa ethers.byname +and +.Pa ethers.byaddr +maps in addition to the data in the +.Pa /etc/ethers +file. +.Sh SEE ALSO +.Xr yp 4 , +.Xr ethers 5 +.Sh BUGS +.Pp +The +.Fn ether_aton +and +.Fn ether_ntoa +functions returns values that are stored in static memory areas +which may be overwritten the next time they are called. +.Sh HISTORY +This particular implementation of the +.Nm ethers +library functions were written for and first appeared in +.Fx 2.1 . diff --git a/cpukit/libnetworking/libc/gethostbydns.c b/cpukit/libnetworking/libc/gethostbydns.c new file mode 100644 index 0000000000..ceb7088160 --- /dev/null +++ b/cpukit/libnetworking/libc/gethostbydns.c @@ -0,0 +1,773 @@ +/* + * ++Copyright++ 1985, 1988, 1993 + * - + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; +static char fromrcsid[] = "From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <netdb.h> +#include <resolv.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> + +#include "res_config.h" + +#define SPRINTF(x) ((size_t)sprintf x) + +#define MAXALIASES 35 +#define MAXADDRS 35 + +static const char AskedForGot[] = + "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; + +static char *h_addr_ptrs[MAXADDRS + 1]; + +static struct hostent host; +static char *host_aliases[MAXALIASES]; +static char hostbuf[8*1024]; +static u_char host_addr[16]; /* IPv4 or IPv6 */ + +#ifdef RESOLVSORT +static void addrsort __P((char **, int)); +#endif + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +typedef union { + int32_t al; + char ac; +} align; + +extern int h_errno; +int _dns_ttl_; + +#ifdef DEBUG +static void +dprintf(msg, num) + char *msg; + int num; +{ + if (_res.options & RES_DEBUG) { + int save = errno; + + printf(msg, num); + errno = save; + } +} +#else +# define dprintf(msg, num) /*nada*/ +#endif + +#define BOUNDED_INCR(x) \ + do { \ + cp += x; \ + if (cp > eom) { \ + h_errno = NO_RECOVERY; \ + return (NULL); \ + } \ + } while (0) + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eom) { \ + h_errno = NO_RECOVERY; \ + return (NULL); \ + } \ + } while (0) + +static struct hostent * +gethostanswer(answer, anslen, qname, qtype) + const querybuf *answer; + int anslen; + const char *qname; + int qtype; +{ + register const HEADER *hp; + register const u_char *cp; + register int n; + const u_char *eom, *erdata; + char *bp, **ap, **hap; + int type, class, buflen, ancount, qdcount; + int haveanswer, had_error; + int toobig = 0; + char tbuf[MAXDNAME]; + const char *tname; + int (*name_ok) __P((const char *)); + + tname = qname; + host.h_name = NULL; + eom = answer->buf + anslen; + switch (qtype) { + case T_A: + case T_AAAA: + name_ok = res_hnok; + break; + case T_PTR: + name_ok = res_dnok; + break; + default: + h_errno = NO_RECOVERY; + return (NULL); /* XXX should be abort(); */ + } + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = hostbuf; + buflen = sizeof hostbuf; + cp = answer->buf; + BOUNDED_INCR(HFIXEDSZ); + if (qdcount != 1) { + h_errno = NO_RECOVERY; + return (NULL); + } + n = dn_expand(answer->buf, eom, cp, bp, buflen); + if ((n < 0) || !(*name_ok)(bp)) { + h_errno = NO_RECOVERY; + return (NULL); + } + BOUNDED_INCR(n + QFIXEDSZ); + if (qtype == T_A || qtype == T_AAAA) { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + h_errno = NO_RECOVERY; + return (NULL); + } + host.h_name = bp; + bp += n; + buflen -= n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = host.h_name; + } + ap = host_aliases; + *ap = NULL; + host.h_aliases = host_aliases; + hap = h_addr_ptrs; + *hap = NULL; + host.h_addr_list = h_addr_ptrs; + haveanswer = 0; + had_error = 0; + _dns_ttl_ = -1; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dn_expand(answer->buf, eom, cp, bp, buflen); + if ((n < 0) || !(*name_ok)(bp)) { + had_error++; + continue; + } + cp += n; /* name */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + type = _getshort(cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ; /* class */ + if (qtype == T_A && type == T_A) + _dns_ttl_ = _getlong(cp); + cp += INT32SZ; /* TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + BOUNDS_CHECK(cp, n); + erdata = cp + n; + if (class != C_IN) { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { + if (ap >= &host_aliases[MAXALIASES-1]) + continue; + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if ((n < 0) || !(*name_ok)(tbuf)) { + had_error++; + continue; + } + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return (NULL); + } + /* Store alias. */ + *ap++ = bp; + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + bp += n; + buflen -= n; + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > buflen || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strcpy(bp, tbuf); + host.h_name = bp; + bp += n; + buflen -= n; + continue; + } + if (qtype == T_PTR && type == T_CNAME) { + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if (n < 0 || !res_dnok(tbuf)) { + had_error++; + continue; + } + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return (NULL); + } + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > buflen || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strcpy(bp, tbuf); + tname = bp; + bp += n; + buflen -= n; + continue; + } + if (type != qtype) { + syslog(LOG_NOTICE|LOG_AUTH, + "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class(C_IN), p_type(qtype), + p_type(type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + switch (type) { + case T_PTR: + if (strcasecmp(tname, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + n = dn_expand(answer->buf, eom, cp, bp, buflen); + if ((n < 0) || !res_hnok(bp)) { + had_error++; + break; + } +#if MULTI_PTRS_ARE_ALIASES + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return (NULL); + } + if (!haveanswer) + host.h_name = bp; + else if (ap < &host_aliases[MAXALIASES-1]) + *ap++ = bp; + else + n = -1; + if (n != -1) { + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + bp += n; + buflen -= n; + } + break; +#else + host.h_name = bp; + if (_res.options & RES_USE_INET6) { + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + bp += n; + buflen -= n; + _map_v4v6_hostent(&host, &bp, &buflen); + } + h_errno = NETDB_SUCCESS; + return (&host); +#endif + case T_A: + case T_AAAA: + if (strcasecmp(host.h_name, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, host.h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (n != host.h_length) { + cp += n; + continue; + } + if (!haveanswer) { + register int nn; + + host.h_name = bp; + nn = strlen(bp) + 1; /* for the \0 */ + bp += nn; + buflen -= nn; + } + + bp += sizeof(align) - ((u_long)bp % sizeof(align)); + + if (bp + n >= &hostbuf[sizeof hostbuf]) { + dprintf("size (%d) too big\n", n); + had_error++; + continue; + } + if (hap >= &h_addr_ptrs[MAXADDRS-1]) { + if (!toobig++) + dprintf("Too many addresses (%d)\n", + MAXADDRS); + cp += n; + continue; + } + bcopy(cp, *hap++ = bp, n); + bp += n; + buflen -= n; + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return (NULL); + } + break; + default: + dprintf("Impossible condition (type=%d)\n", type); + h_errno = NO_RECOVERY; + return (NULL); + /* BIND has abort() here, too risky on bad data */ + } + if (!had_error) + haveanswer++; + } + if (haveanswer) { + *ap = NULL; + *hap = NULL; +# if defined(RESOLVSORT) + /* + * Note: we sort even if host can take only one address + * in its return structures - should give it the "best" + * address in that case, not some random one + */ + if (_res.nsort && haveanswer > 1 && qtype == T_A) + addrsort(h_addr_ptrs, haveanswer); +# endif /*RESOLVSORT*/ + if (!host.h_name) { + n = strlen(qname) + 1; /* for the \0 */ + if (n > buflen || n >= MAXHOSTNAMELEN) + goto no_recovery; + strcpy(bp, qname); + host.h_name = bp; + bp += n; + buflen -= n; + } + if (_res.options & RES_USE_INET6) + _map_v4v6_hostent(&host, &bp, &buflen); + h_errno = NETDB_SUCCESS; + return (&host); + } + no_recovery: + h_errno = NO_RECOVERY; + return (NULL); +} + +struct hostent * +__dns_getanswer(answer, anslen, qname, qtype) + const char *answer; + int anslen; + const char *qname; + int qtype; +{ + switch(qtype) { + case T_AAAA: + host.h_addrtype = AF_INET6; + host.h_length = IN6ADDRSZ; + break; + case T_A: + default: + host.h_addrtype = AF_INET; + host.h_length = INADDRSZ; + break; + } + + return(gethostanswer((const querybuf *)answer, anslen, qname, qtype)); +} + +struct hostent * +_gethostbydnsname(name, af) + const char *name; + int af; +{ + querybuf buf; + register const char *cp; + char *bp; + int n, size, type, len; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (NULL); + } + + switch (af) { + case AF_INET: + size = INADDRSZ; + type = T_A; + break; + case AF_INET6: + size = IN6ADDRSZ; + type = T_AAAA; + break; + default: + h_errno = NETDB_INTERNAL; + errno = EAFNOSUPPORT; + return (NULL); + } + + host.h_addrtype = af; + host.h_length = size; + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_query() since we are not the only + * function that looks up host names. + */ + if (!strchr(name, '.') && (cp = __hostalias(name))) + name = cp; + + /* + * disallow names consisting only of digits/dots, unless + * they end in a dot. + */ + if (isdigit(name[0])) + for (cp = name;; ++cp) { + if (!*cp) { + if (*--cp == '.') + break; + /* + * All-numeric, no dot at the end. + * Fake up a hostent as if we'd actually + * done a lookup. + */ + if (inet_pton(af, name, host_addr) <= 0) { + h_errno = HOST_NOT_FOUND; + return (NULL); + } + strncpy(hostbuf, name, MAXDNAME); + hostbuf[MAXDNAME] = '\0'; + bp = hostbuf + MAXDNAME; + len = sizeof hostbuf - MAXDNAME; + host.h_name = hostbuf; + host.h_aliases = host_aliases; + host_aliases[0] = NULL; + h_addr_ptrs[0] = (char *)host_addr; + h_addr_ptrs[1] = NULL; + host.h_addr_list = h_addr_ptrs; + if (_res.options & RES_USE_INET6) + _map_v4v6_hostent(&host, &bp, &len); + h_errno = NETDB_SUCCESS; + return (&host); + } + if (!isdigit(*cp) && *cp != '.') + break; + } + if ((isxdigit(name[0]) && strchr(name, ':') != NULL) || + name[0] == ':') + for (cp = name;; ++cp) { + if (!*cp) { + if (*--cp == '.') + break; + /* + * All-IPv6-legal, no dot at the end. + * Fake up a hostent as if we'd actually + * done a lookup. + */ + if (inet_pton(af, name, host_addr) <= 0) { + h_errno = HOST_NOT_FOUND; + return (NULL); + } + strncpy(hostbuf, name, MAXDNAME); + hostbuf[MAXDNAME] = '\0'; + bp = hostbuf + MAXDNAME; + len = sizeof hostbuf - MAXDNAME; + host.h_name = hostbuf; + host.h_aliases = host_aliases; + host_aliases[0] = NULL; + h_addr_ptrs[0] = (char *)host_addr; + h_addr_ptrs[1] = NULL; + host.h_addr_list = h_addr_ptrs; + h_errno = NETDB_SUCCESS; + return (&host); + } + if (!isxdigit(*cp) && *cp != ':' && *cp != '.') + break; + } + + if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) { + dprintf("res_search failed (%d)\n", n); + return (NULL); + } + return (gethostanswer(&buf, n, name, type)); +} + +struct hostent * +_gethostbydnsaddr(addr, len, af) + const char *addr; /* XXX should have been def'd as u_char! */ + int len, af; +{ + const u_char *uaddr = (const u_char *)addr; + static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; + static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + int n, size; + querybuf buf; + register struct hostent *hp; + char qbuf[MAXDNAME+1], *qp; +#ifdef SUNSECURITY + register struct hostent *rhp; + char **haddr; + u_long old_options; + char hname2[MAXDNAME+1]; +#endif /*SUNSECURITY*/ + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (NULL); + } + if (af == AF_INET6 && len == IN6ADDRSZ && + (!bcmp(uaddr, mapped, sizeof mapped) || + !bcmp(uaddr, tunnelled, sizeof tunnelled))) { + /* Unmap. */ + addr += sizeof mapped; + uaddr += sizeof mapped; + af = AF_INET; + len = INADDRSZ; + } + switch (af) { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + errno = EAFNOSUPPORT; + h_errno = NETDB_INTERNAL; + return (NULL); + } + if (size != len) { + errno = EINVAL; + h_errno = NETDB_INTERNAL; + return (NULL); + } + switch (af) { + case AF_INET: + (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", + (uaddr[3] & 0xff), + (uaddr[2] & 0xff), + (uaddr[1] & 0xff), + (uaddr[0] & 0xff)); + break; + case AF_INET6: + qp = qbuf; + for (n = IN6ADDRSZ - 1; n >= 0; n--) { + qp += SPRINTF((qp, "%x.%x.", + uaddr[n] & 0xf, + (uaddr[n] >> 4) & 0xf)); + } + strcpy(qp, "ip6.int"); + break; + default: + abort(); + } + n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf); + if (n < 0) { + dprintf("res_query failed (%d)\n", n); + return (NULL); + } + if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR))) + return (NULL); /* h_errno was set by gethostanswer() */ +#ifdef SUNSECURITY + if (af == AF_INET) { + /* + * turn off search as the name should be absolute, + * 'localhost' should be matched by defnames + */ + strncpy(hname2, hp->h_name, MAXDNAME); + hname2[MAXDNAME] = '\0'; + old_options = _res.options; + _res.options &= ~RES_DNSRCH; + _res.options |= RES_DEFNAMES; + if (!(rhp = gethostbyname(hname2))) { + syslog(LOG_NOTICE|LOG_AUTH, + "gethostbyaddr: No A record for %s (verifying [%s])", + hname2, inet_ntoa(*((struct in_addr *)addr))); + _res.options = old_options; + h_errno = HOST_NOT_FOUND; + return (NULL); + } + _res.options = old_options; + for (haddr = rhp->h_addr_list; *haddr; haddr++) + if (!memcmp(*haddr, addr, INADDRSZ)) + break; + if (!*haddr) { + syslog(LOG_NOTICE|LOG_AUTH, + "gethostbyaddr: A record of %s != PTR record [%s]", + hname2, inet_ntoa(*((struct in_addr *)addr))); + h_errno = HOST_NOT_FOUND; + return (NULL); + } + } +#endif /*SUNSECURITY*/ + hp->h_addrtype = af; + hp->h_length = len; + bcopy(addr, host_addr, len); + h_addr_ptrs[0] = (char *)host_addr; + h_addr_ptrs[1] = NULL; + if (af == AF_INET && (_res.options & RES_USE_INET6)) { + _map_v4v6_address((char*)host_addr, (char*)host_addr); + hp->h_addrtype = AF_INET6; + hp->h_length = IN6ADDRSZ; + } + h_errno = NETDB_SUCCESS; + return (hp); +} + +#ifdef RESOLVSORT +static void +addrsort(ap, num) + char **ap; + int num; +{ + int i, j; + char **p; + short aval[MAXADDRS]; + int needsort = 0; + + p = ap; + for (i = 0; i < num; i++, p++) { + for (j = 0 ; (unsigned)j < _res.nsort; j++) + if (_res.sort_list[j].addr.s_addr == + (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask)) + break; + aval[i] = j; + if (needsort == 0 && i > 0 && j < aval[i-1]) + needsort = i; + } + if (!needsort) + return; + + while (needsort < num) { + for (j = needsort - 1; j >= 0; j--) { + if (aval[j] > aval[j+1]) { + char *hp; + + i = aval[j]; + aval[j] = aval[j+1]; + aval[j+1] = i; + + hp = ap[j]; + ap[j] = ap[j+1]; + ap[j+1] = hp; + + } else + break; + } + needsort++; + } +} +#endif +void +_sethostdnsent(stayopen) + int stayopen; +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + if (stayopen) + _res.options |= RES_STAYOPEN | RES_USEVC; +} + +void +_endhostdnsent() +{ + _res.options &= ~(RES_STAYOPEN | RES_USEVC); + res_close(); +} diff --git a/cpukit/libnetworking/libc/gethostbyht.c b/cpukit/libnetworking/libc/gethostbyht.c new file mode 100644 index 0000000000..29f2805367 --- /dev/null +++ b/cpukit/libnetworking/libc/gethostbyht.c @@ -0,0 +1,202 @@ +/*- + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <arpa/nameser.h> /* XXX */ +#include <resolv.h> /* XXX */ + +#define MAXALIASES 35 + +static struct hostent host; +static char *host_aliases[MAXALIASES]; +static char hostbuf[BUFSIZ+1]; +static FILE *hostf = NULL; +static u_char host_addr[16]; /* IPv4 or IPv6 */ +static char *h_addr_ptrs[2]; +static int stayopen = 0; + +void +_sethosthtent(f) + int f; +{ + if (!hostf) + hostf = fopen(_PATH_HOSTS, "r" ); + else + rewind(hostf); + stayopen = f; +} + +void +_endhosthtent() +{ + if (hostf && !stayopen) { + (void) fclose(hostf); + hostf = NULL; + } +} + +struct hostent * +gethostent() +{ + char *p; + register char *cp, **q; + int af, len; + + if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) { + h_errno = NETDB_INTERNAL; + return (NULL); + } + again: + if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) { + h_errno = HOST_NOT_FOUND; + return (NULL); + } + if (*p == '#') + goto again; + if (!(cp = strpbrk(p, "#\n"))) + goto again; + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) + goto again; + *cp++ = '\0'; + if (inet_pton(AF_INET6, p, host_addr) > 0) { + af = AF_INET6; + len = IN6ADDRSZ; + } else if (inet_pton(AF_INET, p, host_addr) > 0) { + if (_res.options & RES_USE_INET6) { + _map_v4v6_address((char*)host_addr, (char*)host_addr); + af = AF_INET6; + len = IN6ADDRSZ; + } else { + af = AF_INET; + len = INADDRSZ; + } + } else { + goto again; + } + h_addr_ptrs[0] = (char *)host_addr; + h_addr_ptrs[1] = NULL; + host.h_addr_list = h_addr_ptrs; + host.h_length = len; + host.h_addrtype = af; + while (*cp == ' ' || *cp == '\t') + cp++; + host.h_name = cp; + q = host.h_aliases = host_aliases; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &host_aliases[MAXALIASES - 1]) + *q++ = cp; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + } + *q = NULL; + h_errno = NETDB_SUCCESS; + return (&host); +} + +struct hostent * +_gethostbyhtname(name, af) + const char *name; + int af; +{ + register struct hostent *p; + register char **cp; + + sethostent(0); + while ((p = gethostent()) != NULL) { + if (p->h_addrtype != af) + continue; + if (strcasecmp(p->h_name, name) == 0) + break; + for (cp = p->h_aliases; *cp != 0; cp++) + if (strcasecmp(*cp, name) == 0) + goto found; + } +found: + endhostent(); + return (p); +} + +struct hostent * +_gethostbyhtaddr(addr, len, af) + const char *addr; + int len, af; +{ + register struct hostent *p; + + sethostent(0); + while ((p = gethostent()) != NULL) + if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len)) + break; + endhostent(); + return (p); +} diff --git a/cpukit/libnetworking/libc/gethostbyname.3 b/cpukit/libnetworking/libc/gethostbyname.3 new file mode 100644 index 0000000000..e21dc79f1d --- /dev/null +++ b/cpukit/libnetworking/libc/gethostbyname.3 @@ -0,0 +1,305 @@ +.\" Copyright (c) 1983, 1987, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95 +.\" $Id$ +.\" +.Dd May 25, 1995 +.Dt GETHOSTBYNAME 3 +.Os BSD 4.2 +.Sh NAME +.Nm gethostbyname , +.Nm gethostbyname2 , +.Nm gethostbyaddr , +.Nm gethostent , +.Nm sethostent , +.Nm endhostent , +.Nm herror , +.Nm hstrerror +.Nd get network host entry +.Sh SYNOPSIS +.Fd #include <netdb.h> +.Vt extern int h_errno; +.Ft struct hostent * +.Fn gethostbyname "const char *name" +.Ft struct hostent * +.Fn gethostbyname2 "const char *name" "int af" +.Ft struct hostent * +.Fn gethostbyaddr "const char *addr" "int len" "int type" +.Ft struct hostent * +.Fn gethostent void +.Ft void +.Fn sethostent "int stayopen" +.Ft void +.Fn endhostent void +.Ft void +.Fn herror "const char *string" +.Ft const char * +.Fn hstrerror "int err" +.Sh DESCRIPTION +The +.Fn gethostbyname , +.Fn gethostbyname2 +and +.Fn gethostbyaddr +functions +each return a pointer to an object with the +following structure describing an internet host +referenced by name or by address, respectively. +This structure contains either the information obtained from the name server, +.Xr named 8 , +or broken-out fields from a line in +.Pa /etc/hosts . +If the local name server is not running these routines do a lookup in +.Pa /etc/hosts . +.Bd -literal +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +}; +#define h_addr h_addr_list[0] /* address, for backward compatibility */ +.Ed +.Pp +The members of this structure are: +.Bl -tag -width h_addr_list +.It Fa h_name +Official name of the host. +.It Fa h_aliases +A NULL-terminated array of alternate names for the host. +.It Fa h_addrtype +The type of address being returned; usually +.Dv AF_INET . +.It Fa h_length +The length, in bytes, of the address. +.It Fa h_addr_list +A NULL-terminated array of network addresses for the host. +Host addresses are returned in network byte order. +.It Fa h_addr +The first address in +.Fa h_addr_list ; +this is for backward compatibility. +.El +.Pp +When using the nameserver, +.Fn gethostbyname +and +.Fn gethostbyname +will search for the named host in the current domain and its parents +unless the name ends in a dot. +If the name contains no dot, and if the environment variable +.Dq Ev HOSTALIASES +contains the name of an alias file, the alias file will first be searched +for an alias matching the input name. +See +.Xr hostname 7 +for the domain search procedure and the alias file format. +.Pp +The +.Fn gethostbyname2 +function is an evolution of +.Fn gethostbyname +which is intended to allow lookups in address families other than +.Dv AF_INET , +for example +.Dv AF_INET6 . +Currently the +.Fa af +argument must be specified as +.Dv AF_INET +else the function will return +.Dv NULL +after having set +.Va h_errno +to +.Dv NETDB_INTERNAL +.Pp +The +.Fn sethostent +function +may be used to request the use of a connected +.Tn TCP +socket for queries. +If the +.Fa stayopen +flag is non-zero, +this sets the option to send all queries to the name server using +.Tn TCP +and to retain the connection after each call to +.Fn gethostbyname , +.Fn gethostbyname2 +or +.Fn gethostbyaddr . +Otherwise, queries are performed using +.Tn UDP +datagrams. +.Pp +The +.Fn endhostent +function +closes the +.Tn TCP +connection. +.Pp +The +.Fn herror +function writes a message to the diagnostic output consisting of the +string parameter +.Fa s , +the constant string ": ", and a message corresponding to the value of +.Va h_errno . +.Pp +The +.Fn hstrerror +function returns a string which is the message text corresponding to the +value of the +.Fa err +parameter. +.Sh FILES +.Bl -tag -width /etc/resolv.conf -compact +.It Pa /etc/hosts +.It Pa /etc/host.conf +.It Pa /etc/resolv.conf +.El +.Sh DIAGNOSTICS +Error return status from +.Fn gethostbyname , +.Fn gethostbyname2 +and +.Fn gethostbyaddr +is indicated by return of a null pointer. +The external integer +.Va h_errno +may then be checked to see whether this is a temporary failure +or an invalid or unknown host. +The routine +.Fn herror +can be used to print an error message describing the failure. +If its argument +.Fa string +is +.Pf non Dv -NULL , +it is printed, followed by a colon and a space. +The error message is printed with a trailing newline. +.Pp +The variable +.Va h_errno +can have the following values: +.Bl -tag -width HOST_NOT_FOUND +.It Dv HOST_NOT_FOUND +No such host is known. +.It Dv TRY_AGAIN +This is usually a temporary error +and means that the local server did not receive +a response from an authoritative server. +A retry at some later time may succeed. +.It Dv NO_RECOVERY +Some unexpected server failure was encountered. +This is a non-recoverable error. +.It Dv NO_DATA +The requested name is valid but does not have an IP address; +this is not a temporary error. +This means that the name is known to the name server but there is no address +associated with this name. +Another type of request to the name server using this domain name +will result in an answer; +for example, a mail-forwarder may be registered for this domain. +.El +.Sh SEE ALSO +.Xr resolver 3 , +.Xr hosts 5 , +.Xr hostname 7 , +.Xr named 8 +.Sh CAVEAT +The +.Fn gethostent +function +is defined, and +.Fn sethostent +and +.Fn endhostent +are redefined, +when +.Xr libc 3 +is built to use only the routines to lookup in +.Pa /etc/hosts +and not the name server. +.Pp +The +.Fn gethostent +function +reads the next line of +.Pa /etc/hosts , +opening the file if necessary. +.Pp +The +.Fn sethostent +function +opens and/or rewinds the file +.Pa /etc/hosts . +If the +.Fa stayopen +argument is non-zero, +the file will not be closed after each call to +.Fn gethostbyname , +.Fn gethostbyname2 +or +.Fn gethostbyaddr . +.Pp +The +.Fn endhostent +function +closes the file. +.Sh HISTORY +The +.Fn herror +function appeared in +.Bx 4.3 . +The +.Fn endhostent , +.Fn gethostbyaddr , +.Fn gethostbyname , +.Fn gethostent , +and +.Fn sethostent +functions appeared in +.Bx 4.2 . +The +.Fn gethostbyname2 +function first appeared in bind-4.9.4. +.Sh BUGS +These functions use static data storage; +if the data is needed for future use, it should be +copied before any subsequent calls overwrite it. +Only the Internet +address format is currently understood. diff --git a/cpukit/libnetworking/libc/gethostbynis.c b/cpukit/libnetworking/libc/gethostbynis.c new file mode 100644 index 0000000000..45dbe5a85d --- /dev/null +++ b/cpukit/libnetworking/libc/gethostbynis.c @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 1994, Garrett Wollman + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)$Id$"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +#define MAXALIASES 35 +#define MAXADDRS 35 + +#ifdef YP +static char *host_aliases[MAXALIASES]; +static char hostaddr[MAXADDRS]; +static char *host_addrs[2]; +#endif /* YP */ + +static struct hostent * +_gethostbynis(name, map, af) + const char *name; + char *map; + int af; +{ +#ifdef YP + register char *cp, **q; + char *result; + int resultlen; + static struct hostent h; + static char *domain = (char *)NULL; + static char ypbuf[YPMAXRECORD + 2]; + + switch(af) { + case AF_INET: + break; + default: + case AF_INET6: + errno = EAFNOSUPPORT; + return NULL; + } + + if (domain == (char *)NULL) + if (yp_get_default_domain (&domain)) + return ((struct hostent *)NULL); + + if (yp_match(domain, map, name, strlen(name), &result, &resultlen)) + return ((struct hostent *)NULL); + + /* avoid potential memory leak */ + bcopy((char *)result, (char *)&ypbuf, resultlen); + ypbuf[resultlen] = '\0'; + free(result); + result = (char *)&ypbuf; + + if ((cp = index(result, '\n'))) + *cp = '\0'; + + cp = strpbrk(result, " \t"); + *cp++ = '\0'; + h.h_addr_list = host_addrs; + h.h_addr = hostaddr; + *((u_long *)h.h_addr) = inet_addr(result); + h.h_length = sizeof(u_long); + h.h_addrtype = AF_INET; + while (*cp == ' ' || *cp == '\t') + cp++; + h.h_name = cp; + q = h.h_aliases = host_aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &host_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&h); +#else + return (NULL); +#endif /* YP */ +} + +struct hostent * +_gethostbynisname(name, af) + const char *name; + int af; +{ + return _gethostbynis(name, "hosts.byname", af); +} + +struct hostent * +_gethostbynisaddr(addr, len, af) + const char *addr; + int len; + int af; +{ + return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af); +} diff --git a/cpukit/libnetworking/libc/gethostnamadr.c b/cpukit/libnetworking/libc/gethostnamadr.c new file mode 100644 index 0000000000..2ad832f4b1 --- /dev/null +++ b/cpukit/libnetworking/libc/gethostnamadr.c @@ -0,0 +1,224 @@ +/*- + * Copyright (c) 1994, Garrett Wollman + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)$Id$"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <arpa/nameser.h> /* XXX hack for _res */ +#include <resolv.h> /* XXX hack for _res */ + +#define _PATH_HOSTCONF "/etc/host.conf" + +enum service_type { + SERVICE_NONE = 0, + SERVICE_BIND, + SERVICE_HOSTS, + SERVICE_NIS }; +#define SERVICE_MAX SERVICE_NIS + +static struct { + const char *name; + enum service_type type; +} service_names[] = { + { "hosts", SERVICE_HOSTS }, + { "/etc/hosts", SERVICE_HOSTS }, + { "hosttable", SERVICE_HOSTS }, + { "htable", SERVICE_HOSTS }, + { "bind", SERVICE_BIND }, + { "dns", SERVICE_BIND }, + { "domain", SERVICE_BIND }, + { "yp", SERVICE_NIS }, + { "yellowpages", SERVICE_NIS }, + { "nis", SERVICE_NIS }, + { 0, SERVICE_NONE } +}; + +static enum service_type service_order[SERVICE_MAX + 1]; +static int service_done = 0; + +static enum service_type +get_service_name(const char *name) { + int i; + for(i = 0; service_names[i].type != SERVICE_NONE; i++) { + if(!strcasecmp(name, service_names[i].name)) { + return service_names[i].type; + } + } + return SERVICE_NONE; +} + +static void +init_services() +{ + char *cp, *p, buf[BUFSIZ]; + register int cc = 0; + FILE *fd; + + if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) { + /* make some assumptions */ + service_order[0] = SERVICE_BIND; + service_order[1] = SERVICE_HOSTS; + service_order[2] = SERVICE_NONE; + } else { + while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) { + if(buf[0] == '#') + continue; + + p = buf; + while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0') + ; + if (cp == NULL) + continue; + do { + if (isalpha(cp[0])) { + service_order[cc] = get_service_name(cp); + if(service_order[cc] != SERVICE_NONE) + cc++; + } + while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0') + ; + } while(cp != NULL && cc < SERVICE_MAX); + } + service_order[cc] = SERVICE_NONE; + fclose(fd); + } + service_done = 1; +} + +struct hostent * +gethostbyname(const char *name) +{ + struct hostent *hp; + + if (_res.options & RES_USE_INET6) { /* XXX */ + hp = gethostbyname2(name, AF_INET6); /* XXX */ + if (hp) /* XXX */ + return (hp); /* XXX */ + } /* XXX */ + return (gethostbyname2(name, AF_INET)); +} + +struct hostent * +gethostbyname2(const char *name, int type) +{ + struct hostent *hp = 0; + int nserv = 0; + + if (!service_done) + init_services(); + + while (!hp) { + switch (service_order[nserv]) { + case SERVICE_NONE: + return NULL; + case SERVICE_HOSTS: + hp = _gethostbyhtname(name, type); + break; + case SERVICE_BIND: + hp = _gethostbydnsname(name, type); + break; + case SERVICE_NIS: + hp = _gethostbynisname(name, type); + break; + } + nserv++; + } + return hp; +} + +struct hostent * +gethostbyaddr(const char *addr, int len, int type) +{ + struct hostent *hp = 0; + int nserv = 0; + + if (!service_done) + init_services(); + + while (!hp) { + switch (service_order[nserv]) { + case SERVICE_NONE: + return 0; + case SERVICE_HOSTS: + hp = _gethostbyhtaddr(addr, len, type); + break; + case SERVICE_BIND: + hp = _gethostbydnsaddr(addr, len, type); + break; + case SERVICE_NIS: + hp = _gethostbynisaddr(addr, len, type); + break; + } + nserv++; + } + return hp; +} + +#ifdef _THREAD_SAFE +struct hostent_data; + +/* + * Temporary function (not thread safe) + */ +int gethostbyaddr_r(const char *addr, int len, int type, + struct hostent *result, struct hostent_data *buffer) +{ + struct hostent *hp; + int ret; + if ((hp = gethostbyaddr(addr, len, type)) == NULL) { + ret = -1; + } else { + memcpy(result, hp, sizeof(struct hostent)); + ret = 0; + } + return(ret); +} +#endif + +void +sethostent(stayopen) + int stayopen; +{ + _sethosthtent(stayopen); + _sethostdnsent(stayopen); +} + +void +endhostent() +{ + _endhosthtent(); + _endhostdnsent(); +} diff --git a/cpukit/libnetworking/libc/gethostname.c b/cpukit/libnetworking/libc/gethostname.c new file mode 100644 index 0000000000..5b8e85acf9 --- /dev/null +++ b/cpukit/libnetworking/libc/gethostname.c @@ -0,0 +1,22 @@ +#include "config.h" + +/* + * Solaris doesn't include the gethostname call by default. + */ +#include <sys/utsname.h> +#include <sys/systeminfo.h> + +#include <netdb.h> + +/* + * PUBLIC: #ifndef HAVE_GETHOSTNAME + * PUBLIC: int gethostname __P((char *, int)); + * PUBLIC: #endif + */ +int +gethostname(host, len) + char *host; + int len; +{ + return (sysinfo(SI_HOSTNAME, host, len) == -1 ? -1 : 0); +} diff --git a/cpukit/libnetworking/libc/getnetbydns.c b/cpukit/libnetworking/libc/getnetbydns.c new file mode 100644 index 0000000000..8f8c576332 --- /dev/null +++ b/cpukit/libnetworking/libc/getnetbydns.c @@ -0,0 +1,313 @@ +/*- + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ +/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro + * Dep. Matematica Universidade de Coimbra, Portugal, Europe + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <stdio.h> +#include <netdb.h> +#include <resolv.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> + +#include "res_config.h" + +extern int h_errno; + +#define BYADDR 0 +#define BYNAME 1 +#define MAXALIASES 35 + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +typedef union { + long al; + char ac; +} align; + +static struct netent * +getnetanswer(answer, anslen, net_i) + querybuf *answer; + int anslen; + int net_i; +{ + + register HEADER *hp; + register u_char *cp; + register int n; + u_char *eom; + int type, class, buflen, ancount, qdcount, haveanswer, i, nchar; + char aux1[MAXHOSTNAMELEN], aux2[MAXHOSTNAMELEN], ans[MAXHOSTNAMELEN]; + char *in, *st, *pauxt, *bp, **ap; + char *paux1 = &aux1[0], *paux2 = &aux2[0], flag = 0; +static struct netent net_entry; +static char *net_aliases[MAXALIASES], netbuf[PACKETSZ]; + + /* + * find first satisfactory answer + * + * answer --> +------------+ ( MESSAGE ) + * | Header | + * +------------+ + * | Question | the question for the name server + * +------------+ + * | Answer | RRs answering the question + * +------------+ + * | Authority | RRs pointing toward an authority + * | Additional | RRs holding additional information + * +------------+ + */ + eom = answer->buf + anslen; + hp = &answer->hdr; + ancount = ntohs(hp->ancount); /* #/records in the answer section */ + qdcount = ntohs(hp->qdcount); /* #/entries in the question section */ + bp = netbuf; + buflen = sizeof(netbuf); + cp = answer->buf + HFIXEDSZ; + if (!qdcount) { + if (hp->aa) + h_errno = HOST_NOT_FOUND; + else + h_errno = TRY_AGAIN; + return (NULL); + } + while (qdcount-- > 0) + cp += __dn_skipname(cp, eom) + QFIXEDSZ; + ap = net_aliases; + *ap = NULL; + net_entry.n_aliases = net_aliases; + haveanswer = 0; + while (--ancount >= 0 && cp < eom) { + n = dn_expand(answer->buf, eom, cp, bp, buflen); + if ((n < 0) || !res_dnok(bp)) + break; + cp += n; + ans[0] = '\0'; + (void)strncpy(&ans[0], bp, sizeof(ans) - 1); + ans[sizeof(ans) - 1] = '\0'; + GETSHORT(type, cp); + GETSHORT(class, cp); + cp += INT32SZ; /* TTL */ + GETSHORT(n, cp); + if (class == C_IN && type == T_PTR) { + n = dn_expand(answer->buf, eom, cp, bp, buflen); + if ((n < 0) || !res_hnok(bp)) { + cp += n; + return (NULL); + } + cp += n; + *ap++ = bp; + bp += strlen(bp) + 1; + net_entry.n_addrtype = + (class == C_IN) ? AF_INET : AF_UNSPEC; + haveanswer++; + } + } + if (haveanswer) { + *ap = NULL; + switch (net_i) { + case BYADDR: + net_entry.n_name = *net_entry.n_aliases; + net_entry.n_net = 0L; + break; + case BYNAME: + in = *net_entry.n_aliases; + net_entry.n_name = &ans[0]; + aux2[0] = '\0'; + for (i = 0; i < 4; i++) { + for (st = in, nchar = 0; + *st != '.'; + st++, nchar++) + ; + if (nchar != 1 || *in != '0' || flag) { + flag = 1; + (void)strncpy(paux1, + (i==0) ? in : in-1, + (i==0) ?nchar : nchar+1); + paux1[(i==0) ? nchar : nchar+1] = '\0'; + pauxt = paux2; + paux2 = strcat(paux1, paux2); + paux1 = pauxt; + } + in = ++st; + } + net_entry.n_net = inet_network(paux2); + break; + } + net_entry.n_aliases++; + return (&net_entry); + } + h_errno = TRY_AGAIN; + return (NULL); +} + +struct netent * +_getnetbydnsaddr(net, net_type) + register unsigned long net; + register int net_type; +{ + unsigned int netbr[4]; + int nn, anslen; + querybuf buf; + char qbuf[MAXDNAME]; + unsigned long net2; + struct netent *net_entry; + + if (net_type != AF_INET) + return (NULL); + + for (nn = 4, net2 = net; net2; net2 >>= 8) + netbr[--nn] = net2 & 0xff; + switch (nn) { + case 3: /* Class A */ + sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]); + break; + case 2: /* Class B */ + sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]); + break; + case 1: /* Class C */ + sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2], + netbr[1]); + break; + case 0: /* Class D - E */ + sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2], + netbr[1], netbr[0]); + break; + } + anslen = res_query(qbuf, C_IN, T_PTR, (u_char *)&buf, sizeof(buf)); + if (anslen < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query failed\n"); +#endif + return (NULL); + } + net_entry = getnetanswer(&buf, anslen, BYADDR); + if (net_entry) { + unsigned u_net = net; /* maybe net should be unsigned ? */ + + /* Strip trailing zeros */ + while ((u_net & 0xff) == 0 && u_net != 0) + u_net >>= 8; + net_entry->n_net = u_net; + return (net_entry); + } + return (NULL); +} + +struct netent * +_getnetbydnsname(net) + register const char *net; +{ + int anslen; + querybuf buf; + char qbuf[MAXDNAME]; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (NULL); + } + strncpy(qbuf, net, sizeof(qbuf) - 1); + qbuf[sizeof(qbuf) - 1] = '\0'; + anslen = res_search(qbuf, C_IN, T_PTR, (u_char *)&buf, sizeof(buf)); + if (anslen < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query failed\n"); +#endif + return (NULL); + } + return getnetanswer(&buf, anslen, BYNAME); +} + +void +_setnetdnsent(stayopen) + int stayopen; +{ + if (stayopen) + _res.options |= RES_STAYOPEN | RES_USEVC; +} + +void +_endnetdnsent() +{ + _res.options &= ~(RES_STAYOPEN | RES_USEVC); + res_close(); +} diff --git a/cpukit/libnetworking/libc/getnetbyht.c b/cpukit/libnetworking/libc/getnetbyht.c new file mode 100644 index 0000000000..f7b7b1091d --- /dev/null +++ b/cpukit/libnetworking/libc/getnetbyht.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro + * Dep. Matematica Universidade de Coimbra, Portugal, Europe + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * from getnetent.c 1.1 (Coimbra) 93/06/02 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetent.c 8.1 (Berkeley) 6/4/93"; +static char orig_rcsid[] = "From: Id: getnetent.c,v 8.4 1997/06/01 20:34:37 vixie Exp"; +static chat rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> + +#define MAXALIASES 35 + +static FILE *netf; +static char line[BUFSIZ+1]; +static struct netent net; +static char *net_aliases[MAXALIASES]; +static int _net_stayopen; + +void +_setnethtent(f) + int f; +{ + + if (netf == NULL) + netf = fopen(_PATH_NETWORKS, "r" ); + else + rewind(netf); + _net_stayopen |= f; +} + +void +_endnethtent() +{ + + if (netf) { + fclose(netf); + netf = NULL; + } + _net_stayopen = 0; +} + +struct netent * +getnetent() +{ + char *p; + register char *cp, **q; + + if (netf == NULL && (netf = fopen(_PATH_NETWORKS, "r" )) == NULL) + return (NULL); +again: + p = fgets(line, sizeof line, netf); + if (p == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = strpbrk(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + net.n_name = p; + cp = strpbrk(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = strpbrk(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + net.n_net = inet_network(cp); + net.n_addrtype = AF_INET; + q = net.n_aliases = net_aliases; + if (p != NULL) + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &net_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&net); +} + +struct netent * +_getnetbyhtname(name) + register const char *name; +{ + register struct netent *p; + register char **cp; + + setnetent(_net_stayopen); + while ( (p = getnetent()) ) { + if (strcasecmp(p->n_name, name) == 0) + break; + for (cp = p->n_aliases; *cp != 0; cp++) + if (strcasecmp(*cp, name) == 0) + goto found; + } +found: + if (!_net_stayopen) + endnetent(); + return (p); +} + +struct netent * +_getnetbyhtaddr(net, type) + register unsigned long net; + register int type; +{ + register struct netent *p; + + setnetent(_net_stayopen); + while ( (p = getnetent()) ) + if (p->n_addrtype == type && p->n_net == net) + break; + if (!_net_stayopen) + endnetent(); + return (p); +} diff --git a/cpukit/libnetworking/libc/getnetbynis.c b/cpukit/libnetworking/libc/getnetbynis.c new file mode 100644 index 0000000000..0549016ba2 --- /dev/null +++ b/cpukit/libnetworking/libc/getnetbynis.c @@ -0,0 +1,177 @@ +/*- + * Copyright (c) 1994, Garrett Wollman + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)$Id$"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <arpa/nameser.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +#define MAXALIASES 35 +#define MAXADDRS 35 + +#ifdef YP +static char *host_aliases[MAXALIASES]; +#endif /* YP */ + +static struct netent * +_getnetbynis(name, map, af) + const char *name; + char *map; + int af; +{ +#ifdef YP + register char *cp, **q; + static char *result; + int resultlen; + static struct netent h; + static char *domain = (char *)NULL; + static char ypbuf[YPMAXRECORD + 2]; + + switch(af) { + case AF_INET: + break; + default: + case AF_INET6: + errno = EAFNOSUPPORT; + return NULL; + } + + if (domain == (char *)NULL) + if (yp_get_default_domain (&domain)) + return (NULL); + + if (yp_match(domain, map, name, strlen(name), &result, &resultlen)) + return (NULL); + + bcopy((char *)result, (char *)&ypbuf, resultlen); + ypbuf[resultlen] = '\0'; + free(result); + result = (char *)&ypbuf; + + if ((cp = index(result, '\n'))) + *cp = '\0'; + + cp = strpbrk(result, " \t"); + *cp++ = '\0'; + h.n_name = result; + + while (*cp == ' ' || *cp == '\t') + cp++; + + h.n_net = inet_network(cp); + h.n_addrtype = AF_INET; + + q = h.n_aliases = host_aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &host_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&h); +#else + return (NULL); +#endif +} + +struct netent * +_getnetbynisname(name) + const char *name; +{ + return _getnetbynis(name, "networks.byname", AF_INET); +} + +struct netent * +_getnetbynisaddr(addr, af) + unsigned long addr; + int af; +{ + char *str, *cp; + unsigned long net2; + int nn; + unsigned int netbr[4]; + char buf[MAXDNAME]; + + if (af != AF_INET) { + errno = EAFNOSUPPORT; + return (NULL); + } + + for (nn = 4, net2 = addr; net2; net2 >>= 8) { + netbr[--nn] = net2 & 0xff; + } + + switch (nn) { + case 3: /* Class A */ + sprintf(buf, "%u", netbr[3]); + break; + case 2: /* Class B */ + sprintf(buf, "%u.%u", netbr[2], netbr[3]); + break; + case 1: /* Class C */ + sprintf(buf, "%u.%u.%u", netbr[1], netbr[2], netbr[3]); + break; + case 0: /* Class D - E */ + sprintf(buf, "%u.%u.%u.%u", netbr[0], netbr[1], + netbr[2], netbr[3]); + break; + } + + str = (char *)&buf; + cp = str + (strlen(str) - 2); + + while(!strcmp(cp, ".0")) { + *cp = '\0'; + cp = str + (strlen(str) - 2); + } + + return _getnetbynis(str, "networks.byaddr", af); +} diff --git a/cpukit/libnetworking/libc/getnetent.3 b/cpukit/libnetworking/libc/getnetent.3 new file mode 100644 index 0000000000..8fb13c0b75 --- /dev/null +++ b/cpukit/libnetworking/libc/getnetent.3 @@ -0,0 +1,158 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" @(#)getnetent.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETNETENT 3 +.Os BSD 4.2 +.Sh NAME +.Nm getnetent , +.Nm getnetbyaddr , +.Nm getnetbyname , +.Nm setnetent , +.Nm endnetent +.Nd get network entry +.Sh SYNOPSIS +.Fd #include <netdb.h> +.Ft struct netent * +.Fn getnetent void +.Ft struct netent * +.Fn getnetbyname "const char *name" +.Ft struct netent * +.Fn getnetbyaddr "unsigned long net" "int type" +.Ft void +.Fn setnetent "int stayopen" +.Ft void +.Fn endnetent void +.Sh DESCRIPTION +The +.Fn getnetent , +.Fn getnetbyname , +and +.Fn getnetbyaddr +functions +each return a pointer to an object with the +following structure +containing the broken-out +fields of a line in the network data base, +.Pa /etc/networks . +.Bd -literal -offset indent +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + int n_addrtype; /* net number type */ + unsigned long n_net; /* net number */ +}; +.Ed +.Pp +The members of this structure are: +.Bl -tag -width n_addrtype +.It Fa n_name +The official name of the network. +.It Fa n_aliases +A zero terminated list of alternate names for the network. +.It Fa n_addrtype +The type of the network number returned; currently only AF_INET. +.It Fa n_net +The network number. Network numbers are returned in machine byte +order. +.El +.Pp +The +.Fn getnetent +function +reads the next line of the file, opening the file if necessary. +.Pp +The +.Fn setnetent +function +opens and rewinds the file. If the +.Fa stayopen +flag is non-zero, +the net data base will not be closed after each call to +.Fn getnetbyname +or +.Fn getnetbyaddr . +.Pp +The +.Fn endnetent +function +closes the file. +.Pp +The +.Fn getnetbyname +function +and +.Fn getnetbyaddr +sequentially search from the beginning +of the file until a matching +net name or +net address and type is found, +or until +.Dv EOF +is encountered. The +.Fa type +must be +.Dv AF_INET . +Network numbers are supplied in host order. +.Sh FILES +.Bl -tag -width /etc/networks -compact +.It Pa /etc/networks +.El +.Sh DIAGNOSTICS +Null pointer +(0) returned on +.Dv EOF +or error. +.Sh SEE ALSO +.Xr networks 5 +.Pp +.%T RFC 1101 +.Sh HISTORY +The +.Fn getnetent , +.Fn getnetbyaddr , +.Fn getnetbyname , +.Fn setnetent , +and +.Fn endnetent +functions appeared in +.Bx 4.2 . +.Sh BUGS +The data space used by +these functions is static; if future use requires the data, it should be +copied before any subsequent calls to these functions overwrite it. +Only Internet network +numbers are currently understood. +Expecting network numbers to fit +in no more than 32 bits is probably +naive. diff --git a/cpukit/libnetworking/libc/getnetnamadr.c b/cpukit/libnetworking/libc/getnetnamadr.c new file mode 100644 index 0000000000..4d6597f98c --- /dev/null +++ b/cpukit/libnetworking/libc/getnetnamadr.c @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 1994, Garrett Wollman + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> + +#ifndef _PATH_NETCONF +#define _PATH_NETCONF "/etc/host.conf" +#endif + +enum service_type { + SERVICE_NONE = 0, + SERVICE_BIND, + SERVICE_TABLE, + SERVICE_NIS }; +#define SERVICE_MAX SERVICE_NIS + +static struct { + const char *name; + enum service_type type; +} service_names[] = { + { "hosts", SERVICE_TABLE }, + { "/etc/hosts", SERVICE_TABLE }, + { "hosttable", SERVICE_TABLE }, + { "htable", SERVICE_TABLE }, + { "bind", SERVICE_BIND }, + { "dns", SERVICE_BIND }, + { "domain", SERVICE_BIND }, + { "yp", SERVICE_NIS }, + { "yellowpages", SERVICE_NIS }, + { "nis", SERVICE_NIS }, + { 0, SERVICE_NONE } +}; + +static enum service_type service_order[SERVICE_MAX + 1]; +static int service_done = 0; + +static enum service_type +get_service_name(const char *name) { + int i; + for(i = 0; service_names[i].type != SERVICE_NONE; i++) { + if(!strcasecmp(name, service_names[i].name)) { + return service_names[i].type; + } + } + return SERVICE_NONE; +} + +static void +init_services() +{ + char *cp, *p, buf[BUFSIZ]; + register int cc = 0; + FILE *fd; + + if ((fd = (FILE *)fopen(_PATH_NETCONF, "r")) == NULL) { + /* make some assumptions */ + service_order[0] = SERVICE_TABLE; + service_order[1] = SERVICE_NONE; + } else { + while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) { + if(buf[0] == '#') + continue; + + p = buf; + while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0') + ; + if (cp == NULL) + continue; + do { + if (isalpha(cp[0])) { + service_order[cc] = get_service_name(cp); + if(service_order[cc] != SERVICE_NONE) + cc++; + } + while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0') + ; + } while(cp != NULL && cc < SERVICE_MAX); + } + service_order[cc] = SERVICE_NONE; + fclose(fd); + } + service_done = 1; +} + +struct netent * +getnetbyname(const char *name) +{ + struct netent *hp = 0; + int nserv = 0; + + if (!service_done) + init_services(); + + while (!hp) { + switch (service_order[nserv]) { + case SERVICE_NONE: + return NULL; + case SERVICE_TABLE: + hp = _getnetbyhtname(name); + break; + case SERVICE_BIND: + hp = _getnetbydnsname(name); + break; + case SERVICE_NIS: + hp = _getnetbynisname(name); + break; + } + nserv++; + } + return hp; +} + +struct netent * +getnetbyaddr(addr, af) + u_long addr; + int af; +{ + struct netent *hp = 0; + int nserv = 0; + + if (!service_done) + init_services(); + + while (!hp) { + switch (service_order[nserv]) { + case SERVICE_NONE: + return 0; + case SERVICE_TABLE: + hp = _getnetbyhtaddr(addr, af); + break; + case SERVICE_BIND: + hp = _getnetbydnsaddr(addr, af); + break; + case SERVICE_NIS: + hp = _getnetbynisaddr(addr, af); + break; + } + nserv++; + } + return hp; +} + +void +setnetent(stayopen) + int stayopen; +{ + _setnethtent(stayopen); + _setnetdnsent(stayopen); +} + +void +endnetent() +{ + _endnethtent(); + _endnetdnsent(); +} diff --git a/cpukit/libnetworking/libc/getproto.c b/cpukit/libnetworking/libc/getproto.c new file mode 100644 index 0000000000..46f46d38e1 --- /dev/null +++ b/cpukit/libnetworking/libc/getproto.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getproto.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> + +extern int _proto_stayopen; + +struct protoent * +getprotobynumber(proto) + register int proto; +{ + register struct protoent *p; + + setprotoent(_proto_stayopen); + while ( (p = getprotoent()) ) + if (p->p_proto == proto) + break; + if (!_proto_stayopen) + endprotoent(); + return (p); +} diff --git a/cpukit/libnetworking/libc/getprotoent.3 b/cpukit/libnetworking/libc/getprotoent.3 new file mode 100644 index 0000000000..dbf3d1a1c3 --- /dev/null +++ b/cpukit/libnetworking/libc/getprotoent.3 @@ -0,0 +1,146 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" @(#)getprotoent.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt GETPROTOENT 3 +.Os BSD 4.2 +.Sh NAME +.Nm getprotoent , +.Nm getprotobynumber , +.Nm getprotobyname , +.Nm setprotoent , +.Nm endprotoent +.Nd get protocol entry +.Sh SYNOPSIS +.Fd #include <netdb.h> +.Ft struct protoent * +.Fn getprotoent void +.Ft struct protoent * +.Fn getprotobyname "const char *name" +.Ft struct protoent * +.Fn getprotobynumber "int proto" +.Ft void +.Fn setprotoent "int stayopen" +.Ft void +.Fn endprotoent void +.Sh DESCRIPTION +The +.Fn getprotoent , +.Fn getprotobyname , +and +.Fn getprotobynumber +functions +each return a pointer to an object with the +following structure +containing the broken-out +fields of a line in the network protocol data base, +.Pa /etc/protocols . +.Bd -literal -offset indent +.Pp +struct protoent { + char *p_name; /* official name of protocol */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol number */ +}; +.Ed +.Pp +The members of this structure are: +.Bl -tag -width p_aliases +.It Fa p_name +The official name of the protocol. +.It Fa p_aliases +A zero terminated list of alternate names for the protocol. +.It Fa p_proto +The protocol number. +.El +.Pp +The +.Fn getprotoent +function +reads the next line of the file, opening the file if necessary. +.Pp +The +.Fn setprotoent +function +opens and rewinds the file. If the +.Fa stayopen +flag is non-zero, +the net data base will not be closed after each call to +.Fn getprotobyname +or +.Fn getprotobynumber . +.Pp +The +.Fn endprotoent +function +closes the file. +.Pp +The +.Fn getprotobyname +function +and +.Fn getprotobynumber +sequentially search from the beginning +of the file until a matching +protocol name or +protocol number is found, +or until +.Dv EOF +is encountered. +.Sh RETURN VALUES +Null pointer +(0) returned on +.Dv EOF +or error. +.Sh FILES +.Bl -tag -width /etc/protocols -compact +.It Pa /etc/protocols +.El +.Sh SEE ALSO +.Xr protocols 5 +.Sh HISTORY +The +.Fn getprotoent , +.Fn getprotobynumber , +.Fn getprotobyname , +.Fn setprotoent , +and +.Fn endprotoent +functions appeared in +.Bx 4.2 . +.Sh BUGS +These functions use a static data space; +if the data is needed for future use, it should be +copied before any subsequent calls overwrite it. +Only the Internet +protocols are currently understood. diff --git a/cpukit/libnetworking/libc/getprotoent.c b/cpukit/libnetworking/libc/getprotoent.c new file mode 100644 index 0000000000..c10ae330e4 --- /dev/null +++ b/cpukit/libnetworking/libc/getprotoent.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getprotoent.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define MAXALIASES 35 + +static FILE *protof = NULL; +static char line[BUFSIZ+1]; +static struct protoent proto; +static char *proto_aliases[MAXALIASES]; +int _proto_stayopen; + +void +setprotoent(f) + int f; +{ + if (protof == NULL) + protof = fopen(_PATH_PROTOCOLS, "r" ); + else + rewind(protof); + _proto_stayopen |= f; +} + +void +endprotoent() +{ + if (protof) { + fclose(protof); + protof = NULL; + } + _proto_stayopen = 0; +} + +struct protoent * +getprotoent() +{ + char *p; + register char *cp, **q; + + if (protof == NULL && (protof = fopen(_PATH_PROTOCOLS, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(line, BUFSIZ, protof)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = strpbrk(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + proto.p_name = p; + cp = strpbrk(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + p = strpbrk(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + proto.p_proto = atoi(cp); + q = proto.p_aliases = proto_aliases; + if (p != NULL) { + cp = p; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &proto_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + return (&proto); +} diff --git a/cpukit/libnetworking/libc/getprotoname.c b/cpukit/libnetworking/libc/getprotoname.c new file mode 100644 index 0000000000..0832acf08a --- /dev/null +++ b/cpukit/libnetworking/libc/getprotoname.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getprotoname.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> +#include <string.h> + +extern int _proto_stayopen; + +struct protoent * +getprotobyname(name) + register const char *name; +{ + register struct protoent *p; + register char **cp; + + setprotoent(_proto_stayopen); + while ( (p = getprotoent()) ) { + if (strcmp(p->p_name, name) == 0) + break; + for (cp = p->p_aliases; *cp != 0; cp++) + if (strcmp(*cp, name) == 0) + goto found; + } +found: + if (!_proto_stayopen) + endprotoent(); + return (p); +} diff --git a/cpukit/libnetworking/libc/getservbyname.c b/cpukit/libnetworking/libc/getservbyname.c new file mode 100644 index 0000000000..124f5ac181 --- /dev/null +++ b/cpukit/libnetworking/libc/getservbyname.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservbyname.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> +#include <string.h> + +extern int _serv_stayopen; + +struct servent * +getservbyname(name, proto) + const char *name, *proto; +{ + register struct servent *p; + register char **cp; + +#ifdef YP + extern char *___getservbyname_yp; + extern char *___getservbyproto_yp; + + ___getservbyname_yp = (char *)name; + ___getservbyproto_yp = (char *)proto; +#endif + + setservent(_serv_stayopen); + while ( (p = getservent()) ) { + if (strcmp(name, p->s_name) == 0) + goto gotname; + for (cp = p->s_aliases; *cp; cp++) + if (strcmp(name, *cp) == 0) + goto gotname; + continue; +gotname: + if (proto == 0 || strcmp(p->s_proto, proto) == 0) + break; + } + if (!_serv_stayopen) + endservent(); + +#ifdef YP + ___getservbyname_yp = NULL; + ___getservbyproto_yp = NULL; +#endif + + return (p); +} diff --git a/cpukit/libnetworking/libc/getservbyport.c b/cpukit/libnetworking/libc/getservbyport.c new file mode 100644 index 0000000000..ef9a2e858a --- /dev/null +++ b/cpukit/libnetworking/libc/getservbyport.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservbyport.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> +#include <string.h> + +extern int _serv_stayopen; + +struct servent * +getservbyport(port, proto) + int port; + const char *proto; +{ + register struct servent *p; + +#ifdef YP + extern int ___getservbyport_yp; + extern char *___getservbyproto_yp; + + ___getservbyport_yp = port; + ___getservbyproto_yp = (char *)proto; +#endif + + setservent(_serv_stayopen); + while ( (p = getservent()) ) { + if (p->s_port != port) + continue; + if (proto == 0 || strcmp(p->s_proto, proto) == 0) + break; + } + if (!_serv_stayopen) + endservent(); + +#ifdef YP + ___getservbyport_yp = 0; + ___getservbyproto_yp = NULL; +#endif + + return (p); +} diff --git a/cpukit/libnetworking/libc/getservent.3 b/cpukit/libnetworking/libc/getservent.3 new file mode 100644 index 0000000000..79c18a3beb --- /dev/null +++ b/cpukit/libnetworking/libc/getservent.3 @@ -0,0 +1,156 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" From: @(#)getservent.3 8.3 (Berkeley) 1/12/94 +.\" $Id$ +.\" +.Dd July 9, 1995 +.Dt GETSERVENT 3 +.Os BSD 4.2 +.Sh NAME +.Nm getservent , +.Nm getservbyport , +.Nm getservbyname , +.Nm setservent , +.Nm endservent +.Nd get service entry +.Sh SYNOPSIS +.Fd #include <netdb.h> +.Ft struct servent * +.Fn getservent +.Ft struct servent * +.Fn getservbyname "const char *name" "const char *proto" +.Ft struct servent * +.Fn getservbyport "int port" "const char *proto" +.Ft void +.Fn setservent "int stayopen" +.Ft void +.Fn endservent void +.Sh DESCRIPTION +The +.Fn getservent , +.Fn getservbyname , +and +.Fn getservbyport +functions +each return a pointer to an object with the +following structure +containing the broken-out +fields of a line in the network services data base, +.Pa /etc/services . +.Bd -literal -offset indent +struct servent { + char *s_name; /* official name of service */ + char **s_aliases; /* alias list */ + int s_port; /* port service resides at */ + char *s_proto; /* protocol to use */ +}; +.Ed +.Pp +The members of this structure are: +.Bl -tag -width s_aliases +.It Fa s_name +The official name of the service. +.It Fa s_aliases +A zero terminated list of alternate names for the service. +.It Fa s_port +The port number at which the service resides. +Port numbers are returned in network byte order. +.It Fa s_proto +The name of the protocol to use when contacting the +service. +.El +.Pp +The +.Fn getservent +function +reads the next line of the file, opening the file if necessary. +.Pp +The +.Fn setservent +function +opens and rewinds the file. If the +.Fa stayopen +flag is non-zero, +the net data base will not be closed after each call to +.Fn getservbyname +or +.Fn getservbyport . +.Pp +The +.Fn endservent +function +closes the file. +.Pp +The +.Fn getservbyname +and +.Fn getservbyport +functions +sequentially search from the beginning +of the file until a matching +protocol name or +port number is found, +or until +.Dv EOF +is encountered. +If a protocol name is also supplied (non- +.Dv NULL ) , +searches must also match the protocol. +.ne 1i +.Sh FILES +.Bl -tag -width /etc/services -compact +.It Pa /etc/services +.El +.Sh DIAGNOSTICS +Null pointer +(0) returned on +.Dv EOF +or error. +.Sh SEE ALSO +.Xr getprotoent 3 , +.Xr services 5 +.Sh HISTORY +The +.Fn getservent , +.Fn getservbyport , +.Fn getservbyname , +.Fn setservent , +and +.Fn endservent +functions appeared in +.Bx 4.2 . +.Sh BUGS +These functions use static data storage; +if the data is needed for future use, it should be +copied before any subsequent calls overwrite it. +Expecting port numbers to fit in a 32 bit +quantity is probably naive. diff --git a/cpukit/libnetworking/libc/getservent.c b/cpukit/libnetworking/libc/getservent.c new file mode 100644 index 0000000000..cd4449fbb8 --- /dev/null +++ b/cpukit/libnetworking/libc/getservent.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +static int serv_stepping_yp = 0; +extern int _yp_check __P(( char ** )); +#endif + + +#define MAXALIASES 35 + +static FILE *servf = NULL; +static char line[BUFSIZ+1]; +static struct servent serv; +static char *serv_aliases[MAXALIASES]; +int _serv_stayopen; + +#ifdef YP +char *___getservbyname_yp = NULL; +char *___getservbyproto_yp = NULL; +int ___getservbyport_yp = 0; +static char *yp_domain = NULL; + +static int +_getservbyport_yp(line) + char *line; +{ + char *result; + int resultlen; + char buf[YPMAXRECORD + 2]; + int rv; + + snprintf(buf, sizeof(buf), "%d/%s", ntohs(___getservbyport_yp), + ___getservbyproto_yp); + + ___getservbyport_yp = 0; + ___getservbyproto_yp = NULL; + + if(!yp_domain) { + if(yp_get_default_domain(&yp_domain)) + return (0); + } + + /* + * We have to be a little flexible here. Ideally you're supposed + * to have both a services.byname and a services.byport map, but + * some systems have only services.byname. FreeBSD cheats a little + * by putting the services.byport information in the same map as + * services.byname so that either case will work. We allow for both + * possibilities here: if there is no services.byport map, we try + * services.byname instead. + */ + if ((rv = yp_match(yp_domain, "services.byport", buf, strlen(buf), + &result, &resultlen))) { + if (rv == YPERR_MAP) { + if (yp_match(yp_domain, "services.byname", buf, + strlen(buf), &result, &resultlen)) + return(0); + } else + return(0); + } + + /* getservent() expects lines terminated with \n -- make it happy */ + snprintf(line, BUFSIZ, "%.*s\n", resultlen, result); + + free(result); + return(1); +} + +static int +_getservbyname_yp(line) + char *line; +{ + char *result; + int resultlen; + char buf[YPMAXRECORD + 2]; + + if(!yp_domain) { + if(yp_get_default_domain(&yp_domain)) + return (0); + } + + snprintf(buf, sizeof(buf), "%s/%s", ___getservbyname_yp, + ___getservbyproto_yp); + + ___getservbyname_yp = 0; + ___getservbyproto_yp = NULL; + + if (yp_match(yp_domain, "services.byname", buf, strlen(buf), + &result, &resultlen)) { + return(0); + } + + /* getservent() expects lines terminated with \n -- make it happy */ + snprintf(line, BUFSIZ, "%.*s\n", resultlen, result); + + free(result); + return(1); +} + +static int +_getservent_yp(line) + char *line; +{ + static char *key = NULL; + static int keylen; + char *lastkey, *result; + int resultlen; + int rv; + + if(!yp_domain) { + if(yp_get_default_domain(&yp_domain)) + return (0); + } + + if (!serv_stepping_yp) { + if (key) + free(key); + if ((rv = yp_first(yp_domain, "services.byname", &key, &keylen, + &result, &resultlen))) { + serv_stepping_yp = 0; + return(0); + } + serv_stepping_yp = 1; + } else { + lastkey = key; + rv = yp_next(yp_domain, "services.byname", key, keylen, &key, + &keylen, &result, &resultlen); + free(lastkey); + if (rv) { + serv_stepping_yp = 0; + return (0); + } + } + + /* getservent() expects lines terminated with \n -- make it happy */ + snprintf(line, BUFSIZ, "%.*s\n", resultlen, result); + + free(result); + + return(1); +} +#endif + +void +setservent(f) + int f; +{ + if (servf == NULL) + servf = fopen(_PATH_SERVICES, "r" ); + else + rewind(servf); + _serv_stayopen |= f; +} + +void +endservent() +{ + if (servf) { + fclose(servf); + servf = NULL; + } + _serv_stayopen = 0; +} + +struct servent * +getservent() +{ + char *p; + register char *cp, **q; + +#ifdef YP + if (serv_stepping_yp && _getservent_yp(line)) { + p = (char *)&line; + goto unpack; + } +tryagain: +#endif + if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL) + return (NULL); +again: + if ((p = fgets(line, BUFSIZ, servf)) == NULL) + return (NULL); +#ifdef YP + if (*p == '+' && _yp_check(NULL)) { + if (___getservbyname_yp != NULL) { + if (!_getservbyname_yp(line)) + goto tryagain; + } + else if (___getservbyport_yp != 0) { + if (!_getservbyport_yp(line)) + goto tryagain; + } + else if (!_getservent_yp(line)) + goto tryagain; + } +unpack: +#endif + if (*p == '#') + goto again; + cp = strpbrk(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + serv.s_name = p; + p = strpbrk(p, " \t"); + if (p == NULL) + goto again; + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + cp = strpbrk(p, ",/"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + serv.s_port = htons((u_short)atoi(p)); + serv.s_proto = cp; + q = serv.s_aliases = serv_aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &serv_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&serv); +} diff --git a/cpukit/libnetworking/libc/herror.c b/cpukit/libnetworking/libc/herror.c new file mode 100644 index 0000000000..ba1dae934d --- /dev/null +++ b/cpukit/libnetworking/libc/herror.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <netdb.h> +#include <string.h> +#include <unistd.h> + +const char *h_errlist[] = { + "Resolver Error 0 (no error)", + "Unknown host", /* 1 HOST_NOT_FOUND */ + "Host name lookup failure", /* 2 TRY_AGAIN */ + "Unknown server error", /* 3 NO_RECOVERY */ + "No address associated with name", /* 4 NO_ADDRESS */ +}; +int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; + +int h_errno; + +/* + * herror -- + * print the error indicated by the h_errno value. + */ +void +herror(s) + const char *s; +{ +#if 0 + struct iovec iov[4]; + register struct iovec *v = iov; + + if (s && *s) { + v->iov_base = (char *)s; + v->iov_len = strlen(s); + v++; + v->iov_base = ": "; + v->iov_len = 2; + v++; + } + v->iov_base = (char *)hstrerror(h_errno); + v->iov_len = strlen(v->iov_base); + v++; + v->iov_base = "\n"; + v->iov_len = 1; + writev(STDERR_FILENO, iov, (v - iov) + 1); +#else + /* + * RTEMS: no writev yet + */ + if (s && *s) { + write (2, s, strlen (s)); + write (2, ": ", 2); + } + s = (char *)hstrerror(h_errno); + write (2, s, strlen (s)); + write (2, "\n", 1); +#endif +} + +const char * +hstrerror(err) + int err; +{ + if (err < 0) + return ("Resolver internal error"); + else if (err < h_nerr) + return (h_errlist[err]); + return ("Unknown resolver error"); +} diff --git a/cpukit/libnetworking/libc/inet.3 b/cpukit/libnetworking/libc/inet.3 new file mode 100644 index 0000000000..1052f538f2 --- /dev/null +++ b/cpukit/libnetworking/libc/inet.3 @@ -0,0 +1,210 @@ +.\" Copyright (c) 1983, 1990, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" From: @(#)inet.3 8.1 (Berkeley) 6/4/93 +.\" $Id$ +.\" +.Dd June 17, 1996 +.Dt INET 3 +.Os BSD 4.2 +.Sh NAME +.Nm inet_aton , +.Nm inet_addr , +.Nm inet_network , +.Nm inet_ntoa , +.Nm inet_makeaddr , +.Nm inet_lnaof , +.Nm inet_netof +.Nd Internet address manipulation routines +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <sys/socket.h> +.Fd #include <netinet/in.h> +.Fd #include <arpa/inet.h> +.Ft int +.Fn inet_aton "const char *cp" "struct in_addr *pin" +.Ft unsigned long +.Fn inet_addr "const char *cp" +.Ft unsigned long +.Fn inet_network "const char *cp" +.Ft char * +.Fn inet_ntoa "struct in_addr in" +.Ft struct in_addr +.Fn inet_makeaddr "unsigned long net" "unsigned long lna" +.Ft unsigned long +.Fn inet_lnaof "struct in_addr in" +.Ft unsigned long +.Fn inet_netof "struct in_addr in" +.Sh DESCRIPTION +The routines +.Fn inet_aton , +.Fn inet_addr +and +.Fn inet_network +interpret character strings representing +numbers expressed in the Internet standard +.Ql \&. +notation. +The +.Fn inet_aton +routine interprets the specified character string as an Internet address, +placing the address into the structure provided. +It returns 1 if the string was successfully interpreted, +or 0 if the string is invalid. +The +.Fn inet_addr +and +.Fn inet_network +functions return numbers suitable for use +as Internet addresses and Internet network +numbers, respectively. +The routine +.Fn inet_ntoa +takes an Internet address and returns an +.Tn ASCII +string representing the address in +.Ql \&. +notation. The routine +.Fn inet_makeaddr +takes an Internet network number and a local +network address and constructs an Internet address +from it. The routines +.Fn inet_netof +and +.Fn inet_lnaof +break apart Internet host addresses, returning +the network number and local network address part, +respectively. +.Pp +All Internet addresses are returned in network +order (bytes ordered from left to right). +All network numbers and local address parts are +returned as machine format integer values. +.Sh INTERNET ADDRESSES +Values specified using the +.Ql \&. +notation take one +of the following forms: +.Bd -literal -offset indent +a.b.c.d +a.b.c +a.b +a +.Ed +.Pp +When four parts are specified, each is interpreted +as a byte of data and assigned, from left to right, +to the four bytes of an Internet address. Note +that when an Internet address is viewed as a 32-bit +integer quantity on the +.Tn VAX +the bytes referred to +above appear as +.Dq Li d.c.b.a . +That is, +.Tn VAX +bytes are +ordered from right to left. +.Pp +When a three part address is specified, the last +part is interpreted as a 16-bit quantity and placed +in the right-most two bytes of the network address. +This makes the three part address format convenient +for specifying Class B network addresses as +.Dq Li 128.net.host . +.Pp +When a two part address is supplied, the last part +is interpreted as a 24-bit quantity and placed in +the right most three bytes of the network address. +This makes the two part address format convenient +for specifying Class A network addresses as +.Dq Li net.host . +.Pp +When only one part is given, the value is stored +directly in the network address without any byte +rearrangement. +.Pp +All numbers supplied as +.Dq parts +in a +.Ql \&. +notation +may be decimal, octal, or hexadecimal, as specified +in the C language (i.e., a leading 0x or 0X implies +hexadecimal; otherwise, a leading 0 implies octal; +otherwise, the number is interpreted as decimal). +.Pp +The +.Fn inet_aton +and +.Fn inet_ntoa +functions are semi-deprecated in favor of the +.Xr addr2ascii 3 +family. However, since those functions are not yet widely implemented, +portable programs cannot rely on their presence and will continue +to use the +.Xr inet 3 +functions for some time. +.Sh DIAGNOSTICS +The constant +.Dv INADDR_NONE +is returned by +.Fn inet_addr +and +.Fn inet_network +for malformed requests. +.Sh SEE ALSO +.Xr addr2ascii 3 , +.Xr gethostbyname 3 , +.Xr getnetent 3 , +.Xr hosts 5 , +.Xr networks 5 +.Sh HISTORY +These +functions appeared in +.Bx 4.2 . +.Sh BUGS +The value +.Dv INADDR_NONE +(0xffffffff) is a valid broadcast address, but +.Fn inet_addr +cannot return that value without indicating failure. +The newer +.Fn inet_aton +function does not share this problem. +The problem of host byte ordering versus network byte ordering is +confusing. +The string returned by +.Fn inet_ntoa +resides in a static memory area. +.Pp +Inet_addr should return a +.Fa struct in_addr . diff --git a/cpukit/libnetworking/libc/inet_addr.c b/cpukit/libnetworking/libc/inet_addr.c new file mode 100644 index 0000000000..a1ac899519 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_addr.c @@ -0,0 +1,180 @@ +/* + * ++Copyright++ 1983, 1990, 1993 + * - + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> + +/* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +u_long +inet_addr(cp) + register const char *cp; +{ + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (INADDR_NONE); +} + +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) + register const char *cp; + struct in_addr *addr; +{ + register u_long val; + register int base, n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + for (;;) { + if (isascii(c) && isdigit(c)) { + val = (val * base) + (c - '0'); + c = *++cp; + } else if (base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) | + (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace(c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} diff --git a/cpukit/libnetworking/libc/inet_lnaof.c b/cpukit/libnetworking/libc/inet_lnaof.c new file mode 100644 index 0000000000..406be30034 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_lnaof.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* + * Return the local network address portion of an + * internet address; handles class a/b/c network + * number formats. + */ +u_long +inet_lnaof(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return ((i)&IN_CLASSA_HOST); + else if (IN_CLASSB(i)) + return ((i)&IN_CLASSB_HOST); + else + return ((i)&IN_CLASSC_HOST); +} diff --git a/cpukit/libnetworking/libc/inet_makeaddr.c b/cpukit/libnetworking/libc/inet_makeaddr.c new file mode 100644 index 0000000000..7976188ea5 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_makeaddr.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* + * Formulate an Internet address from network + host. Used in + * building addresses stored in the ifnet structure. + */ +struct in_addr +inet_makeaddr(net, host) + u_long net, host; +{ + u_long addr; + + if (net < 128) + addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); + else if (net < 65536) + addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); + else if (net < 16777216L) + addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); + else + addr = net | host; + addr = htonl(addr); + return (*(struct in_addr *)&addr); +} diff --git a/cpukit/libnetworking/libc/inet_net_ntop.c b/cpukit/libnetworking/libc/inet_net_ntop.c new file mode 100644 index 0000000000..4c7893d417 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_net_ntop.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char orig_rcsid[] = "From Id: inet_net_ntop.c,v 8.2 1996/08/08 06:54:44 vixie Exp"; +static const char rcsid[] = "$Id$"; +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +static char * inet_net_ntop_ipv4 __P((const u_char *src, int bits, + char *dst, size_t size)); + +/* + * char * + * inet_net_ntop(af, src, bits, dst, size) + * convert network number from network to presentation format. + * generates CIDR style result always. + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * author: + * Paul Vixie (ISC), July 1996 + */ +char * +inet_net_ntop(af, src, bits, dst, size) + int af; + const void *src; + int bits; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_net_ntop_ipv4(src, bits, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } +} + +/* + * static char * + * inet_net_ntop_ipv4(src, bits, dst, size) + * convert IPv4 network number from network to presentation format. + * generates CIDR style result always. + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), July 1996 + */ +static char * +inet_net_ntop_ipv4(src, bits, dst, size) + const u_char *src; + int bits; + char *dst; + size_t size; +{ + char *odst = dst; + char *t; + u_int m; + int b; + + if (bits < 0 || bits > 32) { + errno = EINVAL; + return (NULL); + } + if (bits == 0) { + if (size < sizeof "0") + goto emsgsize; + *dst++ = '0'; + *dst = '\0'; + } + + /* Format whole octets. */ + for (b = bits / 8; b > 0; b--) { + if (size < sizeof "255.") + goto emsgsize; + t = dst; + dst += SPRINTF((dst, "%u", *src++)); + if (b > 1) { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - t); + } + + /* Format partial octet. */ + b = bits % 8; + if (b > 0) { + if (size < sizeof ".255") + goto emsgsize; + t = dst; + if (dst != odst) + *dst++ = '.'; + m = ((1 << b) - 1) << (8 - b); + dst += SPRINTF((dst, "%u", *src & m)); + size -= (size_t)(dst - t); + } + + /* Format CIDR /width. */ + if (size < sizeof "/32") + goto emsgsize; + dst += SPRINTF((dst, "/%u", bits)); + return (odst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); +} diff --git a/cpukit/libnetworking/libc/inet_net_pton.c b/cpukit/libnetworking/libc/inet_net_pton.c new file mode 100644 index 0000000000..8915c2a5be --- /dev/null +++ b/cpukit/libnetworking/libc/inet_net_pton.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char orig_rcsid[] = "From Id: inet_net_pton.c,v 1.8 1996/11/21 10:28:12 vixie Exp $"; +static const char rcsid[] = "$Id$"; +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +static int inet_net_pton_ipv4 __P((const char *src, u_char *dst, + size_t size)); + +/* + * static int + * inet_net_pton(af, src, dst, size) + * convert network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not a valid network specification. + * author: + * Paul Vixie (ISC), June 1996 + */ +int +inet_net_pton(af, src, dst, size) + int af; + const char *src; + void *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_net_pton_ipv4(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (-1); + } +} + +/* + * static int + * inet_net_pton_ipv4(src, dst, size) + * convert IPv4 network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not an IPv4 network specification. + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), June 1996 + */ +static int +inet_net_pton_ipv4(src, dst, size) + const char *src; + u_char *dst; + size_t size; +{ + static const char + xdigits[] = "0123456789abcdef", + digits[] = "0123456789"; + int n, ch, tmp, dirty, bits; + const u_char *odst = dst; + + ch = *src++; + if (ch == '0' && (src[0] == 'x' || src[0] == 'X') + && isascii(src[1]) && isxdigit(src[1])) { + /* Hexadecimal: Eat nybble string. */ + if (size <= 0) + goto emsgsize; + *dst = 0, dirty = 0; + src++; /* skip x or X. */ + while ((ch = *src++) != '\0' && + isascii(ch) && isxdigit(ch)) { + if (isupper(ch)) + ch = tolower(ch); + n = strchr(xdigits, ch) - xdigits; + assert(n >= 0 && n <= 15); + *dst |= n; + if (!dirty++) + *dst <<= 4; + else if (size-- > 0) + *++dst = 0, dirty = 0; + else + goto emsgsize; + } + if (dirty) + size--; + } else if (isascii(ch) && isdigit(ch)) { + /* Decimal: eat dotted digit string. */ + for (;;) { + tmp = 0; + do { + n = strchr(digits, ch) - digits; + assert(n >= 0 && n <= 9); + tmp *= 10; + tmp += n; + if (tmp > 255) + goto enoent; + } while ((ch = *src++) != '\0' && + isascii(ch) && isdigit(ch)); + if (size-- <= 0) + goto emsgsize; + *dst++ = (u_char) tmp; + if (ch == '\0' || ch == '/') + break; + if (ch != '.') + goto enoent; + ch = *src++; + if (!isascii(ch) || !isdigit(ch)) + goto enoent; + } + } else + goto enoent; + + bits = -1; + if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) { + /* CIDR width specifier. Nothing can follow it. */ + ch = *src++; /* Skip over the /. */ + bits = 0; + do { + n = strchr(digits, ch) - digits; + assert(n >= 0 && n <= 9); + bits *= 10; + bits += n; + } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); + if (ch != '\0') + goto enoent; + if (bits > 32) + goto emsgsize; + } + + /* Firey death and destruction unless we prefetched EOS. */ + if (ch != '\0') + goto enoent; + + /* If nothing was written to the destination, we found no address. */ + if (dst == odst) + goto enoent; + /* If no CIDR spec was given, infer width from net class. */ + if (bits == -1) { + if (*odst >= 240) /* Class E */ + bits = 32; + else if (*odst >= 224) /* Class D */ + bits = 4; + else if (*odst >= 192) /* Class C */ + bits = 24; + else if (*odst >= 128) /* Class B */ + bits = 16; + else /* Class A */ + bits = 8; + /* If imputed mask is narrower than specified octets, widen. */ + if (bits >= 8 && bits < ((dst - odst) * 8)) + bits = (dst - odst) * 8; + } + /* Extend network to cover the actual mask. */ + while (bits > ((dst - odst) * 8)) { + if (size-- <= 0) + goto emsgsize; + *dst++ = '\0'; + } + return (bits); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} diff --git a/cpukit/libnetworking/libc/inet_neta.c b/cpukit/libnetworking/libc/inet_neta.c new file mode 100644 index 0000000000..59b156f7f6 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_neta.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char orig_rcsid[] = "From Id: inet_neta.c,v 8.2 1996/08/08 06:54:44 vixie Exp"; +static const char rcsid[] = "$Id$"; +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* + * char * + * inet_neta(src, dst, size) + * format a u_long network number into presentation format. + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * format of ``src'' is as for inet_network(). + * author: + * Paul Vixie (ISC), July 1996 + */ +char * +inet_neta(src, dst, size) + u_long src; + char *dst; + size_t size; +{ + char *odst = dst; + char *tp; + + while (src & 0xffffffff) { + u_char b = (src & 0xff000000) >> 24; + + src <<= 8; + if (b) { + if (size < sizeof "255.") + goto emsgsize; + tp = dst; + dst += SPRINTF((dst, "%u", b)); + if (src != 0L) { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - tp); + } + } + if (dst == odst) { + if (size < sizeof "0.0.0.0") + goto emsgsize; + strcpy(dst, "0.0.0.0"); + } + return (odst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); +} diff --git a/cpukit/libnetworking/libc/inet_netof.c b/cpukit/libnetworking/libc/inet_netof.c new file mode 100644 index 0000000000..d6de694243 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_netof.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* + * Return the network number from an internet + * address; handles class a/b/c network #'s. + */ +u_long +inet_netof(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT); + else if (IN_CLASSB(i)) + return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); + else + return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); +} diff --git a/cpukit/libnetworking/libc/inet_network.c b/cpukit/libnetworking/libc/inet_network.c new file mode 100644 index 0000000000..a62efc7185 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_network.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> + +/* + * Internet network address interpretation routine. + * The library routines call this routine to interpret + * network numbers. + */ +u_long +inet_network(cp) + register const char *cp; +{ + register u_long val, base, n, i; + register char c; + u_long parts[4], *pp = parts; + +again: + val = 0; base = 10; + if (*cp == '0') + base = 8, cp++; + if (*cp == 'x' || *cp == 'X') + base = 16, cp++; + while ((c = *cp) != 0) { + if (isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isxdigit(c)) { + val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + if (pp >= parts + 3) + return (INADDR_NONE); + *pp++ = val, cp++; + goto again; + } + if (*cp && !isspace(*cp)) + return (INADDR_NONE); + *pp++ = val; + n = pp - parts; + for (val = 0, i = 0; i < n; i++) { + val <<= 8; + val |= parts[i] & 0xff; + } + return (val); +} diff --git a/cpukit/libnetworking/libc/inet_ntoa.c b/cpukit/libnetworking/libc/inet_ntoa.c new file mode 100644 index 0000000000..4fdceeed48 --- /dev/null +++ b/cpukit/libnetworking/libc/inet_ntoa.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> + +/* + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +char * +inet_ntoa(in) + struct in_addr in; +{ + static char ret[18]; + + strcpy(ret, "[inet_ntoa error]"); + (void) inet_ntop(AF_INET, &in, ret, sizeof ret); + return (ret); +} diff --git a/cpukit/libnetworking/libc/inet_ntop.c b/cpukit/libnetworking/libc/inet_ntop.c new file mode 100644 index 0000000000..76a538755a --- /dev/null +++ b/cpukit/libnetworking/libc/inet_ntop.c @@ -0,0 +1,191 @@ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#define SPRINTF(x) ((size_t)sprintf x) + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size)); +static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size)); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} diff --git a/cpukit/libnetworking/libc/inet_pton.c b/cpukit/libnetworking/libc/inet_pton.c new file mode 100644 index 0000000000..8d21111cfa --- /dev/null +++ b/cpukit/libnetworking/libc/inet_pton.c @@ -0,0 +1,214 @@ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <string.h> +#include <errno.h> + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 __P((const char *src, u_char *dst)); +static int inet_pton6 __P((const char *src, u_char *dst)); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(af, src, dst) + int af; + const char *src; + void *dst; +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(src, dst) + const char *src; + u_char *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (pch - digits); + + if (new > 255) + return (0); + *tp = new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(src, dst) + const char *src; + u_char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} diff --git a/cpukit/libnetworking/libc/iso_addr.3 b/cpukit/libnetworking/libc/iso_addr.3 new file mode 100644 index 0000000000..05653735c3 --- /dev/null +++ b/cpukit/libnetworking/libc/iso_addr.3 @@ -0,0 +1,110 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" @(#)iso_addr.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt ISO_ADDR 3 +.Os +.Sh NAME +.Nm iso_addr , +.Nm iso_ntoa +.Nd "elementary network address conversion routines for Open System Interconnection +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <netiso/iso.h> +.Ft struct iso_addr * +.Fn iso_addr "char *cp" +.Ft char * +.Fn iso_ntoa "struct iso_addr *isoa" +.Sh DESCRIPTION +The routine +.Fn iso_addr +interprets character strings representing +.Tn OSI +addresses, returning binary information suitable +for use in system calls. +The routine +.Fn iso_ntoa +takes +.Tn OSI +addresses and returns +.Tn ASCII +strings representing NSAPs (network service +access points) in a +notation inverse to that accepted by +.Fn iso_addr . +.Pp +Unfortunately, no universal standard exists for representing +.Tn OSI +network addresses. +.Pp +The format employed by +.Fn iso_addr +is a sequence of hexadecimal +.Dq digits +(optionally separated by periods), +of the form: +.Bd -filled -offset indent +<hex digits>.<hex digits>.<hex digits> +.Ed +.Pp +Each pair of hexadecimal digits represents a byte +with the leading digit indicating the higher-ordered bits. +A period following an even number of bytes has no +effect (but may be used to increase legibility). +A period following an odd number of bytes has the +effect of causing the byte of address being translated +to have its higher order bits filled with zeros. +.Sh RETURN VALUES +.Fn iso_ntoa +always returns a null terminated string. +.Fn iso_addr +always returns a pointer to a struct iso_addr. +(See +.Sx BUGS . ) +.Sh SEE ALSO +.Xr iso 4 +.Sh HISTORY +The +.Fn iso_addr +and +.Fn iso_ntoa +functions appeared in +.Bx 4.3 Reno . +.Sh BUGS +The returned values +reside in a static memory area. +.Pp +The function +.Fn iso_addr +should diagnose improperly formed input, and there should be an unambiguous +way to recognize this. diff --git a/cpukit/libnetworking/libc/iso_addr.c b/cpukit/libnetworking/libc/iso_addr.c new file mode 100644 index 0000000000..8829497973 --- /dev/null +++ b/cpukit/libnetworking/libc/iso_addr.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)iso_addr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <netiso/iso.h> +#include <string.h> + +/* States*/ +#define VIRGIN 0 +#define GOTONE 1 +#define GOTTWO 2 +/* Inputs */ +#define DIGIT (4*0) +#define END (4*1) +#define DELIM (4*2) + +struct iso_addr * +iso_addr(addr) + register const char *addr; +{ + static struct iso_addr out_addr; + register char *cp = out_addr.isoa_genaddr; + char *cplim = cp + sizeof(out_addr.isoa_genaddr); + register int byte = 0, state = VIRGIN, new; + + bzero((char *)&out_addr, sizeof(out_addr)); + do { + if ((*addr >= '0') && (*addr <= '9')) { + new = *addr - '0'; + } else if ((*addr >= 'a') && (*addr <= 'f')) { + new = *addr - 'a' + 10; + } else if ((*addr >= 'A') && (*addr <= 'F')) { + new = *addr - 'A' + 10; + } else if (*addr == 0) + state |= END; + else + state |= DELIM; + addr++; + switch (state /* | INPUT */) { + case GOTTWO | DIGIT: + *cp++ = byte; /*FALLTHROUGH*/ + case VIRGIN | DIGIT: + state = GOTONE; byte = new; continue; + case GOTONE | DIGIT: + state = GOTTWO; byte = new + (byte << 4); continue; + default: /* | DELIM */ + state = VIRGIN; *cp++ = byte; byte = 0; continue; + case GOTONE | END: + case GOTTWO | END: + *cp++ = byte; /* FALLTHROUGH */ + case VIRGIN | END: + break; + } + break; + } while (cp < cplim); + out_addr.isoa_len = cp - out_addr.isoa_genaddr; + return (&out_addr); +} + +static char hexlist[] = "0123456789abcdef"; + +char * +iso_ntoa(isoa) + const struct iso_addr *isoa; +{ + static char tmpbuf[sizeof(isoa->isoa_genaddr)*3]; + const u_char *binary; + char *cp; + int i; + + binary = isoa->isoa_genaddr; + cp = tmpbuf; + + for (i = 0; i < isoa->isoa_len; i++) { + *cp++ = hexlist[*binary >> 4]; + *cp++ = hexlist[*binary++ & 0xf]; + + if ((((i % 2) == 0) && ((i + 1) < isoa->isoa_len))) + *cp++ = '.'; + } + *cp = '\0'; + return tmpbuf; +} diff --git a/cpukit/libnetworking/libc/linkaddr.3 b/cpukit/libnetworking/libc/linkaddr.3 new file mode 100644 index 0000000000..6999add0e8 --- /dev/null +++ b/cpukit/libnetworking/libc/linkaddr.3 @@ -0,0 +1,138 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Donn Seeley at BSDI. +.\" +.\" 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" From: @(#)linkaddr.3 8.1 (Berkeley) 7/28/93 +.\" $Id$ +.\" +.Dd June 17, 1996 +.Dt LINK_ADDR 3 +.Os BSD 4.4 +.Sh NAME +.Nm link_addr , +.Nm link_ntoa +.Nd elementary address specification routines for link level access +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <sys/socket.h> +.Fd #include <net/if_dl.h> +.Ft void +.Fn link_addr "const char *addr" "struct sockaddr_dl *sdl" +.Ft char * +.Fn link_ntoa "const struct sockaddr_dl *sdl" +.Sh DESCRIPTION +The routine +.Fn link_addr +interprets character strings representing +link-level addresses, returning binary information suitable +for use in system calls. +The routine +.Fn link_ntoa +takes +a link-level +address and returns an +.Tn ASCII +string representing some of the information present, +including the link level address itself, and the interface name +or number, if present. +This facility is experimental and is +still subject to change. +.Pp +For +.Fn link_addr , +the string +.Fa addr +may contain +an optional network interface identifier of the form +.Dq "name unit-number" , +suitable for the first argument to +.Xr ifconfig 8 , +followed in all cases by a colon and +an interface address in the form of +groups of hexadecimal digits +separated by periods. +Each group represents a byte of address; +address bytes are filled left to right from +low order bytes through high order bytes. +.Pp +.\" A regular expression may make this format clearer: +.\" .Bd -literal -offset indent +.\" ([a-z]+[0-9]+:)?[0-9a-f]+(\e.[0-9a-f]+)* +.\" .Ed +.\" .Pp +Thus +.Li le0:8.0.9.13.d.30 +represents an ethernet address +to be transmitted on the first Lance ethernet interface. +.Pp +The direct use of these functions is deprecated in favor of the +.Xr addr2ascii 3 +interface; however, portable programs cannot rely on the latter as it is +not yet widely implemented. +.Sh RETURN VALUES +.Fn link_ntoa +always returns a null terminated string. +.Fn link_addr +has no return value. +(See +.Sx BUGS . ) +.Sh SEE ALSO +.Xr addr2ascii 3 +.\" .Xr iso 4 +.Sh HISTORY +The +.Fn link_addr +and +.Fn link_ntoa +functions appeared in +.Bx 4.3 Reno . +.Sh BUGS +The returned values for link_ntoa +reside in a static memory area. +.Pp +The function +.Fn link_addr +should diagnose improperly formed input, and there should be an unambiguous +way to recognize this. +.Pp +If the +.Va sdl_len +field of the link socket address +.Fa sdl +is 0, +.Fn link_ntoa +will not insert a colon before the interface address bytes. +If this translated address is given to +.Fn link_addr +without inserting an initial colon, +the latter will not interpret it correctly. diff --git a/cpukit/libnetworking/libc/linkaddr.c b/cpukit/libnetworking/libc/linkaddr.c new file mode 100644 index 0000000000..68eed3df33 --- /dev/null +++ b/cpukit/libnetworking/libc/linkaddr.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)linkaddr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if_dl.h> +#include <string.h> + +/* States*/ +#define NAMING 0 +#define GOTONE 1 +#define GOTTWO 2 +#define RESET 3 +/* Inputs */ +#define DIGIT (4*0) +#define END (4*1) +#define DELIM (4*2) +#define LETTER (4*3) + +void +link_addr(addr, sdl) + register const char *addr; + register struct sockaddr_dl *sdl; +{ + register char *cp = sdl->sdl_data; + char *cplim = sdl->sdl_len + (char *)sdl; + register int byte = 0, state = NAMING, new; + + bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1); + sdl->sdl_family = AF_LINK; + do { + state &= ~LETTER; + if ((*addr >= '0') && (*addr <= '9')) { + new = *addr - '0'; + } else if ((*addr >= 'a') && (*addr <= 'f')) { + new = *addr - 'a' + 10; + } else if ((*addr >= 'A') && (*addr <= 'F')) { + new = *addr - 'A' + 10; + } else if (*addr == 0) { + state |= END; + } else if (state == NAMING && + (((*addr >= 'A') && (*addr <= 'Z')) || + ((*addr >= 'a') && (*addr <= 'z')))) + state |= LETTER; + else + state |= DELIM; + addr++; + switch (state /* | INPUT */) { + case NAMING | DIGIT: + case NAMING | LETTER: + *cp++ = addr[-1]; + continue; + case NAMING | DELIM: + state = RESET; + sdl->sdl_nlen = cp - sdl->sdl_data; + continue; + case GOTTWO | DIGIT: + *cp++ = byte; + /* FALLTHROUGH */ + case RESET | DIGIT: + state = GOTONE; + byte = new; + continue; + case GOTONE | DIGIT: + state = GOTTWO; + byte = new + (byte << 4); + continue; + default: /* | DELIM */ + state = RESET; + *cp++ = byte; + byte = 0; + continue; + case GOTONE | END: + case GOTTWO | END: + *cp++ = byte; + /* FALLTHROUGH */ + case RESET | END: + break; + } + break; + } while (cp < cplim); + sdl->sdl_alen = cp - LLADDR(sdl); + new = cp - (char *)sdl; + if (new > sizeof(*sdl)) + sdl->sdl_len = new; + return; +} + +static char hexlist[] = "0123456789abcdef"; + +char * +link_ntoa(sdl) + register const struct sockaddr_dl *sdl; +{ + static char obuf[64]; + register char *out = obuf; + register int i; + register u_char *in = (u_char *)LLADDR(sdl); + u_char *inlim = in + sdl->sdl_alen; + int firsttime = 1; + + if (sdl->sdl_nlen) { + bcopy(sdl->sdl_data, obuf, sdl->sdl_nlen); + out += sdl->sdl_nlen; + if (sdl->sdl_alen) + *out++ = ':'; + } + while (in < inlim) { + if (firsttime) + firsttime = 0; + else + *out++ = '.'; + i = *in++; + if (i > 0xf) { + out[1] = hexlist[i & 0xf]; + i >>= 4; + out[0] = hexlist[i]; + out += 2; + } else + *out++ = hexlist[i]; + } + *out = 0; + return (obuf); +} diff --git a/cpukit/libnetworking/libc/map_v4v6.c b/cpukit/libnetworking/libc/map_v4v6.c new file mode 100644 index 0000000000..0f8658e117 --- /dev/null +++ b/cpukit/libnetworking/libc/map_v4v6.c @@ -0,0 +1,128 @@ +/* + * ++Copyright++ 1985, 1988, 1993 + * - + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <stdio.h> +#include <string.h> +#include <netdb.h> +#include <resolv.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> + +typedef union { + int32_t al; + char ac; +} align; + +void +_map_v4v6_address(src, dst) + const char *src; + char *dst; +{ + u_char *p = (u_char *)dst; + char tmp[INADDRSZ]; + int i; + + /* Stash a temporary copy so our caller can update in place. */ + bcopy(src, tmp, INADDRSZ); + /* Mark this ipv6 addr as a mapped ipv4. */ + for (i = 0; i < 10; i++) + *p++ = 0x00; + *p++ = 0xff; + *p++ = 0xff; + /* Retrieve the saved copy and we're done. */ + bcopy(tmp, (void*)p, INADDRSZ); +} + +void +_map_v4v6_hostent(hp, bpp, lenp) + struct hostent *hp; + char **bpp; + int *lenp; +{ + char **ap; + + if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) + return; + hp->h_addrtype = AF_INET6; + hp->h_length = IN6ADDRSZ; + for (ap = hp->h_addr_list; *ap; ap++) { + int i = sizeof(align) - ((u_long)*bpp % sizeof(align)); + + if (*lenp < (i + IN6ADDRSZ)) { + /* Out of memory. Truncate address list here. XXX */ + *ap = NULL; + return; + } + *bpp += i; + *lenp -= i; + _map_v4v6_address(*ap, *bpp); + *ap = *bpp; + *bpp += IN6ADDRSZ; + *lenp -= IN6ADDRSZ; + } +} diff --git a/cpukit/libnetworking/libc/ns.3 b/cpukit/libnetworking/libc/ns.3 new file mode 100644 index 0000000000..e621ad2d90 --- /dev/null +++ b/cpukit/libnetworking/libc/ns.3 @@ -0,0 +1,131 @@ +.\" Copyright (c) 1986, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" @(#)ns.3 8.1 (Berkeley) 6/4/93 +.\" $Id$ +.\" +.Dd June 4, 1993 +.Dt NS 3 +.Os BSD 4.3 +.Sh NAME +.Nm ns_addr , +.Nm ns_ntoa +.Nd Xerox +.Tn NS Ns (tm) +address conversion routines +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <netns/ns.h> +.Ft struct ns_addr +.Fn ns_addr "char *cp" +.Ft char * +.Fn ns_ntoa "struct ns_addr ns" +.Sh DESCRIPTION +The routine +.Fn ns_addr +interprets character strings representing +.Tn XNS +addresses, returning binary information suitable +for use in system calls. +The routine +.Fn ns_ntoa +takes +.Tn XNS +addresses and returns +.Tn ASCII +strings representing the address in a +notation in common use in the Xerox Development Environment: +.Bd -filled -offset indent +<network number>.<host number>.<port number> +.Ed +.Pp +Trailing zero fields are suppressed, and each number is printed in hexadecimal, +in a format suitable for input to +.Fn ns_addr . +Any fields lacking super-decimal digits will have a +trailing +.Ql H +appended. +.Pp +Unfortunately, no universal standard exists for representing +.Tn XNS +addresses. +An effort has been made to insure that +.Fn ns_addr +be compatible with most formats in common use. +It will first separate an address into 1 to 3 fields using a single delimiter +chosen from +period +.Ql \&. , +colon +.Ql \&: +or pound-sign +.Ql \&# . +Each field is then examined for byte separators (colon or period). +If there are byte separators, each subfield separated is taken to be +a small hexadecimal number, and the entirety is taken as a network-byte-ordered +quantity to be zero extended in the high-network-order bytes. +Next, the field is inspected for hyphens, in which case +the field is assumed to be a number in decimal notation +with hyphens separating the millenia. +Next, the field is assumed to be a number: +It is interpreted +as hexadecimal if there is a leading +.Ql 0x +(as in C), +a trailing +.Ql H +(as in Mesa), or there are any super-decimal digits present. +It is interpreted as octal is there is a leading +.Ql 0 +and there are no super-octal digits. +Otherwise, it is converted as a decimal number. +.Sh RETURN VALUES +None. (See +.Sx BUGS . ) +.Sh SEE ALSO +.Xr hosts 5 , +.Xr networks 5 +.Sh HISTORY +The +.Fn ns_addr +and +.Fn ns_toa +functions appeared in +.Bx 4.3 . +.Sh BUGS +The string returned by +.Fn ns_ntoa +resides in a static memory area. +The function +.Fn ns_addr +should diagnose improperly formed input, and there should be an unambiguous +way to recognize this. diff --git a/cpukit/libnetworking/libc/ns_addr.c b/cpukit/libnetworking/libc/ns_addr.c new file mode 100644 index 0000000000..3446e08c19 --- /dev/null +++ b/cpukit/libnetworking/libc/ns_addr.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * J.Q. Johnson. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ns_addr.c 8.1 (Berkeley) 6/7/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netns/ns.h> +#include <stdio.h> +#include <string.h> + +static struct ns_addr addr, zero_addr; + +static void Field(), cvtbase(); + +struct ns_addr +ns_addr(name) + const char *name; +{ + char separator; + char *hostname, *socketname, *cp; + char buf[50]; + + (void)strncpy(buf, name, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + /* + * First, figure out what he intends as a field separtor. + * Despite the way this routine is written, the prefered + * form 2-272.AA001234H.01777, i.e. XDE standard. + * Great efforts are made to insure backward compatability. + */ + if ((hostname = strchr(buf, '#')) != NULL) + separator = '#'; + else { + hostname = strchr(buf, '.'); + if ((cp = strchr(buf, ':')) && + ((hostname && cp < hostname) || (hostname == 0))) { + hostname = cp; + separator = ':'; + } else + separator = '.'; + } + if (hostname) + *hostname++ = 0; + + addr = zero_addr; + Field(buf, addr.x_net.c_net, 4); + if (hostname == 0) + return (addr); /* No separator means net only */ + + socketname = strchr(hostname, separator); + if (socketname) { + *socketname++ = 0; + Field(socketname, (u_char *)&addr.x_port, 2); + } + + Field(hostname, addr.x_host.c_host, 6); + + return (addr); +} + +static void +Field(buf, out, len) + char *buf; + u_char *out; + int len; +{ + register char *bp = buf; + int i, ibase, base16 = 0, base10 = 0, clen = 0; + int hb[6], *hp; + char *fmt; + + /* + * first try 2-273#2-852-151-014#socket + */ + if ((*buf != '-') && + (1 < (i = sscanf(buf, "%d-%d-%d-%d-%d", + &hb[0], &hb[1], &hb[2], &hb[3], &hb[4])))) { + cvtbase(1000L, 256, hb, i, out, len); + return; + } + /* + * try form 8E1#0.0.AA.0.5E.E6#socket + */ + if (1 < (i = sscanf(buf,"%x.%x.%x.%x.%x.%x", + &hb[0], &hb[1], &hb[2], &hb[3], &hb[4], &hb[5]))) { + cvtbase(256L, 256, hb, i, out, len); + return; + } + /* + * try form 8E1#0:0:AA:0:5E:E6#socket + */ + if (1 < (i = sscanf(buf,"%x:%x:%x:%x:%x:%x", + &hb[0], &hb[1], &hb[2], &hb[3], &hb[4], &hb[5]))) { + cvtbase(256L, 256, hb, i, out, len); + return; + } + /* + * This is REALLY stretching it but there was a + * comma notation separting shorts -- definitely non standard + */ + if (1 < (i = sscanf(buf,"%x,%x,%x", + &hb[0], &hb[1], &hb[2]))) { + hb[0] = htons(hb[0]); hb[1] = htons(hb[1]); + hb[2] = htons(hb[2]); + cvtbase(65536L, 256, hb, i, out, len); + return; + } + + /* Need to decide if base 10, 16 or 8 */ + while (*bp) switch (*bp++) { + + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '-': + break; + + case '8': case '9': + base10 = 1; + break; + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + base16 = 1; + break; + + case 'x': case 'X': + *--bp = '0'; + base16 = 1; + break; + + case 'h': case 'H': + base16 = 1; + /* fall into */ + + default: + *--bp = 0; /* Ends Loop */ + } + if (base16) { + fmt = "%3x"; + ibase = 4096; + } else if (base10 == 0 && *buf == '0') { + fmt = "%3o"; + ibase = 512; + } else { + fmt = "%3d"; + ibase = 1000; + } + + for (bp = buf; *bp++; ) clen++; + if (clen == 0) clen++; + if (clen > 18) clen = 18; + i = ((clen - 1) / 3) + 1; + bp = clen + buf - 3; + hp = hb + i - 1; + + while (hp > hb) { + (void)sscanf(bp, fmt, hp); + bp[0] = 0; + hp--; + bp -= 3; + } + (void)sscanf(buf, fmt, hp); + cvtbase((long)ibase, 256, hb, i, out, len); +} + +static void +cvtbase(oldbase,newbase,input,inlen,result,reslen) + long oldbase; + int newbase; + int input[]; + int inlen; + unsigned char result[]; + int reslen; +{ + int d, e; + long sum; + + e = 1; + while (e > 0 && reslen > 0) { + d = 0; e = 0; sum = 0; + /* long division: input=input/newbase */ + while (d < inlen) { + sum = sum*oldbase + (long) input[d]; + e += (sum > 0); + input[d++] = sum / newbase; + sum %= newbase; + } + result[--reslen] = sum; /* accumulate remainder */ + } + for (d=0; d < reslen; d++) + result[d] = 0; +} diff --git a/cpukit/libnetworking/libc/ns_name.c b/cpukit/libnetworking/libc/ns_name.c new file mode 100644 index 0000000000..3e6b2b87fa --- /dev/null +++ b/cpukit/libnetworking/libc/ns_name.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +#include <sys/types.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> + +#include <errno.h> +#include <resolv.h> +#include <string.h> + +/* Data. */ + +static char digits[] = "0123456789"; + +/* Forward. */ + +static int special(int); +static int printable(int); +static int dn_find(const u_char *, const u_char *, + const u_char * const *, + const u_char * const *); + +/* Public. */ + +/* + * ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) { + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; n > 0; n--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +/* + * ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { + u_char *label, *bp, *eom; + int c, n, escaped; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + return (1); + } + if (c == 0) { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + return (0); +} + +/* + * ns_name_unpack(msg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +int +ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, + u_char *dst, size_t dstsiz) +{ + const u_char *srcp, *dstlim; + u_char *dstp; + int n, c, len, checked; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + /* Limit checks. */ + if (dstp + n + 1 >= dstlim || srcp + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += n + 1; + *dstp++ = n; + memcpy(dstp, srcp, n); + dstp += n; + srcp += n; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /* Out of range. */ + errno = EMSGSIZE; + return (-1); + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} + +/* + * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +int +ns_name_pack(const u_char *src, u_char *dst, int dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + int n, l; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + n = *srcp; + if ((n & NS_CMPRSFLGS) != 0) { + errno = EMSGSIZE; + return (-1); + } + l += n + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += n + 1; + } while (n != 0); + + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + errno = EMSGSIZE; + return (-1); + } + *dstp++ = (l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000) { + *cpp++ = dstp; + *cpp = NULL; + } + } + /* copy label to buffer */ + if (n & NS_CMPRSFLGS) { /* Should not happen. */ + errno = EMSGSIZE; + return (-1); + } + if (dstp + 1 + n >= eob) { + errno = EMSGSIZE; + return (-1); + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + return (dstp - dst); +} + +/* + * ns_name_uncompress(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +int +ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, size_t dstsiz) +{ + u_char tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/* + * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) + * Compress a domain name into wire format, using compression pointers. + * return: + * Number of bytes consumed in `dst' or -1 (with errno set). + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. + * The list ends with NULL. 'lastdnptr' is a pointer to the end of the + * array pointed to by 'dnptrs'. Side effect is to update the list of + * pointers for labels inserted into the message as we compress the name. + * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +int +ns_name_compress(const char *src, u_char *dst, size_t dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +int +ns_name_skip(const u_char **ptrptr, const u_char *eom) { + const u_char *cp; + u_int n; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +/* Private. */ + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * boolean. + */ +static int +special(int ch) { + switch (ch) { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return (1); + default: + return (0); + } +} + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static int +printable(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mklower(int ch) { + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +/* + * dn_find(domain, msg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from msg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +dn_find(const u_char *domain, const u_char *msg, + const u_char * const *dnptrs, + const u_char * const *lastdnptr) +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + dn = domain; + sp = cp = *cpp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + if (n != *dn++) + goto next; + for ((void)NULL; n > 0; n--) + if (mklower(*dn++) != mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + } + errno = ENOENT; + return (-1); +} diff --git a/cpukit/libnetworking/libc/ns_netint.c b/cpukit/libnetworking/libc/ns_netint.c new file mode 100644 index 0000000000..bf0f793c2c --- /dev/null +++ b/cpukit/libnetworking/libc/ns_netint.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +/* Import. */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> + +u_int +ns_get16(const u_char *src) { + u_int dst; + + NS_GET16(dst, src); + return (dst); +} + +u_long +ns_get32(const u_char *src) { + u_long dst; + + NS_GET32(dst, src); + return (dst); +} + +void +ns_put16(u_int src, u_char *dst) { + NS_PUT16(src, dst); +} + +void +ns_put32(u_long src, u_char *dst) { + NS_PUT32(src, dst); +} diff --git a/cpukit/libnetworking/libc/ns_ntoa.c b/cpukit/libnetworking/libc/ns_ntoa.c new file mode 100644 index 0000000000..de5f305887 --- /dev/null +++ b/cpukit/libnetworking/libc/ns_ntoa.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ns_ntoa.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netns/ns.h> +#include <stdio.h> + +char * +ns_ntoa(addr) + struct ns_addr addr; +{ + static char obuf[40]; + union { union ns_net net_e; u_long long_e; } net; + u_short port = htons(addr.x_port); + register char *cp; + char *cp2; + register u_char *up = addr.x_host.c_host; + u_char *uplim = up + 6; + static char *spectHex(); + + net.net_e = addr.x_net; + sprintf(obuf, "%lx", (u_long)ntohl(net.long_e)); + cp = spectHex(obuf); + cp2 = cp + 1; + while (*up==0 && up < uplim) up++; + if (up == uplim) { + if (port) { + sprintf(cp, ".0"); + cp += 2; + } + } else { + sprintf(cp, ".%x", *up++); + while (up < uplim) { + while (*cp) cp++; + sprintf(cp, "%02x", *up++); + } + cp = spectHex(cp2); + } + if (port) { + sprintf(cp, ".%x", port); + spectHex(cp + 1); + } + return (obuf); +} + +static char * +spectHex(p0) + char *p0; +{ + int ok = 0; + int nonzero = 0; + register char *p = p0; + for (; *p; p++) switch (*p) { + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + *p += ('A' - 'a'); + /* fall into . . . */ + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + ok = 1; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + nonzero = 1; + } + if (nonzero && !ok) { *p++ = 'H'; *p = 0; } + return (p); +} diff --git a/cpukit/libnetworking/libc/ns_parse.c b/cpukit/libnetworking/libc/ns_parse.c new file mode 100644 index 0000000000..13b9956d93 --- /dev/null +++ b/cpukit/libnetworking/libc/ns_parse.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +#include <sys/types.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> + +#include <errno.h> +#include <resolv.h> +#include <string.h> + +/* These need to be in the same order as the nres.h:ns_flag enum. */ +struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /* qr. */ + { 0x7800, 11 }, /* opcode. */ + { 0x0400, 10 }, /* aa. */ + { 0x0200, 9 }, /* tc. */ + { 0x0100, 8 }, /* rd. */ + { 0x0080, 7 }, /* ra. */ + { 0x0040, 6 }, /* z. */ + { 0x0020, 5 }, /* ad. */ + { 0x0010, 4 }, /* cd. */ + { 0x000f, 0 }, /* rcode. */ + { 0x0000, 0 }, /* expansion (1/6). */ + { 0x0000, 0 }, /* expansion (2/6). */ + { 0x0000, 0 }, /* expansion (3/6). */ + { 0x0000, 0 }, /* expansion (4/6). */ + { 0x0000, 0 }, /* expansion (5/6). */ + { 0x0000, 0 }, /* expansion (6/6). */ +}; + +static int +skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { + const u_char *optr = ptr; + + for ((void)NULL; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) + goto emsgsize; + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ > eom) + goto emsgsize; + ptr += NS_INT32SZ/*TTL*/; + if (ptr + NS_INT16SZ > eom) + goto emsgsize; + NS_GET16(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + goto emsgsize; + return (ptr - optr); + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +int +ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { + const u_char *eom = msg + msglen; + int i; + + memset(handle, 0x5e, sizeof *handle); + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + goto emsgsize; + NS_GET16(handle->_id, msg); + if (msg + NS_INT16SZ > eom) + goto emsgsize; + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) + goto emsgsize; + NS_GET16(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg != eom) + goto emsgsize; + handle->_sect = ns_s_max; + handle->_rrnum = -1; + handle->_ptr = NULL; + return (0); + emsgsize: + errno = EMSGSIZE; + return (-1); +} + +int +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { + int b; + + /* Make section right. */ + if (section < 0 || section >= ns_s_max) + goto enodev; + if ((int)section != (int)handle->_sect) { + handle->_sect = section; + handle->_rrnum = 0; + handle->_ptr = handle->_sections[(int)section]; + } + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + goto enodev; + if (rrnum < handle->_rrnum) { + handle->_rrnum = 0; + handle->_ptr = handle->_sections[(int)section]; + } + + b = skiprr(handle->_msg, handle->_eom, section, + rrnum - handle->_rrnum); + if (b < 0) + return (-1); + handle->_ptr += b; + handle->_rrnum = rrnum; + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_ptr += b; + if (handle->_ptr + NS_INT16SZ > handle->_eom) + goto emsgsize; + NS_GET16(rr->type, handle->_ptr); + if (handle->_ptr + NS_INT16SZ > handle->_eom) + goto emsgsize; + NS_GET16(rr->class, handle->_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_ptr + NS_INT32SZ > handle->_eom) + goto emsgsize; + NS_GET32(rr->ttl, handle->_ptr); + if (handle->_ptr + NS_INT16SZ > handle->_eom) + goto emsgsize; + NS_GET16(rr->rdlength, handle->_ptr); + if (handle->_ptr + rr->rdlength > handle->_eom) + goto emsgsize; + rr->rdata = handle->_ptr; + handle->_ptr += rr->rdlength; + } + handle->_rrnum++; + + /* All done. */ + return (0); + enodev: + errno = ENODEV; + return (-1); + emsgsize: + errno = EMSGSIZE; + return (-1); +} diff --git a/cpukit/libnetworking/libc/ns_print.c b/cpukit/libnetworking/libc/ns_print.c new file mode 100644 index 0000000000..8e27c1290c --- /dev/null +++ b/cpukit/libnetworking/libc/ns_print.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +/* Import. */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <errno.h> +#include <resolv.h> +#include <string.h> +#include <ctype.h> + +#define SPRINTF(x) ((size_t)sprintf x) + +/* Forward. */ + +static size_t prune_origin(const char *name, const char *origin); +static int charstr(const u_char *rdata, const u_char *edata, + char **buf, size_t *buflen); +static int addname(const u_char *msg, size_t msglen, + const u_char **p, const char *origin, + char **buf, size_t *buflen); +static void addlen(size_t len, char **buf, size_t *buflen); +static int addstr(const char *src, size_t len, + char **buf, size_t *buflen); +static int addtab(size_t len, size_t target, int spaced, + char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) \ + do { \ + if ((x) < 0) \ + return (-1); \ + } while (0) + +/* Public. */ + +/* + * int + * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen) + * Convert an RR to presentation format. + * return: + * Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrr(const ns_msg *handle, const ns_rr *rr, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + int n; + + n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), + ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), + ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), + name_ctx, origin, buf, buflen); + return (n); +} + +/* + * int + * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen, + * name_ctx, origin, buf, buflen) + * Convert the fields of an RR into presentation format. + * return: + * Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrrf(const u_char *msg, size_t msglen, + const char *name, ns_class class, ns_type type, + u_long ttl, const u_char *rdata, size_t rdlen, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + const char *obuf = buf; + const u_char *edata = rdata + rdlen; + int spaced = 0; + + const char *comment; + char tmp[100]; + int len, x; + + /* + * Owner. + */ + if (name_ctx != NULL && strcasecmp(name_ctx, name) == 0) { + T(addstr("\t\t\t", 3, &buf, &buflen)); + } else { + len = prune_origin(name, origin); + if (len == 0) { + T(addstr("@\t\t\t", 4, &buf, &buflen)); + } else { + T(addstr(name, len, &buf, &buflen)); + /* Origin not used and no trailing dot? */ + if ((!origin || !origin[0] || name[len] == '\0') && + name[len - 1] != '.') { + T(addstr(".", 1, &buf, &buflen)); + len++; + } + T(spaced = addtab(len, 24, spaced, &buf, &buflen)); + } + } + + /* + * TTL, Class, Type. + */ + T(x = ns_format_ttl(ttl, buf, buflen)); + addlen(x, &buf, &buflen); + len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); + T(addstr(tmp, len, &buf, &buflen)); + T(spaced = addtab(x + len, 16, spaced, &buf, &buflen)); + + /* + * RData. + */ + switch (type) { + case ns_t_a: + if (rdlen != NS_INADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + case ns_t_ns: + case ns_t_ptr: + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + + case ns_t_hinfo: + case ns_t_isdn: + /* First word. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Second word. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_soa: { + u_long t; + + /* Server name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Administrator name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" (\n", 3, &buf, &buflen)); + spaced = 0; + + if ((edata - rdata) != 5*NS_INT32SZ) + goto formerr; + + /* Serial number. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + len = SPRINTF((tmp, "%lu", t)); + T(addstr(tmp, len, &buf, &buflen)); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; serial\n", 9, &buf, &buflen)); + spaced = 0; + + /* Refresh interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; refresh\n", 10, &buf, &buflen)); + spaced = 0; + + /* Retry interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; retry\n", 8, &buf, &buflen)); + spaced = 0; + + /* Expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; expiry\n", 9, &buf, &buflen)); + spaced = 0; + + /* Minimum TTL. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen(len, &buf, &buflen); + T(addstr(" )", 2, &buf, &buflen)); + T(spaced = addtab(len, 16, spaced, &buf, &buflen)); + T(addstr("; minimum\n", 10, &buf, &buflen)); + + break; + } + + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: { + u_int t; + + if (rdlen < NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", t)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Target. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_px: { + u_int t; + + if (rdlen < NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", t)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_x25: + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_txt: + while (rdata < edata) { + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + if (rdata < edata) + T(addstr(" ", 1, &buf, &buflen)); + } + break; + + case ns_t_nsap: { + char t[255*3]; + + (void) inet_nsap_ntoa(rdlen, rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_aaaa: + if (rdlen != NS_IN6ADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET6, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_loc: { + char t[255]; + + /* XXX protocol format checking? */ + (void) loc_ntoa(rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_naptr: { + u_int order, preference; + char t[50]; + + if (rdlen < 2*NS_INT16SZ) + goto formerr; + + /* Order, Precedence. */ + order = ns_get16(rdata); rdata += NS_INT16SZ; + preference = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((t, "%u %u ", order, preference)); + T(addstr(t, len, &buf, &buflen)); + + /* Flags. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Service. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Regexp. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len < 0) + return (-1); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", 1, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_srv: { + u_int priority, weight, port; + char t[50]; + + if (rdlen < NS_INT16SZ*3) + goto formerr; + + /* Priority, Weight, Port. */ + priority = ns_get16(rdata); rdata += NS_INT16SZ; + weight = ns_get16(rdata); rdata += NS_INT16SZ; + port = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((t, "%u %u %u ", priority, weight, port)); + T(addstr(t, len, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_minfo: + case ns_t_rp: + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + + case ns_t_wks: { + int n, lcnt; + + if (rdlen < NS_INT32SZ + 1) + goto formerr; + + /* Address. */ + (void) inet_ntop(AF_INET, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += NS_INADDRSZ; + + /* Protocol. */ + len = SPRINTF((tmp, " %u ( ", *rdata)); + T(addstr(tmp, len, &buf, &buflen)); + rdata += NS_INT8SZ; + + /* Bit map. */ + n = 0; + lcnt = 0; + while (rdata < edata) { + u_int c = *rdata++; + do { + if (c & 0200) { + if (lcnt == 0) { + T(addstr("\n\t\t\t\t", 5, + &buf, &buflen)); + lcnt = 10; + spaced = 0; + } + len = SPRINTF((tmp, "%d ", n)); + T(addstr(tmp, len, &buf, &buflen)); + lcnt--; + } + c <<= 1; + } while (++n & 07); + } + T(addstr(")", 1, &buf, &buflen)); + + break; + } + + case ns_t_key: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int keyflags, protocol, algorithm; + const char *leader; + int n; + + if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) + goto formerr; + + /* Key flags, Protocol, Algorithm. */ + keyflags = ns_get16(rdata); rdata += NS_INT16SZ; + protocol = *rdata++; + algorithm = *rdata++; + len = SPRINTF((tmp, "0x%04x %u %u", + keyflags, protocol, algorithm)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Public key data. */ + len = b64_ntop(rdata, edata - rdata, + base64_key, sizeof base64_key); + if (len < 0) + goto formerr; + if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + + break; + } + + case ns_t_sig: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int type, algorithm, labels, footprint; + const char *leader; + u_long t; + int n; + + if (rdlen < 22) + goto formerr; + + /* Type covered, Algorithm, Label count, Original TTL. */ + type = ns_get16(rdata); rdata += NS_INT16SZ; + algorithm = *rdata++; + labels = *rdata++; + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, " %s %d %lu ", + p_type(type), algorithm, t)); + T(addstr(tmp, len, &buf, &buflen)); + if (labels != (u_int)dn_count_labels(name)) + goto formerr; + + /* Signature expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, len, &buf, &buflen)); + + /* Time signed. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, len, &buf, &buflen)); + + /* Signature Footprint. */ + footprint = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", footprint)); + T(addstr(tmp, len, &buf, &buflen)); + + /* Signer's name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Signature. */ + len = b64_ntop(rdata, edata - rdata, + base64_key, sizeof base64_key); + if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + if (len < 0) + goto formerr; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + + break; + } + + case ns_t_nxt: { + int n, c; + + /* Next domain name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Type bit map. */ + n = edata - rdata; + for (c = 0; c < n*8; c++) + if (NS_NXT_BIT_ISSET(c, rdata)) { + len = SPRINTF((tmp, " %s", p_type(c))); + T(addstr(tmp, len, &buf, &buflen)); + } + break; + } + + default: + comment = "unknown RR type"; + goto hexify; + } + return (buf - obuf); + formerr: + comment = "RR format error"; + hexify: { + int n, m; + char *p; + + len = SPRINTF((tmp, "\\#(\t\t; %s", comment)); + T(addstr(tmp, len, &buf, &buflen)); + while (rdata < edata) { + p = tmp; + p += SPRINTF((p, "\n\t")); + spaced = 0; + n = MIN(16, edata - rdata); + for (m = 0; m < n; m++) + p += SPRINTF((p, "%02x ", rdata[m])); + T(addstr(tmp, p - tmp, &buf, &buflen)); + if (n < 16) { + T(addstr(")", 1, &buf, &buflen)); + T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen)); + } + p = tmp; + p += SPRINTF((p, "; ")); + for (m = 0; m < n; m++) + *p++ = (isascii(rdata[m]) && isprint(rdata[m])) + ? rdata[m] + : '.'; + T(addstr(tmp, p - tmp, &buf, &buflen)); + rdata += n; + } + return (buf - obuf); + } +} + +/* Private. */ + +/* + * size_t + * prune_origin(name, origin) + * Find out if the name is at or under the current origin. + * return: + * Number of characters in name before start of origin, + * or length of name if origin does not match. + * notes: + * This function should share code with samedomain(). + */ +static size_t +prune_origin(const char *name, const char *origin) { + const char *oname = name; + + while (*name != '\0') { + if (origin != NULL && strcasecmp(name, origin) == 0) + return (name - oname - (name > oname)); + while (*name != '\0') { + if (*name == '\\') { + name++; + /* XXX need to handle \nnn form. */ + if (*name == '\0') + break; + } else if (*name == '.') { + name++; + break; + } + name++; + } + } + return (name - oname); +} + +/* + * int + * charstr(rdata, edata, buf, buflen) + * Format a <character-string> into the presentation buffer. + * return: + * Number of rdata octets consumed + * 0 for protocol format error + * -1 for output buffer error + * side effects: + * buffer is advanced on success. + */ +static int +charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { + const u_char *odata = rdata; + size_t save_buflen = *buflen; + char *save_buf = *buf; + + if (addstr("\"", 1, buf, buflen) < 0) + goto enospc; + if (rdata < edata) { + int n = *rdata; + + if (rdata + 1 + n <= edata) { + rdata++; + while (n-- > 0) { + if (strchr("\n\"\\", *rdata) != NULL) + if (addstr("\\", 1, buf, buflen) < 0) + goto enospc; + if (addstr((const char *)rdata, 1, + buf, buflen) < 0) + goto enospc; + rdata++; + } + } + } + if (addstr("\"", 1, buf, buflen) < 0) + goto enospc; + return (rdata - odata); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static int +addname(const u_char *msg, size_t msglen, + const u_char **pp, const char *origin, + char **buf, size_t *buflen) +{ + size_t newlen, save_buflen = *buflen; + char *save_buf = *buf; + int n; + + n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen); + if (n < 0) + goto enospc; /* Guess. */ + newlen = prune_origin(*buf, origin); + if ((origin == NULL || origin[0] == '\0' || (*buf)[newlen] == '\0') && + (newlen == 0 || (*buf)[newlen - 1] != '.')) { + /* No trailing dot. */ + if (newlen + 2 > *buflen) + goto enospc; /* No room for ".\0". */ + (*buf)[newlen++] = '.'; + (*buf)[newlen] = '\0'; + } + if (newlen == 0) { + /* Use "@" instead of name. */ + if (newlen + 2 > *buflen) + goto enospc; /* No room for "@\0". */ + (*buf)[newlen++] = '@'; + (*buf)[newlen] = '\0'; + } + *pp += n; + addlen(newlen, buf, buflen); + **buf = '\0'; + return (newlen); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static void +addlen(size_t len, char **buf, size_t *buflen) { + assert(len <= *buflen); + *buf += len; + *buflen -= len; +} + +static int +addstr(const char *src, size_t len, char **buf, size_t *buflen) { + if (len > *buflen) { + errno = ENOSPC; + return (-1); + } + memcpy(*buf, src, len); + addlen(len, buf, buflen); + **buf = '\0'; + return (0); +} + +static int +addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { + size_t save_buflen = *buflen; + char *save_buf = *buf; + int t; + + if (spaced || len >= target - 1) { + T(addstr(" ", 2, buf, buflen)); + spaced = 1; + } else { + for (t = (target - len - 1) / 8; t >= 0; t--) + if (addstr("\t", 1, buf, buflen) < 0) { + *buflen = save_buflen; + *buf = save_buf; + return (-1); + } + spaced = 0; + } + return (spaced); +} diff --git a/cpukit/libnetworking/libc/ns_ttl.c b/cpukit/libnetworking/libc/ns_ttl.c new file mode 100644 index 0000000000..cca162b270 --- /dev/null +++ b/cpukit/libnetworking/libc/ns_ttl.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +/* Import. */ + +#include <arpa/nameser.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#define SPRINTF(x) ((size_t)sprintf x) + +/* Forward. */ + +static int fmt1(int t, char s, char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) if ((x) < 0) return (-1); else (void)NULL + +/* Public. */ + +int +ns_format_ttl(u_long src, char *dst, size_t dstlen) { + char *odst = dst; + int secs, mins, hours, days, weeks, x; + char tmp[50], *p; + + secs = src % 60; src /= 60; + mins = src % 60; src /= 60; + hours = src % 24; src /= 24; + days = src % 7; src /= 7; + weeks = src; src = 0; + + x = 0; + if (weeks) { + T(fmt1(weeks, 'W', &dst, &dstlen)); + x++; + } + if (days) { + T(fmt1(days, 'D', &dst, &dstlen)); + x++; + } + if (hours) { + T(fmt1(hours, 'H', &dst, &dstlen)); + x++; + } + if (mins) { + T(fmt1(mins, 'M', &dst, &dstlen)); + x++; + } + if (secs || !(weeks || days || hours || mins)) { + T(fmt1(secs, 'S', &dst, &dstlen)); + x++; + } + + if (x > 1) { + int ch; + + for (p = odst; (ch = *p) != '\0'; p++) + if (isascii(ch) && isupper(ch)) + *p = tolower(ch); + } + + return (dst - odst); +} + +int +ns_parse_ttl(const char *src, u_long *dst) { + u_long ttl, tmp; + int ch, digits, dirty; + + ttl = 0; + tmp = 0; + digits = 0; + dirty = 0; + while ((ch = *src++) != '\0') { + if (!isascii(ch) || !isprint(ch)) + goto einval; + if (isdigit(ch)) { + tmp *= 10; + tmp += (ch - '0'); + digits++; + continue; + } + if (digits == 0) + goto einval; + if (islower(ch)) + ch = toupper(ch); + switch (ch) { + case 'W': tmp *= 7; + case 'D': tmp *= 24; + case 'H': tmp *= 60; + case 'M': tmp *= 60; + case 'S': break; + default: goto einval; + } + ttl += tmp; + tmp = 0; + digits = 0; + dirty = 1; + } + if (digits > 0) { + if (dirty) + goto einval; + else + ttl += tmp; + } + *dst = ttl; + return (0); + + einval: + errno = EINVAL; + return (-1); +} + +/* Private. */ + +static int +fmt1(int t, char s, char **buf, size_t *buflen) { + char tmp[50]; + size_t len; + + len = SPRINTF((tmp, "%d%c", t, s)); + if (len + 1 > *buflen) + return (-1); + strcpy(*buf, tmp); + *buf += len; + *buflen -= len; + return (0); +} diff --git a/cpukit/libnetworking/libc/nsap_addr.c b/cpukit/libnetworking/libc/nsap_addr.c new file mode 100644 index 0000000000..a7af57a266 --- /dev/null +++ b/cpukit/libnetworking/libc/nsap_addr.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <ctype.h> +#include <resolv.h> + +static char +xtob(c) + register int c; +{ + return (c - (((c >= '0') && (c <= '9')) ? '0' : '7')); +} + +u_int +inet_nsap_addr(ascii, binary, maxlen) + const char *ascii; + u_char *binary; + int maxlen; +{ + u_char c, nib; + u_int len = 0; + + while ((c = *ascii++) != '\0' && len < (u_int)maxlen) { + if (c == '.' || c == '+' || c == '/') + continue; + if (!isascii(c)) + return (0); + if (islower(c)) + c = toupper(c); + if (isxdigit(c)) { + nib = xtob(c); + c = *ascii++; + if (c != '\0') { + c = toupper(c); + if (isxdigit(c)) { + *binary++ = (nib << 4) | xtob(c); + len++; + } else + return (0); + } + else + return (0); + } + else + return (0); + } + return (len); +} + +char * +inet_nsap_ntoa(binlen, binary, ascii) + int binlen; + register const u_char *binary; + register char *ascii; +{ + register int nib; + int i; + static char tmpbuf[255*3]; + char *start; + + if (ascii) + start = ascii; + else { + ascii = tmpbuf; + start = tmpbuf; + } + + if (binlen > 255) + binlen = 255; + + for (i = 0; i < binlen; i++) { + nib = *binary >> 4; + *ascii++ = nib + (nib < 10 ? '0' : '7'); + nib = *binary++ & 0x0f; + *ascii++ = nib + (nib < 10 ? '0' : '7'); + if (((i % 2) == 0 && (i + 1) < binlen)) + *ascii++ = '.'; + } + *ascii = '\0'; + return (start); +} diff --git a/cpukit/libnetworking/libc/rcmd.3 b/cpukit/libnetworking/libc/rcmd.3 new file mode 100644 index 0000000000..e25057fa4e --- /dev/null +++ b/cpukit/libnetworking/libc/rcmd.3 @@ -0,0 +1,204 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" From: @(#)rcmd.3 8.1 (Berkeley) 6/4/93 +.\" $Id$ +.\" +.Dd February 15, 1996 +.Dt RCMD 3 +.Os BSD 4.2 +.Sh NAME +.Nm rcmd , +.Nm rresvport , +.Nm iruserok , +.Nm ruserok +.Nd routines for returning a stream to a remote command +.Sh SYNOPSIS +.Fd #include <unistd.h> +.Ft int +.Fn rcmd "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" +.Ft int +.Fn rresvport "int *port" +.Ft int +.Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser" +.Ft int +.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser" +.Sh DESCRIPTION +The +.Fn rcmd +function +is used by the super-user to execute a command on +a remote machine using an authentication scheme based +on reserved port numbers. +The +.Fn rresvport +function +returns a descriptor to a socket +with an address in the privileged port space. +The +.Fn ruserok +function +is used by servers +to authenticate clients requesting service with +.Fn rcmd . +All three functions are present in the same file and are used +by the +.Xr rshd 8 +server (among others). +.Pp +The +.Fn rcmd +function +looks up the host +.Fa *ahost +using +.Xr gethostbyname 3 , +returning \-1 if the host does not exist. +Otherwise +.Fa *ahost +is set to the standard name of the host +and a connection is established to a server +residing at the well-known Internet port +.Fa inport . +.Pp +If the connection succeeds, +a socket in the Internet domain of type +.Dv SOCK_STREAM +is returned to the caller, and given to the remote +command as +.Em stdin +and +.Em stdout . +If +.Fa fd2p +is non-zero, then an auxiliary channel to a control +process will be set up, and a descriptor for it will be placed +in +.Fa *fd2p . +The control process will return diagnostic +output from the command (unit 2) on this channel, and will also +accept bytes on this channel as being +.Tn UNIX +signal numbers, to be +forwarded to the process group of the command. +If +.Fa fd2p +is 0, then the +.Em stderr +(unit 2 of the remote +command) will be made the same as the +.Em stdout +and no +provision is made for sending arbitrary signals to the remote process, +although you may be able to get its attention by using out-of-band data. +.Pp +The protocol is described in detail in +.Xr rshd 8 . +.Pp +The +.Fn rresvport +function is used to obtain a socket with a privileged +address bound to it. This socket is suitable for use +by +.Fn rcmd +and several other functions. Privileged Internet ports are those +in the range 0 to 1023. Only the super-user +is allowed to bind an address of this sort to a socket. +.Pp +The +.Fn iruserok +and +.Fn ruserok +functions take a remote host's IP address or name, as returned by the +.Xr gethostbyname 3 +routines, two user names and a flag indicating whether the local user's +name is that of the super-user. +Then, if the user is +.Em NOT +the super-user, it checks the +.Pa /etc/hosts.equiv +file. +If that lookup is not done, or is unsuccessful, the +.Pa .rhosts +in the local user's home directory is checked to see if the request for +service is allowed. +.Pp +If this file does not exist, is not a regular file, is owned by anyone +other than the user or the super-user, or is writable by anyone other +than the owner, the check automatically fails. +Zero is returned if the machine name is listed in the +.Dq Pa hosts.equiv +file, or the host and remote user name are found in the +.Dq Pa .rhosts +file; otherwise +.Fn iruserok +and +.Fn ruserok +return \-1. +If the local domain (as obtained from +.Xr gethostname 3 ) +is the same as the remote domain, only the machine name need be specified. +.Pp +The +.Fn iruserok +function is strongly preferred for security reasons. +It requires trusting the local DNS at most, while the +.Fn ruserok +function requires trusting the entire DNS, which can be spoofed. +.Sh DIAGNOSTICS +The +.Fn rcmd +function +returns a valid socket descriptor on success. +It returns \-1 on error and prints a diagnostic message on the standard error. +.Pp +The +.Fn rresvport +function +returns a valid, bound socket descriptor on success. +It returns \-1 on error with the global value +.Va errno +set according to the reason for failure. +The error code +.Dv EAGAIN +is overloaded to mean ``All network ports in use.'' +.Sh SEE ALSO +.Xr rlogin 1 , +.Xr rsh 1 , +.Xr intro 2 , +.Xr rexec 3 , +.Xr rexecd 8 , +.Xr rlogind 8 , +.Xr rshd 8 +.Sh HISTORY +These +functions appeared in +.Bx 4.2 . diff --git a/cpukit/libnetworking/libc/rcmd.c b/cpukit/libnetworking/libc/rcmd.c new file mode 100644 index 0000000000..ff108d9d03 --- /dev/null +++ b/cpukit/libnetworking/libc/rcmd.c @@ -0,0 +1,518 @@ +/* + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <signal.h> +#include <fcntl.h> +#include <netdb.h> +#include <unistd.h> +#include <pwd.h> +#include <errno.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +extern int innetgr __P(( const char *, const char *, const char *, const char * )); + +#define max(a, b) ((a > b) ? a : b) + +int __ivaliduser __P((FILE *, u_long, const char *, const char *)); +static int __icheckhost __P((u_long, char *)); + +int +rcmd(ahost, rport, locuser, remuser, cmd, fd2p) + char **ahost; + u_short rport; + const char *locuser, *remuser, *cmd; + int *fd2p; +{ + struct hostent *hp; + struct sockaddr_in sin, from; + fd_set reads; + long oldmask; + pid_t pid; + int s, lport, timo; + char c; + + pid = getpid(); + hp = gethostbyname(*ahost); + if (hp == NULL) { + herror(*ahost); + return (-1); + } + *ahost = hp->h_name; + oldmask = sigblock(sigmask(SIGURG)); + for (timo = 1, lport = IPPORT_RESERVED - 1;;) { + s = rresvport(&lport); + if (s < 0) { + if (errno == EAGAIN) + (void)fprintf(stderr, + "rcmd: socket: All ports in use\n"); + else + (void)fprintf(stderr, "rcmd: socket: %s\n", + strerror(errno)); + sigsetmask(oldmask); + return (-1); + } + fcntl(s, F_SETOWN, pid); + bzero(&sin, sizeof sin); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = hp->h_addrtype; + sin.sin_port = rport; + bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr)); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + break; + (void)close(s); + if (errno == EADDRINUSE) { + lport--; + continue; + } + if (errno == ECONNREFUSED && timo <= 16) { + (void)sleep(timo); + timo *= 2; + continue; + } + if (hp->h_addr_list[1] != NULL) { + int oerrno = errno; + + (void)fprintf(stderr, "connect to address %s: ", + inet_ntoa(sin.sin_addr)); + errno = oerrno; + perror(0); + hp->h_addr_list++; + bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr)); + (void)fprintf(stderr, "Trying %s...\n", + inet_ntoa(sin.sin_addr)); + continue; + } + (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); + sigsetmask(oldmask); + return (-1); + } + lport--; + if (fd2p == 0) { + write(s, "", 1); + lport = 0; + } else { + char num[8]; + int s2 = rresvport(&lport), s3; + int len = sizeof(from); + int nfds; + + if (s2 < 0) + goto bad; + listen(s2, 1); + (void)snprintf(num, sizeof(num), "%d", lport); + if (write(s, num, strlen(num)+1) != strlen(num)+1) { + (void)fprintf(stderr, + "rcmd: write (setting up stderr): %s\n", + strerror(errno)); + (void)close(s2); + goto bad; + } + nfds = max(s, s2)+1; + if(nfds > FD_SETSIZE) { + fprintf(stderr, "rcmd: too many files\n"); + (void)close(s2); + goto bad; + } +again: + FD_ZERO(&reads); + FD_SET(s, &reads); + FD_SET(s2, &reads); + errno = 0; + if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){ + if (errno != 0) + (void)fprintf(stderr, + "rcmd: select (setting up stderr): %s\n", + strerror(errno)); + else + (void)fprintf(stderr, + "select: protocol failure in circuit setup\n"); + (void)close(s2); + goto bad; + } + s3 = accept(s2, (struct sockaddr *)&from, &len); + /* + * XXX careful for ftp bounce attacks. If discovered, shut them + * down and check for the real auxiliary channel to connect. + */ + if (from.sin_family == AF_INET && from.sin_port == htons(20)) { + close(s3); + goto again; + } + (void)close(s2); + if (s3 < 0) { + (void)fprintf(stderr, + "rcmd: accept: %s\n", strerror(errno)); + lport = 0; + goto bad; + } + *fd2p = s3; + from.sin_port = ntohs((u_short)from.sin_port); + if (from.sin_family != AF_INET || + from.sin_port >= IPPORT_RESERVED || + from.sin_port < IPPORT_RESERVED / 2) { + (void)fprintf(stderr, + "socket: protocol failure in circuit setup.\n"); + goto bad2; + } + } + (void)write(s, locuser, strlen(locuser)+1); + (void)write(s, remuser, strlen(remuser)+1); + (void)write(s, cmd, strlen(cmd)+1); + if (read(s, &c, 1) != 1) { + (void)fprintf(stderr, + "rcmd: %s: %s\n", *ahost, strerror(errno)); + goto bad2; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void)write(STDERR_FILENO, &c, 1); + if (c == '\n') + break; + } + goto bad2; + } + sigsetmask(oldmask); + return (s); +bad2: + if (lport) + (void)close(*fd2p); +bad: + (void)close(s); + sigsetmask(oldmask); + return (-1); +} + +int +rresvport(alport) + int *alport; +{ + struct sockaddr_in sin; + int s; + + bzero(&sin, sizeof sin); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return (-1); +#if 0 /* compat_exact_traditional_rresvport_semantics */ + sin.sin_port = htons((u_short)*alport); + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void)close(s); + return (-1); + } +#endif + sin.sin_port = 0; + if (bindresvport(s, &sin) == -1) { + (void)close(s); + return (-1); + } + *alport = (int)ntohs(sin.sin_port); + return (s); +} + +int __check_rhosts_file = 1; +char *__rcmd_errstr; + +int +ruserok(rhost, superuser, ruser, luser) + const char *rhost, *ruser, *luser; + int superuser; +{ + struct hostent *hp; + u_long addr; + char **ap; + + if ((hp = gethostbyname(rhost)) == NULL) + return (-1); + for (ap = hp->h_addr_list; *ap; ++ap) { + bcopy(*ap, &addr, sizeof(addr)); + if (iruserok(addr, superuser, ruser, luser) == 0) + return (0); + } + return (-1); +} + +/* + * New .rhosts strategy: We are passed an ip address. We spin through + * hosts.equiv and .rhosts looking for a match. When the .rhosts only + * has ip addresses, we don't have to trust a nameserver. When it + * contains hostnames, we spin through the list of addresses the nameserver + * gives us and look for a match. + * + * Returns 0 if ok, -1 if not ok. + */ +int +iruserok(raddr, superuser, ruser, luser) + u_long raddr; + int superuser; + const char *ruser, *luser; +{ + register char *cp; + struct stat sbuf; + struct passwd *pwd; + FILE *hostf; + uid_t uid; + int first; + char pbuf[MAXPATHLEN]; + + first = 1; + hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); +again: + if (hostf) { + if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { + (void)fclose(hostf); + return (0); + } + (void)fclose(hostf); + } + if (first == 1 && (__check_rhosts_file || superuser)) { + first = 0; + if ((pwd = getpwnam(luser)) == NULL) + return (-1); + (void)strcpy(pbuf, pwd->pw_dir); + (void)strcat(pbuf, "/.rhosts"); + + /* + * Change effective uid while opening .rhosts. If root and + * reading an NFS mounted file system, can't read files that + * are protected read/write owner only. + */ + uid = geteuid(); + (void)seteuid(pwd->pw_uid); + hostf = fopen(pbuf, "r"); + (void)seteuid(uid); + + if (hostf == NULL) + return (-1); + /* + * If not a regular file, or is owned by someone other than + * user or root or if writeable by anyone but the owner, quit. + */ + cp = NULL; + if (lstat(pbuf, &sbuf) < 0) + cp = ".rhosts lstat failed"; + else if (!S_ISREG(sbuf.st_mode)) + cp = ".rhosts not regular file"; + else if (fstat(fileno(hostf), &sbuf) < 0) + cp = ".rhosts fstat failed"; + else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) + cp = "bad .rhosts owner"; + else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) + cp = ".rhosts writeable by other than owner"; + /* If there were any problems, quit. */ + if (cp) { + __rcmd_errstr = cp; + (void)fclose(hostf); + return (-1); + } + goto again; + } + return (-1); +} + +/* + * XXX + * Don't make static, used by lpd(8). + * + * Returns 0 if ok, -1 if not ok. + */ +int +__ivaliduser(hostf, raddr, luser, ruser) + FILE *hostf; + u_long raddr; + const char *luser, *ruser; +{ + register char *user, *p; + int ch; + char buf[MAXHOSTNAMELEN + 128]; /* host + login */ + char hname[MAXHOSTNAMELEN]; + struct hostent *hp; + /* Presumed guilty until proven innocent. */ + int userok = 0, hostok = 0; +#ifdef YP + char *ypdomain; + + if (yp_get_default_domain(&ypdomain)) + ypdomain = NULL; +#else +#define ypdomain NULL +#endif + /* We need to get the damn hostname back for netgroup matching. */ + if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), + AF_INET)) == NULL) + return (-1); + strncpy(hname, hp->h_name, sizeof(hname)); + hname[sizeof(hname) - 1] = '\0'; + + while (fgets(buf, sizeof(buf), hostf)) { + p = buf; + /* Skip lines that are too long. */ + if (strchr(p, '\n') == NULL) { + while ((ch = getc(hostf)) != '\n' && ch != EOF); + continue; + } + if (*p == '\n' || *p == '#') { + /* comment... */ + continue; + } + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { + *p = isupper(*p) ? tolower(*p) : *p; + p++; + } + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + user = p; + while (*p != '\n' && *p != ' ' && + *p != '\t' && *p != '\0') + p++; + } else + user = p; + *p = '\0'; + /* + * Do +/- and +@/-@ checking. This looks really nasty, + * but it matches SunOS's behavior so far as I can tell. + */ + switch(buf[0]) { + case '+': + if (!buf[1]) { /* '+' matches all hosts */ + hostok = 1; + break; + } + if (buf[1] == '@') /* match a host by netgroup */ + hostok = innetgr((char *)&buf[2], + (char *)&hname, NULL, ypdomain); + else /* match a host by addr */ + hostok = __icheckhost(raddr,(char *)&buf[1]); + break; + case '-': /* reject '-' hosts and all their users */ + if (buf[1] == '@') { + if (innetgr((char *)&buf[2], + (char *)&hname, NULL, ypdomain)) + return(-1); + } else { + if (__icheckhost(raddr,(char *)&buf[1])) + return(-1); + } + break; + default: /* if no '+' or '-', do a simple match */ + hostok = __icheckhost(raddr, buf); + break; + } + switch(*user) { + case '+': + if (!*(user+1)) { /* '+' matches all users */ + userok = 1; + break; + } + if (*(user+1) == '@') /* match a user by netgroup */ + userok = innetgr(user+2, NULL, ruser, ypdomain); + else /* match a user by direct specification */ + userok = !(strcmp(ruser, user+1)); + break; + case '-': /* if we matched a hostname, */ + if (hostok) { /* check for user field rejections */ + if (!*(user+1)) + return(-1); + if (*(user+1) == '@') { + if (innetgr(user+2, NULL, + ruser, ypdomain)) + return(-1); + } else { + if (!strcmp(ruser, user+1)) + return(-1); + } + } + break; + default: /* no rejections: try to match the user */ + if (hostok) + userok = !(strcmp(ruser,*user ? user : luser)); + break; + } + if (hostok && userok) + return(0); + } + return (-1); +} + +/* + * Returns "true" if match, 0 if no match. + */ +static int +__icheckhost(raddr, lhost) + u_long raddr; + register char *lhost; +{ + register struct hostent *hp; + register u_long laddr; + register char **pp; + + /* Try for raw ip address first. */ + if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1) + return (raddr == laddr); + + /* Better be a hostname. */ + if ((hp = gethostbyname(lhost)) == NULL) + return (0); + + /* Spin through ip addresses. */ + for (pp = hp->h_addr_list; *pp; ++pp) + if (!bcmp(&raddr, *pp, sizeof(u_long))) + return (1); + + /* No match. */ + return (0); +} diff --git a/cpukit/libnetworking/libc/recv.c b/cpukit/libnetworking/libc/recv.c new file mode 100644 index 0000000000..65ec9d4b38 --- /dev/null +++ b/cpukit/libnetworking/libc/recv.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)recv.c 8.2 (Berkeley) 2/21/94"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stddef.h> + +ssize_t +recv(s, buf, len, flags) + int s, flags; + size_t len; + void *buf; +{ + return (recvfrom(s, buf, len, flags, NULL, 0)); +} diff --git a/cpukit/libnetworking/libc/res_comp.c b/cpukit/libnetworking/libc/res_comp.c new file mode 100644 index 0000000000..93043276f2 --- /dev/null +++ b/cpukit/libnetworking/libc/res_comp.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static char orig_rcsid[] = "From: Id: res_comp.c,v 8.11 1997/05/21 19:31:04 halley Exp $"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define BIND_4_COMPAT + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +dn_expand(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, int dstsiz) +{ + int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return (n); +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +int +dn_comp(const char *src, u_char *dst, int dstsiz, + u_char **dnptrs, u_char **lastdnptr) +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +dn_skipname(const u_char *ptr, const u_char *eom) { + const u_char *saveptr = ptr; + + if (ns_name_skip(&ptr, eom) == -1) + return (-1); + return (ptr - saveptr); +} + +/* + * Verify that a domain name uses an acceptable character set. + */ + +/* + * Note the conspicuous absence of ctype macros in these definitions. On + * non-ASCII hosts, we can't depend on string literals or ctype macros to + * tell us anything about network-format data. The rest of the BIND system + * is not careful about this, but for some reason, we're doing it right here. + */ +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ + || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +int +res_hnok(dn) + const char *dn; +{ + int ppch = '\0', pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + (void)NULL; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + ppch = pch, pch = ch, ch = nch; + } + return (1); +} + +/* + * hostname-like (A, MX, WKS) owners can have "*" as their first label + * but must otherwise be as a host name. + */ +int +res_ownok(dn) + const char *dn; +{ + if (asterchar(dn[0])) { + if (periodchar(dn[1])) + return (res_hnok(dn+2)); + if (dn[1] == '\0') + return (1); + } + return (res_hnok(dn)); +} + +/* + * SOA RNAMEs and RP RNAMEs can have any printable character in their first + * label, but the rest of the name has to look like a host name. + */ +int +res_mailok(dn) + const char *dn; +{ + int ch, escaped = 0; + + /* "." is a valid missing representation */ + if (*dn == '\0') + return (1); + + /* otherwise <label>.<hostname> */ + while ((ch = *dn++) != '\0') { + if (!domainchar(ch)) + return (0); + if (!escaped && periodchar(ch)) + break; + if (escaped) + escaped = 0; + else if (bslashchar(ch)) + escaped = 1; + } + if (periodchar(ch)) + return (res_hnok(dn)); + return (0); +} + +/* + * This function is quite liberal, since RFC 1034's character sets are only + * recommendations. + */ +int +res_dnok(dn) + const char *dn; +{ + int ch; + + while ((ch = *dn++) != '\0') + if (!domainchar(ch)) + return (0); + return (1); +} + +#ifdef BIND_4_COMPAT +/* + * This module must export the following externally-visible symbols: + * ___putlong + * ___putshort + * __getlong + * __getshort + * Note that one _ comes from C and the others come from us. + */ +void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); } +void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); } +u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); } +u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); } +#endif /*BIND_4_COMPAT*/ diff --git a/cpukit/libnetworking/libc/res_config.h b/cpukit/libnetworking/libc/res_config.h new file mode 100644 index 0000000000..644e7d796a --- /dev/null +++ b/cpukit/libnetworking/libc/res_config.h @@ -0,0 +1,8 @@ +#define DEBUG 1 /* enable debugging code (needed for dig) */ +#define RESOLVSORT /* allow sorting of addresses in gethostbyname */ +#define RFC1535 /* comply with RFC1535 (STRONGLY reccomended by vixie)*/ +#undef USELOOPBACK /* res_init() bind to localhost */ +#undef SUNSECURITY /* verify gethostbyaddr() calls - WE DONT NEED IT */ +#define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */ +#define CHECK_SRVR_ADDR 1 /* confirm that the server requested sent the reply */ +#define BIND_UPDATE 1 /* update support */ diff --git a/cpukit/libnetworking/libc/res_data.c b/cpukit/libnetworking/libc/res_data.c new file mode 100644 index 0000000000..fb7d2c66eb --- /dev/null +++ b/cpukit/libnetworking/libc/res_data.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1995,1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "res_config.h" + +const char *_res_opcodes[] = { + "QUERY", + "IQUERY", + "CQUERYM", + "CQUERYU", /* experimental */ + "NOTIFY", /* experimental */ + "UPDATE", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "ZONEINIT", + "ZONEREF", +}; + +const char *_res_resultcodes[] = { + "NOERROR", + "FORMERR", + "SERVFAIL", + "NXDOMAIN", + "NOTIMP", + "REFUSED", + "YXDOMAIN", + "YXRRSET", + "NXRRSET", + "NOTAUTH", + "ZONEERR", + "11", + "12", + "13", + "14", + "NOCHANGE", +}; + +#ifdef BIND_UPDATE +const char *_res_sectioncodes[] = { + "ZONE", + "PREREQUISITES", + "UPDATE", + "ADDITIONAL", +}; +#endif diff --git a/cpukit/libnetworking/libc/res_debug.c b/cpukit/libnetworking/libc/res_debug.c new file mode 100644 index 0000000000..e58867acb3 --- /dev/null +++ b/cpukit/libnetworking/libc/res_debug.c @@ -0,0 +1,966 @@ +/* + * Copyright (c) 1985 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define SPRINTF(x) sprintf x + +extern const char *_res_opcodes[]; +extern const char *_res_resultcodes[]; +extern const char *_res_sectioncodes[]; + +/* + * Print the current options. + */ +void +fp_resstat(struct __res_state *statp, FILE *file) { + u_long mask; + + fprintf(file, ";; res options:"); + if (!statp) + statp = &_res; + for (mask = 1; mask != 0; mask <<= 1) + if (statp->options & mask) + fprintf(file, " %s", p_option(mask)); + putc('\n', file); +} + +static void +do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { + int n, sflag, rrnum; + char buf[2048]; /* XXX need to malloc */ + ns_opcode opcode; + ns_rr rr; + + /* + * Print answer records. + */ + sflag = (_res.pfcode & pflag); + if (_res.pfcode && !sflag) + return; + + opcode = ns_msg_getflag(*handle, ns_f_opcode); + rrnum = 0; + for (;;) { + if (ns_parserr(handle, section, rrnum, &rr)) { + if (errno != ENODEV) + fprintf(file, ";; ns_parserr: %s\n", + strerror(errno)); + else if (rrnum > 0 && sflag != 0 && + (_res.pfcode & RES_PRF_HEAD1)) + putc('\n', file); + return; + } + if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1)) + fprintf(file, ";; %s SECTION:\n", + p_section(section, opcode)); + if (section == ns_s_qd) + fprintf(file, ";;\t%s, type = %s, class = %s\n", + ns_rr_name(rr), + p_type(ns_rr_type(rr)), + p_class(ns_rr_class(rr))); + else { + n = ns_sprintrr(handle, &rr, NULL, NULL, + buf, sizeof buf); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + fputs(buf, file); + fputc('\n', file); + } + rrnum++; + } +} + +void +p_query(const u_char *msg) { + fp_query(msg, stdout); +} + +void +fp_query(const u_char *msg, FILE *file) { + fp_nquery(msg, PACKETSZ, file); +} + +/* + * Print the contents of a query. + * This is intended to be primarily a debugging routine. + */ +void +fp_nquery(const u_char *msg, int len, FILE *file) { + ns_msg handle; + int n, qdcount, ancount, nscount, arcount; + u_int opcode, rcode, id; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + + if (ns_initparse(msg, len, &handle) < 0) { + fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); + return; + } + opcode = ns_msg_getflag(handle, ns_f_opcode); + rcode = ns_msg_getflag(handle, ns_f_rcode); + id = ns_msg_id(handle); + qdcount = ns_msg_count(handle, ns_s_qd); + ancount = ns_msg_count(handle, ns_s_an); + nscount = ns_msg_count(handle, ns_s_ns); + arcount = ns_msg_count(handle, ns_s_ar); + + /* + * Print header fields. + */ + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || rcode) + fprintf(file, + ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n", + _res_opcodes[opcode], _res_resultcodes[rcode], id); + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX)) + putc(';', file); + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) { + fprintf(file, "; flags:"); + if (ns_msg_getflag(handle, ns_f_qr)) + fprintf(file, " qr"); + if (ns_msg_getflag(handle, ns_f_aa)) + fprintf(file, " aa"); + if (ns_msg_getflag(handle, ns_f_tc)) + fprintf(file, " tc"); + if (ns_msg_getflag(handle, ns_f_rd)) + fprintf(file, " rd"); + if (ns_msg_getflag(handle, ns_f_ra)) + fprintf(file, " ra"); + if (ns_msg_getflag(handle, ns_f_z)) + fprintf(file, " ??"); + if (ns_msg_getflag(handle, ns_f_ad)) + fprintf(file, " ad"); + if (ns_msg_getflag(handle, ns_f_cd)) + fprintf(file, " cd"); + } + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) { + fprintf(file, "; %s: %d", + p_section(ns_s_qd, opcode), qdcount); + fprintf(file, ", %s: %d", + p_section(ns_s_an, opcode), ancount); + fprintf(file, ", %s: %d", + p_section(ns_s_ns, opcode), nscount); + fprintf(file, ", %s: %d", + p_section(ns_s_ar, opcode), arcount); + } + if ((!_res.pfcode) || (_res.pfcode & + (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { + putc('\n',file); + } + /* + * Print the various sections. + */ + do_section(&handle, ns_s_qd, RES_PRF_QUES, file); + do_section(&handle, ns_s_an, RES_PRF_ANS, file); + do_section(&handle, ns_s_ns, RES_PRF_AUTH, file); + do_section(&handle, ns_s_ar, RES_PRF_ADD, file); + if (qdcount == 0 && ancount == 0 && + nscount == 0 && arcount == 0) + putc('\n', file); +} + +const u_char * +p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) { + char name[MAXDNAME]; + int n; + + if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0) + return (NULL); + if (name[0] == '\0') + putc('.', file); + else + fputs(name, file); + return (cp + n); +} + +const u_char * +p_cdname(const u_char *cp, const u_char *msg, FILE *file) { + return (p_cdnname(cp, msg, PACKETSZ, file)); +} + +/* Return a fully-qualified domain name from a compressed name (with + length supplied). */ + +const u_char * +p_fqnname(cp, msg, msglen, name, namelen) + const u_char *cp, *msg; + int msglen; + char *name; + int namelen; +{ + int n, newlen; + + if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0) + return (NULL); + newlen = strlen(name); + if (newlen == 0 || name[newlen - 1] != '.') { + if (newlen + 1 >= namelen) /* Lack space for final dot */ + return (NULL); + else + strcpy(name + newlen, "."); + } + return (cp + n); +} + +/* XXX: the rest of these functions need to become length-limited, too. */ + +const u_char * +p_fqname(const u_char *cp, const u_char *msg, FILE *file) { + char name[MAXDNAME]; + const u_char *n; + + n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name); + if (n == NULL) + return (NULL); + fputs(name, file); + return (n); +} + +/* + * Names of RR classes and qclasses. Classes and qclasses are the same, except + * that C_ANY is a qclass but not a class. (You can ask for records of class + * C_ANY, but you can't have any records of that class in the database.) + */ +const struct res_sym __p_class_syms[] = { + {C_IN, "IN"}, + {C_CHAOS, "CHAOS"}, + {C_HS, "HS"}, + {C_HS, "HESIOD"}, + {C_ANY, "ANY"}, + {C_NONE, "NONE"}, + {C_IN, (char *)0} +}; + +/* + * Names of message sections. + */ +const struct res_sym __p_default_section_syms[] = { + {ns_s_qd, "QUERY"}, + {ns_s_an, "ANSWER"}, + {ns_s_ns, "AUTHORITY"}, + {ns_s_ar, "ADDITIONAL"}, + {0, (char *)0} +}; + +const struct res_sym __p_update_section_syms[] = { + {S_ZONE, "ZONE"}, + {S_PREREQ, "PREREQUISITE"}, + {S_UPDATE, "UPDATE"}, + {S_ADDT, "ADDITIONAL"}, + {0, (char *)0} +}; + +/* + * Names of RR types and qtypes. Types and qtypes are the same, except + * that T_ANY is a qtype but not a type. (You can ask for records of type + * T_ANY, but you can't have any records of that type in the database.) + */ +const struct res_sym __p_type_syms[] = { + {T_A, "A", "address"}, + {T_NS, "NS", "name server"}, + {T_MD, "MD", "mail destination (deprecated)"}, + {T_MF, "MF", "mail forwarder (deprecated)"}, + {T_CNAME, "CNAME", "canonical name"}, + {T_SOA, "SOA", "start of authority"}, + {T_MB, "MB", "mailbox"}, + {T_MG, "MG", "mail group member"}, + {T_MR, "MR", "mail rename"}, + {T_NULL, "NULL", "null"}, + {T_WKS, "WKS", "well-known service (deprecated)"}, + {T_PTR, "PTR", "domain name pointer"}, + {T_HINFO, "HINFO", "host information"}, + {T_MINFO, "MINFO", "mailbox information"}, + {T_MX, "MX", "mail exchanger"}, + {T_TXT, "TXT", "text"}, + {T_RP, "RP", "responsible person"}, + {T_AFSDB, "AFSDB", "DCE or AFS server"}, + {T_X25, "X25", "X25 address"}, + {T_ISDN, "ISDN", "ISDN address"}, + {T_RT, "RT", "router"}, + {T_NSAP, "NSAP", "nsap address"}, + {T_NSAP_PTR, "NSAP_PTR", "domain name pointer"}, + {T_SIG, "SIG", "signature"}, + {T_KEY, "KEY", "key"}, + {T_PX, "PX", "mapping information"}, + {T_GPOS, "GPOS", "geographical position (withdrawn)"}, + {T_AAAA, "AAAA", "IPv6 address"}, + {T_LOC, "LOC", "location"}, + {T_NXT, "NXT", "next valid name (unimplemented)"}, + {T_EID, "EID", "endpoint identifier (unimplemented)"}, + {T_NIMLOC, "NIMLOC", "NIMROD locator (unimplemented)"}, + {T_SRV, "SRV", "server selection"}, + {T_ATMA, "ATMA", "ATM address (unimplemented)"}, + {T_IXFR, "IXFR", "incremental zone transfer"}, + {T_AXFR, "AXFR", "zone transfer"}, + {T_MAILB, "MAILB", "mailbox-related data (deprecated)"}, + {T_MAILA, "MAILA", "mail agent (deprecated)"}, + {T_NAPTR, "NAPTR", "URN Naming Authority"}, + {T_ANY, "ANY", "\"any\""}, + {0, NULL, NULL} +}; + +int +sym_ston(const struct res_sym *syms, const char *name, int *success) { + for ((void)NULL; syms->name != 0; syms++) { + if (strcasecmp (name, syms->name) == 0) { + if (success) + *success = 1; + return (syms->number); + } + } + if (success) + *success = 0; + return (syms->number); /* The default value. */ +} + +const char * +sym_ntos(const struct res_sym *syms, int number, int *success) { + static char unname[20]; + + for ((void)NULL; syms->name != 0; syms++) { + if (number == syms->number) { + if (success) + *success = 1; + return (syms->name); + } + } + + sprintf(unname, "%d", number); + if (success) + *success = 0; + return (unname); +} + +const char * +sym_ntop(const struct res_sym *syms, int number, int *success) { + static char unname[20]; + + for ((void)NULL; syms->name != 0; syms++) { + if (number == syms->number) { + if (success) + *success = 1; + return (syms->humanname); + } + } + sprintf(unname, "%d", number); + if (success) + *success = 0; + return (unname); +} + +/* + * Return a string for the type. + */ +const char * +p_type(int type) { + return (sym_ntos(__p_type_syms, type, (int *)0)); +} + +/* + * Return a string for the type. + */ +const char * +p_section(int section, int opcode) { + const struct res_sym *symbols; + + switch (opcode) { + case ns_o_update: + symbols = __p_update_section_syms; + break; + default: + symbols = __p_default_section_syms; + break; + } + return (sym_ntos(symbols, section, (int *)0)); +} + +/* + * Return a mnemonic for class. + */ +const char * +p_class(int class) { + return (sym_ntos(__p_class_syms, class, (int *)0)); +} + +/* + * Return a mnemonic for an option + */ +const char * +p_option(u_long option) { + static char nbuf[40]; + + switch (option) { + case RES_INIT: return "init"; + case RES_DEBUG: return "debug"; + case RES_AAONLY: return "aaonly(unimpl)"; + case RES_USEVC: return "usevc"; + case RES_PRIMARY: return "primry(unimpl)"; + case RES_IGNTC: return "igntc"; + case RES_RECURSE: return "recurs"; + case RES_DEFNAMES: return "defnam"; + case RES_STAYOPEN: return "styopn"; + case RES_DNSRCH: return "dnsrch"; + case RES_INSECURE1: return "insecure1"; + case RES_INSECURE2: return "insecure2"; + default: sprintf(nbuf, "?0x%lx?", (u_long)option); + return (nbuf); + } +} + +/* + * Return a mnemonic for a time to live. + */ +const char * +p_time(u_int32_t value) { + static char nbuf[40]; + + if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0) + sprintf(nbuf, "%u", value); + return (nbuf); +} + + +/* + * routines to convert between on-the-wire RR format and zone file format. + * Does not contain conversion to/from decimal degrees; divide or multiply + * by 60*60*1000 for that. + */ + +static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, + 1000000,10000000,100000000,1000000000}; + +/* takes an XeY precision/size value, returns a string representation. */ +static const char * +precsize_ntoa(prec) + u_int8_t prec; +{ + static char retbuf[sizeof "90000000.00"]; + unsigned long val; + int mantissa, exponent; + + mantissa = (int)((prec >> 4) & 0x0f) % 10; + exponent = (int)((prec >> 0) & 0x0f) % 10; + + val = mantissa * poweroften[exponent]; + + (void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100); + return (retbuf); +} + +/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */ +static u_int8_t +precsize_aton(strptr) + char **strptr; +{ + unsigned int mval = 0, cmval = 0; + u_int8_t retval = 0; + char *cp; + int exponent; + int mantissa; + + cp = *strptr; + + while (isdigit(*cp)) + mval = mval * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit(*cp)) { + cmval = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + cmval += (*cp++ - '0'); + } + } + } + cmval = (mval * 100) + cmval; + + for (exponent = 0; exponent < 9; exponent++) + if (cmval < poweroften[exponent+1]) + break; + + mantissa = cmval / poweroften[exponent]; + if (mantissa > 9) + mantissa = 9; + + retval = (mantissa << 4) | exponent; + + *strptr = cp; + + return (retval); +} + +/* converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */ +static u_int32_t +latlon2ul(latlonstrptr,which) + char **latlonstrptr; + int *which; +{ + char *cp; + u_int32_t retval; + int deg = 0, min = 0, secs = 0, secsfrac = 0; + + cp = *latlonstrptr; + + while (isdigit(*cp)) + deg = deg * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + min = min * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + secs = secs * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal seconds */ + cp++; + if (isdigit(*cp)) { + secsfrac = (*cp++ - '0') * 100; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0') * 10; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0'); + } + } + } + } + + while (!isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) + cp++; + + fndhemi: + switch (*cp) { + case 'N': case 'n': + case 'E': case 'e': + retval = ((unsigned)1<<31) + + (((((deg * 60) + min) * 60) + secs) * 1000) + + secsfrac; + break; + case 'S': case 's': + case 'W': case 'w': + retval = ((unsigned)1<<31) + - (((((deg * 60) + min) * 60) + secs) * 1000) + - secsfrac; + break; + default: + retval = 0; /* invalid value -- indicates error */ + break; + } + + switch (*cp) { + case 'N': case 'n': + case 'S': case 's': + *which = 1; /* latitude */ + break; + case 'E': case 'e': + case 'W': case 'w': + *which = 2; /* longitude */ + break; + default: + *which = 0; /* error */ + break; + } + + cp++; /* skip the hemisphere */ + + while (!isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) /* move to next field */ + cp++; + + *latlonstrptr = cp; + + return (retval); +} + +/* converts a zone file representation in a string to an RDATA on-the-wire + * representation. */ +int +loc_aton(ascii, binary) + const char *ascii; + u_char *binary; +{ + const char *cp, *maxcp; + u_char *bcp; + + u_int32_t latit = 0, longit = 0, alt = 0; + u_int32_t lltemp1 = 0, lltemp2 = 0; + int altmeters = 0, altfrac = 0, altsign = 1; + u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ + u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */ + u_int8_t siz = 0x12; /* default = 1e2 cm = 1.00m */ + int which1 = 0, which2 = 0; + + cp = ascii; + maxcp = cp + strlen(ascii); + + lltemp1 = latlon2ul(&cp, &which1); + + lltemp2 = latlon2ul(&cp, &which2); + + switch (which1 + which2) { + case 3: /* 1 + 2, the only valid combination */ + if ((which1 == 1) && (which2 == 2)) { /* normal case */ + latit = lltemp1; + longit = lltemp2; + } else if ((which1 == 2) && (which2 == 1)) { /* reversed */ + longit = lltemp1; + latit = lltemp2; + } else { /* some kind of brokenness */ + return (0); + } + break; + default: /* we didn't get one of each */ + return (0); + } + + /* altitude */ + if (*cp == '-') { + altsign = -1; + cp++; + } + + if (*cp == '+') + cp++; + + while (isdigit(*cp)) + altmeters = altmeters * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal meters */ + cp++; + if (isdigit(*cp)) { + altfrac = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + altfrac += (*cp++ - '0'); + } + } + } + + alt = (10000000 + (altsign * (altmeters * 100 + altfrac))); + + while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + siz = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + hp = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + vp = precsize_aton(&cp); + + defaults: + + bcp = binary; + *bcp++ = (u_int8_t) 0; /* version byte */ + *bcp++ = siz; + *bcp++ = hp; + *bcp++ = vp; + PUTLONG(latit,bcp); + PUTLONG(longit,bcp); + PUTLONG(alt,bcp); + + return (16); /* size of RR in octets */ +} + +/* takes an on-the-wire LOC RR and formats it in a human readable format. */ +const char * +loc_ntoa(binary, ascii) + const u_char *binary; + char *ascii; +{ + static char *error = "?"; + const u_char *cp = binary; + + int latdeg, latmin, latsec, latsecfrac; + int longdeg, longmin, longsec, longsecfrac; + char northsouth, eastwest; + int altmeters, altfrac, altsign; + + const u_int32_t referencealt = 100000 * 100; + + int32_t latval, longval, altval; + u_int32_t templ; + u_int8_t sizeval, hpval, vpval, versionval; + + char *sizestr, *hpstr, *vpstr; + + versionval = *cp++; + + if (versionval) { + (void) sprintf(ascii, "; error: unknown LOC RR version"); + return (ascii); + } + + sizeval = *cp++; + + hpval = *cp++; + vpval = *cp++; + + GETLONG(templ, cp); + latval = (templ - ((unsigned)1<<31)); + + GETLONG(templ, cp); + longval = (templ - ((unsigned)1<<31)); + + GETLONG(templ, cp); + if (templ < referencealt) { /* below WGS 84 spheroid */ + altval = referencealt - templ; + altsign = -1; + } else { + altval = templ - referencealt; + altsign = 1; + } + + if (latval < 0) { + northsouth = 'S'; + latval = -latval; + } else + northsouth = 'N'; + + latsecfrac = latval % 1000; + latval = latval / 1000; + latsec = latval % 60; + latval = latval / 60; + latmin = latval % 60; + latval = latval / 60; + latdeg = latval; + + if (longval < 0) { + eastwest = 'W'; + longval = -longval; + } else + eastwest = 'E'; + + longsecfrac = longval % 1000; + longval = longval / 1000; + longsec = longval % 60; + longval = longval / 60; + longmin = longval % 60; + longval = longval / 60; + longdeg = longval; + + altfrac = altval % 100; + altmeters = (altval / 100) * altsign; + + if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL) + sizestr = error; + if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL) + hpstr = error; + if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL) + vpstr = error; + + sprintf(ascii, + "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm", + latdeg, latmin, latsec, latsecfrac, northsouth, + longdeg, longmin, longsec, longsecfrac, eastwest, + altmeters, altfrac, sizestr, hpstr, vpstr); + + if (sizestr != error) + free(sizestr); + if (hpstr != error) + free(hpstr); + if (vpstr != error) + free(vpstr); + + return (ascii); +} + + +/* Return the number of DNS hierarchy levels in the name. */ +int +dn_count_labels(const char *name) { + int i, len, count; + + len = strlen(name); + for (i = 0, count = 0; i < len; i++) { + /* XXX need to check for \. or use named's nlabels(). */ + if (name[i] == '.') + count++; + } + + /* don't count initial wildcard */ + if (name[0] == '*') + if (count) + count--; + + /* don't count the null label for root. */ + /* if terminating '.' not found, must adjust */ + /* count to include last label */ + if (len > 0 && name[len-1] != '.') + count++; + return (count); +} + + +/* + * Make dates expressed in seconds-since-Jan-1-1970 easy to read. + * SIG records are required to be printed like this, by the Secure DNS RFC. + */ +char * +p_secstodate (u_long secs) { + static char output[15]; /* YYYYMMDDHHMMSS and null */ + time_t clock = secs; + struct tm *time; + + time = gmtime(&clock); + time->tm_year += 1900; + time->tm_mon += 1; + sprintf(output, "%04d%02d%02d%02d%02d%02d", + time->tm_year, time->tm_mon, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + return (output); +} diff --git a/cpukit/libnetworking/libc/res_init.c b/cpukit/libnetworking/libc/res_init.c new file mode 100644 index 0000000000..8b60889c6f --- /dev/null +++ b/cpukit/libnetworking/libc/res_init.c @@ -0,0 +1,497 @@ +/* + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; +static char orig_rcsid[] = "From: Id: res_init.c,v 8.7 1996/11/18 09:10:04 vixie Exp $"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "res_config.h" + +static void res_setoptions __P((char *, char *)); + +#ifdef RESOLVSORT +static const char sort_mask[] = "/&"; +#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) +static u_int32_t net_mask __P((struct in_addr)); +#endif + +#if !defined(isascii) /* XXX - could be a function */ +# define isascii(c) (!(c & 0200)) +#endif + +/* + * Resolver state default settings. + */ + +struct __res_state _res +# if defined(__BIND_RES_TEXT) + = { RES_TIMEOUT, } /* Motorola, et al. */ +# endif + ; + + +/* + * Set up default settings. If the configuration file exist, the values + * there will have precedence. Otherwise, the server address is set to + * INADDR_ANY and the default domain name comes from the gethostname(). + * + * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 + * rather than INADDR_ANY ("0.0.0.0") as the default name server address + * since it was noted that INADDR_ANY actually meant ``the first interface + * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, + * it had to be "up" in order for you to reach your own name server. It + * was later decided that since the recommended practice is to always + * install local static routes through 127.0.0.1 for all your network + * interfaces, that we could solve this problem without a code change. + * + * The configuration file should always be used, since it is the only way + * to specify a default domain. If you are running a server on your local + * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" + * in the configuration file. + * + * Return 0 if completes successfully, -1 on error + */ +int +res_init() +{ + register FILE *fp; + register char *cp, **pp; + register int n; + char buf[MAXDNAME]; + int nserv = 0; /* number of nameserver records read from file */ + int haveenv = 0; + int havesearch = 0; +#ifdef RESOLVSORT + int nsort = 0; + char *net; +#endif +#ifndef RFC1535 + int dots; +#endif + + /* + * These three fields used to be statically initialized. This made + * it hard to use this code in a shared library. It is necessary, + * now that we're doing dynamic initialization here, that we preserve + * the old semantics: if an application modifies one of these three + * fields of _res before res_init() is called, res_init() will not + * alter them. Of course, if an application is setting them to + * _zero_ before calling res_init(), hoping to override what used + * to be the static default, we can't detect it and unexpected results + * will follow. Zero for any of these fields would make no sense, + * so one can safely assume that the applications were already getting + * unexpected results. + * + * _res.options is tricky since some apps were known to diddle the bits + * before res_init() was first called. We can't replicate that semantic + * with dynamic initialization (they may have turned bits off that are + * set in RES_DEFAULT). Our solution is to declare such applications + * "broken". They could fool us by setting RES_INIT but none do (yet). + */ + if (!_res.retrans) + _res.retrans = RES_TIMEOUT; + if (!_res.retry) + _res.retry = 4; + if (!(_res.options & RES_INIT)) + _res.options = RES_DEFAULT; + + /* + * This one used to initialize implicitly to zero, so unless the app + * has set it to something in particular, we can randomize it now. + */ + if (!_res.id) + _res.id = res_randomid(); + +#ifdef USELOOPBACK + _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); +#else + _res.nsaddr.sin_addr.s_addr = INADDR_ANY; +#endif + _res.nsaddr.sin_family = AF_INET; + _res.nsaddr.sin_port = htons(NAMESERVER_PORT); + _res.nscount = 1; + _res.ndots = 1; + _res.pfcode = 0; + + /* + * RTEMS -- Set up name servers + */ + { +#include <rtems/rtems_bsdnet_internal.h> + int n = 0; + while ((n < rtems_bsdnet_nameserver_count) && (nserv < MAXNS)) { + _res.nsaddr_list[nserv].sin_addr = rtems_bsdnet_nameserver[n]; + _res.nsaddr_list[nserv].sin_family = AF_INET; + _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); + nserv++; + n++; + } + if (rtems_bsdnet_domain_name) + (void)strncpy(_res.defdname, rtems_bsdnet_domain_name, sizeof(_res.defdname) - 1); + } + + /* Allow user to override the local domain definition */ + if ((cp = getenv("LOCALDOMAIN")) != NULL) { + (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); + haveenv++; + + /* + * Set search list to be blank-separated strings + * from rest of env value. Permits users of LOCALDOMAIN + * to still have a search list, and anyone to set the + * one that they want to use as an individual (even more + * important now that the rfc1535 stuff restricts searches) + */ + cp = _res.defdname; + pp = _res.dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + if (*cp == '\n') /* silly backwards compat */ + break; + else if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + havesearch = 1; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp = '\0'; + *pp++ = 0; + } + +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + /* read the config file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* skip comments */ + if (*buf == ';' || *buf == '#') + continue; + /* read default domain name */ + if (MATCH(buf, "domain")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("domain") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); + if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) + *cp = '\0'; + havesearch = 0; + continue; + } + /* set search list */ + if (MATCH(buf, "search")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("search") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); + if ((cp = strchr(_res.defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = _res.defdname; + pp = _res.dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cp = '\0'; + *pp++ = 0; + havesearch = 1; + continue; + } + /* read nameservers to query */ + if (MATCH(buf, "nameserver") && nserv < MAXNS) { + struct in_addr a; + + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { + _res.nsaddr_list[nserv].sin_addr = a; + _res.nsaddr_list[nserv].sin_family = AF_INET; + _res.nsaddr_list[nserv].sin_port = + htons(NAMESERVER_PORT); + nserv++; + } + continue; + } +#ifdef RESOLVSORT + if (MATCH(buf, "sortlist")) { + struct in_addr a; + + cp = buf + sizeof("sortlist") - 1; + while (nsort < MAXRESOLVSORT) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0' || *cp == '\n' || *cp == ';') + break; + net = cp; + while (*cp && !ISSORTMASK(*cp) && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + _res.sort_list[nsort].addr = a; + if (ISSORTMASK(n)) { + *cp++ = n; + net = cp; + while (*cp && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + _res.sort_list[nsort].mask = a.s_addr; + } else { + _res.sort_list[nsort].mask = + net_mask(_res.sort_list[nsort].addr); + } + } else { + _res.sort_list[nsort].mask = + net_mask(_res.sort_list[nsort].addr); + } + nsort++; + } + *cp = n; + } + continue; + } +#endif + if (MATCH(buf, "options")) { + res_setoptions(buf + sizeof("options") - 1, "conf"); + continue; + } + } + if (nserv > 1) + _res.nscount = nserv; +#ifdef RESOLVSORT + _res.nsort = nsort; +#endif + (void) fclose(fp); + } + if (_res.defdname[0] == 0 && + gethostname(buf, sizeof(_res.defdname) - 1) == 0 && + (cp = strchr(buf, '.')) != NULL) + strcpy(_res.defdname, cp + 1); + + /* find components of local domain that might be searched */ + if (havesearch == 0) { + pp = _res.dnsrch; + *pp++ = _res.defdname; + *pp = NULL; + +#ifndef RFC1535 + dots = 0; + for (cp = _res.defdname; *cp; cp++) + dots += (*cp == '.'); + + cp = _res.defdname; + while (pp < _res.dnsrch + MAXDFLSRCH) { + if (dots < LOCALDOMAINPARTS) + break; + cp = strchr(cp, '.') + 1; /* we know there is one */ + *pp++ = cp; + dots--; + } + *pp = NULL; +#ifdef DEBUG + if (_res.options & RES_DEBUG) { + printf(";; res_init()... default dnsrch list:\n"); + for (pp = _res.dnsrch; *pp; pp++) + printf(";;\t%s\n", *pp); + printf(";;\t..END..\n"); + } +#endif +#endif /* !RFC1535 */ + } + + if ((cp = getenv("RES_OPTIONS")) != NULL) + res_setoptions(cp, "env"); + _res.options |= RES_INIT; + return (0); +} + +static void +res_setoptions(options, source) + char *options, *source; +{ + char *cp = options; + int i; + +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_setoptions(\"%s\", \"%s\")...\n", + options, source); +#endif + while (*cp) { + /* skip leading and inner runs of spaces */ + while (*cp == ' ' || *cp == '\t') + cp++; + /* search for and process individual options */ + if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { + i = atoi(cp + sizeof("ndots:") - 1); + if (i <= RES_MAXNDOTS) + _res.ndots = i; + else + _res.ndots = RES_MAXNDOTS; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";;\tndots=%d\n", _res.ndots); +#endif + } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { +#ifdef DEBUG + if (!(_res.options & RES_DEBUG)) { + printf(";; res_setoptions(\"%s\", \"%s\")..\n", + options, source); + _res.options |= RES_DEBUG; + } + printf(";;\tdebug\n"); +#endif + } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { + _res.options |= RES_USE_INET6; + } else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1)) { + _res.options |= RES_NOTLDQUERY; + } else { + /* XXX - print a warning here? */ + } + /* skip to next run of spaces */ + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } +} + +#ifdef RESOLVSORT +/* XXX - should really support CIDR which means explicit masks always. */ +static u_int32_t +net_mask(in) /* XXX - should really use system's version of this */ + struct in_addr in; +{ + register u_int32_t i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (htonl(IN_CLASSA_NET)); + else if (IN_CLASSB(i)) + return (htonl(IN_CLASSB_NET)); + return (htonl(IN_CLASSC_NET)); +} +#endif + +u_int +res_randomid() +{ + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} diff --git a/cpukit/libnetworking/libc/res_mkquery.c b/cpukit/libnetworking/libc/res_mkquery.c new file mode 100644 index 0000000000..d3fabfa5ab --- /dev/null +++ b/cpukit/libnetworking/libc/res_mkquery.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; +static char orig_rcsid[] = "From: Id: res_mkquery.c,v 8.9 1997/04/24 22:22:36 vixie Exp $"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> + +#include "res_config.h" + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +int +res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) + int op; /* opcode of query */ + const char *dname; /* domain name */ + int class, type; /* class and type of query */ + const u_char *data; /* resource record data */ + int datalen; /* length of data */ + const u_char *newrr_in; /* new rr for modify or append */ + u_char *buf; /* buffer to put query */ + int buflen; /* size of buffer */ +{ + register HEADER *hp; + register u_char *cp; + register int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_mkquery(%d, %s, %d, %d)\n", + op, dname, class, type); +#endif + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + hp->id = htons(++_res.id); + hp->opcode = op; + hp->rd = (_res.options & RES_RECURSE) != 0; + hp->rcode = NOERROR; + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: + if ((buflen -= QFIXEDSZ) < 0) + return (-1); + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + buflen -= n; + __putshort(type, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + buflen -= RRFIXEDSZ; + n = dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + buflen -= n; + __putshort(T_NULL, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + __putlong(0, cp); + cp += INT32SZ; + __putshort(0, cp); + cp += INT16SZ; + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (buflen < 1 + RRFIXEDSZ + datalen) + return (-1); + *cp++ = '\0'; /* no domain name */ + __putshort(type, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + __putlong(0, cp); + cp += INT32SZ; + __putshort(datalen, cp); + cp += INT16SZ; + if (datalen) { + memcpy(cp, data, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return (-1); + } + return (cp - buf); +} diff --git a/cpukit/libnetworking/libc/res_mkupdate.c b/cpukit/libnetworking/libc/res_mkupdate.c new file mode 100644 index 0000000000..b74f16ba78 --- /dev/null +++ b/cpukit/libnetworking/libc/res_mkupdate.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Based on the Dynamic DNS reference implementation by Viraj Bais + * <viraj_bais@ccm.fm.intel.com> + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid[] = "$Id$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> + +#include "res_config.h" + +static int getnum_str(u_char **, u_char *); +static int getword_str(char *, int, u_char **, u_char *); + +#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); + +/* + * Form update packets. + * Returns the size of the resulting packet if no error + * On error, + * returns -1 if error in reading a word/number in rdata + * portion for update packets + * -2 if length of buffer passed is insufficient + * -3 if zone section is not the first section in + * the linked list, or section order has a problem + * -4 on a number overflow + * -5 unknown operation or no records + */ +int +res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { + ns_updrec *rrecp_start = rrecp_in; + HEADER *hp; + u_char c, *cp, *cp1, *sp1, *sp2, *startp, *endp; + int n, i, j, found, soanum, multiline; + ns_updrec *rrecp, *tmprrecp, *recptr = NULL; + struct in_addr ina; + char buf2[MAXDNAME]; + int section, numrrs = 0, counts[ns_s_max]; + u_int16_t rtype, rclass; + u_int32_t n1, rttl; + u_char *dnptrs[20], **dpp, **lastdnptr; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + hp->id = htons(++_res.id); + hp->opcode = ns_o_update; + hp->rcode = NOERROR; + sp1 = buf + 2*INT16SZ; /* save pointer to zocount */ + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + + if (rrecp_start == NULL) + return (-5); + else if (rrecp_start->r_section != S_ZONE) + return (-3); + + memset(counts, 0, sizeof counts); + for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) { + numrrs++; + section = rrecp->r_section; + if (section < 0 || section >= ns_s_max) + return (-1); + counts[section]++; + for (i = section + 1; i < ns_s_max; i++) + if (counts[i]) + return (-3); + rtype = rrecp->r_type; + rclass = rrecp->r_class; + rttl = rrecp->r_ttl; + /* overload class and type */ + if (section == S_PREREQ) { + rttl = 0; + switch (rrecp->r_opcode) { + case YXDOMAIN: + rclass = C_ANY; + rtype = T_ANY; + rrecp->r_size = 0; + break; + case NXDOMAIN: + rclass = C_NONE; + rtype = T_ANY; + rrecp->r_size = 0; + break; + case NXRRSET: + rclass = C_NONE; + rrecp->r_size = 0; + break; + case YXRRSET: + if (rrecp->r_size == 0) + rclass = C_ANY; + break; + default: + fprintf(stderr, + "res_mkupdate: incorrect opcode: %d\n", + rrecp->r_opcode); + fflush(stderr); + return (-1); + } + } else if (section == S_UPDATE) { + switch (rrecp->r_opcode) { + case DELETE: + rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; + break; + case ADD: + break; + default: + fprintf(stderr, + "res_mkupdate: incorrect opcode: %d\n", + rrecp->r_opcode); + fflush(stderr); + return (-1); + } + } + + /* + * XXX appending default domain to owner name is omitted, + * fqdn must be provided + */ + if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, + lastdnptr)) < 0) + return (-1); + cp += n; + ShrinkBuffer(n + 2*INT16SZ); + PUTSHORT(rtype, cp); + PUTSHORT(rclass, cp); + if (section == S_ZONE) { + if (numrrs != 1 || rrecp->r_type != T_SOA) + return (-3); + continue; + } + ShrinkBuffer(INT32SZ + INT16SZ); + PUTLONG(rttl, cp); + sp2 = cp; /* save pointer to length byte */ + cp += INT16SZ; + if (rrecp->r_size == 0) { + if (section == S_UPDATE && rclass != C_ANY) + return (-1); + else { + PUTSHORT(0, sp2); + continue; + } + } + startp = rrecp->r_data; + endp = startp + rrecp->r_size - 1; + /* XXX this should be done centrally. */ + switch (rrecp->r_type) { + case T_A: + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if (!inet_aton(buf2, &ina)) + return (-1); + n1 = ntohl(ina.s_addr); + ShrinkBuffer(INT32SZ); + PUTLONG(n1, cp); + break; + case T_CNAME: + case T_MB: + case T_MG: + case T_MR: + case T_NS: + case T_PTR: + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + break; + case T_MINFO: + case T_SOA: + case T_RP: + for (i = 0; i < 2; i++) { + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, + dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + } + if (rrecp->r_type == T_SOA) { + ShrinkBuffer(5 * INT32SZ); + while (isspace(*startp) || !*startp) + startp++; + if (*startp == '(') { + multiline = 1; + startp++; + } else + multiline = 0; + /* serial, refresh, retry, expire, minimum */ + for (i = 0; i < 5; i++) { + soanum = getnum_str(&startp, endp); + if (soanum < 0) + return (-1); + PUTLONG(soanum, cp); + } + if (multiline) { + while (isspace(*startp) || !*startp) + startp++; + if (*startp != ')') + return (-1); + } + } + break; + case T_MX: + case T_AFSDB: + case T_RT: + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + PUTSHORT(n, cp); + ShrinkBuffer(INT16SZ); + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + break; + case T_PX: + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + PUTSHORT(n, cp); + ShrinkBuffer(INT16SZ); + for (i = 0; i < 2; i++) { + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, + lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + } + break; + case T_WKS: + case T_HINFO: + case T_TXT: + case T_X25: + case T_ISDN: + case T_NSAP: + case T_LOC: + /* XXX - more fine tuning needed here */ + ShrinkBuffer(rrecp->r_size); + memcpy(cp, rrecp->r_data, rrecp->r_size); + cp += rrecp->r_size; + break; + default: + return (-1); + } /*switch*/ + n = (u_int16_t)((cp - sp2) - INT16SZ); + PUTSHORT(n, sp2); + } /*for*/ + + hp->qdcount = htons(counts[0]); + hp->ancount = htons(counts[1]); + hp->nscount = htons(counts[2]); + hp->arcount = htons(counts[3]); + return (cp - buf); +} + +/* + * Get a whitespace delimited word from a string (not file) + * into buf. modify the start pointer to point after the + * word in the string. + */ +static int +getword_str(char *buf, int size, u_char **startpp, u_char *endp) { + char *cp; + int c; + + for (cp = buf; *startpp <= endp; ) { + c = **startpp; + if (isspace(c) || c == '\0') { + if (cp != buf) /* trailing whitespace */ + break; + else { /* leading whitespace */ + (*startpp)++; + continue; + } + } + (*startpp)++; + if (cp >= buf+size-1) + break; + *cp++ = (u_char)c; + } + *cp = '\0'; + return (cp != buf); +} + +/* + * Get a whitespace delimited number from a string (not file) into buf + * update the start pointer to point after the number in the string. + */ +static int +getnum_str(u_char **startpp, u_char *endp) { + int c, n; + int seendigit = 0; + int seendecimal = 0; + int m = 0; + + for (n = 0; *startpp <= endp; ) { + c = **startpp; + if (isspace(c) || c == '\0') { + if (seendigit) /* trailing whitespace */ + break; + else { /* leading whitespace */ + (*startpp)++; + continue; + } + } + if (c == ';') { + while ((*startpp <= endp) && + ((c = **startpp) != '\n')) + (*startpp)++; + if (seendigit) + break; + continue; + } + if (!isdigit(c)) { + if (c == ')' && seendigit) { + (*startpp)--; + break; + } + return (-1); + } + (*startpp)++; + n = n * 10 + (c - '0'); + seendigit = 1; + } + return (n + m); +} + +/* + * Allocate a resource record buffer & save rr info. + */ +ns_updrec * +res_mkupdrec(int section, const char *dname, + u_int class, u_int type, u_long ttl) { + ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); + + if (!rrecp || !(rrecp->r_dname = strdup(dname))) + return (NULL); + rrecp->r_class = class; + rrecp->r_type = type; + rrecp->r_ttl = ttl; + rrecp->r_section = section; + return (rrecp); +} + +/* + * Free a resource record buffer created by res_mkupdrec. + */ +void +res_freeupdrec(ns_updrec *rrecp) { + /* Note: freeing r_dp is the caller's responsibility. */ + if (rrecp->r_dname != NULL) + free(rrecp->r_dname); + free(rrecp); +} diff --git a/cpukit/libnetworking/libc/res_query.c b/cpukit/libnetworking/libc/res_query.c new file mode 100644 index 0000000000..42b7f1ecc2 --- /dev/null +++ b/cpukit/libnetworking/libc/res_query.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; +static char orig_rcsid = "From: Id: res_query.c,v 8.14 1997/06/09 17:47:05 halley Exp $"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "res_config.h" + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in h_errno. + * + * Caller must parse answer and determine whether it answers the question. + */ +int +res_query(name, class, type, answer, anslen) + const char *name; /* domain name */ + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer buffer */ +{ + u_char buf[MAXPACKET]; + HEADER *hp = (HEADER *) answer; + int n; + + hp->rcode = NOERROR; /* default */ + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_query(%s, %d, %d)\n", name, class, type); +#endif + + n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); + if (n <= 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_query: mkquery failed\n"); +#endif + h_errno = NO_RECOVERY; + return (n); + } + n = res_send(buf, n, answer, anslen); + if (n < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + h_errno = TRY_AGAIN; + return (n); + } + + if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; rcode = %d, ancount=%d\n", hp->rcode, + ntohs(hp->ancount)); +#endif + switch (hp->rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + return (-1); + } + return (n); +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error code, if any, is left in h_errno. + */ +int +res_search(name, class, type, answer, anslen) + const char *name; /* domain name */ + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer */ +{ + const char *cp, * const *domain; + HEADER *hp = (HEADER *) answer; + u_int dots; + int trailing_dot, ret, saved_herrno; + int got_nodata = 0, got_servfail = 0, tried_as_is = 0; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } + errno = 0; + h_errno = HOST_NOT_FOUND; /* default, if we never query */ + dots = 0; + for (cp = name; *cp; cp++) + dots += (*cp == '.'); + trailing_dot = 0; + if (cp > name && *--cp == '.') + trailing_dot++; + + /* If there aren't any dots, it could be a user-level alias */ + if (!dots && (cp = hostalias(name)) != NULL) + return (res_query(cp, class, type, answer, anslen)); + + /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + saved_herrno = -1; + if (dots >= _res.ndots) { + ret = res_querydomain(name, NULL, class, type, answer, anslen); + if (ret > 0) + return (ret); + saved_herrno = h_errno; + tried_as_is++; + } + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (_res.options & RES_DEFNAMES)) || + (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { + int done = 0; + + for (domain = (const char * const *)_res.dnsrch; + *domain && !done; + domain++) { + + ret = res_querydomain(name, *domain, class, type, + answer, anslen); + if (ret > 0) + return (ret); + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + h_errno = TRY_AGAIN; + return (-1); + } + + switch (h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + + /* if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if (!(_res.options & RES_DNSRCH)) + done++; + } + } + + /* + * If we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot unless NOTLDQUERY is set. + */ + if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { + ret = res_querydomain(name, NULL, class, type, answer, anslen); + if (ret > 0) + return (ret); + } + + /* if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's h_errno + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless h_errno, that being the one from + * the last DNSRCH we did. + */ + if (saved_herrno != -1) + h_errno = saved_herrno; + else if (got_nodata) + h_errno = NO_DATA; + else if (got_servfail) + h_errno = TRY_AGAIN; + return (-1); +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +int +res_querydomain(name, domain, class, type, answer, anslen) + const char *name, *domain; + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer */ +{ + char nbuf[MAXDNAME]; + const char *longname = nbuf; + int n, d; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_querydomain(%s, %s, %d, %d)\n", + name, domain?domain:"<Nil>", class, type); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name); + if (n >= MAXDNAME) { + h_errno = NO_RECOVERY; + return (-1); + } + n--; + if (n >= 0 && name[n] == '.') { + strncpy(nbuf, name, n); + nbuf[n] = '\0'; + } else + longname = name; + } else { + n = strlen(name); + d = strlen(domain); + if (n + d + 1 >= MAXDNAME) { + h_errno = NO_RECOVERY; + return (-1); + } + sprintf(nbuf, "%s.%s", name, domain); + } + return (res_query(longname, class, type, answer, anslen)); +} + +const char * +hostalias(name) + const char *name; +{ + register char *cp1, *cp2; + FILE *fp; + char *file; + char buf[BUFSIZ]; + static char abuf[MAXDNAME]; + + if (_res.options & RES_NOALIASES) + return (NULL); + if (issetugid()) + return (NULL); + file = getenv("HOSTALIASES"); + if (file == NULL || (fp = fopen(file, "r")) == NULL) + return (NULL); + setbuf(fp, NULL); + buf[sizeof(buf) - 1] = '\0'; + while (fgets(buf, sizeof(buf), fp)) { + for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1) + ; + if (!*cp1) + break; + *cp1 = '\0'; + if (!strcasecmp(buf, name)) { + while (isspace(*++cp1)) + ; + if (!*cp1) + break; + for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2) + ; + abuf[sizeof(abuf) - 1] = *cp2 = '\0'; + strncpy(abuf, cp1, sizeof(abuf) - 1); + fclose(fp); + return (abuf); + } + } + fclose(fp); + return (NULL); +} diff --git a/cpukit/libnetworking/libc/res_send.c b/cpukit/libnetworking/libc/res_send.c new file mode 100644 index 0000000000..cfb1e2eb9d --- /dev/null +++ b/cpukit/libnetworking/libc/res_send.c @@ -0,0 +1,923 @@ +/* + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; +static char orig_rcsid[] = "From: Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $"; +static char rcsid[] = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Send query to name server and wait for reply. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <poll.h> + +#include "res_config.h" + +#ifdef NOPOLL /* libc_r doesn't wrap poll yet() */ +static int use_poll = 0; +#else +static int use_poll = 1; /* adapt to poll() syscall availability */ + /* 0 = not present, 1 = try it, 2 = exists */ +#endif + +static int s = -1; /* socket used for communications */ +static int connected = 0; /* is the socket connected */ +static int vc = 0; /* is the socket a virtual circuit? */ +static res_send_qhook Qhook = NULL; +static res_send_rhook Rhook = NULL; + + +#define CAN_RECONNECT 1 + +#ifndef DEBUG +# define Dprint(cond, args) /*empty*/ +# define DprintQ(cond, args, query, size) /*empty*/ +# define Aerror(file, string, error, address) /*empty*/ +# define Perror(file, string, error) /*empty*/ +#else +# define Dprint(cond, args) if (cond) {fprintf args;} else {} +# define DprintQ(cond, args, query, size) if (cond) {\ + fprintf args;\ + __fp_nquery(query, size, stdout);\ + } else {} + static void + Aerror(file, string, error, address) + FILE *file; + char *string; + int error; + struct sockaddr_in address; + { + int save = errno; + + if (_res.options & RES_DEBUG) { + fprintf(file, "res_send: %s ([%s].%u): %s\n", + string, + inet_ntoa(address.sin_addr), + ntohs(address.sin_port), + strerror(error)); + } + errno = save; + } + static void + Perror(file, string, error) + FILE *file; + char *string; + int error; + { + int save = errno; + + if (_res.options & RES_DEBUG) { + fprintf(file, "res_send: %s: %s\n", + string, strerror(error)); + } + errno = save; + } +#endif + +void +res_send_setqhook(hook) + res_send_qhook hook; +{ + + Qhook = hook; +} + +void +res_send_setrhook(hook) + res_send_rhook hook; +{ + + Rhook = hook; +} + +/* int + * res_isourserver(ina) + * looks up "ina" in _res.ns_addr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_isourserver(inp) + const struct sockaddr_in *inp; +{ + struct sockaddr_in ina; + int ns, ret; + + ina = *inp; + ret = 0; + for (ns = 0; ns < _res.nscount; ns++) { + const struct sockaddr_in *srv = &_res.nsaddr_list[ns]; + + if (srv->sin_family == ina.sin_family && + srv->sin_port == ina.sin_port && + (srv->sin_addr.s_addr == INADDR_ANY || + srv->sin_addr.s_addr == ina.sin_addr.s_addr)) { + ret++; + break; + } + } + return (ret); +} + +/* int + * res_nameinquery(name, type, class, buf, eom) + * look for (name,type,class) in the query section of packet (buf,eom) + * requires: + * buf + HFIXEDSZ <= eom + * returns: + * -1 : format error + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_nameinquery(name, type, class, buf, eom) + const char *name; + int type, class; + const u_char *buf, *eom; +{ + const u_char *cp = buf + HFIXEDSZ; + int qdcount = ntohs(((HEADER*)buf)->qdcount); + + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + int n, ttype, tclass; + + n = dn_expand(buf, eom, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + if (cp + 2 * INT16SZ > eom) + return (-1); + ttype = ns_get16(cp); cp += INT16SZ; + tclass = ns_get16(cp); cp += INT16SZ; + if (ttype == type && + tclass == class && + strcasecmp(tname, name) == 0) + return (1); + } + return (0); +} + +/* int + * res_queriesmatch(buf1, eom1, buf2, eom2) + * is there a 1:1 mapping of (name,type,class) + * in (buf1,eom1) and (buf2,eom2)? + * returns: + * -1 : format error + * 0 : not a 1:1 mapping + * >0 : is a 1:1 mapping + * author: + * paul vixie, 29may94 + */ +int +res_queriesmatch(buf1, eom1, buf2, eom2) + const u_char *buf1, *eom1; + const u_char *buf2, *eom2; +{ + const u_char *cp = buf1 + HFIXEDSZ; + int qdcount = ntohs(((HEADER*)buf1)->qdcount); + + if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) + return (-1); + + /* + * Only header section present in replies to + * dynamic update packets. + */ + if ( (((HEADER *)buf1)->opcode == ns_o_update) && + (((HEADER *)buf2)->opcode == ns_o_update) ) + return (1); + + if (qdcount != ntohs(((HEADER*)buf2)->qdcount)) + return (0); + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + int n, ttype, tclass; + + n = dn_expand(buf1, eom1, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + if (cp + 2 * INT16SZ > eom1) + return (-1); + ttype = ns_get16(cp); cp += INT16SZ; + tclass = ns_get16(cp); cp += INT16SZ; + if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) + return (0); + } + return (1); +} + +int +res_send(buf, buflen, ans, anssiz) + const u_char *buf; + int buflen; + u_char *ans; + int anssiz; +{ + HEADER *hp = (HEADER *) buf; + HEADER *anhp = (HEADER *) ans; + int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n; + u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */ + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + /* errno should have been set by res_init() in this case. */ + return (-1); + } + if (anssiz < HFIXEDSZ) { + errno = EINVAL; + return (-1); + } + DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY), + (stdout, ";; res_send()\n"), buf, buflen); + v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; + gotsomewhere = 0; + connreset = 0; + terrno = ETIMEDOUT; + badns = 0; + + /* + * Send request, RETRY times, or until successful + */ + for (try = 0; try < _res.retry; try++) { + for (ns = 0; ns < _res.nscount; ns++) { + struct sockaddr_in *nsap = &_res.nsaddr_list[ns]; + same_ns: + if (badns & (1 << ns)) { + res_close(); + goto next_ns; + } + + if (Qhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*Qhook)(&nsap, &buf, &buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + done = 1; + break; + case res_nextns: + res_close(); + goto next_ns; + case res_done: + return (resplen); + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + return (-1); + } + } while (!done); + } + + Dprint(_res.options & RES_DEBUG, + (stdout, ";; Querying server (# %d) address = %s\n", + ns + 1, inet_ntoa(nsap->sin_addr))); + + if (v_circuit) { + int truncated; + struct iovec iov[2]; + u_short len; + u_char *cp; + + /* + * Use virtual circuit; + * at most one attempt per server. + */ + try = _res.retry; + truncated = 0; + if (s < 0 || !vc || hp->opcode == ns_o_update) { + if (s >= 0) + res_close(); + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s < 0) { + terrno = errno; + Perror(stderr, "socket(vc)", errno); + return (-1); + } + errno = 0; + if (connect(s, (struct sockaddr *)nsap, + sizeof *nsap) < 0) { + terrno = errno; + Aerror(stderr, "connect/vc", + errno, *nsap); + badns |= (1 << ns); + res_close(); + goto next_ns; + } + vc = 1; + } + /* + * Send length & message + */ + putshort((u_short)buflen, (u_char*)&len); +#if 0 + iov[0].iov_base = (caddr_t)&len; + iov[0].iov_len = INT16SZ; + iov[1].iov_base = (caddr_t)buf; + iov[1].iov_len = buflen; + if (writev(s, iov, 2) != (INT16SZ + buflen)) { +#else + /* + * RTEMS doesn't have writev (yet) + */ + if ((write (s, len, INT16SZ) != INT16SZ) + || (write (s, buf, buflen) != buflen)) { +#endif + terrno = errno; + Perror(stderr, "write failed", errno); + badns |= (1 << ns); + res_close(); + goto next_ns; + } + /* + * Receive length & response + */ +read_len: + cp = ans; + len = INT16SZ; + while ((n = read(s, (char *)cp, (int)len)) > 0) { + cp += n; + if ((len -= n) <= 0) + break; + } + if (n <= 0) { + terrno = errno; + Perror(stderr, "read failed", errno); + res_close(); + /* + * A long running process might get its TCP + * connection reset if the remote server was + * restarted. Requery the server instead of + * trying a new one. When there is only one + * server, this means that a query might work + * instead of failing. We only allow one reset + * per query to prevent looping. + */ + if (terrno == ECONNRESET && !connreset) { + connreset = 1; + res_close(); + goto same_ns; + } + res_close(); + goto next_ns; + } + resplen = ns_get16(ans); + if (resplen > anssiz) { + Dprint(_res.options & RES_DEBUG, + (stdout, ";; response truncated\n") + ); + truncated = 1; + len = anssiz; + } else + len = resplen; + if (len < HFIXEDSZ) { + /* + * Undersized message. + */ + Dprint(_res.options & RES_DEBUG, + (stdout, ";; undersized: %d\n", len)); + terrno = EMSGSIZE; + badns |= (1 << ns); + res_close(); + goto next_ns; + } + cp = ans; + while (len != 0 && + (n = read(s, (char *)cp, (int)len)) > 0) { + cp += n; + len -= n; + } + if (n <= 0) { + terrno = errno; + Perror(stderr, "read(vc)", errno); + res_close(); + goto next_ns; + } + if (truncated) { + /* + * Flush rest of answer + * so connection stays in synch. + */ + anhp->tc = 1; + len = resplen - anssiz; + while (len != 0) { + char junk[PACKETSZ]; + + n = (len > sizeof(junk) + ? sizeof(junk) + : len); + if ((n = read(s, junk, n)) > 0) + len -= n; + else + break; + } + } + /* + * The calling applicating has bailed out of + * a previous call and failed to arrange to have + * the circuit closed or the server has got + * itself confused. Anyway drop the packet and + * wait for the correct one. + */ + if (hp->id != anhp->id) { + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; old answer (unexpected):\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto read_len; + } + } else { + /* + * Use datagrams. + */ +#ifndef NOPOLL + struct pollfd pfd; + int msec; +#endif + struct timeval timeout; + fd_set dsmask, *dsmaskp; + int dsmasklen; + struct sockaddr_in from; + int fromlen; + + if ((s < 0) || vc) { + if (vc) + res_close(); + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) { +#ifndef CAN_RECONNECT + bad_dg_sock: +#endif + terrno = errno; + Perror(stderr, "socket(dg)", errno); + return (-1); + } + connected = 0; + } +#ifndef CANNOT_CONNECT_DGRAM + /* + * On a 4.3BSD+ machine (client and server, + * actually), sending to a nameserver datagram + * port with no nameserver will cause an + * ICMP port unreachable message to be returned. + * If our datagram socket is "connected" to the + * server, we get an ECONNREFUSED error on the next + * socket operation, and select returns if the + * error message is received. We can thus detect + * the absence of a nameserver without timing out. + * If we have sent queries to at least two servers, + * however, we don't want to remain connected, + * as we wish to receive answers from the first + * server to respond. + */ + if (_res.nscount == 1 || (try == 0 && ns == 0)) { + /* + * Connect only if we are sure we won't + * receive a response from another server. + */ + if (!connected) { + if (connect(s, (struct sockaddr *)nsap, + sizeof *nsap + ) < 0) { + Aerror(stderr, + "connect(dg)", + errno, *nsap); + badns |= (1 << ns); + res_close(); + goto next_ns; + } + connected = 1; + } + if (send(s, (char*)buf, buflen, 0) != buflen) { + Perror(stderr, "send", errno); + badns |= (1 << ns); + res_close(); + goto next_ns; + } + } else { + /* + * Disconnect if we want to listen + * for responses from more than one server. + */ + if (connected) { +#ifdef CAN_RECONNECT + struct sockaddr_in no_addr; + + no_addr.sin_family = AF_INET; + no_addr.sin_addr.s_addr = INADDR_ANY; + no_addr.sin_port = 0; + (void) connect(s, + (struct sockaddr *) + &no_addr, + sizeof no_addr); +#else + int s1 = socket(PF_INET, SOCK_DGRAM,0); + if (s1 < 0) + goto bad_dg_sock; + (void) dup2(s1, s); + (void) close(s1); + Dprint(_res.options & RES_DEBUG, + (stdout, ";; new DG socket\n")) +#endif /* CAN_RECONNECT */ + connected = 0; + errno = 0; + } +#endif /* !CANNOT_CONNECT_DGRAM */ + if (sendto(s, (char*)buf, buflen, 0, + (struct sockaddr *)nsap, + sizeof *nsap) + != buflen) { + Aerror(stderr, "sendto", errno, *nsap); + badns |= (1 << ns); + res_close(); + goto next_ns; + } +#ifndef CANNOT_CONNECT_DGRAM + } +#endif /* !CANNOT_CONNECT_DGRAM */ + + /* + * Wait for reply + */ +#ifndef NOPOLL + othersyscall: + if (use_poll) { + msec = (_res.retrans << try) * 1000; + if (try > 0) + msec /= _res.nscount; + if (msec <= 0) + msec = 1000; + } else { +#endif + timeout.tv_sec = (_res.retrans << try); + if (try > 0) + timeout.tv_sec /= _res.nscount; + if ((long) timeout.tv_sec <= 0) + timeout.tv_sec = 1; + timeout.tv_usec = 0; +#ifndef NOPOLL + } +#endif + wait: + if (s < 0) { + Perror(stderr, "s out-of-bounds", EMFILE); + res_close(); + goto next_ns; + } +#ifndef NOPOLL + if (use_poll) { + struct sigaction sa, osa; + int sigsys_installed = 0; + + pfd.fd = s; + pfd.events = POLLIN; + if (use_poll == 1) { + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_IGN; + if (sigaction(SIGSYS, &sa, &osa) >= 0) + sigsys_installed = 1; + } + n = poll(&pfd, 1, msec); + if (sigsys_installed == 1) { + int oerrno = errno; + sigaction(SIGSYS, &osa, NULL); + errno = oerrno; + } + /* XXX why does nosys() return EINVAL? */ + if (n < 0 && (errno == ENOSYS || + errno == EINVAL)) { + use_poll = 0; + goto othersyscall; + } else if (use_poll == 1) + use_poll = 2; + if (n < 0) { + if (errno == EINTR) + goto wait; + Perror(stderr, "poll", errno); + res_close(); + goto next_ns; + } + } else { +#endif +#ifndef NOSELECT + dsmasklen = howmany(s + 1, NFDBITS) * + sizeof(fd_mask); + if (dsmasklen > sizeof(fd_set)) { + dsmaskp = (fd_set *)malloc(dsmasklen); + if (dsmaskp == NULL) { + res_close(); + goto next_ns; + } + } else + dsmaskp = &dsmask; + /* only zero what we need */ + bzero((char *)dsmaskp, dsmasklen); + FD_SET(s, dsmaskp); + n = select(s + 1, dsmaskp, (fd_set *)NULL, + (fd_set *)NULL, &timeout); + if (dsmaskp != &dsmask) + free(dsmaskp); + if (n < 0) { + if (errno == EINTR) + goto wait; + Perror(stderr, "select", errno); + res_close(); + goto next_ns; + } +#endif +#ifndef NOPOLL + } +#endif + +#ifdef NOSELECT + setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout); +#else + if (n == 0) { + /* + * timeout + */ + Dprint(_res.options & RES_DEBUG, + (stdout, ";; timeout\n")); + gotsomewhere = 1; + res_close(); + goto next_ns; + } +#endif + errno = 0; + fromlen = sizeof(struct sockaddr_in); + resplen = recvfrom(s, (char*)ans, anssiz, 0, + (struct sockaddr *)&from, &fromlen); + if (resplen <= 0) { +#ifdef NOSELECT + if (errno == ETIMEDOUT) { + Dprint(_res.options & RES_DEBUG, + (stdout, ";; timeout\n")); + gotsomewhere = 1; + res_close(); + goto next_ns; + } +#endif + Perror(stderr, "recvfrom", errno); + res_close(); + goto next_ns; + } + gotsomewhere = 1; + if (resplen < HFIXEDSZ) { + /* + * Undersized message. + */ + Dprint(_res.options & RES_DEBUG, + (stdout, ";; undersized: %d\n", + resplen)); + terrno = EMSGSIZE; + badns |= (1 << ns); + res_close(); + goto next_ns; + } + if (hp->id != anhp->id) { + /* + * response from old query, ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; old answer:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto wait; + } +#ifdef CHECK_SRVR_ADDR + if (!(_res.options & RES_INSECURE1) && + !res_isourserver(&from)) { + /* + * response from wrong server? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; not our server:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto wait; + } +#endif + if (!(_res.options & RES_INSECURE2) && + !res_queriesmatch(buf, buf + buflen, + ans, ans + anssiz)) { + /* + * response contains wrong query? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; wrong query name:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto wait; + } + if (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || + anhp->rcode == REFUSED) { + DprintQ(_res.options & RES_DEBUG, + (stdout, "server rejected query:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + badns |= (1 << ns); + res_close(); + /* don't retry if called from dig */ + if (!_res.pfcode) + goto next_ns; + } + if (!(_res.options & RES_IGNTC) && anhp->tc) { + /* + * get rest of answer; + * use TCP with same server. + */ + Dprint(_res.options & RES_DEBUG, + (stdout, ";; truncated answer\n")); + v_circuit = 1; + res_close(); + goto same_ns; + } + } /*if vc/dg*/ + Dprint((_res.options & RES_DEBUG) || + ((_res.pfcode & RES_PRF_REPLY) && + (_res.pfcode & RES_PRF_HEAD1)), + (stdout, ";; got answer:\n")); + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ""), + ans, (resplen>anssiz)?anssiz:resplen); + /* + * If using virtual circuits, we assume that the first server + * is preferred over the rest (i.e. it is on the local + * machine) and only keep that one open. + * If we have temporarily opened a virtual circuit, + * or if we haven't been asked to keep a socket open, + * close the socket. + */ + if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) || + !(_res.options & RES_STAYOPEN)) { + res_close(); + } + if (Rhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*Rhook)(nsap, buf, buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + case res_done: + done = 1; + break; + case res_nextns: + res_close(); + goto next_ns; + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + return (-1); + } + } while (!done); + + } + return (resplen); + next_ns: ; + } /*foreach ns*/ + } /*foreach retry*/ + res_close(); + if (!v_circuit) { + if (!gotsomewhere) + errno = ECONNREFUSED; /* no nameservers found */ + else + errno = ETIMEDOUT; /* no answer obtained */ + } else + errno = terrno; + return (-1); +} + +/* + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it. This provides support for endhostent() + * which expects to close the socket. + * + * This routine is not expected to be user visible. + */ +void +res_close() +{ + if (s >= 0) { + (void) close(s); + s = -1; + connected = 0; + vc = 0; + } +} diff --git a/cpukit/libnetworking/libc/res_stubs.c b/cpukit/libnetworking/libc/res_stubs.c new file mode 100644 index 0000000000..92cf0fac54 --- /dev/null +++ b/cpukit/libnetworking/libc/res_stubs.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 1996 Peter Wemm <peter@freebsd.org>. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id$ + */ + +/* + * This file is for FreeBSD-3.0 that has a bind-4.9.5-P1 derived + * resolver in the libc. It provides aliases for functions that + * have moved since 4.9.4-P1. + * + * I'll save everybody the trouble and say it now: *THIS IS A HACK*! + * + * Yes, many of these are private functions to the resolver, but some are + * needed as there is no other way to provide the functionality and they've + * turned up all over the place. :-( + */ + +#include <sys/types.h> +#include <sys/cdefs.h> + +__weak_reference(__inet_addr, inet_addr); +__weak_reference(__inet_aton, inet_aton); +__weak_reference(__inet_lnaof, inet_lnaof); +__weak_reference(__inet_makeaddr, inet_makeaddr); +__weak_reference(__inet_neta, inet_neta); +__weak_reference(__inet_netof, inet_netof); +__weak_reference(__inet_network, inet_network); +__weak_reference(__inet_net_ntop, inet_net_ntop); +__weak_reference(__inet_net_pton, inet_net_pton); +__weak_reference(__inet_ntoa, inet_ntoa); +__weak_reference(__inet_pton, inet_pton); +__weak_reference(__inet_ntop, inet_ntop); +__weak_reference(__inet_nsap_addr, inet_nsap_addr); +__weak_reference(__inet_nsap_ntoa, inet_nsap_ntoa); + +__weak_reference(__sym_ston, sym_ston); +__weak_reference(__sym_ntos, sym_ntos); +__weak_reference(__sym_ntop, sym_ntop); +__weak_reference(__fp_resstat, fp_resstat); +__weak_reference(__p_query, p_query); +__weak_reference(__p_fqnname, p_fqnname); +__weak_reference(__p_secstodate, p_secstodate); +__weak_reference(__dn_count_labels, dn_count_labels); +__weak_reference(__dn_comp, dn_comp); +__weak_reference(__res_close, _res_close); +__weak_reference(__dn_expand, dn_expand); +__weak_reference(__res_init, res_init); +__weak_reference(__res_query, res_query); +__weak_reference(__res_search, res_search); +__weak_reference(__res_querydomain, res_querydomain); +__weak_reference(__res_mkquery, res_mkquery); +__weak_reference(__res_send, res_send); diff --git a/cpukit/libnetworking/libc/res_update.c b/cpukit/libnetworking/libc/res_update.c new file mode 100644 index 0000000000..1c5f20abd7 --- /dev/null +++ b/cpukit/libnetworking/libc/res_update.c @@ -0,0 +1,516 @@ +#if !defined(lint) && !defined(SABER) +static char rcsid[] = "$Id$"; +#endif /* not lint */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Based on the Dynamic DNS reference implementation by Viraj Bais + * <viraj_bais@ccm.fm.intel.com> + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* + * Separate a linked list of records into groups so that all records + * in a group will belong to a single zone on the nameserver. + * Create a dynamic update packet for each zone and send it to the + * nameservers for that zone, and await answer. + * Abort if error occurs in updating any zone. + * Return the number of zones updated on success, < 0 on error. + * + * On error, caller must deal with the unsynchronized zones + * eg. an A record might have been successfully added to the forward + * zone but the corresponding PTR record would be missing if error + * was encountered while updating the reverse zone. + */ + +#define NSMAX 16 + +struct ns1 { + char nsname[MAXDNAME]; + struct in_addr nsaddr1; +}; + +struct zonegrp { + char z_origin[MAXDNAME]; + int16_t z_class; + char z_soardata[MAXDNAME + 5 * INT32SZ]; + struct ns1 z_ns[NSMAX]; + int z_nscount; + ns_updrec * z_rr; + struct zonegrp *z_next; +}; + + +int +res_update(ns_updrec *rrecp_in) { + ns_updrec *rrecp, *tmprrecp; + u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ]; + char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME], + mailaddr[MAXDNAME]; + u_char soardata[2*MAXCDNAME+5*INT32SZ]; + char *dname, *svdname, *cp1, *target; + u_char *cp, *eom; + HEADER *hp = (HEADER *) answer; + struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL; + int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize, + newgroup, done, myzone, seen_before, numzones = 0; + u_int16_t dlen, class, qclass, type, qtype; + u_int32_t ttl; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } + + for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) { + dname = rrecp->r_dname; + n = strlen(dname); + if (dname[n-1] == '.') + dname[n-1] = '\0'; + qtype = T_SOA; + qclass = rrecp->r_class; + done = 0; + seen_before = 0; + + while (!done && dname) { + if (qtype == T_SOA) { + for (tmpzptr = zgrp_start; + tmpzptr && !seen_before; + tmpzptr = tmpzptr->z_next) { + if (strcasecmp(dname, + tmpzptr->z_origin) == 0 && + tmpzptr->z_class == qclass) + seen_before++; + for (tmprrecp = tmpzptr->z_rr; + tmprrecp && !seen_before; + tmprrecp = tmprrecp->r_grpnext) + if (strcasecmp(dname, tmprrecp->r_dname) == 0 + && tmprrecp->r_class == qclass) { + seen_before++; + break; + } + if (seen_before) { + /* + * Append to the end of + * current group. + */ + for (tmprrecp = tmpzptr->z_rr; + tmprrecp->r_grpnext; + tmprrecp = tmprrecp->r_grpnext) + (void)NULL; + tmprrecp->r_grpnext = rrecp; + rrecp->r_grpnext = NULL; + done = 1; + break; + } + } + } else if (qtype == T_A) { + for (tmpzptr = zgrp_start; + tmpzptr && !done; + tmpzptr = tmpzptr->z_next) + for (i = 0; i < tmpzptr->z_nscount; i++) + if (tmpzptr->z_class == qclass && + strcasecmp(tmpzptr->z_ns[i].nsname, + dname) == 0 && + tmpzptr->z_ns[i].nsaddr1.s_addr != 0) { + zptr->z_ns[k].nsaddr1.s_addr = + tmpzptr->z_ns[i].nsaddr1.s_addr; + done = 1; + break; + } + } + if (done) + break; + n = res_mkquery(QUERY, dname, qclass, qtype, NULL, + 0, NULL, buf, sizeof buf); + if (n <= 0) { + fprintf(stderr, "res_update: mkquery failed\n"); + return (n); + } + n = res_send(buf, n, answer, sizeof answer); + if (n < 0) { + fprintf(stderr, "res_update: send error for %s\n", + rrecp->r_dname); + return (n); + } + if (n < HFIXEDSZ) + return (-1); + ancount = ntohs(hp->ancount); + nscount = ntohs(hp->nscount); + arcount = ntohs(hp->arcount); + rcode = hp->rcode; + cp = answer + HFIXEDSZ; + eom = answer + n; + /* skip the question section */ + n = dn_skipname(cp, eom); + if (n < 0 || cp + n + 2 * INT16SZ > eom) + return (-1); + cp += n + 2 * INT16SZ; + + if (qtype == T_SOA) { + if (ancount == 0 && nscount == 0 && arcount == 0) { + /* + * if (rcode == NOERROR) then the dname exists but + * has no soa record associated with it. + * if (rcode == NXDOMAIN) then the dname does not + * exist and the server is replying out of NCACHE. + * in either case, proceed with the next try + */ + dname = strchr(dname, '.'); + if (dname != NULL) + dname++; + continue; + } else if ((rcode == NOERROR || rcode == NXDOMAIN) && + ancount == 0 && + nscount == 1 && arcount == 0) { + /* + * name/data does not exist, soa record supplied in the + * authority section + */ + /* authority section must contain the soa record */ + if ((n = dn_expand(answer, eom, cp, zname, + sizeof zname)) < 0) + return (n); + cp += n; + if (cp + 2 * INT16SZ > eom) + return (-1); + GETSHORT(type, cp); + GETSHORT(class, cp); + if (type != T_SOA || class != qclass) { + fprintf(stderr, "unknown answer\n"); + return (-1); + } + myzone = 0; + svdname = dname; + while (dname) + if (strcasecmp(dname, zname) == 0) { + myzone = 1; + break; + } else if ((dname = strchr(dname, '.')) != NULL) + dname++; + if (!myzone) { + dname = strchr(svdname, '.'); + if (dname != NULL) + dname++; + continue; + } + nscount = 0; + /* fallthrough */ + } else if (rcode == NOERROR && ancount == 1) { + /* + * found the zone name + * new servers will supply NS records for the zone + * in authority section and A records for those + * nameservers in the additional section + * older servers have to be explicitly queried for + * NS records for the zone + */ + /* answer section must contain the soa record */ + if ((n = dn_expand(answer, eom, cp, zname, + sizeof zname)) < 0) + return (n); + else + cp += n; + if (cp + 2 * INT16SZ > eom) + return (-1); + GETSHORT(type, cp); + GETSHORT(class, cp); + if (type == T_CNAME) { + dname = strchr(dname, '.'); + if (dname != NULL) + dname++; + continue; + } + if (strcasecmp(dname, zname) != 0 || + type != T_SOA || + class != rrecp->r_class) { + fprintf(stderr, "unknown answer\n"); + return (-1); + } + /* FALLTHROUGH */ + } else { + fprintf(stderr, + "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n", + ancount, nscount, arcount, hp->rcode); + return (-1); + } + if (cp + INT32SZ + INT16SZ > eom) + return (-1); + /* continue processing the soa record */ + GETLONG(ttl, cp); + GETSHORT(dlen, cp); + if (cp + dlen > eom) + return (-1); + newgroup = 1; + zptr = zgrp_start; + prevzptr = NULL; + while (zptr) { + if (strcasecmp(zname, zptr->z_origin) == 0 && + type == T_SOA && class == qclass) { + newgroup = 0; + break; + } + prevzptr = zptr; + zptr = zptr->z_next; + } + if (!newgroup) { + for (tmprrecp = zptr->z_rr; + tmprrecp->r_grpnext; + tmprrecp = tmprrecp->r_grpnext) + ; + tmprrecp->r_grpnext = rrecp; + rrecp->r_grpnext = NULL; + done = 1; + cp += dlen; + break; + } else { + if ((n = dn_expand(answer, eom, cp, primary, + sizeof primary)) < 0) + return (n); + cp += n; + /* + * We don't have to bounds check here because the + * next use of 'cp' is in dn_expand(). + */ + cp1 = (char *)soardata; + strcpy(cp1, primary); + cp1 += strlen(cp1) + 1; + if ((n = dn_expand(answer, eom, cp, mailaddr, + sizeof mailaddr)) < 0) + return (n); + cp += n; + strcpy(cp1, mailaddr); + cp1 += strlen(cp1) + 1; + if (cp + 5*INT32SZ > eom) + return (-1); + memcpy(cp1, cp, 5*INT32SZ); + cp += 5*INT32SZ; + cp1 += 5*INT32SZ; + rdatasize = (u_char *)cp1 - soardata; + zptr = calloc(1, sizeof(struct zonegrp)); + if (zptr == NULL) + return (-1); + if (zgrp_start == NULL) + zgrp_start = zptr; + else + prevzptr->z_next = zptr; + zptr->z_rr = rrecp; + rrecp->r_grpnext = NULL; + strcpy(zptr->z_origin, zname); + zptr->z_class = class; + memcpy(zptr->z_soardata, soardata, rdatasize); + /* fallthrough to process NS and A records */ + } + } else if (qtype == T_NS) { + if (rcode == NOERROR && ancount > 0) { + strcpy(zname, dname); + for (zptr = zgrp_start; zptr; zptr = zptr->z_next) { + if (strcasecmp(zname, zptr->z_origin) == 0) + break; + } + if (zptr == NULL) + /* should not happen */ + return (-1); + if (nscount > 0) { + /* + * answer and authority sections contain + * the same information, skip answer section + */ + for (j = 0; j < ancount; j++) { + n = dn_skipname(cp, eom); + if (n < 0) + return (-1); + n += 2*INT16SZ + INT32SZ; + if (cp + n + INT16SZ > eom) + return (-1); + cp += n; + GETSHORT(dlen, cp); + cp += dlen; + } + } else + nscount = ancount; + /* fallthrough to process NS and A records */ + } else { + fprintf(stderr, "cannot determine nameservers for %s:\ +ans=%d, auth=%d, add=%d, rcode=%d\n", + dname, ancount, nscount, arcount, hp->rcode); + return (-1); + } + } else if (qtype == T_A) { + if (rcode == NOERROR && ancount > 0) { + arcount = ancount; + ancount = nscount = 0; + /* fallthrough to process A records */ + } else { + fprintf(stderr, "cannot determine address for %s:\ +ans=%d, auth=%d, add=%d, rcode=%d\n", + dname, ancount, nscount, arcount, hp->rcode); + return (-1); + } + } + /* process NS records for the zone */ + j = 0; + for (i = 0; i < nscount; i++) { + if ((n = dn_expand(answer, eom, cp, name, + sizeof name)) < 0) + return (n); + cp += n; + if (cp + 3 * INT16SZ + INT32SZ > eom) + return (-1); + GETSHORT(type, cp); + GETSHORT(class, cp); + GETLONG(ttl, cp); + GETSHORT(dlen, cp); + if (cp + dlen > eom) + return (-1); + if (strcasecmp(name, zname) == 0 && + type == T_NS && class == qclass) { + if ((n = dn_expand(answer, eom, cp, + name, sizeof name)) < 0) + return (n); + target = zptr->z_ns[j++].nsname; + strcpy(target, name); + } + cp += dlen; + } + if (zptr->z_nscount == 0) + zptr->z_nscount = j; + /* get addresses for the nameservers */ + for (i = 0; i < arcount; i++) { + if ((n = dn_expand(answer, eom, cp, name, + sizeof name)) < 0) + return (n); + cp += n; + if (cp + 3 * INT16SZ + INT32SZ > eom) + return (-1); + GETSHORT(type, cp); + GETSHORT(class, cp); + GETLONG(ttl, cp); + GETSHORT(dlen, cp); + if (cp + dlen > eom) + return (-1); + if (type == T_A && dlen == INT32SZ && class == qclass) { + for (j = 0; j < zptr->z_nscount; j++) + if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) { + memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp, + INT32SZ); + break; + } + } + cp += dlen; + } + if (zptr->z_nscount == 0) { + dname = zname; + qtype = T_NS; + continue; + } + done = 1; + for (k = 0; k < zptr->z_nscount; k++) + if (zptr->z_ns[k].nsaddr1.s_addr == 0) { + done = 0; + dname = zptr->z_ns[k].nsname; + qtype = T_A; + } + + } /* while */ + } + + _res.options |= RES_DEBUG; + for (zptr = zgrp_start; zptr; zptr = zptr->z_next) { + + /* append zone section */ + rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, + zptr->z_class, ns_t_soa, 0); + if (rrecp == NULL) { + fprintf(stderr, "saverrec error\n"); + fflush(stderr); + return (-1); + } + rrecp->r_grpnext = zptr->z_rr; + zptr->z_rr = rrecp; + + n = res_mkupdate(zptr->z_rr, packet, sizeof packet); + if (n < 0) { + fprintf(stderr, "res_mkupdate error\n"); + fflush(stderr); + return (-1); + } else + fprintf(stdout, "res_mkupdate: packet size = %d\n", n); + + /* + * Override the list of NS records from res_init() with + * the authoritative nameservers for the zone being updated. + * Sort primary to be the first in the list of nameservers. + */ + for (i = 0; i < zptr->z_nscount; i++) { + if (strcasecmp(zptr->z_ns[i].nsname, + zptr->z_soardata) == 0) { + struct in_addr tmpaddr; + + if (i != 0) { + strcpy(zptr->z_ns[i].nsname, + zptr->z_ns[0].nsname); + strcpy(zptr->z_ns[0].nsname, + zptr->z_soardata); + tmpaddr = zptr->z_ns[i].nsaddr1; + zptr->z_ns[i].nsaddr1 = + zptr->z_ns[0].nsaddr1; + zptr->z_ns[0].nsaddr1 = tmpaddr; + } + break; + } + } + for (i = 0; i < MAXNS; i++) { + _res.nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1; + _res.nsaddr_list[i].sin_family = AF_INET; + _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); + } + _res.nscount = (zptr->z_nscount < MAXNS) ? + zptr->z_nscount : MAXNS; + n = res_send(packet, n, answer, sizeof(answer)); + if (n < 0) { + fprintf(stderr, "res_send: send error, n=%d\n", n); + break; + } else + numzones++; + } + + /* free malloc'ed memory */ + while(zgrp_start) { + zptr = zgrp_start; + zgrp_start = zgrp_start->z_next; + res_freeupdrec(zptr->z_rr); /* Zone section we allocated. */ + free((char *)zptr); + } + + return (numzones); +} diff --git a/cpukit/libnetworking/libc/resolver.3 b/cpukit/libnetworking/libc/resolver.3 new file mode 100644 index 0000000000..818acf24b8 --- /dev/null +++ b/cpukit/libnetworking/libc/resolver.3 @@ -0,0 +1,351 @@ +.\" Copyright (c) 1985, 1991, 1993 +.\" The Regents of the University of California. 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 the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. +.\" +.\" @(#)resolver.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt RESOLVER 3 +.Os BSD 4.3 +.Sh NAME +.Nm res_query , +.Nm res_search , +.Nm res_mkquery , +.Nm res_send , +.Nm res_init , +.Nm dn_comp , +.Nm dn_expand +.Nd resolver routines +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <netinet/in.h> +.Fd #include <arpa/nameser.h> +.Fd #include <resolv.h> +.Ft int +.Fo res_query +.Fa "const char *dname" +.Fa "int class" +.Fa "int type" +.Fa "u_char *answer" +.Fa "int anslen" +.Fc +.Ft int +.Fo res_search +.Fa "const char *dname" +.Fa "int class" +.Fa "int type" +.Fa "u_char *answer" +.Fa "int anslen" +.Fc +.Ft int +.Fo res_mkquery +.Fa "int op" +.Fa "const char *dname" +.Fa "int class" +.Fa "int type" +.Fa "const u_char *data" +.Fa "int datalen" +.Fa "const u_char *newrr_in" +.Fa "u_char *buf" +.Fa "int buflen" +.Fc +.Ft int +.Fo res_send +.Fa "const u_char *msg" +.Fa "int msglen" +.Fa "u_char *answer" +.Fa "int anslen" +.Fc +.Ft int +.Fn res_init +.Fo dn_comp +.Fa "const char *exp_dn" +.Fa "u_char *comp_dn" +.Fa "int length" +.Fa "u_char **dnptrs" +.Fa "u_char **lastdnptr" +.Fc +.Ft int +.Fo dn_expand +.Fa "const u_char *msg" +.Fa "const u_char *eomorig" +.Fa "const u_char *comp_dn" +.Fa "char *exp_dn" +.Fa "int length" +.Fc +.Sh DESCRIPTION +These routines are used for making, sending and interpreting +query and reply messages with Internet domain name servers. +.Pp +Global configuration and state information that is used by the +resolver routines is kept in the structure +.Em _res . +Most of the values have reasonable defaults and can be ignored. +Options +stored in +.Em _res.options +are defined in +.Pa resolv.h +and are as follows. +Options are stored as a simple bit mask containing the bitwise ``or'' +of the options enabled. +.Bl -tag -width RES_DEFNAMES +.It Dv RES_INIT +True if the initial name server address and default domain name are +initialized (i.e., +.Fn res_init +has been called). +.It Dv RES_DEBUG +Print debugging messages. +.It Dv RES_AAONLY +Accept authoritative answers only. +With this option, +.Fn res_send +should continue until it finds an authoritative answer or finds an error. +Currently this is not implemented. +.It Dv RES_USEVC +Use +.Tn TCP +connections for queries instead of +.Tn UDP +datagrams. +.It Dv RES_STAYOPEN +Used with +.Dv RES_USEVC +to keep the +.Tn TCP +connection open between +queries. +This is useful only in programs that regularly do many queries. +.Tn UDP +should be the normal mode used. +.It Dv RES_IGNTC +Unused currently (ignore truncation errors, i.e., don't retry with +.Tn TCP ) . +.It Dv RES_RECURSE +Set the recursion-desired bit in queries. +This is the default. +.Pf ( Fn res_send +does not do iterative queries and expects the name server +to handle recursion.) +.It Dv RES_DEFNAMES +If set, +.Fn res_search +will append the default domain name to single-component names +(those that do not contain a dot). +This option is enabled by default. +.It Dv RES_DNSRCH +If this option is set, +.Fn res_search +will search for host names in the current domain and in parent domains; see +.Xr hostname 7 . +This is used by the standard host lookup routine +.Xr gethostbyname 3 . +This option is enabled by default. +.It Dv RES_NOALIASES +This option turns off the user level aliasing feature controlled by the +.Dq Ev HOSTALIASES +environment variable. Network daemons should set this option. +.El +.Pp +The +.Fn res_init +routine +reads the configuration file (if any; see +.Xr resolver 5 ) +to get the default domain name, +search list and +the Internet address of the local name server(s). +If no server is configured, the host running +the resolver is tried. +The current domain name is defined by the hostname +if not specified in the configuration file; +it can be overridden by the environment variable +.Ev LOCALDOMAIN . +This environment variable may contain several blank-separated +tokens if you wish to override the +.Em "search list" +on a per-process basis. This is similar to the +.Em search +command in the configuration file. +Another environment variable ( +.Dq Ev RES_OPTIONS +can be set to +override certain internal resolver options which are otherwise +set by changing fields in the +.Em _res +structure or are inherited from the configuration file's +.Em options +command. The syntax of the +.Dq Ev RES_OPTIONS +environment variable is explained in +.Xr resolver 5 . +Initialization normally occurs on the first call +to one of the following routines. +.Pp +The +.Fn res_query +function provides an interface to the server query mechanism. +It constructs a query, sends it to the local server, +awaits a response, and makes preliminary checks on the reply. +The query requests information of the specified +.Fa type +and +.Fa class +for the specified fully-qualified domain name +.Fa dname . +The reply message is left in the +.Fa answer +buffer with length +.Fa anslen +supplied by the caller. +.Pp +The +.Fn res_search +routine makes a query and awaits a response like +.Fn res_query , +but in addition, it implements the default and search rules +controlled by the +.Dv RES_DEFNAMES +and +.Dv RES_DNSRCH +options. +It returns the first successful reply. +.Pp +The remaining routines are lower-level routines used by +.Fn res_query . +The +.Fn res_mkquery +function +constructs a standard query message and places it in +.Fa buf . +It returns the size of the query, or \-1 if the query is +larger than +.Fa buflen . +The query type +.Fa op +is usually +.Dv QUERY , +but can be any of the query types defined in +.Aq Pa arpa/nameser.h . +The domain name for the query is given by +.Fa dname . +.Fa Newrr +is currently unused but is intended for making update messages. +.Pp +The +.Fn res_send +routine +sends a pre-formatted query and returns an answer. +It will call +.Fn res_init +if +.Dv RES_INIT +is not set, send the query to the local name server, and +handle timeouts and retries. +The length of the reply message is returned, or +\-1 if there were errors. +.Pp +The +.Fn dn_comp +function +compresses the domain name +.Fa exp_dn +and stores it in +.Fa comp_dn . +The size of the compressed name is returned or \-1 if there were errors. +The size of the array pointed to by +.Fa comp_dn +is given by +.Fa length . +The compression uses +an array of pointers +.Fa dnptrs +to previously-compressed names in the current message. +The first pointer points to +to the beginning of the message and the list ends with +.Dv NULL . +The limit to the array is specified by +.Fa lastdnptr . +A side effect of +.Fn dn_comp +is to update the list of pointers for +labels inserted into the message +as the name is compressed. +If +.Em dnptr +is +.Dv NULL, names are not compressed. +If +.Fa lastdnptr +is +.Dv NULL , +the list of labels is not updated. +.Pp +The +.Fn dn_expand +entry +expands the compressed domain name +.Fa comp_dn +to a full domain name +The compressed name is contained in a query or reply message; +.Fa msg +is a pointer to the beginning of the message. +The uncompressed name is placed in the buffer indicated by +.Fa exp_dn +which is of size +.Fa length . +The size of compressed name is returned or \-1 if there was an error. +.Sh FILES +.Bl -tag -width Pa +/etc/resolv.conf +The configuration file +see +.Xr resolver 5 . +.El +.Sh SEE ALSO +.Xr gethostbyname 3 , +.Xr resolver 5 , +.Xr hostname 7 , +.Xr named 8 +.Pp +.%T RFC1032 , +.%T RFC1033 , +.%T RFC1034 , +.%T RFC1035 , +.%T RFC974 +.Rs +.%T "Name Server Operations Guide for BIND" +.Re +.Sh HISTORY +The +.Nm +function appeared in +.Bx 4.3 . diff --git a/cpukit/libnetworking/libc/send.c b/cpukit/libnetworking/libc/send.c new file mode 100644 index 0000000000..81151c4909 --- /dev/null +++ b/cpukit/libnetworking/libc/send.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)send.c 8.2 (Berkeley) 2/21/94"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stddef.h> + +ssize_t +send(s, msg, len, flags) + int s, flags; + size_t len; + const void *msg; +{ + return (sendto(s, msg, len, flags, NULL, 0)); +} diff --git a/cpukit/libnetworking/libc/strsep.c b/cpukit/libnetworking/libc/strsep.c new file mode 100644 index 0000000000..33115f0e41 --- /dev/null +++ b/cpukit/libnetworking/libc/strsep.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include "config.h" + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <string.h> +#include <stdio.h> + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + * + * PUBLIC: #ifndef HAVE_STRSEP + * PUBLIC: char *strsep __P((char **, const char *)); + * PUBLIC: #endif + */ +char * +strsep(stringp, delim) + register char **stringp; + register const char *delim; +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/cpukit/libnetworking/loop.h b/cpukit/libnetworking/loop.h new file mode 100644 index 0000000000..15a837a810 --- /dev/null +++ b/cpukit/libnetworking/loop.h @@ -0,0 +1 @@ +#define NLOOP 1 diff --git a/cpukit/libnetworking/net/bpf.h b/cpukit/libnetworking/net/bpf.h new file mode 100644 index 0000000000..7847d72470 --- /dev/null +++ b/cpukit/libnetworking/net/bpf.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1990, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 8.1 (Berkeley) 6/10/93 + * @(#)bpf.h 1.34 (LBL) 6/16/96 + * + * $Id$ + */ + +#ifndef _NET_BPF_H_ +#define _NET_BPF_H_ + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +typedef int32_t bpf_int32; +typedef u_int32_t bpf_u_int32; + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXINSNS 512 +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for BIOCSETF. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct returned by BIOCGSTATS. + */ +struct bpf_stat { + u_int bs_recv; /* number of packets received */ + u_int bs_drop; /* number of packets dropped */ +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +#define BIOCGBLEN _IOR('B',102, u_int) +#define BIOCSBLEN _IOWR('B',102, u_int) +#define BIOCSETF _IOW('B',103, struct bpf_program) +#define BIOCFLUSH _IO('B',104) +#define BIOCPROMISC _IO('B',105) +#define BIOCGDLT _IOR('B',106, u_int) +#define BIOCGETIF _IOR('B',107, struct ifreq) +#define BIOCSETIF _IOW('B',108, struct ifreq) +#define BIOCSRTIMEOUT _IOW('B',109, struct timeval) +#define BIOCGRTIMEOUT _IOR('B',110, struct timeval) +#define BIOCGSTATS _IOR('B',111, struct bpf_stat) +#define BIOCIMMEDIATE _IOW('B',112, u_int) +#define BIOCVERSION _IOR('B',113, struct bpf_version) +#define BIOCGRSIG _IOR('B',114, u_int) +#define BIOCSRSIG _IOW('B',115, u_int) + +/* + * Structure prepended to each packet. + */ +struct bpf_hdr { + struct timeval bh_tstamp; /* time stamp */ + bpf_u_int32 bh_caplen; /* length of captured portion */ + bpf_u_int32 bh_datalen; /* original length of packet */ + u_short bh_hdrlen; /* length of bpf header (this struct + plus alignment padding) */ +}; +/* + * Because the structure above is not a multiple of 4 bytes, some compilers + * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work. + * Only the kernel needs to know about it; applications use bh_hdrlen. + */ +#ifdef KERNEL +#define SIZEOF_BPF_HDR 18 +#endif + +/* + * Data-link level type codes. + */ +#define DLT_NULL 0 /* no link-layer encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* IEEE 802 Networks */ +#define DLT_ARCNET 7 /* ARCNET */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ +#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#ifdef KERNEL +int bpf_validate __P((struct bpf_insn *, int)); +void bpf_tap __P((struct ifnet *, u_char *, u_int)); +void bpf_mtap __P((struct ifnet *, struct mbuf *)); +void bpfattach __P((struct ifnet *, u_int, u_int)); +void bpfilterattach __P((int)); +u_int bpf_filter __P((struct bpf_insn *, u_char *, u_int, u_int)); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#endif diff --git a/cpukit/libnetworking/net/ethernet.h b/cpukit/libnetworking/net/ethernet.h new file mode 100644 index 0000000000..c6c07189ec --- /dev/null +++ b/cpukit/libnetworking/net/ethernet.h @@ -0,0 +1,63 @@ +/* + * Fundamental constants relating to ethernet. + * + * $Id$ + * + */ + +#ifndef _NET_ETHERNET_H_ +#define _NET_ETHERNET_H_ + +/* + * The number of bytes in an ethernet (MAC) address. + */ +#define ETHER_ADDR_LEN 6 + +/* + * The number of bytes in the type field. + */ +#define ETHER_TYPE_LEN 2 + +/* + * The number of bytes in the trailing CRC field. + */ +#define ETHER_CRC_LEN 4 + +/* + * The length of the combined header. + */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN) + +/* + * The minimum packet length. + */ +#define ETHER_MIN_LEN 64 + +/* + * The maximum packet length. + */ +#define ETHER_MAX_LEN 1518 + +/* + * A macro to validate a length with + */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +/* + * Structure of a 10Mb/s Ethernet header. + */ +struct ether_header { + u_char ether_dhost[ETHER_ADDR_LEN]; + u_char ether_shost[ETHER_ADDR_LEN]; + u_short ether_type; +}; + +/* + * Structure of a 48-bit Ethernet address. + */ +struct ether_addr { + u_char octet[ETHER_ADDR_LEN]; +}; + +#endif diff --git a/cpukit/libnetworking/net/if.c b/cpukit/libnetworking/net/if.c new file mode 100644 index 0000000000..af6f003de3 --- /dev/null +++ b/cpukit/libnetworking/net/if.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if.c 8.3 (Berkeley) 1/4/94 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/mbuf.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/kernel.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/radix.h> + +/* + * System initialization + */ + +static int ifconf __P((int, caddr_t)); + void ifinit __P((void *)); +static void if_qflush __P((struct ifqueue *)); +static void if_slowtimo __P((void *)); +static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *)); + +SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) + + +int ifqmaxlen = IFQ_MAXLEN; +struct ifnet *ifnet; + +/* + * Network interface utility routines. + * + * Routines with ifa_ifwith* names take sockaddr *'s as + * parameters. + * + * This routine assumes that it will be called at splimp() or higher. + */ +/* ARGSUSED*/ +void +ifinit(dummy) + void *dummy; +{ + register struct ifnet *ifp; + + for (ifp = ifnet; ifp; ifp = ifp->if_next) + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + if_slowtimo(0); +} + +int if_index = 0; +struct ifaddr **ifnet_addrs; + + +/* + * Attach an interface to the + * list of "active" interfaces. + */ +void +if_attach(ifp) + struct ifnet *ifp; +{ + unsigned socksize, ifasize; + int namelen, masklen; + char workbuf[64]; + register struct ifnet **p = &ifnet; + register struct sockaddr_dl *sdl; + register struct ifaddr *ifa; + static int if_indexlim = 8; + + + while (*p) + p = &((*p)->if_next); + *p = ifp; + ifp->if_index = ++if_index; + microtime(&ifp->if_lastchange); + if (ifnet_addrs == 0 || if_index >= if_indexlim) { + unsigned n = (if_indexlim <<= 1) * sizeof(ifa); + struct ifaddr **q = (struct ifaddr **) + malloc(n, M_IFADDR, M_WAITOK); + bzero((caddr_t)q, n); + if (ifnet_addrs) { + bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); + free((caddr_t)ifnet_addrs, M_IFADDR); + } + ifnet_addrs = q; + } + /* + * create a Link Level name for this device + */ + namelen = sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); +#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) + masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; + socksize = masklen + ifp->if_addrlen; +#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) + socksize = ROUNDUP(socksize); + if (socksize < sizeof(*sdl)) + socksize = sizeof(*sdl); + ifasize = sizeof(*ifa) + 2 * socksize; + ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); + if (ifa) { + bzero((caddr_t)ifa, ifasize); + sdl = (struct sockaddr_dl *)(ifa + 1); + sdl->sdl_len = socksize; + sdl->sdl_family = AF_LINK; + bcopy(workbuf, sdl->sdl_data, namelen); + sdl->sdl_nlen = namelen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + ifnet_addrs[if_index - 1] = ifa; + ifa->ifa_ifp = ifp; + ifa->ifa_next = ifp->if_addrlist; + ifa->ifa_rtrequest = link_rtrequest; + ifp->if_addrlist = ifa; + ifa->ifa_addr = (struct sockaddr *)sdl; + + sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); + ifa->ifa_netmask = (struct sockaddr *)sdl; + sdl->sdl_len = masklen; + while (namelen != 0) + sdl->sdl_data[--namelen] = 0xff; + } +} +/* + * Locate an interface based on a complete address. + */ +/*ARGSUSED*/ +struct ifaddr * +ifa_ifwithaddr(addr) + register struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + +#define equal(a1, a2) \ + (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) + for (ifp = ifnet; ifp; ifp = ifp->if_next) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != addr->sa_family) + continue; + if (equal(addr, ifa->ifa_addr)) + return (ifa); + if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && + equal(ifa->ifa_broadaddr, addr)) + return (ifa); + } + return ((struct ifaddr *)0); +} +/* + * Locate the point to point interface with a given destination address. + */ +/*ARGSUSED*/ +struct ifaddr * +ifa_ifwithdstaddr(addr) + register struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + + for (ifp = ifnet; ifp; ifp = ifp->if_next) + if (ifp->if_flags & IFF_POINTOPOINT) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != addr->sa_family) + continue; + if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) + return (ifa); + } + return ((struct ifaddr *)0); +} + +/* + * Find an interface on a specific network. If many, choice + * is most specific found. + */ +struct ifaddr * +ifa_ifwithnet(addr) + struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + struct ifaddr *ifa_maybe = (struct ifaddr *) 0; + u_int af = addr->sa_family; + char *addr_data = addr->sa_data, *cplim; + + if (af == AF_LINK) { + register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; + if (sdl->sdl_index && sdl->sdl_index <= if_index) + return (ifnet_addrs[sdl->sdl_index - 1]); + } + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + register char *cp, *cp2, *cp3; + + if (ifa->ifa_addr->sa_family != af) + next: continue; + if (ifp->if_flags & IFF_POINTOPOINT) { + if (ifa->ifa_dstaddr != 0 + && equal(addr, ifa->ifa_dstaddr)) + return (ifa); + } else { + /* + * if we have a special address handler, + * then use it instead of the generic one. + */ + if (ifa->ifa_claim_addr) { + if ((*ifa->ifa_claim_addr)(ifa, addr)) { + return (ifa); + } else { + continue; + } + } + + /* + * Scan all the bits in the ifa's address. + * If a bit dissagrees with what we are + * looking for, mask it with the netmask + * to see if it really matters. + * (A byte at a time) + */ + if (ifa->ifa_netmask == 0) + continue; + cp = addr_data; + cp2 = ifa->ifa_addr->sa_data; + cp3 = ifa->ifa_netmask->sa_data; + cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; + while (cp3 < cplim) + if ((*cp++ ^ *cp2++) & *cp3++) + goto next; + if (ifa_maybe == 0 || + rn_refines((caddr_t)ifa->ifa_netmask, + (caddr_t)ifa_maybe->ifa_netmask)) + ifa_maybe = ifa; + } + } + } + return (ifa_maybe); +} + +/* + * Find an interface address specific to an interface best matching + * a given address. + */ +struct ifaddr * +ifaof_ifpforaddr(addr, ifp) + struct sockaddr *addr; + register struct ifnet *ifp; +{ + register struct ifaddr *ifa; + register char *cp, *cp2, *cp3; + register char *cplim; + struct ifaddr *ifa_maybe = 0; + u_int af = addr->sa_family; + + if (af >= AF_MAX) + return (0); + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != af) + continue; + if (ifa_maybe == 0) + ifa_maybe = ifa; + if (ifa->ifa_netmask == 0) { + if (equal(addr, ifa->ifa_addr) || + (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) + return (ifa); + continue; + } + if (ifp->if_flags & IFF_POINTOPOINT) { + if (equal(addr, ifa->ifa_dstaddr)) + return (ifa); + } else { + cp = addr->sa_data; + cp2 = ifa->ifa_addr->sa_data; + cp3 = ifa->ifa_netmask->sa_data; + cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; + for (; cp3 < cplim; cp3++) + if ((*cp++ ^ *cp2++) & *cp3) + break; + if (cp3 == cplim) + return (ifa); + } + } + return (ifa_maybe); +} + +#include <net/route.h> + +/* + * Default action when installing a route with a Link Level gateway. + * Lookup an appropriate real ifa to point to. + * This should be moved to /sys/net/link.c eventually. + */ +static void +link_rtrequest(cmd, rt, sa) + int cmd; + register struct rtentry *rt; + struct sockaddr *sa; +{ + register struct ifaddr *ifa; + struct sockaddr *dst; + struct ifnet *ifp; + + if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || + ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) + return; + ifa = ifaof_ifpforaddr(dst, ifp); + if (ifa) { + IFAFREE(rt->rt_ifa); + rt->rt_ifa = ifa; + ifa->ifa_refcnt++; + if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) + ifa->ifa_rtrequest(cmd, rt, sa); + } +} + +/* + * Mark an interface down and notify protocols of + * the transition. + * NOTE: must be called at splnet or eqivalent. + */ +void +if_down(ifp) + register struct ifnet *ifp; +{ + register struct ifaddr *ifa; + + ifp->if_flags &= ~IFF_UP; + microtime(&ifp->if_lastchange); + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + pfctlinput(PRC_IFDOWN, ifa->ifa_addr); + if_qflush(&ifp->if_snd); + rt_ifmsg(ifp); +} + +/* + * Mark an interface up and notify protocols of + * the transition. + * NOTE: must be called at splnet or eqivalent. + */ +void +if_up(ifp) + register struct ifnet *ifp; +{ + + ifp->if_flags |= IFF_UP; + microtime(&ifp->if_lastchange); +#ifdef notyet + register struct ifaddr *ifa; + /* this has no effect on IP, and will kill all iso connections XXX */ + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + pfctlinput(PRC_IFUP, ifa->ifa_addr); +#endif + rt_ifmsg(ifp); +} + +/* + * Flush an interface queue. + */ +static void +if_qflush(ifq) + register struct ifqueue *ifq; +{ + register struct mbuf *m, *n; + + n = ifq->ifq_head; + while ((m = n) != 0) { + n = m->m_act; + m_freem(m); + } + ifq->ifq_head = 0; + ifq->ifq_tail = 0; + ifq->ifq_len = 0; +} + +/* + * Handle interface watchdog timer routines. Called + * from softclock, we decrement timers (if set) and + * call the appropriate interface routine on expiration. + */ +static void +if_slowtimo(arg) + void *arg; +{ + register struct ifnet *ifp; + int s = splimp(); + + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if (ifp->if_timer == 0 || --ifp->if_timer) + continue; + if (ifp->if_watchdog) + (*ifp->if_watchdog)(ifp); + } + splx(s); + timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); +} + +/* + * Map interface name to + * interface structure pointer. + */ +struct ifnet * +ifunit(name) + register char *name; +{ + register char *cp; + register struct ifnet *ifp; + int unit; + unsigned len; + char *ep, c; + + for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) + if (*cp >= '0' && *cp <= '9') + break; + if (*cp == '\0' || cp == name + IFNAMSIZ) + return ((struct ifnet *)0); + /* + * Save first char of unit, and pointer to it, + * so we can put a null there to avoid matching + * initial substrings of interface names. + */ + len = cp - name + 1; + c = *cp; + ep = cp; + for (unit = 0; *cp >= '0' && *cp <= '9'; ) + unit = unit * 10 + *cp++ - '0'; + if (*cp != '\0') + return 0; /* no trailing garbage allowed */ + *ep = 0; + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if (bcmp(ifp->if_name, name, len)) + continue; + if (unit == ifp->if_unit) + break; + } + *ep = c; + return (ifp); +} + +/* + * Interface ioctls. + */ +int +ifioctl(so, cmd, data, p) + struct socket *so; + int cmd; + caddr_t data; + struct proc *p; +{ + register struct ifnet *ifp; + register struct ifreq *ifr; + int error; + + switch (cmd) { + + case SIOCGIFCONF: + case OSIOCGIFCONF: + return (ifconf(cmd, data)); + } + ifr = (struct ifreq *)data; + ifp = ifunit(ifr->ifr_name); + if (ifp == 0) + return (ENXIO); + switch (cmd) { + + case SIOCGIFFLAGS: + ifr->ifr_flags = ifp->if_flags; + break; + + case SIOCGIFMETRIC: + ifr->ifr_metric = ifp->if_metric; + break; + + case SIOCGIFMTU: + ifr->ifr_mtu = ifp->if_mtu; + break; + + case SIOCGIFPHYS: + ifr->ifr_phys = ifp->if_physical; + break; + + case SIOCSIFFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { + int s = splimp(); + if_down(ifp); + splx(s); + } + if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { + int s = splimp(); + if_up(ifp); + splx(s); + } + ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | + (ifr->ifr_flags &~ IFF_CANTCHANGE); + if (ifp->if_ioctl) + (void) (*ifp->if_ioctl)(ifp, cmd, data); + microtime(&ifp->if_lastchange); + break; + + case SIOCSIFMETRIC: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + ifp->if_metric = ifr->ifr_metric; + microtime(&ifp->if_lastchange); + break; + + case SIOCSIFPHYS: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return error; + if (!ifp->if_ioctl) + return EOPNOTSUPP; + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return(error); + + case SIOCSIFMTU: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_ioctl == NULL) + return (EOPNOTSUPP); + /* + * 72 was chosen below because it is the size of a TCP/IP + * header (40) + the minimum mss (32). + */ + if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535) + return (EINVAL); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return(error); + + case SIOCADDMULTI: + case SIOCDELMULTI: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_ioctl == NULL) + return (EOPNOTSUPP); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0 ) + microtime(&ifp->if_lastchange); + return(error); + + case SIOCSIFMEDIA: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_ioctl == 0) + return (EOPNOTSUPP); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return error; + + case SIOCGIFMEDIA: + if (ifp->if_ioctl == 0) + return (EOPNOTSUPP); + return ((*ifp->if_ioctl)(ifp, cmd, data)); + + default: + if (so->so_proto == 0) + return (EOPNOTSUPP); +#ifndef COMPAT_43 + return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, + data, + ifp)); +#else + { + int ocmd = cmd; + + switch (cmd) { + + case SIOCSIFDSTADDR: + case SIOCSIFADDR: + case SIOCSIFBRDADDR: + case SIOCSIFNETMASK: +#if BYTE_ORDER != BIG_ENDIAN + if (ifr->ifr_addr.sa_family == 0 && + ifr->ifr_addr.sa_len < 16) { + ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; + ifr->ifr_addr.sa_len = 16; + } +#else + if (ifr->ifr_addr.sa_len == 0) + ifr->ifr_addr.sa_len = 16; +#endif + break; + + case OSIOCGIFADDR: + cmd = SIOCGIFADDR; + break; + + case OSIOCGIFDSTADDR: + cmd = SIOCGIFDSTADDR; + break; + + case OSIOCGIFBRDADDR: + cmd = SIOCGIFBRDADDR; + break; + + case OSIOCGIFNETMASK: + cmd = SIOCGIFNETMASK; + } + error = ((*so->so_proto->pr_usrreqs->pru_control)(so, + cmd, + data, + ifp)); + switch (ocmd) { + + case OSIOCGIFADDR: + case OSIOCGIFDSTADDR: + case OSIOCGIFBRDADDR: + case OSIOCGIFNETMASK: + *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; + } + return (error); + + } +#endif + } + return (0); +} + +/* + * Set/clear promiscuous mode on interface ifp based on the truth value + * of pswitch. The calls are reference counted so that only the first + * "on" request actually has an effect, as does the final "off" request. + * Results are undefined if the "off" and "on" requests are not matched. + */ +int +ifpromisc(ifp, pswitch) + struct ifnet *ifp; + int pswitch; +{ + struct ifreq ifr; + + if (pswitch) { + /* + * If the device is not configured up, we cannot put it in + * promiscuous mode. + */ + if ((ifp->if_flags & IFF_UP) == 0) + return (ENETDOWN); + if (ifp->if_pcount++ != 0) + return (0); + ifp->if_flags |= IFF_PROMISC; + log(LOG_INFO, "%s%d: promiscuous mode enabled\n", + ifp->if_name, ifp->if_unit); + } else { + if (--ifp->if_pcount > 0) + return (0); + ifp->if_flags &= ~IFF_PROMISC; + } + ifr.ifr_flags = ifp->if_flags; + return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); +} + +/* + * Return interface configuration + * of system. List may be used + * in later ioctl's (above) to get + * other information. + */ +/*ARGSUSED*/ +static int +ifconf(cmd, data) + int cmd; + caddr_t data; +{ + register struct ifconf *ifc = (struct ifconf *)data; + register struct ifnet *ifp = ifnet; + register struct ifaddr *ifa; + struct ifreq ifr, *ifrp; + int space = ifc->ifc_len, error = 0; + + ifrp = ifc->ifc_req; + for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { + char workbuf[64]; + int ifnlen; + + ifnlen = sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); + if(ifnlen + 1 > sizeof ifr.ifr_name) { + error = ENAMETOOLONG; + } else { + strcpy(ifr.ifr_name, workbuf); + } + + if ((ifa = ifp->if_addrlist) == 0) { + bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); + error = copyout((caddr_t)&ifr, (caddr_t)ifrp, + sizeof (ifr)); + if (error) + break; + space -= sizeof (ifr), ifrp++; + } else + for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { + register struct sockaddr *sa = ifa->ifa_addr; +#ifdef COMPAT_43 + if (cmd == OSIOCGIFCONF) { + struct osockaddr *osa = + (struct osockaddr *)&ifr.ifr_addr; + ifr.ifr_addr = *sa; + osa->sa_family = sa->sa_family; + error = copyout((caddr_t)&ifr, (caddr_t)ifrp, + sizeof (ifr)); + ifrp++; + } else +#endif + if (sa->sa_len <= sizeof(*sa)) { + ifr.ifr_addr = *sa; + error = copyout((caddr_t)&ifr, (caddr_t)ifrp, + sizeof (ifr)); + ifrp++; + } else { + space -= sa->sa_len - sizeof(*sa); + if (space < sizeof (ifr)) + break; + error = copyout((caddr_t)&ifr, (caddr_t)ifrp, + sizeof (ifr.ifr_name)); + if (error == 0) + error = copyout((caddr_t)sa, + (caddr_t)&ifrp->ifr_addr, sa->sa_len); + ifrp = (struct ifreq *) + (sa->sa_len + (caddr_t)&ifrp->ifr_addr); + } + if (error) + break; + space -= sizeof (ifr); + } + } + ifc->ifc_len -= space; + return (error); +} + +SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); +SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); diff --git a/cpukit/libnetworking/net/if.h b/cpukit/libnetworking/net/if.h new file mode 100644 index 0000000000..acddd4f095 --- /dev/null +++ b/cpukit/libnetworking/net/if.h @@ -0,0 +1,467 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_H_ +#define _NET_IF_H_ + +/* + * Structures defining a network interface, providing a packet + * transport mechanism (ala level 0 of the PUP protocols). + * + * Each interface accepts output datagrams of a specified maximum + * length, and provides higher level routines with input datagrams + * received from its medium. + * + * Output occurs when the routine if_output is called, with three parameters: + * (*ifp->if_output)(ifp, m, dst, rt) + * Here m is the mbuf chain to be sent and dst is the destination address. + * The output routine encapsulates the supplied datagram if necessary, + * and then transmits it on its medium. + * + * On input, each interface unwraps the data received by it, and either + * places it on the input queue of a internetwork datagram routine + * and posts the associated software interrupt, or passes the datagram to a raw + * packet input routine. + * + * Routines exist for locating interfaces by their addresses + * or for locating a interface on a certain network, as well as more general + * routing and gateway routines maintaining information used to locate + * interfaces. These routines live in the files if.c and route.c + */ + +#ifndef _TIME_ /* XXX fast fix for SNMP, going away soon */ +#include <sys/time.h> +#endif + +#ifdef __STDC__ +/* + * Forward structure declarations for function prototypes [sic]. + */ +struct mbuf; +struct proc; +struct rtentry; +struct socket; +struct ether_header; +#endif + +/* + * Structure describing information about an interface + * which may be of interest to management entities. + */ +struct if_data { + /* generic interface information */ + u_char ifi_type; /* ethernet, tokenring, etc */ + u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ + u_char ifi_addrlen; /* media address length */ + u_char ifi_hdrlen; /* media header length */ + u_char ifi_recvquota; /* polling quota for receive intrs */ + u_char ifi_xmitquota; /* polling quota for xmit intrs */ + u_long ifi_mtu; /* maximum transmission unit */ + u_long ifi_metric; /* routing metric (external only) */ + u_long ifi_baudrate; /* linespeed */ + /* volatile statistics */ + u_long ifi_ipackets; /* packets received on interface */ + u_long ifi_ierrors; /* input errors on interface */ + u_long ifi_opackets; /* packets sent on interface */ + u_long ifi_oerrors; /* output errors on interface */ + u_long ifi_collisions; /* collisions on csma interfaces */ + u_long ifi_ibytes; /* total number of octets received */ + u_long ifi_obytes; /* total number of octets sent */ + u_long ifi_imcasts; /* packets received via multicast */ + u_long ifi_omcasts; /* packets sent via multicast */ + u_long ifi_iqdrops; /* dropped on input, this interface */ + u_long ifi_noproto; /* destined for unsupported protocol */ + u_long ifi_recvtiming; /* usec spent receiving when timing */ + u_long ifi_xmittiming; /* usec spent xmitting when timing */ + struct timeval ifi_lastchange; /* time of last administrative change */ +}; + +/* + * Structure defining a queue for a network interface. + */ +struct ifqueue { + struct mbuf *ifq_head; + struct mbuf *ifq_tail; + int ifq_len; + int ifq_maxlen; + int ifq_drops; +}; + +/* + * Structure defining a network interface. + * + * (Would like to call this struct ``if'', but C isn't PL/1.) + */ +struct ifnet { + void *if_softc; /* pointer to driver state */ + char *if_name; /* name, e.g. ``en'' or ``lo'' */ + struct ifnet *if_next; /* all struct ifnets are chained */ + struct ifaddr *if_addrlist; /* linked list of addresses per if */ + int if_pcount; /* number of promiscuous listeners */ + struct bpf_if *if_bpf; /* packet filter structure */ + u_short if_index; /* numeric abbreviation for this if */ + short if_unit; /* sub-unit for lower level driver */ + short if_timer; /* time 'til if_watchdog called */ + short if_flags; /* up/down, broadcast, etc. */ + int if_ipending; /* interrupts pending */ + void *if_linkmib; /* link-type-specific MIB data */ + size_t if_linkmiblen; /* length of above data */ + struct if_data if_data; +/* procedure handles */ + int (*if_output) /* output routine (enqueue) */ + __P((struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *)); + void (*if_start) /* initiate output routine */ + __P((struct ifnet *)); + int (*if_done) /* output complete routine */ + __P((struct ifnet *)); /* (XXX not used; fake prototype) */ + int (*if_ioctl) /* ioctl routine */ + __P((struct ifnet *, int, caddr_t)); + void (*if_watchdog) /* timer routine */ + __P((struct ifnet *)); + int (*if_poll_recv) /* polled receive routine */ + __P((struct ifnet *, int *)); + int (*if_poll_xmit) /* polled transmit routine */ + __P((struct ifnet *, int *)); + void (*if_poll_intren) /* polled interrupt reenable routine */ + __P((struct ifnet *)); + void (*if_poll_slowinput) /* input routine for slow devices */ + __P((struct ifnet *, struct mbuf *)); + void (*if_init) /* Init routine */ + __P((void *)); + struct ifqueue if_snd; /* output queue */ + struct ifqueue *if_poll_slowq; /* input queue for slow devices */ +}; +typedef void if_init_f_t __P((void *)); + +#define if_mtu if_data.ifi_mtu +#define if_type if_data.ifi_type +#define if_physical if_data.ifi_physical +#define if_addrlen if_data.ifi_addrlen +#define if_hdrlen if_data.ifi_hdrlen +#define if_metric if_data.ifi_metric +#define if_baudrate if_data.ifi_baudrate +#define if_ipackets if_data.ifi_ipackets +#define if_ierrors if_data.ifi_ierrors +#define if_opackets if_data.ifi_opackets +#define if_oerrors if_data.ifi_oerrors +#define if_collisions if_data.ifi_collisions +#define if_ibytes if_data.ifi_ibytes +#define if_obytes if_data.ifi_obytes +#define if_imcasts if_data.ifi_imcasts +#define if_omcasts if_data.ifi_omcasts +#define if_iqdrops if_data.ifi_iqdrops +#define if_noproto if_data.ifi_noproto +#define if_lastchange if_data.ifi_lastchange +#define if_recvquota if_data.ifi_recvquota +#define if_xmitquota if_data.ifi_xmitquota +#define if_rawoutput(if, m, sa) if_output(if, m, sa, (struct rtentry *)0) + +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_DEBUG 0x4 /* turn on debugging */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */ +/*#define IFF_NOTRAILERS 0x20 * obsolete: avoid use of trailers */ +#define IFF_RUNNING 0x40 /* resources allocated */ +#define IFF_NOARP 0x80 /* no address resolution protocol */ +#define IFF_PROMISC 0x100 /* receive all packets */ +#define IFF_ALLMULTI 0x200 /* receive all multicast packets */ +#define IFF_OACTIVE 0x400 /* transmission in progress */ +#define IFF_SIMPLEX 0x800 /* can't hear own transmissions */ +#define IFF_LINK0 0x1000 /* per link layer defined bit */ +#define IFF_LINK1 0x2000 /* per link layer defined bit */ +#define IFF_LINK2 0x4000 /* per link layer defined bit */ +#define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ +#define IFF_MULTICAST 0x8000 /* supports multicast */ + +/* flags set internally only: */ +#define IFF_CANTCHANGE \ + (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ + IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI) + + +/* + * These really don't belong here, but there's no other obviously appropriate + * location. + */ +#define IFP_AUI 0 +#define IFP_10BASE2 1 +#define IFP_10BASET 2 +/* etc. */ + +/* + * Bit values in if_ipending + */ +#define IFI_RECV 1 /* I want to receive */ +#define IFI_XMIT 2 /* I want to transmit */ + +/* + * Output queues (ifp->if_snd) and slow device input queues (*ifp->if_slowq) + * are queues of messages stored on ifqueue structures + * (defined above). Entries are added to and deleted from these structures + * by these macros, which should be called with ipl raised to splimp(). + */ +#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen) +#define IF_DROP(ifq) ((ifq)->ifq_drops++) +#define IF_ENQUEUE(ifq, m) { \ + (m)->m_nextpkt = 0; \ + if ((ifq)->ifq_tail == 0) \ + (ifq)->ifq_head = m; \ + else \ + (ifq)->ifq_tail->m_nextpkt = m; \ + (ifq)->ifq_tail = m; \ + (ifq)->ifq_len++; \ +} +#define IF_PREPEND(ifq, m) { \ + (m)->m_nextpkt = (ifq)->ifq_head; \ + if ((ifq)->ifq_tail == 0) \ + (ifq)->ifq_tail = (m); \ + (ifq)->ifq_head = (m); \ + (ifq)->ifq_len++; \ +} +#define IF_DEQUEUE(ifq, m) { \ + (m) = (ifq)->ifq_head; \ + if (m) { \ + if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \ + (ifq)->ifq_tail = 0; \ + (m)->m_nextpkt = 0; \ + (ifq)->ifq_len--; \ + } \ +} + +#ifdef KERNEL +#define IF_ENQ_DROP(ifq, m) if_enq_drop(ifq, m) + +#if defined(__GNUC__) && defined(MT_HEADER) +static inline int +if_queue_drop(struct ifqueue *ifq, struct mbuf *m) +{ + IF_DROP(ifq); + return 0; +} + +static inline int +if_enq_drop(struct ifqueue *ifq, struct mbuf *m) +{ + if (IF_QFULL(ifq) && + !if_queue_drop(ifq, m)) + return 0; + IF_ENQUEUE(ifq, m); + return 1; +} +#else + +#ifdef MT_HEADER +int if_enq_drop __P((struct ifqueue *, struct mbuf *)); +#endif + +#endif +#endif /* KERNEL */ + +#define IFQ_MAXLEN 50 +#define IFNET_SLOWHZ 1 /* granularity is 1 second */ + +/* + * The ifaddr structure contains information about one address + * of an interface. They are maintained by the different address families, + * are allocated and attached when an address is set, and are linked + * together so all addresses for an interface can be located. + */ +struct ifaddr { + struct sockaddr *ifa_addr; /* address of interface */ + struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */ +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ + struct sockaddr *ifa_netmask; /* used to determine subnet */ + struct ifnet *ifa_ifp; /* back-pointer to interface */ + struct ifaddr *ifa_next; /* next address for interface */ + void (*ifa_rtrequest) /* check or clean routes (+ or -)'d */ + __P((int, struct rtentry *, struct sockaddr *)); + u_short ifa_flags; /* mostly rt_flags for cloning */ + short ifa_refcnt; /* references to this structure */ + int ifa_metric; /* cost of going out this interface */ +#ifdef notdef + struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */ +#endif + int (*ifa_claim_addr) /* check if an addr goes to this if */ + __P((struct ifaddr *, struct sockaddr *)); + +}; +#define IFA_ROUTE RTF_UP /* route installed */ + +/* + * Message format for use in obtaining information about interfaces + * from getkerninfo and the routing socket + */ +struct if_msghdr { + u_short ifm_msglen; /* to skip over non-understood messages */ + u_char ifm_version; /* future binary compatability */ + u_char ifm_type; /* message type */ + int ifm_addrs; /* like rtm_addrs */ + int ifm_flags; /* value of if_flags */ + u_short ifm_index; /* index for associated ifp */ + struct if_data ifm_data;/* statistics and other data about if */ +}; + +/* + * Message format for use in obtaining information about interface addresses + * from getkerninfo and the routing socket + */ +struct ifa_msghdr { + u_short ifam_msglen; /* to skip over non-understood messages */ + u_char ifam_version; /* future binary compatability */ + u_char ifam_type; /* message type */ + int ifam_addrs; /* like rtm_addrs */ + int ifam_flags; /* value of ifa_flags */ + u_short ifam_index; /* index for associated ifp */ + int ifam_metric; /* value of ifa_metric */ +}; + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ +struct ifreq { +#define IFNAMSIZ 16 + char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + int ifru_phys; + int ifru_media; + caddr_t ifru_data; + } ifr_ifru; +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_phys ifr_ifru.ifru_phys /* physical wire */ +#define ifr_media ifr_ifru.ifru_media /* physical media */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ +}; + +struct ifaliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr ifra_addr; + struct sockaddr ifra_broadaddr; + struct sockaddr ifra_mask; +}; + +struct ifmediareq { + char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + int ifm_current; /* current media options */ + int ifm_mask; /* don't care mask */ + int ifm_status; /* media status */ + int ifm_active; /* active options */ + int ifm_count; /* # entries in ifm_ulist array */ + int *ifm_ulist; /* media words */ +}; +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ +struct ifconf { + int ifc_len; /* size of associated buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ +}; + +#include <net/if_arp.h> + +#ifdef KERNEL +#define IFAFREE(ifa) \ + if ((ifa)->ifa_refcnt <= 0) \ + ifafree(ifa); \ + else \ + (ifa)->ifa_refcnt--; + +extern struct ifnet *ifnet; +extern int ifqmaxlen; +extern struct ifnet loif[]; +extern int if_index; +extern struct ifaddr **ifnet_addrs; + +void ether_ifattach __P((struct ifnet *)); +void ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *)); +int ether_output __P((struct ifnet *, + struct mbuf *, struct sockaddr *, struct rtentry *)); +int ether_ioctl __P((struct ifnet *, int , caddr_t )); + +void if_attach __P((struct ifnet *)); +void if_down __P((struct ifnet *)); +void if_up __P((struct ifnet *)); +#ifdef vax +void ifubareset __P((int)); +#endif +/*void ifinit __P((void));*/ /* declared in systm.h for main() */ +int ifioctl __P((struct socket *, int, caddr_t, struct proc *)); +int ifpromisc __P((struct ifnet *, int)); +struct ifnet *ifunit __P((char *)); + +int if_poll_recv_slow __P((struct ifnet *ifp, int *quotap)); +void if_poll_xmit_slow __P((struct ifnet *ifp, int *quotap)); +void if_poll_throttle __P((void)); +void if_poll_unthrottle __P((void *)); +void if_poll_init __P((void)); +void if_poll __P((void)); + +struct ifaddr *ifa_ifwithaddr __P((struct sockaddr *)); +struct ifaddr *ifa_ifwithdstaddr __P((struct sockaddr *)); +struct ifaddr *ifa_ifwithnet __P((struct sockaddr *)); +struct ifaddr *ifa_ifwithroute __P((int, struct sockaddr *, + struct sockaddr *)); +struct ifaddr *ifaof_ifpforaddr __P((struct sockaddr *, struct ifnet *)); +void ifafree __P((struct ifaddr *)); + +int looutput __P((struct ifnet *, + struct mbuf *, struct sockaddr *, struct rtentry *)); +#endif /* KERNEL */ + +#endif /* !_NET_IF_H_ */ diff --git a/cpukit/libnetworking/net/if_arp.h b/cpukit/libnetworking/net/if_arp.h new file mode 100644 index 0000000000..dd726bf856 --- /dev/null +++ b/cpukit/libnetworking/net/if_arp.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_arp.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_ARP_H_ +#define _NET_IF_ARP_H_ + +/* + * Address Resolution Protocol. + * + * See RFC 826 for protocol description. ARP packets are variable + * in size; the arphdr structure defines the fixed-length portion. + * Protocol type values are the same as those for 10 Mb/s Ethernet. + * It is followed by the variable-sized fields ar_sha, arp_spa, + * arp_tha and arp_tpa in that order, according to the lengths + * specified. Field names used correspond to RFC 826. + */ +struct arphdr { + u_short ar_hrd; /* format of hardware address */ +#define ARPHRD_ETHER 1 /* ethernet hardware format */ +#define ARPHRD_FRELAY 15 /* frame relay hardware format */ + u_short ar_pro; /* format of protocol address */ + u_char ar_hln; /* length of hardware address */ + u_char ar_pln; /* length of protocol address */ + u_short ar_op; /* one of: */ +#define ARPOP_REQUEST 1 /* request to resolve address */ +#define ARPOP_REPLY 2 /* response to previous request */ +#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ +#define ARPOP_REVREPLY 4 /* response giving protocol address */ +#define ARPOP_INVREQUEST 8 /* request to identify peer */ +#define ARPOP_INVREPLY 9 /* response identifying peer */ +/* + * The remaining fields are variable in size, + * according to the sizes above. + */ +#ifdef COMMENT_ONLY + u_char ar_sha[]; /* sender hardware address */ + u_char ar_spa[]; /* sender protocol address */ + u_char ar_tha[]; /* target hardware address */ + u_char ar_tpa[]; /* target protocol address */ +#endif +}; + +/* + * ARP ioctl request + */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ +}; +/* arp_flags and at_flags field values */ +#define ATF_INUSE 0x01 /* entry in use */ +#define ATF_COM 0x02 /* completed entry (enaddr valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry (respond for other host) */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ + +#endif /* !_NET_IF_ARP_H_ */ diff --git a/cpukit/libnetworking/net/if_dl.h b/cpukit/libnetworking/net/if_dl.h new file mode 100644 index 0000000000..053ae3e92f --- /dev/null +++ b/cpukit/libnetworking/net/if_dl.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_dl.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_DL_H_ +#define _NET_IF_DL_H_ + +/* + * A Link-Level Sockaddr may specify the interface in one of two + * ways: either by means of a system-provided index number (computed + * anew and possibly differently on every reboot), or by a human-readable + * string such as "il0" (for managerial convenience). + * + * Census taking actions, such as something akin to SIOCGCONF would return + * both the index and the human name. + * + * High volume transactions (such as giving a link-level ``from'' address + * in a recvfrom or recvmsg call) may be likely only to provide the indexed + * form, (which requires fewer copy operations and less space). + * + * The form and interpretation of the link-level address is purely a matter + * of convention between the device driver and its consumers; however, it is + * expected that all drivers for an interface of a given if_type will agree. + */ + +/* + * Structure of a Link-Level sockaddr: + */ +struct sockaddr_dl { + u_char sdl_len; /* Total length of sockaddr */ + u_char sdl_family; /* AF_DLI */ + u_short sdl_index; /* if != 0, system given index for interface */ + u_char sdl_type; /* interface type */ + u_char sdl_nlen; /* interface name length, no trailing 0 reqd. */ + u_char sdl_alen; /* link level address length */ + u_char sdl_slen; /* link layer selector length */ + char sdl_data[12]; /* minimum work area, can be larger; + contains both if name and ll address */ +}; + +#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) + +#ifndef KERNEL + +#include <sys/cdefs.h> + +__BEGIN_DECLS +void link_addr __P((const char *, struct sockaddr_dl *)); +char *link_ntoa __P((const struct sockaddr_dl *)); +__END_DECLS + +#endif /* !KERNEL */ + +#endif diff --git a/cpukit/libnetworking/net/if_ethersubr.c b/cpukit/libnetworking/net/if_ethersubr.c new file mode 100644 index 0000000000..9ff1a5932a --- /dev/null +++ b/cpukit/libnetworking/net/if_ethersubr.c @@ -0,0 +1,981 @@ +/* + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/if_llc.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/ethernet.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_var.h> +#endif +#include <netinet/if_ether.h> + +#ifdef IPX +#include <netipx/ipx.h> +#include <netipx/ipx_if.h> +#endif + +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +ushort ns_nettype; +int ether_outputdebug = 0; +int ether_inputdebug = 0; +#endif + +#ifdef ISO +#include <netiso/argo_debug.h> +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_snpac.h> +#endif + +/*#ifdef LLC +#include <netccitt/dll.h> +#include <netccitt/llc_var.h> +#endif*/ + +#if defined(LLC) && defined(CCITT) +extern struct ifqueue pkintrq; +#endif + +#ifdef NETATALK +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#include <netatalk/at_extern.h> + +#define llc_snap_org_code llc_un.type_snap.org_code +#define llc_snap_ether_type llc_un.type_snap.ether_type + +extern u_char at_org_code[ 3 ]; +extern u_char aarp_org_code[ 3 ]; +#endif NETATALK + +u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#define senderr(e) { error = (e); goto bad;} + +/* + * Ethernet output routine. + * Encapsulate a packet of type family for the local net. + * Use trailer local net encapsulation if enough data in first + * packet leaves a multiple of 512 bytes of data in remainder. + * Assumes that ifp is actually pointer to arpcom structure. + */ +int +ether_output(ifp, m0, dst, rt0) + register struct ifnet *ifp; + struct mbuf *m0; + struct sockaddr *dst; + struct rtentry *rt0; +{ + short type; + int s, error = 0; + u_char *cp, edst[6]; + register struct mbuf *m2, *m = m0; + register struct rtentry *rt; + struct mbuf *mcopy = (struct mbuf *)0; + register struct ether_header *eh; + int off, len = m->m_pkthdr.len; + struct arpcom *ac = (struct arpcom *)ifp; + register struct ifqueue *inq; +#ifdef NETATALK + struct at_ifaddr *aa; +#endif NETATALK + + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) + senderr(ENETDOWN); + rt = rt0; + if (rt) { + if ((rt->rt_flags & RTF_UP) == 0) { + rt0 = rt = rtalloc1(dst, 1, 0UL); + if (rt0) + rt->rt_refcnt--; + else + senderr(EHOSTUNREACH); + } + if (rt->rt_flags & RTF_GATEWAY) { + if (rt->rt_gwroute == 0) + goto lookup; + if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { + rtfree(rt); rt = rt0; + lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, + 0UL); + if ((rt = rt->rt_gwroute) == 0) + senderr(EHOSTUNREACH); + } + } + if (rt->rt_flags & RTF_REJECT) + if (rt->rt_rmx.rmx_expire == 0 || + rtems_bsdnet_seconds_since_boot() < rt->rt_rmx.rmx_expire) + senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); + } + switch (dst->sa_family) { + +#ifdef INET + case AF_INET: + if (!arpresolve(ac, rt, m, dst, edst, rt0)) + return (0); /* if not yet resolved */ + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + off = m->m_pkthdr.len - m->m_len; + type = htons(ETHERTYPE_IP); + break; +#endif +#ifdef IPX + case AF_IPX: + { + struct ifaddr *ia; + + type = htons(ETHERTYPE_IPX); + bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), + (caddr_t)edst, sizeof (edst)); + for (ia = ifp->if_addrlist; ia != NULL; ia = ia->ifa_next) + if(ia->ifa_addr->sa_family == AF_IPX && + !bcmp((caddr_t)edst, + (caddr_t)&((struct ipx_ifaddr *)ia)->ia_addr.sipx_addr.x_host, + sizeof(edst))) + return (looutput(ifp, m, dst, rt)); + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + break; + } +#endif +#ifdef NETATALK + case AF_APPLETALK: + { + struct sockaddr_at *sat = (struct sockaddr_at *)dst; + + /* + * super hack.. + * Most of this loopback code should move into the appletalk + * code, but it's here for now.. remember to move it! [JRE] + * This may not get the same interface we started with + * fix asap. XXX + */ + aa = at_ifawithnet( sat ); + if (aa == NULL) { + goto bad; + } + if( aa->aa_ifa.ifa_ifp != ifp ) { + (*aa->aa_ifa.ifa_ifp->if_output)(aa->aa_ifa.ifa_ifp, + m,dst,rt); + } + if (((sat->sat_addr.s_net == ATADDR_ANYNET) + && (sat->sat_addr.s_node == ATADDR_ANYNODE)) + || ((sat->sat_addr.s_net == aa->aa_addr.sat_addr.s_net ) + && (sat->sat_addr.s_node == aa->aa_addr.sat_addr.s_node))) { + (void) looutput(ifp, m, dst, rt); + return(0); + } + + if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { +#ifdef NETATALKDEBUG + extern char *prsockaddr(struct sockaddr *); + printf("aarpresolv: failed for %s\n", prsockaddr(dst)); +#endif NETATALKDEBUG + return (0); + } + + /* + * If broadcasting on a simplex interface, loopback a copy + */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + } + /* + * In the phase 2 case, we need to prepend an mbuf for the llc header. + * Since we must preserve the value of m, which is passed to us by + * value, we m_copy() the first mbuf, and use it for our llc header. + */ + if ( aa->aa_flags & AFA_PHASE2 ) { + struct llc llc; + + M_PREPEND(m, sizeof(struct llc), M_WAIT); + len += sizeof(struct llc); + llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; + llc.llc_control = LLC_UI; + bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); + llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); + bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); + type = htons(m->m_pkthdr.len); + } else { + type = htons(ETHERTYPE_AT); + } + break; +#endif NETATALK +#ifdef NS + case AF_NS: + switch(ns_nettype){ + default: + case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ + type = 0x8137; + break; + case 0x0: /* Novell 802.3 */ + type = htons( m->m_pkthdr.len); + break; + case 0xe0e0: /* Novell 802.2 and Token-Ring */ + M_PREPEND(m, 3, M_WAIT); + type = htons( m->m_pkthdr.len); + cp = mtod(m, u_char *); + *cp++ = 0xE0; + *cp++ = 0xE0; + *cp++ = 0x03; + break; + } + bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), + (caddr_t)edst, sizeof (edst)); + if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ + m->m_pkthdr.rcvif = ifp; + schednetisr(NETISR_NS); + inq = &nsintrq; + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else + IF_ENQUEUE(inq, m); + splx(s); + return (error); + } + if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ + m2 = m_copy(m, 0, (int)M_COPYALL); + m2->m_pkthdr.rcvif = ifp; + schednetisr(NETISR_NS); + inq = &nsintrq; + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m2); + } else + IF_ENQUEUE(inq, m2); + splx(s); + } + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)){ + mcopy = m_copy(m, 0, (int)M_COPYALL); + } + break; +#endif /* NS */ +#ifdef ISO + case AF_ISO: { + int snpalen; + struct llc *l; + register struct sockaddr_dl *sdl; + + if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && + sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { + bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); + } else if (error = + iso_snparesolve(ifp, (struct sockaddr_iso *)dst, + (char *)edst, &snpalen)) + goto bad; /* Not Resolved */ + /* If broadcasting on a simplex interface, loopback a copy */ + if (*edst & 1) + m->m_flags |= (M_BCAST|M_MCAST); + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && + (mcopy = m_copy(m, 0, (int)M_COPYALL))) { + M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); + if (mcopy) { + eh = mtod(mcopy, struct ether_header *); + bcopy((caddr_t)edst, + (caddr_t)eh->ether_dhost, sizeof (edst)); + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)eh->ether_shost, sizeof (edst)); + } + } + M_PREPEND(m, 3, M_DONTWAIT); + if (m == NULL) + return (0); + type = htons(m->m_pkthdr.len); + l = mtod(m, struct llc *); + l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; + l->llc_control = LLC_UI; + len += 3; + IFDEBUG(D_ETHER) + int i; + printf("unoutput: sending pkt to: "); + for (i=0; i<6; i++) + printf("%x ", edst[i] & 0xff); + printf("\n"); + ENDDEBUG + } break; +#endif /* ISO */ +#ifdef LLC +/* case AF_NSAP: */ + case AF_CCITT: { + register struct sockaddr_dl *sdl = + (struct sockaddr_dl *) rt -> rt_gateway; + + if (sdl && sdl->sdl_family == AF_LINK + && sdl->sdl_alen > 0) { + bcopy(LLADDR(sdl), (char *)edst, + sizeof(edst)); + } else goto bad; /* Not a link interface ? Funny ... */ + if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && + (mcopy = m_copy(m, 0, (int)M_COPYALL))) { + M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); + if (mcopy) { + eh = mtod(mcopy, struct ether_header *); + bcopy((caddr_t)edst, + (caddr_t)eh->ether_dhost, sizeof (edst)); + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)eh->ether_shost, sizeof (edst)); + } + } + type = htons(m->m_pkthdr.len); +#ifdef LLC_DEBUG + { + int i; + register struct llc *l = mtod(m, struct llc *); + + printf("ether_output: sending LLC2 pkt to: "); + for (i=0; i<6; i++) + printf("%x ", edst[i] & 0xff); + printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", + type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, + l->llc_control & 0xff); + + } +#endif /* LLC_DEBUG */ + } break; +#endif /* LLC */ + + case AF_UNSPEC: + eh = (struct ether_header *)dst->sa_data; + (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); + type = eh->ether_type; + break; + + default: + printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, + dst->sa_family); + senderr(EAFNOSUPPORT); + } + + + if (mcopy) + (void) looutput(ifp, mcopy, dst, rt); + /* + * Add local net header. If no space in first mbuf, + * allocate another. + */ + M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); + if (m == 0) + senderr(ENOBUFS); + eh = mtod(m, struct ether_header *); + (void)memcpy(&eh->ether_type, &type, + sizeof(eh->ether_type)); + (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); + (void)memcpy(eh->ether_shost, ac->ac_enaddr, + sizeof(eh->ether_shost)); + s = splimp(); + /* + * Queue message on interface, and start output if interface + * not yet active. + */ + if (IF_QFULL(&ifp->if_snd)) { + IF_DROP(&ifp->if_snd); + splx(s); + senderr(ENOBUFS); + } + IF_ENQUEUE(&ifp->if_snd, m); + if ((ifp->if_flags & IFF_OACTIVE) == 0) + (*ifp->if_start)(ifp); + splx(s); + ifp->if_obytes += len + sizeof (struct ether_header); + if (m->m_flags & M_MCAST) + ifp->if_omcasts++; + return (error); + +bad: + if (m) + m_freem(m); + return (error); +} + +/* + * Process a received Ethernet packet; + * the packet is in the mbuf chain m without + * the ether header, which is provided separately. + */ +void +ether_input(ifp, eh, m) + struct ifnet *ifp; + register struct ether_header *eh; + struct mbuf *m; +{ + register struct ifqueue *inq; + u_short ether_type, *checksum; + int s; +#if defined (ISO) || defined (LLC) || defined(NETATALK) + register struct llc *l; +#endif + + if ((ifp->if_flags & IFF_UP) == 0) { + m_freem(m); + return; + } + ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); + if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, + sizeof(etherbroadcastaddr)) == 0) + m->m_flags |= M_BCAST; + else if (eh->ether_dhost[0] & 1) + m->m_flags |= M_MCAST; + if (m->m_flags & (M_BCAST|M_MCAST)) + ifp->if_imcasts++; + + ether_type = ntohs(eh->ether_type); + + switch (ether_type) { +#ifdef INET + case ETHERTYPE_IP: + schednetisr(NETISR_IP); + inq = &ipintrq; + break; + + case ETHERTYPE_ARP: + schednetisr(NETISR_ARP); + inq = &arpintrq; + break; +#endif +#ifdef IPX + case ETHERTYPE_IPX: + schednetisr(NETISR_IPX); + inq = &ipxintrq; + break; +#endif +#ifdef NS + case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ + schednetisr(NETISR_NS); + inq = &nsintrq; + break; + +#endif /* NS */ +#ifdef NETATALK + case ETHERTYPE_AT: + schednetisr(NETISR_ATALK); + inq = &atintrq1; + break; + case ETHERTYPE_AARP: + /* probably this should be done with a NETISR as well */ + aarpinput((struct arpcom *)ifp, m); /* XXX */ + return; +#endif NETATALK + default: +#ifdef NS + checksum = mtod(m, ushort *); + /* Novell 802.3 */ + if ((ether_type <= ETHERMTU) && + ((*checksum == 0xffff) || (*checksum == 0xE0E0))){ + if(*checksum == 0xE0E0) { + m->m_pkthdr.len -= 3; + m->m_len -= 3; + m->m_data += 3; + } + schednetisr(NETISR_NS); + inq = &nsintrq; + break; + } +#endif /* NS */ +#if defined (ISO) || defined (LLC) || defined(NETATALK) + if (ether_type > ETHERMTU) + goto dropanyway; + l = mtod(m, struct llc *); + switch (l->llc_dsap) { +#ifdef NETATALK + case LLC_SNAP_LSAP: + switch (l->llc_control) { + case LLC_UI: + if (l->llc_ssap != LLC_SNAP_LSAP) + goto dropanyway; + + if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, + sizeof(at_org_code)) == 0 && + ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { + inq = &atintrq2; + m_adj( m, sizeof( struct llc )); + schednetisr(NETISR_ATALK); + break; + } + + if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, + sizeof(aarp_org_code)) == 0 && + ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { + m_adj( m, sizeof( struct llc )); + aarpinput((struct arpcom *)ifp, m); /* XXX */ + return; + } + + default: + goto dropanyway; + } + break; +#endif NETATALK +#ifdef ISO + case LLC_ISO_LSAP: + switch (l->llc_control) { + case LLC_UI: + /* LLC_UI_P forbidden in class 1 service */ + if ((l->llc_dsap == LLC_ISO_LSAP) && + (l->llc_ssap == LLC_ISO_LSAP)) { + /* LSAP for ISO */ + if (m->m_pkthdr.len > ether_type) + m_adj(m, ether_type - m->m_pkthdr.len); + m->m_data += 3; /* XXX */ + m->m_len -= 3; /* XXX */ + m->m_pkthdr.len -= 3; /* XXX */ + M_PREPEND(m, sizeof *eh, M_DONTWAIT); + if (m == 0) + return; + *mtod(m, struct ether_header *) = *eh; + IFDEBUG(D_ETHER) + printf("clnp packet"); + ENDDEBUG + schednetisr(NETISR_ISO); + inq = &clnlintrq; + break; + } + goto dropanyway; + + case LLC_XID: + case LLC_XID_P: + if(m->m_len < 6) + goto dropanyway; + l->llc_window = 0; + l->llc_fid = 9; + l->llc_class = 1; + l->llc_dsap = l->llc_ssap = 0; + /* Fall through to */ + case LLC_TEST: + case LLC_TEST_P: + { + struct sockaddr sa; + register struct ether_header *eh2; + int i; + u_char c = l->llc_dsap; + + l->llc_dsap = l->llc_ssap; + l->llc_ssap = c; + if (m->m_flags & (M_BCAST | M_MCAST)) + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)eh->ether_dhost, 6); + sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); + eh2 = (struct ether_header *)sa.sa_data; + for (i = 0; i < 6; i++) { + eh2->ether_shost[i] = c = eh->ether_dhost[i]; + eh2->ether_dhost[i] = + eh->ether_dhost[i] = eh->ether_shost[i]; + eh->ether_shost[i] = c; + } + ifp->if_output(ifp, m, &sa, NULL); + return; + } + default: + m_freem(m); + return; + } + break; +#endif /* ISO */ +#ifdef LLC + case LLC_X25_LSAP: + { + if (m->m_pkthdr.len > ether_type) + m_adj(m, ether_type - m->m_pkthdr.len); + M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); + if (m == 0) + return; + if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, + eh->ether_dhost, LLC_X25_LSAP, 6, + mtod(m, struct sdl_hdr *))) + panic("ETHER cons addr failure"); + mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type; +#ifdef LLC_DEBUG + printf("llc packet\n"); +#endif /* LLC_DEBUG */ + schednetisr(NETISR_CCITT); + inq = &llcintrq; + break; + } +#endif /* LLC */ + dropanyway: + default: + m_freem(m); + return; + } +#else /* ISO || LLC || NETATALK */ + m_freem(m); + return; +#endif /* ISO || LLC || NETATALK */ + } + + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else + IF_ENQUEUE(inq, m); + splx(s); +} + +/* + * Perform common duties while attaching to interface list + */ +void +ether_ifattach(ifp) + register struct ifnet *ifp; +{ + register struct ifaddr *ifa; + register struct sockaddr_dl *sdl; + + ifp->if_type = IFT_ETHER; + ifp->if_addrlen = 6; + ifp->if_hdrlen = 14; + ifp->if_mtu = ETHERMTU; + if (ifp->if_baudrate == 0) + ifp->if_baudrate = 10000000; + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && + sdl->sdl_family == AF_LINK) { + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ifp->if_addrlen; + bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, + LLADDR(sdl), ifp->if_addrlen); + break; + } +} + +static u_char ether_ipmulticast_min[6] = + { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; +static u_char ether_ipmulticast_max[6] = + { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; +/* + * Add an Ethernet multicast address or range of addresses to the list for a + * given interface. + */ +int +ether_addmulti(ifr, ac) + struct ifreq *ifr; + register struct arpcom *ac; +{ + register struct ether_multi *enm; + struct sockaddr_in *sin; + u_char addrlo[6]; + u_char addrhi[6]; + int set_allmulti = 0; + int s = splimp(); + + switch (ifr->ifr_addr.sa_family) { + + case AF_UNSPEC: + bcopy(ifr->ifr_addr.sa_data, addrlo, 6); + bcopy(addrlo, addrhi, 6); + break; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&(ifr->ifr_addr); + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* + * An IP address of INADDR_ANY means listen to all + * of the Ethernet multicast addresses used for IP. + * (This is for the sake of IP multicast routers.) + */ + bcopy(ether_ipmulticast_min, addrlo, 6); + bcopy(ether_ipmulticast_max, addrhi, 6); + set_allmulti = 1; + } + else { + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); + bcopy(addrlo, addrhi, 6); + } + break; +#endif + + default: + splx(s); + return (EAFNOSUPPORT); + } + + /* + * Verify that we have valid Ethernet multicast addresses. + */ + if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { + splx(s); + return (EINVAL); + } + /* + * See if the address range is already in the list. + */ + ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); + if (enm != NULL) { + /* + * Found it; just increment the reference count. + */ + ++enm->enm_refcount; + splx(s); + return (0); + } + /* + * New address or range; malloc a new multicast record + * and link it into the interface's multicast list. + */ + enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); + if (enm == NULL) { + splx(s); + return (ENOBUFS); + } + bcopy(addrlo, enm->enm_addrlo, 6); + bcopy(addrhi, enm->enm_addrhi, 6); + enm->enm_ac = ac; + enm->enm_refcount = 1; + enm->enm_next = ac->ac_multiaddrs; + ac->ac_multiaddrs = enm; + ac->ac_multicnt++; + splx(s); + if (set_allmulti) + ac->ac_if.if_flags |= IFF_ALLMULTI; + + /* + * Return ENETRESET to inform the driver that the list has changed + * and its reception filter should be adjusted accordingly. + */ + return (ENETRESET); +} + +/* + * Delete a multicast address record. + */ +int +ether_delmulti(ifr, ac) + struct ifreq *ifr; + register struct arpcom *ac; +{ + register struct ether_multi *enm; + register struct ether_multi **p; + struct sockaddr_in *sin; + u_char addrlo[6]; + u_char addrhi[6]; + int unset_allmulti = 0; + int s = splimp(); + + switch (ifr->ifr_addr.sa_family) { + + case AF_UNSPEC: + bcopy(ifr->ifr_addr.sa_data, addrlo, 6); + bcopy(addrlo, addrhi, 6); + break; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&(ifr->ifr_addr); + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* + * An IP address of INADDR_ANY means stop listening + * to the range of Ethernet multicast addresses used + * for IP. + */ + bcopy(ether_ipmulticast_min, addrlo, 6); + bcopy(ether_ipmulticast_max, addrhi, 6); + unset_allmulti = 1; + } + else { + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); + bcopy(addrlo, addrhi, 6); + } + break; +#endif + + default: + splx(s); + return (EAFNOSUPPORT); + } + + /* + * Look up the address in our list. + */ + ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); + if (enm == NULL) { + splx(s); + return (ENXIO); + } + if (--enm->enm_refcount != 0) { + /* + * Still some claims to this record. + */ + splx(s); + return (0); + } + /* + * No remaining claims to this record; unlink and free it. + */ + for (p = &enm->enm_ac->ac_multiaddrs; + *p != enm; + p = &(*p)->enm_next) + continue; + *p = (*p)->enm_next; + free(enm, M_IFMADDR); + ac->ac_multicnt--; + splx(s); + if (unset_allmulti) + ac->ac_if.if_flags &= ~IFF_ALLMULTI; + + /* + * Return ENETRESET to inform the driver that the list has changed + * and its reception filter should be adjusted accordingly. + */ + return (ENETRESET); +} + +SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); + +int +ether_ioctl(struct ifnet *ifp, int command, caddr_t data) +{ + struct ifaddr *ifa = (struct ifaddr *) data; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; + + switch (command) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + ifp->if_init(ifp->if_softc); /* before arpwhohas */ + arp_ifinit((struct arpcom *)ifp, ifa); + break; +#endif +#ifdef IPX + /* + * XXX - This code is probably wrong + */ + case AF_IPX: + { + register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); + struct arpcom *ac = (struct arpcom *) (ifp->if_softc); + + if (ipx_nullhost(*ina)) + ina->x_host = + *(union ipx_host *) + ac->ac_enaddr; + else { + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) ac->ac_enaddr, + sizeof(ac->ac_enaddr)); + } + + /* + * Set new address + */ + ifp->if_init(ifp->if_softc); + break; + } +#endif +#ifdef NS + /* + * XXX - This code is probably wrong + */ + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + struct arpcom *ac = (struct arpcom *) (ifp->if_softc); + + if (ns_nullhost(*ina)) + ina->x_host = + *(union ns_host *) (ac->ac_enaddr); + else { + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) ac->ac_enaddr, + sizeof(ac->ac_enaddr)); + } + + /* + * Set new address + */ + ifp->if_init(ifp->if_softc); + break; + } +#endif + default: + ifp->if_init(ifp->if_softc); + break; + } + break; + + case SIOCGIFADDR: + { + struct sockaddr *sa; + + sa = (struct sockaddr *) & ifr->ifr_data; + bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, + (caddr_t) sa->sa_data, ETHER_ADDR_LEN); + } + break; + + case SIOCSIFMTU: + /* + * Set the interface MTU. + */ + if (ifr->ifr_mtu > ETHERMTU) { + error = EINVAL; + } else { + ifp->if_mtu = ifr->ifr_mtu; + } + break; + } + return (error); +} diff --git a/cpukit/libnetworking/net/if_llc.h b/cpukit/libnetworking/net/if_llc.h new file mode 100644 index 0000000000..3cdf652167 --- /dev/null +++ b/cpukit/libnetworking/net/if_llc.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_llc.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_LLC_H_ +#define _NET_IF_LLC_H_ + +/* + * IEEE 802.2 Link Level Control headers, for use in conjunction with + * 802.{3,4,5} media access control methods. + * + * Headers here do not use bit fields due to shortcomings in many + * compilers. + */ + +struct llc { + u_char llc_dsap; + u_char llc_ssap; + union { + struct { + u_char control; + u_char format_id; + u_char class; + u_char window_x2; + } type_u; + struct { + u_char num_snd_x2; + u_char num_rcv_x2; + } type_i; + struct { + u_char control; + u_char num_rcv_x2; + } type_s; + struct { + u_char control; + struct frmrinfo { + u_char rej_pdu_0; + u_char rej_pdu_1; + u_char frmr_control; + u_char frmr_control_ext; + u_char frmr_cause; + } frmrinfo; + } type_frmr; + struct { + u_char control; + u_char org_code[3]; + u_short ether_type; + } type_snap; + struct { + u_char control; + u_char control_ext; + } type_raw; + } llc_un; +}; +#define llc_control llc_un.type_u.control +#define llc_control_ext llc_un.type_raw.control_ext +#define llc_fid llc_un.type_u.format_id +#define llc_class llc_un.type_u.class +#define llc_window llc_un.type_u.window_x2 +#define llc_frmrinfo llc_un.type_frmr.frmrinfo +#define llc_frmr_pdu0 llc_un.type_frmr.frmrinfo.rej_pdu0 +#define llc_frmr_pdu1 llc_un.type_frmr.frmrinfo.rej_pdu1 +#define llc_frmr_control llc_un.type_frmr.frmrinfo.frmr_control +#define llc_frmr_control_ext llc_un.type_frmr.frmrinfo.frmr_control_ext +#define llc_frmr_cause llc_un.type_frmr.frmrinfo.frmr_control_ext + +/* + * Don't use sizeof(struct llc_un) for LLC header sizes + */ +#define LLC_ISFRAMELEN 4 +#define LLC_UFRAMELEN 3 +#define LLC_FRMRLEN 7 + +/* + * Unnumbered LLC format commands + */ +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_DISC 0x43 +#define LLC_DISC_P 0x53 +#define LLC_UA 0x63 +#define LLC_UA_P 0x73 +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 +#define LLC_FRMR 0x87 +#define LLC_FRMR_P 0x97 +#define LLC_DM 0x0f +#define LLC_DM_P 0x1f +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_SABME 0x6f +#define LLC_SABME_P 0x7f + +/* + * Supervisory LLC commands + */ +#define LLC_RR 0x01 +#define LLC_RNR 0x05 +#define LLC_REJ 0x09 + +/* + * Info format - dummy only + */ +#define LLC_INFO 0x00 + +/* + * ISO PDTR 10178 contains among others + */ +#define LLC_X25_LSAP 0x7e +#define LLC_SNAP_LSAP 0xaa +#define LLC_ISO_LSAP 0xfe + +#endif diff --git a/cpukit/libnetworking/net/if_loop.c b/cpukit/libnetworking/net/if_loop.c new file mode 100644 index 0000000000..3823c28744 --- /dev/null +++ b/cpukit/libnetworking/net/if_loop.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +/* + * Loopback interface driver for protocol testing and timing. + */ +#include "loop.h" +#if NLOOP > 0 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/bpf.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#ifdef IPX +#include <netipx/ipx.h> +#include <netipx/ipx_if.h> +#endif + +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + +#ifdef ISO +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#endif + +#ifdef NETATALK +#include <netinet/if_ether.h> +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#endif NETATALK + +#include "bpfilter.h" + +static int loioctl __P((struct ifnet *, int, caddr_t)); +static void lortrequest __P((int, struct rtentry *, struct sockaddr *)); + + void rtems_bsdnet_loopattach __P((void *)); +PSEUDO_SET(loopattach, if_loop); + +#ifdef TINY_LOMTU +#define LOMTU (1024+512) +#else +#define LOMTU 16384 +#endif + +struct ifnet loif[NLOOP]; + +/* ARGSUSED */ +void +rtems_bsdnet_loopattach(dummy) + void *dummy; +{ + register struct ifnet *ifp; + register int i = 0; + + for (ifp = loif; i < NLOOP; ifp++) { + ifp->if_name = "lo"; + ifp->if_next = NULL; + ifp->if_unit = i++; + ifp->if_mtu = LOMTU; + ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; + ifp->if_ioctl = loioctl; + ifp->if_output = looutput; + ifp->if_type = IFT_LOOP; + ifp->if_hdrlen = 0; + ifp->if_addrlen = 0; + if_attach(ifp); +#if NBPFILTER > 0 + bpfattach(ifp, DLT_NULL, sizeof(u_int)); +#endif + } +} + +int +looutput(ifp, m, dst, rt) + struct ifnet *ifp; + register struct mbuf *m; + struct sockaddr *dst; + register struct rtentry *rt; +{ + int s, isr; + register struct ifqueue *ifq = 0; + + if ((m->m_flags & M_PKTHDR) == 0) + panic("looutput no HDR"); +#if NBPFILTER > 0 + /* BPF write needs to be handled specially */ + if (dst->sa_family == AF_UNSPEC) { + dst->sa_family = *(mtod(m, int *)); + m->m_len -= sizeof(int); + m->m_pkthdr.len -= sizeof(int); + m->m_data += sizeof(int); + } + + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + u_int af = dst->sa_family; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(ifp, &m0); + } +#endif + m->m_pkthdr.rcvif = ifp; + + if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { + m_freem(m); + return (rt->rt_flags & RTF_BLACKHOLE ? 0 : + rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + } + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + switch (dst->sa_family) { + +#ifdef INET + case AF_INET: + ifq = &ipintrq; + isr = NETISR_IP; + break; +#endif +#ifdef IPX + case AF_IPX: + ifq = &ipxintrq; + isr = NETISR_IPX; + break; +#endif +#ifdef NS + case AF_NS: + ifq = &nsintrq; + isr = NETISR_NS; + break; +#endif +#ifdef ISO + case AF_ISO: + ifq = &clnlintrq; + isr = NETISR_ISO; + break; +#endif +#ifdef NETATALK + case AF_APPLETALK: + ifq = &atintrq2; + isr = NETISR_ATALK; + break; +#endif NETATALK + default: + printf("lo%d: can't handle af%d\n", ifp->if_unit, + dst->sa_family); + m_freem(m); + return (EAFNOSUPPORT); + } + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + m_freem(m); + splx(s); + return (ENOBUFS); + } + IF_ENQUEUE(ifq, m); + schednetisr(isr); + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + splx(s); + return (0); +} + +/* ARGSUSED */ +static void +lortrequest(cmd, rt, sa) + int cmd; + struct rtentry *rt; + struct sockaddr *sa; +{ + if (rt) { + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ + /* + * For optimal performance, the send and receive buffers + * should be at least twice the MTU plus a little more for + * overhead. + */ + rt->rt_rmx.rmx_recvpipe = + rt->rt_rmx.rmx_sendpipe = 3 * LOMTU; + } +} + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +static int +loioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + register struct ifaddr *ifa; + register struct ifreq *ifr = (struct ifreq *)data; + register int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP | IFF_RUNNING; + ifa = (struct ifaddr *)data; + ifa->ifa_rtrequest = lortrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; /* XXX */ + break; + } + switch (ifr->ifr_addr.sa_family) { + +#ifdef INET + case AF_INET: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; + + default: + error = EINVAL; + } + return (error); +} +#endif /* NLOOP > 0 */ diff --git a/cpukit/libnetworking/net/if_types.h b/cpukit/libnetworking/net/if_types.h new file mode 100644 index 0000000000..833ba471c3 --- /dev/null +++ b/cpukit/libnetworking/net/if_types.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_types.h 8.2 (Berkeley) 4/20/94 + * $Id$ + */ + +#ifndef _NET_IF_TYPES_H_ +#define _NET_IF_TYPES_H_ + +/* + * Interface types for benefit of parsing media address headers. + * This list is derived from the SNMP list of ifTypes, currently + * documented in RFC1573. + */ + +#define IFT_OTHER 0x1 /* none of the following */ +#define IFT_1822 0x2 /* old-style arpanet imp */ +#define IFT_HDH1822 0x3 /* HDH arpanet imp */ +#define IFT_X25DDN 0x4 /* x25 to imp */ +#define IFT_X25 0x5 /* PDN X25 interface (RFC877) */ +#define IFT_ETHER 0x6 /* Ethernet CSMACD */ +#define IFT_ISO88023 0x7 /* CMSA CD */ +#define IFT_ISO88024 0x8 /* Token Bus */ +#define IFT_ISO88025 0x9 /* Token Ring */ +#define IFT_ISO88026 0xa /* MAN */ +#define IFT_STARLAN 0xb +#define IFT_P10 0xc /* Proteon 10MBit ring */ +#define IFT_P80 0xd /* Proteon 80MBit ring */ +#define IFT_HY 0xe /* Hyperchannel */ +#define IFT_FDDI 0xf +#define IFT_LAPB 0x10 +#define IFT_SDLC 0x11 +#define IFT_T1 0x12 +#define IFT_CEPT 0x13 /* E1 - european T1 */ +#define IFT_ISDNBASIC 0x14 +#define IFT_ISDNPRIMARY 0x15 +#define IFT_PTPSERIAL 0x16 /* Proprietary PTP serial */ +#define IFT_PPP 0x17 /* RFC 1331 */ +#define IFT_LOOP 0x18 /* loopback */ +#define IFT_EON 0x19 /* ISO over IP */ +#define IFT_XETHER 0x1a /* obsolete 3MB experimental ethernet */ +#define IFT_NSIP 0x1b /* XNS over IP */ +#define IFT_SLIP 0x1c /* IP over generic TTY */ +#define IFT_ULTRA 0x1d /* Ultra Technologies */ +#define IFT_DS3 0x1e /* Generic T3 */ +#define IFT_SIP 0x1f /* SMDS */ +#define IFT_FRELAY 0x20 /* Frame Relay DTE only */ +#define IFT_RS232 0x21 +#define IFT_PARA 0x22 /* parallel-port */ +#define IFT_ARCNET 0x23 +#define IFT_ARCNETPLUS 0x24 +#define IFT_ATM 0x25 /* ATM cells */ +#define IFT_MIOX25 0x26 +#define IFT_SONET 0x27 /* SONET or SDH */ +#define IFT_X25PLE 0x28 +#define IFT_ISO88022LLC 0x29 +#define IFT_LOCALTALK 0x2a +#define IFT_SMDSDXI 0x2b +#define IFT_FRELAYDCE 0x2c /* Frame Relay DCE */ +#define IFT_V35 0x2d +#define IFT_HSSI 0x2e +#define IFT_HIPPI 0x2f +#define IFT_MODEM 0x30 /* Generic Modem */ +#define IFT_AAL5 0x31 /* AAL5 over ATM */ +#define IFT_SONETPATH 0x32 +#define IFT_SONETVT 0x33 +#define IFT_SMDSICIP 0x34 /* SMDS InterCarrier Interface */ +#define IFT_PROPVIRTUAL 0x35 /* Proprietary Virtual/internal */ +#define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */ + +#endif diff --git a/cpukit/libnetworking/net/netisr.h b/cpukit/libnetworking/net/netisr.h new file mode 100644 index 0000000000..73269a4442 --- /dev/null +++ b/cpukit/libnetworking/net/netisr.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1980, 1986, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)netisr.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_NETISR_H_ +#define _NET_NETISR_H_ + +/* + * The networking code runs off software interrupts. + * + * You can switch into the network by doing splnet() and return by splx(). + * The software interrupt level for the network is higher than the software + * level for the clock (so you can enter the network in routines called + * at timeout time). + */ +#if defined(vax) || defined(tahoe) +#define setsoftnet() mtpr(SIRR, 12) +#endif + +/* + * Each ``pup-level-1'' input queue has a bit in a ``netisr'' status + * word which is used to de-multiplex a single software + * interrupt used for scheduling the network code to calls + * on the lowest level routine of each protocol. + */ +#define NETISR_RAW 0 /* same as AF_UNSPEC */ +#define NETISR_IP 2 /* same as AF_INET */ +#define NETISR_IMP 3 /* same as AF_IMPLINK */ +#define NETISR_NS 6 /* same as AF_NS */ +#define NETISR_ISO 7 /* same as AF_ISO */ +#define NETISR_CCITT 10 /* same as AF_CCITT */ +#define NETISR_ATALK 16 /* same as AF_APPLETALK */ +#define NETISR_ARP 18 /* same as AF_LINK */ +#define NETISR_IPX 23 /* same as AF_IPX */ +#define NETISR_ISDN 26 /* same as AF_E164 */ +#define NETISR_PPP 27 /* PPP soft interrupt */ + +#define schednetisr(anisr) rtems_bsdnet_schednetisr(anisr) + +#ifndef LOCORE +#ifdef KERNEL +extern volatile unsigned int netisr; /* scheduling bits for network */ + +typedef void netisr_t(void); + +struct netisrtab { + int nit_num; + netisr_t *nit_isr; +}; + +#define NETISR_SET(num, isr) + +int register_netisr __P((int, netisr_t *)); + +#endif +#endif + +#endif diff --git a/cpukit/libnetworking/net/radix.c b/cpukit/libnetworking/net/radix.c new file mode 100644 index 0000000000..bc1b7ee1d1 --- /dev/null +++ b/cpukit/libnetworking/net/radix.c @@ -0,0 +1,1028 @@ +/* + * Copyright (c) 1988, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)radix.c 8.4 (Berkeley) 11/2/94 + * $Id$ + */ + +/* + * Routines to build and maintain radix trees for routing lookups. + */ +#ifndef _RADIX_H_ +#include <sys/param.h> +#ifdef KERNEL +#include <sys/systm.h> +#include <sys/malloc.h> +#define M_DONTWAIT M_NOWAIT +#include <sys/domain.h> +#else +#include <stdlib.h> +#endif +#include <sys/syslog.h> +#include <net/radix.h> +#endif + +static struct radix_node * + rn_lookup __P((void *v_arg, void *m_arg, + struct radix_node_head *head)); +static int rn_walktree_from __P((struct radix_node_head *h, void *a, + void *m, walktree_f_t *f, void *w)); +static int rn_walktree __P((struct radix_node_head *, walktree_f_t *, void *)); +static struct radix_node + *rn_delete __P((void *, void *, struct radix_node_head *)), + *rn_insert __P((void *, struct radix_node_head *, int *, + struct radix_node [2])), + *rn_newpair __P((void *, int, struct radix_node[2])), + *rn_search __P((void *, struct radix_node *)), + *rn_search_m __P((void *, struct radix_node *, void *)); + +static int max_keylen; +static struct radix_mask *rn_mkfreelist; +static struct radix_node_head *mask_rnhead; +static char *addmask_key; +static char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, -1}; +static char *rn_zeros, *rn_ones; + +#define rn_masktop (mask_rnhead->rnh_treetop) +#undef Bcmp +#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) + +static int rn_lexobetter __P((void *m_arg, void *n_arg)); +static struct radix_mask * + rn_new_radix_mask __P((struct radix_node *tt, + struct radix_mask *next)); +static int rn_satsifies_leaf __P((char *trial, struct radix_node *leaf, + int skip)); + +/* + * The data structure for the keys is a radix tree with one way + * branching removed. The index rn_b at an internal node n represents a bit + * position to be tested. The tree is arranged so that all descendants + * of a node n have keys whose bits all agree up to position rn_b - 1. + * (We say the index of n is rn_b.) + * + * There is at least one descendant which has a one bit at position rn_b, + * and at least one with a zero there. + * + * A route is determined by a pair of key and mask. We require that the + * bit-wise logical and of the key and mask to be the key. + * We define the index of a route to associated with the mask to be + * the first bit number in the mask where 0 occurs (with bit number 0 + * representing the highest order bit). + * + * We say a mask is normal if every bit is 0, past the index of the mask. + * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b, + * and m is a normal mask, then the route applies to every descendant of n. + * If the index(m) < rn_b, this implies the trailing last few bits of k + * before bit b are all 0, (and hence consequently true of every descendant + * of n), so the route applies to all descendants of the node as well. + * + * Similar logic shows that a non-normal mask m such that + * index(m) <= index(n) could potentially apply to many children of n. + * Thus, for each non-host route, we attach its mask to a list at an internal + * node as high in the tree as we can go. + * + * The present version of the code makes use of normal routes in short- + * circuiting an explict mask and compare operation when testing whether + * a key satisfies a normal route, and also in remembering the unique leaf + * that governs a subtree. + */ + +static struct radix_node * +rn_search(v_arg, head) + void *v_arg; + struct radix_node *head; +{ + register struct radix_node *x; + register caddr_t v; + + for (x = head, v = v_arg; x->rn_b >= 0;) { + if (x->rn_bmask & v[x->rn_off]) + x = x->rn_r; + else + x = x->rn_l; + } + return (x); +}; + +static struct radix_node * +rn_search_m(v_arg, head, m_arg) + struct radix_node *head; + void *v_arg, *m_arg; +{ + register struct radix_node *x; + register caddr_t v = v_arg, m = m_arg; + + for (x = head; x->rn_b >= 0;) { + if ((x->rn_bmask & m[x->rn_off]) && + (x->rn_bmask & v[x->rn_off])) + x = x->rn_r; + else + x = x->rn_l; + } + return x; +}; + +int +rn_refines(m_arg, n_arg) + void *m_arg, *n_arg; +{ + register caddr_t m = m_arg, n = n_arg; + register caddr_t lim, lim2 = lim = n + *(u_char *)n; + int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); + int masks_are_equal = 1; + + if (longer > 0) + lim -= longer; + while (n < lim) { + if (*n & ~(*m)) + return 0; + if (*n++ != *m++) + masks_are_equal = 0; + } + while (n < lim2) + if (*n++) + return 0; + if (masks_are_equal && (longer < 0)) + for (lim2 = m - longer; m < lim2; ) + if (*m++) + return 1; + return (!masks_are_equal); +} + +struct radix_node * +rn_lookup(v_arg, m_arg, head) + void *v_arg, *m_arg; + struct radix_node_head *head; +{ + register struct radix_node *x; + caddr_t netmask = 0; + + if (m_arg) { + if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) + return (0); + netmask = x->rn_key; + } + x = rn_match(v_arg, head); + if (x && netmask) { + while (x && x->rn_mask != netmask) + x = x->rn_dupedkey; + } + return x; +} + +static int +rn_satsifies_leaf(trial, leaf, skip) + char *trial; + register struct radix_node *leaf; + int skip; +{ + register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; + char *cplim; + int length = min(*(u_char *)cp, *(u_char *)cp2); + + if (cp3 == 0) + cp3 = rn_ones; + else + length = min(length, *(u_char *)cp3); + cplim = cp + length; cp3 += skip; cp2 += skip; + for (cp += skip; cp < cplim; cp++, cp2++, cp3++) + if ((*cp ^ *cp2) & *cp3) + return 0; + return 1; +} + +struct radix_node * +rn_match(v_arg, head) + void *v_arg; + struct radix_node_head *head; +{ + caddr_t v = v_arg; + register struct radix_node *t = head->rnh_treetop, *x; + register caddr_t cp = v, cp2; + caddr_t cplim; + struct radix_node *saved_t, *top = t; + int off = t->rn_off, vlen = *(u_char *)cp, matched_off; + register int test, b, rn_b; + + /* + * Open code rn_search(v, top) to avoid overhead of extra + * subroutine call. + */ + for (; t->rn_b >= 0; ) { + if (t->rn_bmask & cp[t->rn_off]) + t = t->rn_r; + else + t = t->rn_l; + } + /* + * See if we match exactly as a host destination + * or at least learn how many bits match, for normal mask finesse. + * + * It doesn't hurt us to limit how many bytes to check + * to the length of the mask, since if it matches we had a genuine + * match and the leaf we have is the most specific one anyway; + * if it didn't match with a shorter length it would fail + * with a long one. This wins big for class B&C netmasks which + * are probably the most common case... + */ + if (t->rn_mask) + vlen = *(u_char *)t->rn_mask; + cp += off; cp2 = t->rn_key + off; cplim = v + vlen; + for (; cp < cplim; cp++, cp2++) + if (*cp != *cp2) + goto on1; + /* + * This extra grot is in case we are explicitly asked + * to look up the default. Ugh! + */ + if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey) + t = t->rn_dupedkey; + return t; +on1: + test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */ + for (b = 7; (test >>= 1) > 0;) + b--; + matched_off = cp - v; + b += matched_off << 3; + rn_b = -1 - b; + /* + * If there is a host route in a duped-key chain, it will be first. + */ + if ((saved_t = t)->rn_mask == 0) + t = t->rn_dupedkey; + for (; t; t = t->rn_dupedkey) + /* + * Even if we don't match exactly as a host, + * we may match if the leaf we wound up at is + * a route to a net. + */ + if (t->rn_flags & RNF_NORMAL) { + if (rn_b <= t->rn_b) + return t; + } else if (rn_satsifies_leaf(v, t, matched_off)) + return t; + t = saved_t; + /* start searching up the tree */ + do { + register struct radix_mask *m; + t = t->rn_p; + m = t->rn_mklist; + if (m) { + /* + * If non-contiguous masks ever become important + * we can restore the masking and open coding of + * the search and satisfaction test and put the + * calculation of "off" back before the "do". + */ + do { + if (m->rm_flags & RNF_NORMAL) { + if (rn_b <= m->rm_b) + return (m->rm_leaf); + } else { + off = min(t->rn_off, matched_off); + x = rn_search_m(v, t, m->rm_mask); + while (x && x->rn_mask != m->rm_mask) + x = x->rn_dupedkey; + if (x && rn_satsifies_leaf(v, x, off)) + return x; + } + m = m->rm_mklist; + } while (m); + } + } while (t != top); + return 0; +}; + +#ifdef RN_DEBUG +int rn_nodenum; +struct radix_node *rn_clist; +int rn_saveinfo; +int rn_debug = 1; +#endif + +static struct radix_node * +rn_newpair(v, b, nodes) + void *v; + int b; + struct radix_node nodes[2]; +{ + register struct radix_node *tt = nodes, *t = tt + 1; + t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7); + t->rn_l = tt; t->rn_off = b >> 3; + tt->rn_b = -1; tt->rn_key = (caddr_t)v; tt->rn_p = t; + tt->rn_flags = t->rn_flags = RNF_ACTIVE; +#ifdef RN_DEBUG + tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; + tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt; +#endif + return t; +} + +static struct radix_node * +rn_insert(v_arg, head, dupentry, nodes) + void *v_arg; + struct radix_node_head *head; + int *dupentry; + struct radix_node nodes[2]; +{ + caddr_t v = v_arg; + struct radix_node *top = head->rnh_treetop; + int head_off = top->rn_off, vlen = (int)*((u_char *)v); + register struct radix_node *t = rn_search(v_arg, top); + register caddr_t cp = v + head_off; + register int b; + struct radix_node *tt; + /* + * Find first bit at which v and t->rn_key differ + */ + { + register caddr_t cp2 = t->rn_key + head_off; + register int cmp_res; + caddr_t cplim = v + vlen; + + while (cp < cplim) + if (*cp2++ != *cp++) + goto on1; + *dupentry = 1; + return t; +on1: + *dupentry = 0; + cmp_res = (cp[-1] ^ cp2[-1]) & 0xff; + for (b = (cp - v) << 3; cmp_res; b--) + cmp_res >>= 1; + } + { + register struct radix_node *p, *x = top; + cp = v; + do { + p = x; + if (cp[x->rn_off] & x->rn_bmask) + x = x->rn_r; + else x = x->rn_l; + } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */ +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p); +#endif + t = rn_newpair(v_arg, b, nodes); tt = t->rn_l; + if ((cp[p->rn_off] & p->rn_bmask) == 0) + p->rn_l = t; + else + p->rn_r = t; + x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */ + if ((cp[t->rn_off] & t->rn_bmask) == 0) { + t->rn_r = x; + } else { + t->rn_r = tt; t->rn_l = x; + } +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p); +#endif + } + return (tt); +} + +struct radix_node * +rn_addmask(n_arg, search, skip) + int search, skip; + void *n_arg; +{ + caddr_t netmask = (caddr_t)n_arg; + register struct radix_node *x; + register caddr_t cp, cplim; + register int b = 0, mlen, j; + int maskduplicated, m0, isnormal; + struct radix_node *saved_x; + static int last_zeroed = 0; + + if ((mlen = *(u_char *)netmask) > max_keylen) + mlen = max_keylen; + if (skip == 0) + skip = 1; + if (mlen <= skip) + return (mask_rnhead->rnh_nodes); + if (skip > 1) + Bcopy(rn_ones + 1, addmask_key + 1, skip - 1); + if ((m0 = mlen) > skip) + Bcopy(netmask + skip, addmask_key + skip, mlen - skip); + /* + * Trim trailing zeroes. + */ + for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;) + cp--; + mlen = cp - addmask_key; + if (mlen <= skip) { + if (m0 >= last_zeroed) + last_zeroed = mlen; + return (mask_rnhead->rnh_nodes); + } + if (m0 < last_zeroed) + Bzero(addmask_key + m0, last_zeroed - m0); + *addmask_key = last_zeroed = mlen; + x = rn_search(addmask_key, rn_masktop); + if (Bcmp(addmask_key, x->rn_key, mlen) != 0) + x = 0; + if (x || search) + return (x); + R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x)); + if ((saved_x = x) == 0) + return (0); + Bzero(x, max_keylen + 2 * sizeof (*x)); + netmask = cp = (caddr_t)(x + 2); + Bcopy(addmask_key, cp, mlen); + x = rn_insert(cp, mask_rnhead, &maskduplicated, x); + if (maskduplicated) { + log(LOG_ERR, "rn_addmask: mask impossibly already in tree"); + Free(saved_x); + return (x); + } + /* + * Calculate index of mask, and check for normalcy. + */ + cplim = netmask + mlen; isnormal = 1; + for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;) + cp++; + if (cp != cplim) { + for (j = 0x80; (j & *cp) != 0; j >>= 1) + b++; + if (*cp != normal_chars[b] || cp != (cplim - 1)) + isnormal = 0; + } + b += (cp - netmask) << 3; + x->rn_b = -1 - b; + if (isnormal) + x->rn_flags |= RNF_NORMAL; + return (x); +} + +static int /* XXX: arbitrary ordering for non-contiguous masks */ +rn_lexobetter(m_arg, n_arg) + void *m_arg, *n_arg; +{ + register u_char *mp = m_arg, *np = n_arg, *lim; + + if (*mp > *np) + return 1; /* not really, but need to check longer one first */ + if (*mp == *np) + for (lim = mp + *mp; mp < lim;) + if (*mp++ > *np++) + return 1; + return 0; +} + +static struct radix_mask * +rn_new_radix_mask(tt, next) + register struct radix_node *tt; + register struct radix_mask *next; +{ + register struct radix_mask *m; + + MKGet(m); + if (m == 0) { + log(LOG_ERR, "Mask for route not entered\n"); + return (0); + } + Bzero(m, sizeof *m); + m->rm_b = tt->rn_b; + m->rm_flags = tt->rn_flags; + if (tt->rn_flags & RNF_NORMAL) + m->rm_leaf = tt; + else + m->rm_mask = tt->rn_mask; + m->rm_mklist = next; + tt->rn_mklist = m; + return m; +} + +struct radix_node * +rn_addroute(v_arg, n_arg, head, treenodes) + void *v_arg, *n_arg; + struct radix_node_head *head; + struct radix_node treenodes[2]; +{ + caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; + register struct radix_node *t, *x = 0, *tt; + struct radix_node *saved_tt, *top = head->rnh_treetop; + short b = 0, b_leaf = 0; + int keyduplicated; + caddr_t mmask; + struct radix_mask *m, **mp; + + /* + * In dealing with non-contiguous masks, there may be + * many different routes which have the same mask. + * We will find it useful to have a unique pointer to + * the mask to speed avoiding duplicate references at + * nodes and possibly save time in calculating indices. + */ + if (netmask) { + if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0) + return (0); + b_leaf = x->rn_b; + b = -1 - x->rn_b; + netmask = x->rn_key; + } + /* + * Deal with duplicated keys: attach node to previous instance + */ + saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes); + if (keyduplicated) { + for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) { + if (tt->rn_mask == netmask) + return (0); + if (netmask == 0 || + (tt->rn_mask && + ((b_leaf < tt->rn_b) || /* index(netmask) > node */ + rn_refines(netmask, tt->rn_mask) || + rn_lexobetter(netmask, tt->rn_mask)))) + break; + } + /* + * If the mask is not duplicated, we wouldn't + * find it among possible duplicate key entries + * anyway, so the above test doesn't hurt. + * + * We sort the masks for a duplicated key the same way as + * in a masklist -- most specific to least specific. + * This may require the unfortunate nuisance of relocating + * the head of the list. + */ + if (tt == saved_tt) { + struct radix_node *xx = x; + /* link in at head of list */ + (tt = treenodes)->rn_dupedkey = t; + tt->rn_flags = t->rn_flags; + tt->rn_p = x = t->rn_p; + t->rn_p = tt; /* parent */ + if (x->rn_l == t) x->rn_l = tt; else x->rn_r = tt; + saved_tt = tt; x = xx; + } else { + (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; + t->rn_dupedkey = tt; + tt->rn_p = t; /* parent */ + if (tt->rn_dupedkey) /* parent */ + tt->rn_dupedkey->rn_p = tt; /* parent */ + } +#ifdef RN_DEBUG + t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; + tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt; +#endif + tt->rn_key = (caddr_t) v; + tt->rn_b = -1; + tt->rn_flags = RNF_ACTIVE; + } + /* + * Put mask in tree. + */ + if (netmask) { + tt->rn_mask = netmask; + tt->rn_b = x->rn_b; + tt->rn_flags |= x->rn_flags & RNF_NORMAL; + } + t = saved_tt->rn_p; + if (keyduplicated) + goto on2; + b_leaf = -1 - t->rn_b; + if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r; + /* Promote general routes from below */ + if (x->rn_b < 0) { + for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) + if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) { + *mp = m = rn_new_radix_mask(x, 0); + if (m) + mp = &m->rm_mklist; + } + } else if (x->rn_mklist) { + /* + * Skip over masks whose index is > that of new node + */ + for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) + if (m->rm_b >= b_leaf) + break; + t->rn_mklist = m; *mp = 0; + } +on2: + /* Add new route to highest possible ancestor's list */ + if ((netmask == 0) || (b > t->rn_b )) + return tt; /* can't lift at all */ + b_leaf = tt->rn_b; + do { + x = t; + t = t->rn_p; + } while (b <= t->rn_b && x != top); + /* + * Search through routes associated with node to + * insert new route according to index. + * Need same criteria as when sorting dupedkeys to avoid + * double loop on deletion. + */ + for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) { + if (m->rm_b < b_leaf) + continue; + if (m->rm_b > b_leaf) + break; + if (m->rm_flags & RNF_NORMAL) { + mmask = m->rm_leaf->rn_mask; + if (tt->rn_flags & RNF_NORMAL) { + log(LOG_ERR, + "Non-unique normal route, mask not entered"); + return tt; + } + } else + mmask = m->rm_mask; + if (mmask == netmask) { + m->rm_refs++; + tt->rn_mklist = m; + return tt; + } + if (rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask)) + break; + } + *mp = rn_new_radix_mask(tt, *mp); + return tt; +} + +static struct radix_node * +rn_delete(v_arg, netmask_arg, head) + void *v_arg, *netmask_arg; + struct radix_node_head *head; +{ + register struct radix_node *t, *p, *x, *tt; + struct radix_mask *m, *saved_m, **mp; + struct radix_node *dupedkey, *saved_tt, *top; + caddr_t v, netmask; + int b, head_off, vlen; + + v = v_arg; + netmask = netmask_arg; + x = head->rnh_treetop; + tt = rn_search(v, x); + head_off = x->rn_off; + vlen = *(u_char *)v; + saved_tt = tt; + top = x; + if (tt == 0 || + Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off)) + return (0); + /* + * Delete our route from mask lists. + */ + if (netmask) { + if ((x = rn_addmask(netmask, 1, head_off)) == 0) + return (0); + netmask = x->rn_key; + while (tt->rn_mask != netmask) + if ((tt = tt->rn_dupedkey) == 0) + return (0); + } + if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0) + goto on1; + if (tt->rn_flags & RNF_NORMAL) { + if (m->rm_leaf != tt || m->rm_refs > 0) { + log(LOG_ERR, "rn_delete: inconsistent annotation\n"); + return 0; /* dangling ref could cause disaster */ + } + } else { + if (m->rm_mask != tt->rn_mask) { + log(LOG_ERR, "rn_delete: inconsistent annotation\n"); + goto on1; + } + if (--m->rm_refs >= 0) + goto on1; + } + b = -1 - tt->rn_b; + t = saved_tt->rn_p; + if (b > t->rn_b) + goto on1; /* Wasn't lifted at all */ + do { + x = t; + t = t->rn_p; + } while (b <= t->rn_b && x != top); + for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) + if (m == saved_m) { + *mp = m->rm_mklist; + MKFree(m); + break; + } + if (m == 0) { + log(LOG_ERR, "rn_delete: couldn't find our annotation\n"); + if (tt->rn_flags & RNF_NORMAL) + return (0); /* Dangling ref to us */ + } +on1: + /* + * Eliminate us from tree + */ + if (tt->rn_flags & RNF_ROOT) + return (0); +#ifdef RN_DEBUG + /* Get us out of the creation list */ + for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {} + if (t) t->rn_ybro = tt->rn_ybro; +#endif + t = tt->rn_p; + dupedkey = saved_tt->rn_dupedkey; + if (dupedkey) { + /* + * at this point, tt is the deletion target and saved_tt + * is the head of the dupekey chain + */ + if (tt == saved_tt) { + /* remove from head of chain */ + x = dupedkey; x->rn_p = t; + if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x; + } else { + /* find node in front of tt on the chain */ + for (x = p = saved_tt; p && p->rn_dupedkey != tt;) + p = p->rn_dupedkey; + if (p) { + p->rn_dupedkey = tt->rn_dupedkey; + if (tt->rn_dupedkey) /* parent */ + tt->rn_dupedkey->rn_p = p; /* parent */ + } else log(LOG_ERR, "rn_delete: couldn't find us\n"); + } + t = tt + 1; + if (t->rn_flags & RNF_ACTIVE) { +#ifndef RN_DEBUG + *++x = *t; p = t->rn_p; +#else + b = t->rn_info; *++x = *t; t->rn_info = b; p = t->rn_p; +#endif + if (p->rn_l == t) p->rn_l = x; else p->rn_r = x; + x->rn_l->rn_p = x; x->rn_r->rn_p = x; + } + goto out; + } + if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l; + p = t->rn_p; + if (p->rn_r == t) p->rn_r = x; else p->rn_l = x; + x->rn_p = p; + /* + * Demote routes attached to us. + */ + if (t->rn_mklist) { + if (x->rn_b >= 0) { + for (mp = &x->rn_mklist; (m = *mp);) + mp = &m->rm_mklist; + *mp = t->rn_mklist; + } else { + /* If there are any key,mask pairs in a sibling + duped-key chain, some subset will appear sorted + in the same order attached to our mklist */ + for (m = t->rn_mklist; m && x; x = x->rn_dupedkey) + if (m == x->rn_mklist) { + struct radix_mask *mm = m->rm_mklist; + x->rn_mklist = 0; + if (--(m->rm_refs) < 0) + MKFree(m); + m = mm; + } + if (m) + log(LOG_ERR, "%s %p at %x\n", + "rn_delete: Orphaned Mask", m, x); + } + } + /* + * We may be holding an active internal node in the tree. + */ + x = tt + 1; + if (t != x) { +#ifndef RN_DEBUG + *t = *x; +#else + b = t->rn_info; *t = *x; t->rn_info = b; +#endif + t->rn_l->rn_p = t; t->rn_r->rn_p = t; + p = x->rn_p; + if (p->rn_l == x) p->rn_l = t; else p->rn_r = t; + } +out: + tt->rn_flags &= ~RNF_ACTIVE; + tt[1].rn_flags &= ~RNF_ACTIVE; + return (tt); +} + +/* + * This is the same as rn_walktree() except for the parameters and the + * exit. + */ +static int +rn_walktree_from(h, a, m, f, w) + struct radix_node_head *h; + void *a, *m; + walktree_f_t *f; + void *w; +{ + int error; + struct radix_node *base, *next; + u_char *xa = (u_char *)a; + u_char *xm = (u_char *)m; + register struct radix_node *rn, *last = 0 /* shut up gcc */; + int stopping = 0; + int lastb; + + /* + * rn_search_m is sort-of-open-coded here. + */ + /* printf("about to search\n"); */ + for (rn = h->rnh_treetop; rn->rn_b >= 0; ) { + last = rn; + /* printf("rn_b %d, rn_bmask %x, xm[rn_off] %x\n", + rn->rn_b, rn->rn_bmask, xm[rn->rn_off]); */ + if (!(rn->rn_bmask & xm[rn->rn_off])) { + break; + } + if (rn->rn_bmask & xa[rn->rn_off]) { + rn = rn->rn_r; + } else { + rn = rn->rn_l; + } + } + /* printf("done searching\n"); */ + + /* + * Two cases: either we stepped off the end of our mask, + * in which case last == rn, or we reached a leaf, in which + * case we want to start from the last node we looked at. + * Either way, last is the node we want to start from. + */ + rn = last; + lastb = rn->rn_b; + + /* printf("rn %p, lastb %d\n", rn, lastb);*/ + + /* + * This gets complicated because we may delete the node + * while applying the function f to it, so we need to calculate + * the successor node in advance. + */ + while (rn->rn_b >= 0) + rn = rn->rn_l; + + while (!stopping) { + /* printf("node %p (%d)\n", rn, rn->rn_b); */ + base = rn; + /* If at right child go back up, otherwise, go right */ + while (rn->rn_p->rn_r == rn && !(rn->rn_flags & RNF_ROOT)) { + rn = rn->rn_p; + + /* if went up beyond last, stop */ + if (rn->rn_b < lastb) { + stopping = 1; + /* printf("up too far\n"); */ + } + } + + /* Find the next *leaf* since next node might vanish, too */ + for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) + rn = rn->rn_l; + next = rn; + /* Process leaves */ + while ((rn = base) != 0) { + base = rn->rn_dupedkey; + /* printf("leaf %p\n", rn); */ + if (!(rn->rn_flags & RNF_ROOT) + && (error = (*f)(rn, w))) + return (error); + } + rn = next; + + if (rn->rn_flags & RNF_ROOT) { + /* printf("root, stopping"); */ + stopping = 1; + } + + } + return 0; +} + +static int +rn_walktree(h, f, w) + struct radix_node_head *h; + walktree_f_t *f; + void *w; +{ + int error; + struct radix_node *base, *next; + register struct radix_node *rn = h->rnh_treetop; + /* + * This gets complicated because we may delete the node + * while applying the function f to it, so we need to calculate + * the successor node in advance. + */ + /* First time through node, go left */ + while (rn->rn_b >= 0) + rn = rn->rn_l; + for (;;) { + base = rn; + /* If at right child go back up, otherwise, go right */ + while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0) + rn = rn->rn_p; + /* Find the next *leaf* since next node might vanish, too */ + for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) + rn = rn->rn_l; + next = rn; + /* Process leaves */ + while ((rn = base)) { + base = rn->rn_dupedkey; + if (!(rn->rn_flags & RNF_ROOT) && (error = (*f)(rn, w))) + return (error); + } + rn = next; + if (rn->rn_flags & RNF_ROOT) + return (0); + } + /* NOTREACHED */ +} + +int +rn_inithead(head, off) + void **head; + int off; +{ + register struct radix_node_head *rnh; + register struct radix_node *t, *tt, *ttt; + if (*head) + return (1); + R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh)); + if (rnh == 0) + return (0); + Bzero(rnh, sizeof (*rnh)); + *head = rnh; + t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); + ttt = rnh->rnh_nodes + 2; + t->rn_r = ttt; + t->rn_p = t; + tt = t->rn_l; + tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; + tt->rn_b = -1 - off; + *ttt = *tt; + ttt->rn_key = rn_ones; + rnh->rnh_addaddr = rn_addroute; + rnh->rnh_deladdr = rn_delete; + rnh->rnh_matchaddr = rn_match; + rnh->rnh_lookup = rn_lookup; + rnh->rnh_walktree = rn_walktree; + rnh->rnh_walktree_from = rn_walktree_from; + rnh->rnh_treetop = t; + return (1); +} + +void +rn_init() +{ + char *cp, *cplim; +#ifdef KERNEL + struct domain *dom; + + for (dom = domains; dom; dom = dom->dom_next) + if (dom->dom_maxrtkey > max_keylen) + max_keylen = dom->dom_maxrtkey; +#endif + if (max_keylen == 0) { + log(LOG_ERR, + "rn_init: radix functions require max_keylen be set\n"); + return; + } + R_Malloc(rn_zeros, char *, 3 * max_keylen); + if (rn_zeros == NULL) + panic("rn_init"); + Bzero(rn_zeros, 3 * max_keylen); + rn_ones = cp = rn_zeros + max_keylen; + addmask_key = cplim = rn_ones + max_keylen; + while (cp < cplim) + *cp++ = -1; + if (rn_inithead((void **)&mask_rnhead, 0) == 0) + panic("rn_init 2"); +} diff --git a/cpukit/libnetworking/net/radix.h b/cpukit/libnetworking/net/radix.h new file mode 100644 index 0000000000..6ef9aafbac --- /dev/null +++ b/cpukit/libnetworking/net/radix.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1988, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)radix.h 8.2 (Berkeley) 10/31/94 + * $Id$ + */ + +#ifndef _RADIX_H_ +#define _RADIX_H_ + +/* + * Radix search tree node layout. + */ + +struct radix_node { + struct radix_mask *rn_mklist; /* list of masks contained in subtree */ + struct radix_node *rn_p; /* parent */ + short rn_b; /* bit offset; -1-index(netmask) */ + char rn_bmask; /* node: mask for bit test*/ + u_char rn_flags; /* enumerated next */ +#define RNF_NORMAL 1 /* leaf contains normal route */ +#define RNF_ROOT 2 /* leaf is root leaf for tree */ +#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */ + union { + struct { /* leaf only data: */ + caddr_t rn_Key; /* object of search */ + caddr_t rn_Mask; /* netmask, if present */ + struct radix_node *rn_Dupedkey; + } rn_leaf; + struct { /* node only data: */ + int rn_Off; /* where to start compare */ + struct radix_node *rn_L;/* progeny */ + struct radix_node *rn_R;/* progeny */ + } rn_node; + } rn_u; +#ifdef RN_DEBUG + int rn_info; + struct radix_node *rn_twin; + struct radix_node *rn_ybro; +#endif +}; + +#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey +#define rn_key rn_u.rn_leaf.rn_Key +#define rn_mask rn_u.rn_leaf.rn_Mask +#define rn_off rn_u.rn_node.rn_Off +#define rn_l rn_u.rn_node.rn_L +#define rn_r rn_u.rn_node.rn_R + +/* + * Annotations to tree concerning potential routes applying to subtrees. + */ + +extern struct radix_mask { + short rm_b; /* bit offset; -1-index(netmask) */ + char rm_unused; /* cf. rn_bmask */ + u_char rm_flags; /* cf. rn_flags */ + struct radix_mask *rm_mklist; /* more masks to try */ + union { + caddr_t rmu_mask; /* the mask */ + struct radix_node *rmu_leaf; /* for normal routes */ + } rm_rmu; + int rm_refs; /* # of references to this struct */ +} *rn_mkfreelist; + +#define rm_mask rm_rmu.rmu_mask +#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ + +#define MKGet(m) {\ + if (rn_mkfreelist) {\ + m = rn_mkfreelist; \ + rn_mkfreelist = (m)->rm_mklist; \ + } else \ + R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\ + +#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);} + +typedef int walktree_f_t __P((struct radix_node *, void *)); + +struct radix_node_head { + struct radix_node *rnh_treetop; + int rnh_addrsize; /* permit, but not require fixed keys */ + int rnh_pktsize; /* permit, but not require fixed keys */ + struct radix_node *(*rnh_addaddr) /* add based on sockaddr */ + __P((void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[])); + struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ + __P((void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[])); + struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ + __P((void *v, void *mask, struct radix_node_head *head)); + struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ + __P((void *v, void *mask, struct radix_node_head *head)); + struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ + __P((void *v, struct radix_node_head *head)); + struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ + __P((void *v, void *mask, struct radix_node_head *head)); + struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ + __P((void *v, struct radix_node_head *head)); + int (*rnh_walktree) /* traverse tree */ + __P((struct radix_node_head *head, walktree_f_t *f, void *w)); + int (*rnh_walktree_from) /* traverse tree below a */ + __P((struct radix_node_head *head, void *a, void *m, + walktree_f_t *f, void *w)); + void (*rnh_close) /* do something when the last ref drops */ + __P((struct radix_node *rn, struct radix_node_head *head)); + struct radix_node rnh_nodes[3]; /* empty tree for common case */ +}; + +#ifndef KERNEL +#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n)) +#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n)) +#define Bzero(p, n) bzero((char *)(p), (int)(n)); +#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n))) +#define Free(p) free((char *)p); +#else +#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n)) +#define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n)) +#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n)); +#define R_Malloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_DONTWAIT)) +#define Free(p) free((caddr_t)p, M_RTABLE); +#endif /*KERNEL*/ + +extern struct radix_node_head *mask_rnhead; + +void rn_init __P((void)); +int rn_inithead __P((void **, int)); +int rn_refines __P((void *, void *)); +struct radix_node + *rn_addmask __P((void *, int, int)), + *rn_addroute __P((void *, void *, struct radix_node_head *, + struct radix_node [2])), + *rn_match __P((void *, struct radix_node_head *)); + + +#endif /* _RADIX_H_ */ diff --git a/cpukit/libnetworking/net/raw_cb.c b/cpukit/libnetworking/net/raw_cb.c new file mode 100644 index 0000000000..0676931cdc --- /dev/null +++ b/cpukit/libnetworking/net/raw_cb.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)raw_cb.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/raw_cb.h> +#include <netinet/in.h> + +/* + * Routines to manage the raw protocol control blocks. + * + * TODO: + * hash lookups by protocol family/protocol + address family + * take care of unique address problems per AF? + * redo address binding to allow wildcards + */ + +struct rawcb rawcb; +static u_long raw_sendspace = RAWSNDQ; +static u_long raw_recvspace = RAWRCVQ; + +/* + * Allocate a control block and a nominal amount + * of buffer space for the socket. + */ +int +raw_attach(so, proto) + register struct socket *so; + int proto; +{ + register struct rawcb *rp = sotorawcb(so); + int error; + + /* + * It is assumed that raw_attach is called + * after space has been allocated for the + * rawcb. + */ + if (rp == 0) + return (ENOBUFS); + error = soreserve(so, raw_sendspace, raw_recvspace); + if (error) + return (error); + rp->rcb_socket = so; + rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family; + rp->rcb_proto.sp_protocol = proto; + insque(rp, &rawcb); + return (0); +} + +/* + * Detach the raw connection block and discard + * socket resources. + */ +void +raw_detach(rp) + register struct rawcb *rp; +{ + struct socket *so = rp->rcb_socket; + + so->so_pcb = 0; + sofree(so); + remque(rp); +#ifdef notdef + if (rp->rcb_laddr) + m_freem(dtom(rp->rcb_laddr)); + rp->rcb_laddr = 0; +#endif + free((caddr_t)(rp), M_PCB); +} + +/* + * Disconnect and possibly release resources. + */ +void +raw_disconnect(rp) + struct rawcb *rp; +{ + +#ifdef notdef + if (rp->rcb_faddr) + m_freem(dtom(rp->rcb_faddr)); + rp->rcb_faddr = 0; +#endif + if (rp->rcb_socket->so_state & SS_NOFDREF) + raw_detach(rp); +} + +#ifdef notdef +int +raw_bind(so, nam) + register struct socket *so; + struct mbuf *nam; +{ + struct sockaddr *addr = mtod(nam, struct sockaddr *); + register struct rawcb *rp; + + if (ifnet == 0) + return (EADDRNOTAVAIL); + rp = sotorawcb(so); + nam = m_copym(nam, 0, M_COPYALL, M_WAITOK); + rp->rcb_laddr = mtod(nam, struct sockaddr *); + return (0); +} +#endif diff --git a/cpukit/libnetworking/net/raw_cb.h b/cpukit/libnetworking/net/raw_cb.h new file mode 100644 index 0000000000..c1ed5e5e0a --- /dev/null +++ b/cpukit/libnetworking/net/raw_cb.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)raw_cb.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_RAW_CB_H_ +#define _NET_RAW_CB_H_ + +/* + * Raw protocol interface control block. Used + * to tie a socket to the generic raw interface. + */ +struct rawcb { + struct rawcb *rcb_next; /* doubly linked list */ + struct rawcb *rcb_prev; + struct socket *rcb_socket; /* back pointer to socket */ + struct sockaddr *rcb_faddr; /* destination address */ + struct sockaddr *rcb_laddr; /* socket's address */ + struct sockproto rcb_proto; /* protocol family, protocol */ +}; + +#define sotorawcb(so) ((struct rawcb *)(so)->so_pcb) + +/* + * Nominal space allocated to a raw socket. + */ +#define RAWSNDQ 8192 +#define RAWRCVQ 8192 + +#ifdef KERNEL +extern struct rawcb rawcb; /* head of list */ + +int raw_attach __P((struct socket *, int)); +void raw_ctlinput __P((int, struct sockaddr *, void *)); +void raw_detach __P((struct rawcb *)); +void raw_disconnect __P((struct rawcb *)); +void raw_init __P((void)); +void raw_input __P((struct mbuf *, + struct sockproto *, struct sockaddr *, struct sockaddr *)); +int raw_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +#endif + +#endif diff --git a/cpukit/libnetworking/net/raw_usrreq.c b/cpukit/libnetworking/net/raw_usrreq.c new file mode 100644 index 0000000000..fb4faf4d6d --- /dev/null +++ b/cpukit/libnetworking/net/raw_usrreq.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)raw_usrreq.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/netisr.h> +#include <net/raw_cb.h> + +/* + * Initialize raw connection block q. + */ +void +raw_init() +{ + + rawcb.rcb_next = rawcb.rcb_prev = &rawcb; +} + + +/* + * Raw protocol input routine. Find the socket + * associated with the packet(s) and move them over. If + * nothing exists for this packet, drop it. + */ +/* + * Raw protocol interface. + */ +void +raw_input(m0, proto, src, dst) + struct mbuf *m0; + register struct sockproto *proto; + struct sockaddr *src, *dst; +{ + register struct rawcb *rp; + register struct mbuf *m = m0; + register int sockets = 0; + struct socket *last; + + last = 0; + for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { + if (rp->rcb_proto.sp_family != proto->sp_family) + continue; + if (rp->rcb_proto.sp_protocol && + rp->rcb_proto.sp_protocol != proto->sp_protocol) + continue; + /* + * We assume the lower level routines have + * placed the address in a canonical format + * suitable for a structure comparison. + * + * Note that if the lengths are not the same + * the comparison will fail at the first byte. + */ +#define equal(a1, a2) \ + (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) + if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) + continue; + if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) + continue; + if (last) { + struct mbuf *n; + n = m_copy(m, 0, (int)M_COPYALL); + if (n) { + if (sbappendaddr(&last->so_rcv, src, + n, (struct mbuf *)0) == 0) + /* should notify about lost packet */ + m_freem(n); + else { + sorwakeup(last); + sockets++; + } + } + } + last = rp->rcb_socket; + } + if (last) { + if (sbappendaddr(&last->so_rcv, src, + m, (struct mbuf *)0) == 0) + m_freem(m); + else { + sorwakeup(last); + sockets++; + } + } else + m_freem(m); +} + +/*ARGSUSED*/ +void +raw_ctlinput(cmd, arg, dummy) + int cmd; + struct sockaddr *arg; + void *dummy; +{ + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + /* INCOMPLETE */ +} + +/*ARGSUSED*/ +int +raw_usrreq(so, req, m, nam, control) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register struct rawcb *rp = sotorawcb(so); + register int error = 0; + int len; + + if (req == PRU_CONTROL) + return (EOPNOTSUPP); + if (control && control->m_len) { + error = EOPNOTSUPP; + goto release; + } + if (rp == 0) { + error = EINVAL; + goto release; + } + switch (req) { + + /* + * Allocate a raw control block and fill in the + * necessary info to allow packets to be routed to + * the appropriate raw interface routine. + */ + case PRU_ATTACH: + if ((so->so_state & SS_PRIV) == 0) { + error = EACCES; + break; + } + error = raw_attach(so, (int)nam); + break; + + /* + * Destroy state just before socket deallocation. + * Flush data or not depending on the options. + */ + case PRU_DETACH: + if (rp == 0) { + error = ENOTCONN; + break; + } + raw_detach(rp); + break; + + /* + * If a socket isn't bound to a single address, + * the raw input routine will hand it anything + * within that protocol family (assuming there's + * nothing else around it should go to). + */ + case PRU_CONNECT: + error = EINVAL; +#if 0 + if (rp->rcb_faddr) { + error = EISCONN; + break; + } + nam = m_copym(nam, 0, M_COPYALL, M_WAIT); + rp->rcb_faddr = mtod(nam, struct sockaddr *); + soisconnected(so); +#endif + break; + + case PRU_BIND: + error = EINVAL; +#if 0 + if (rp->rcb_laddr) { + error = EINVAL; /* XXX */ + break; + } + error = raw_bind(so, nam); +#endif + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; + goto release; + + case PRU_DISCONNECT: + if (rp->rcb_faddr == 0) { + error = ENOTCONN; + break; + } + raw_disconnect(rp); + soisdisconnected(so); + break; + + /* + * Mark the connection as being incapable of further input. + */ + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + /* + * Ship a packet out. The appropriate raw output + * routine handles any massaging necessary. + */ + case PRU_SEND: + if (nam) { + if (rp->rcb_faddr) { + error = EISCONN; + break; + } + rp->rcb_faddr = mtod(nam, struct sockaddr *); + } else if (rp->rcb_faddr == 0) { + error = ENOTCONN; + break; + } + error = (*so->so_proto->pr_output)(m, so); + m = NULL; + if (nam) + rp->rcb_faddr = 0; + break; + + case PRU_ABORT: + raw_disconnect(rp); + sofree(so); + soisdisconnected(so); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + /* + * Not supported. + */ + case PRU_RCVOOB: + case PRU_RCVD: + return(EOPNOTSUPP); + + case PRU_LISTEN: + case PRU_ACCEPT: + case PRU_SENDOOB: + error = EOPNOTSUPP; + break; + + case PRU_SOCKADDR: + if (rp->rcb_laddr == 0) { + error = EINVAL; + break; + } + len = rp->rcb_laddr->sa_len; + bcopy((caddr_t)rp->rcb_laddr, mtod(nam, caddr_t), (unsigned)len); + nam->m_len = len; + break; + + case PRU_PEERADDR: + if (rp->rcb_faddr == 0) { + error = ENOTCONN; + break; + } + len = rp->rcb_faddr->sa_len; + bcopy((caddr_t)rp->rcb_faddr, mtod(nam, caddr_t), (unsigned)len); + nam->m_len = len; + break; + + default: + panic("raw_usrreq"); + } +release: + if (m != NULL) + m_freem(m); + return (error); +} diff --git a/cpukit/libnetworking/net/route.c b/cpukit/libnetworking/net/route.c new file mode 100644 index 0000000000..0bea64f747 --- /dev/null +++ b/cpukit/libnetworking/net/route.c @@ -0,0 +1,959 @@ +/* + * Copyright (c) 1980, 1986, 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)route.c 8.2 (Berkeley) 11/15/93 + * $Id$ + */ + +#include "opt_mrouting.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/raw_cb.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/ip_mroute.h> + +#define SA(p) ((struct sockaddr *)(p)) + +struct route_cb route_cb; +static struct rtstat rtstat; +struct radix_node_head *rt_tables[AF_MAX+1]; + +static int rttrash; /* routes not in table but not freed */ + +static void rt_maskedcopy __P((struct sockaddr *, + struct sockaddr *, struct sockaddr *)); +static void rtable_init __P((void **)); + +static void +rtable_init(table) + void **table; +{ + struct domain *dom; + for (dom = domains; dom; dom = dom->dom_next) + if (dom->dom_rtattach) + dom->dom_rtattach(&table[dom->dom_family], + dom->dom_rtoffset); +} + +void +route_init() +{ + rn_init(); /* initialize all zeroes, all ones, mask table */ + rtable_init((void **)rt_tables); +} + +/* + * Packet routing routines. + */ +void +rtalloc(ro) + register struct route *ro; +{ + if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) + return; /* XXX */ + ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL); +} + +void +rtalloc_ign(ro, ignore) + register struct route *ro; + u_long ignore; +{ + if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) + return; /* XXX */ + ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore); +} + +/* + * Look up the route that matches the address given + * Or, at least try.. Create a cloned route if needed. + */ +struct rtentry * +rtalloc1(dst, report, ignflags) + register struct sockaddr *dst; + int report; + u_long ignflags; +{ + register struct radix_node_head *rnh = rt_tables[dst->sa_family]; + register struct rtentry *rt; + register struct radix_node *rn; + struct rtentry *newrt = 0; + struct rt_addrinfo info; + u_long nflags; + int s = splnet(), err = 0, msgtype = RTM_MISS; + + /* + * Look up the address in the table for that Address Family + */ + if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && + ((rn->rn_flags & RNF_ROOT) == 0)) { + /* + * If we find it and it's not the root node, then + * get a refernce on the rtentry associated. + */ + newrt = rt = (struct rtentry *)rn; + nflags = rt->rt_flags & ~ignflags; + if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) { + /* + * We are apparently adding (report = 0 in delete). + * If it requires that it be cloned, do so. + * (This implies it wasn't a HOST route.) + */ + err = rtrequest(RTM_RESOLVE, dst, SA(0), + SA(0), 0, &newrt); + if (err) { + /* + * If the cloning didn't succeed, maybe + * what we have will do. Return that. + */ + newrt = rt; + rt->rt_refcnt++; + goto miss; + } + if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { + /* + * If the new route specifies it be + * externally resolved, then go do that. + */ + msgtype = RTM_RESOLVE; + goto miss; + } + } else + rt->rt_refcnt++; + } else { + /* + * Either we hit the root or couldn't find any match, + * Which basically means + * "caint get there frm here" + */ + rtstat.rts_unreach++; + miss: if (report) { + /* + * If required, report the failure to the supervising + * Authorities. + * For a delete, this is not an error. (report == 0) + */ + bzero((caddr_t)&info, sizeof(info)); + info.rti_info[RTAX_DST] = dst; + rt_missmsg(msgtype, &info, 0, err); + } + } + splx(s); + return (newrt); +} + +void +rtfree(rt) + register struct rtentry *rt; +{ + register struct radix_node_head *rnh = + rt_tables[rt_key(rt)->sa_family]; + register struct ifaddr *ifa; + + if (rt == 0 || rnh == 0) + panic("rtfree"); + rt->rt_refcnt--; + if(rnh->rnh_close && rt->rt_refcnt == 0) { + rnh->rnh_close((struct radix_node *)rt, rnh); + } + if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { + if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) + panic ("rtfree 2"); + rttrash--; + if (rt->rt_refcnt < 0) { + printf("rtfree: %p not freed (neg refs)\n", rt); + return; + } + ifa = rt->rt_ifa; + IFAFREE(ifa); + if (rt->rt_parent) { + RTFREE(rt->rt_parent); + } + Free(rt_key(rt)); + Free(rt); + } +} + +void +ifafree(ifa) + register struct ifaddr *ifa; +{ + if (ifa == NULL) + panic("ifafree"); + if (ifa->ifa_refcnt == 0) + free(ifa, M_IFADDR); + else + ifa->ifa_refcnt--; +} + +/* + * Force a routing table entry to the specified + * destination to go through the given gateway. + * Normally called as a result of a routing redirect + * message from the network layer. + * + * N.B.: must be called at splnet + * + */ +void +rtredirect(dst, gateway, netmask, flags, src, rtp) + struct sockaddr *dst, *gateway, *netmask, *src; + int flags; + struct rtentry **rtp; +{ + register struct rtentry *rt; + int error = 0; + short *stat = 0; + struct rt_addrinfo info; + struct ifaddr *ifa; + + /* verify the gateway is directly reachable */ + if ((ifa = ifa_ifwithnet(gateway)) == 0) { + error = ENETUNREACH; + goto out; + } + rt = rtalloc1(dst, 0, 0UL); + /* + * If the redirect isn't from our current router for this dst, + * it's either old or wrong. If it redirects us to ourselves, + * we have a routing loop, perhaps as a result of an interface + * going down recently. + */ +#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) + if (!(flags & RTF_DONE) && rt && + (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) + error = EINVAL; + else if (ifa_ifwithaddr(gateway)) + error = EHOSTUNREACH; + if (error) + goto done; + /* + * Create a new entry if we just got back a wildcard entry + * or the the lookup failed. This is necessary for hosts + * which use routing redirects generated by smart gateways + * to dynamically build the routing tables. + */ + if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) + goto create; + /* + * Don't listen to the redirect if it's + * for a route to an interface. + */ + if (rt->rt_flags & RTF_GATEWAY) { + if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { + /* + * Changing from route to net => route to host. + * Create new route, rather than smashing route to net. + */ + create: + flags |= RTF_GATEWAY | RTF_DYNAMIC; + error = rtrequest((int)RTM_ADD, dst, gateway, + netmask, flags, + (struct rtentry **)0); + stat = &rtstat.rts_dynamic; + } else { + /* + * Smash the current notion of the gateway to + * this destination. Should check about netmask!!! + */ + rt->rt_flags |= RTF_MODIFIED; + flags |= RTF_MODIFIED; + stat = &rtstat.rts_newgateway; + rt_setgate(rt, rt_key(rt), gateway); + } + } else + error = EHOSTUNREACH; +done: + if (rt) { + if (rtp && !error) + *rtp = rt; + else + rtfree(rt); + } +out: + if (error) + rtstat.rts_badredirect++; + else if (stat != NULL) + (*stat)++; + bzero((caddr_t)&info, sizeof(info)); + info.rti_info[RTAX_DST] = dst; + info.rti_info[RTAX_GATEWAY] = gateway; + info.rti_info[RTAX_NETMASK] = netmask; + info.rti_info[RTAX_AUTHOR] = src; + rt_missmsg(RTM_REDIRECT, &info, flags, error); +} + +/* +* Routing table ioctl interface. +*/ +int +rtioctl(req, data, p) + int req; + caddr_t data; + struct proc *p; +{ +#ifdef INET + /* Multicast goop, grrr... */ +#ifdef MROUTING + return mrt_ioctl(req, data); +#else + return mrt_ioctl(req, data, p); +#endif +#else /* INET */ + return ENXIO; +#endif /* INET */ +} + +struct ifaddr * +ifa_ifwithroute(flags, dst, gateway) + int flags; + struct sockaddr *dst, *gateway; +{ + register struct ifaddr *ifa; + if ((flags & RTF_GATEWAY) == 0) { + /* + * If we are adding a route to an interface, + * and the interface is a pt to pt link + * we should search for the destination + * as our clue to the interface. Otherwise + * we can use the local address. + */ + ifa = 0; + if (flags & RTF_HOST) { + ifa = ifa_ifwithdstaddr(dst); + } + if (ifa == 0) + ifa = ifa_ifwithaddr(gateway); + } else { + /* + * If we are adding a route to a remote net + * or host, the gateway may still be on the + * other end of a pt to pt link. + */ + ifa = ifa_ifwithdstaddr(gateway); + } + if (ifa == 0) + ifa = ifa_ifwithnet(gateway); + if (ifa == 0) { + struct rtentry *rt = rtalloc1(dst, 0, 0UL); + if (rt == 0) + return (0); + rt->rt_refcnt--; + if ((ifa = rt->rt_ifa) == 0) + return (0); + } + if (ifa->ifa_addr->sa_family != dst->sa_family) { + struct ifaddr *oifa = ifa; + ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); + if (ifa == 0) + ifa = oifa; + } + return (ifa); +} + +#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +static int rt_fixdelete(struct radix_node *, void *); +static int rt_fixchange(struct radix_node *, void *); + +struct rtfc_arg { + struct rtentry *rt0; + struct radix_node_head *rnh; +}; + +/* + * Do appropriate manipulations of a routing tree given + * all the bits of info needed + */ +int +rtrequest(req, dst, gateway, netmask, flags, ret_nrt) + int req, flags; + struct sockaddr *dst, *gateway, *netmask; + struct rtentry **ret_nrt; +{ + int s = splnet(); int error = 0; + register struct rtentry *rt; + register struct radix_node *rn; + register struct radix_node_head *rnh; + struct ifaddr *ifa; + struct sockaddr *ndst; +#define senderr(x) { error = x ; goto bad; } + + /* + * Find the correct routing tree to use for this Address Family + */ + if ((rnh = rt_tables[dst->sa_family]) == 0) + senderr(ESRCH); + /* + * If we are adding a host route then we don't want to put + * a netmask in the tree + */ + if (flags & RTF_HOST) + netmask = 0; + switch (req) { + case RTM_DELETE: + /* + * Remove the item from the tree and return it. + * Complain if it is not there and do no more processing. + */ + if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) + senderr(ESRCH); + if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) + panic ("rtrequest delete"); + rt = (struct rtentry *)rn; + + /* + * Now search what's left of the subtree for any cloned + * routes which might have been formed from this node. + */ + if ((rt->rt_flags & RTF_PRCLONING) && netmask) { + rnh->rnh_walktree_from(rnh, dst, netmask, + rt_fixdelete, rt); + } + + /* + * Remove any external references we may have. + * This might result in another rtentry being freed if + * we held it's last reference. + */ + if (rt->rt_gwroute) { + rt = rt->rt_gwroute; + RTFREE(rt); + (rt = (struct rtentry *)rn)->rt_gwroute = 0; + } + + /* + * NB: RTF_UP must be set during the search above, + * because we might delete the last ref, causing + * rt to get freed prematurely. + */ + rt->rt_flags &= ~RTF_UP; + + /* + * If there is llinfo or similar associated with the + * route, give the interface a chance to deal with it.. + */ + if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) + ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); + rttrash++; + /* + * If the caller wants it, then it can have it, but it's up to it + * to free the rtentry as we won't be doing it. + */ + if (ret_nrt) + *ret_nrt = rt; + else if (rt->rt_refcnt <= 0) { + rt->rt_refcnt++; /* make a 1->0 transition */ + rtfree(rt); + } + break; + + case RTM_RESOLVE: + if (ret_nrt == 0 || (rt = *ret_nrt) == 0) + senderr(EINVAL); + ifa = rt->rt_ifa; + flags = rt->rt_flags & + ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC); + flags |= RTF_WASCLONED; + gateway = rt->rt_gateway; + if ((netmask = rt->rt_genmask) == 0) + flags |= RTF_HOST; + goto makeroute; + + case RTM_ADD: + if ((flags & RTF_GATEWAY) && !gateway) + panic("rtrequest: GATEWAY but no gateway"); + + if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) + senderr(ENETUNREACH); + + makeroute: + R_Malloc(rt, struct rtentry *, sizeof(*rt)); + if (rt == 0) + senderr(ENOBUFS); + Bzero(rt, sizeof(*rt)); + rt->rt_flags = RTF_UP | flags; + if (error = rt_setgate(rt, dst, gateway)) { + Free(rt); + senderr(error); + } + ndst = rt_key(rt); + if (netmask) { + rt_maskedcopy(dst, ndst, netmask); + } else + Bcopy(dst, ndst, dst->sa_len); + + /* + * This moved from below so that rnh->rnh_addaddr() can + * examine the ifa and ifp if it so desires. + */ + ifa->ifa_refcnt++; + rt->rt_ifa = ifa; + rt->rt_ifp = ifa->ifa_ifp; + + rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, + rnh, rt->rt_nodes); + if (rn == 0) { + struct rtentry *rt2; + /* + * Uh-oh, we already have one of these in the tree. + * We do a special hack: if the route that's already + * there was generated by the protocol-cloning + * mechanism, then we just blow it away and retry + * the insertion of the new one. + */ + rt2 = rtalloc1(dst, 0, RTF_PRCLONING); + if (rt2 && rt2->rt_parent) { + rtrequest(RTM_DELETE, + (struct sockaddr *)rt_key(rt2), + rt2->rt_gateway, + rt_mask(rt2), rt2->rt_flags, 0); + RTFREE(rt2); + rn = rnh->rnh_addaddr((caddr_t)ndst, + (caddr_t)netmask, + rnh, rt->rt_nodes); + } else if (rt2) { + RTFREE(rt2); + } + } + + if (rn == 0) { + if (rt->rt_gwroute) + rtfree(rt->rt_gwroute); + if (rt->rt_ifa) { + IFAFREE(rt->rt_ifa); + } + Free(rt_key(rt)); + Free(rt); + senderr(EEXIST); + } + rt->rt_parent = 0; + + if (req == RTM_RESOLVE) { + rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ + if ((*ret_nrt)->rt_flags & RTF_PRCLONING) { + rt->rt_parent = (*ret_nrt); + (*ret_nrt)->rt_refcnt++; + } + } + if (ifa->ifa_rtrequest) + ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); + /* + * We repeat the same procedure from rt_setgate() here because + * it doesn't fire when we call it there because the node + * hasn't been added to the tree yet. + */ + if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { + struct rtfc_arg arg; + arg.rnh = rnh; + arg.rt0 = rt; + rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), + rt_fixchange, &arg); + } + + if (ret_nrt) { + *ret_nrt = rt; + rt->rt_refcnt++; + } + break; + } +bad: + splx(s); + return (error); +} + +/* + * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family'' + * (i.e., the routes related to it by the operation of cloning). This + * routine is iterated over all potential former-child-routes by way of + * rnh->rnh_walktree_from() above, and those that actually are children of + * the late parent (passed in as VP here) are themselves deleted. + */ +static int +rt_fixdelete(struct radix_node *rn, void *vp) +{ + struct rtentry *rt = (struct rtentry *)rn; + struct rtentry *rt0 = vp; + + if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) { + return rtrequest(RTM_DELETE, rt_key(rt), + (struct sockaddr *)0, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + } + return 0; +} + +/* + * This routine is called from rt_setgate() to do the analogous thing for + * adds and changes. There is the added complication in this case of a + * middle insert; i.e., insertion of a new network route between an older + * network route and (cloned) host routes. For this reason, a simple check + * of rt->rt_parent is insufficient; each candidate route must be tested + * against the (mask, value) of the new route (passed as before in vp) + * to see if the new route matches it. Unfortunately, this has the obnoxious + * property of also triggering for insertion /above/ a pre-existing network + * route and clones. Sigh. This may be fixed some day. + * + * XXX - it may be possible to do fixdelete() for changes and reserve this + * routine just for adds. I'm not sure why I thought it was necessary to do + * changes this way. + */ +#ifdef DEBUG +int rtfcdebug = 0; +#endif + +static int +rt_fixchange(struct radix_node *rn, void *vp) +{ + struct rtentry *rt = (struct rtentry *)rn; + struct rtfc_arg *ap = vp; + struct rtentry *rt0 = ap->rt0; + struct radix_node_head *rnh = ap->rnh; + u_char *xk1, *xm1, *xk2; + int i, len; + +#ifdef DEBUG + if (rtfcdebug) + printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0); +#endif + + if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) { +#ifdef DEBUG + if(rtfcdebug) printf("no parent or pinned\n"); +#endif + return 0; + } + + if (rt->rt_parent == rt0) { +#ifdef DEBUG + if(rtfcdebug) printf("parent match\n"); +#endif + return rtrequest(RTM_DELETE, rt_key(rt), + (struct sockaddr *)0, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + } + + /* + * There probably is a function somewhere which does this... + * if not, there should be. + */ + len = imin(((struct sockaddr *)rt_key(rt0))->sa_len, + ((struct sockaddr *)rt_key(rt))->sa_len); + + xk1 = (u_char *)rt_key(rt0); + xm1 = (u_char *)rt_mask(rt0); + xk2 = (u_char *)rt_key(rt); + + for (i = rnh->rnh_treetop->rn_off; i < len; i++) { + if ((xk2[i] & xm1[i]) != xk1[i]) { +#ifdef DEBUG + if(rtfcdebug) printf("no match\n"); +#endif + return 0; + } + } + + /* + * OK, this node is a clone, and matches the node currently being + * changed/added under the node's mask. So, get rid of it. + */ +#ifdef DEBUG + if(rtfcdebug) printf("deleting\n"); +#endif + return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, + rt_mask(rt), rt->rt_flags, (struct rtentry **)0); +} + +int +rt_setgate(rt0, dst, gate) + struct rtentry *rt0; + struct sockaddr *dst, *gate; +{ + caddr_t new, old; + int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); + register struct rtentry *rt = rt0; + struct radix_node_head *rnh = rt_tables[dst->sa_family]; + + /* + * A host route with the destination equal to the gateway + * will interfere with keeping LLINFO in the routing + * table, so disallow it. + */ + if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) == + (RTF_HOST|RTF_GATEWAY)) && + (dst->sa_len == gate->sa_len) && + (bcmp(dst, gate, dst->sa_len) == 0)) { + /* + * The route might already exist if this is an RTM_CHANGE + * or a routing redirect, so try to delete it. + */ + if (rt_key(rt0)) + rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0), + rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0); + return EADDRNOTAVAIL; + } + + if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { + old = (caddr_t)rt_key(rt); + R_Malloc(new, caddr_t, dlen + glen); + if (new == 0) + return ENOBUFS; + rt->rt_nodes->rn_key = new; + } else { + new = rt->rt_nodes->rn_key; + old = 0; + } + Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); + if (old) { + Bcopy(dst, new, dlen); + Free(old); + } + if (rt->rt_gwroute) { + rt = rt->rt_gwroute; RTFREE(rt); + rt = rt0; rt->rt_gwroute = 0; + } + /* + * Cloning loop avoidance: + * In the presence of protocol-cloning and bad configuration, + * it is possible to get stuck in bottomless mutual recursion + * (rtrequest rt_setgate rtalloc1). We avoid this by not allowing + * protocol-cloning to operate for gateways (which is probably the + * correct choice anyway), and avoid the resulting reference loops + * by disallowing any route to run through itself as a gateway. + * This is obviuosly mandatory when we get rt->rt_output(). + */ + if (rt->rt_flags & RTF_GATEWAY) { + rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING); + if (rt->rt_gwroute == rt) { + RTFREE(rt->rt_gwroute); + rt->rt_gwroute = 0; + return EDQUOT; /* failure */ + } + } + + /* + * This isn't going to do anything useful for host routes, so + * don't bother. Also make sure we have a reasonable mask + * (we don't yet have one during adds). + */ + if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { + struct rtfc_arg arg; + arg.rnh = rnh; + arg.rt0 = rt; + rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), + rt_fixchange, &arg); + } + + return 0; +} + +static void +rt_maskedcopy(src, dst, netmask) + struct sockaddr *src, *dst, *netmask; +{ + register u_char *cp1 = (u_char *)src; + register u_char *cp2 = (u_char *)dst; + register u_char *cp3 = (u_char *)netmask; + u_char *cplim = cp2 + *cp3; + u_char *cplim2 = cp2 + *cp1; + + *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ + cp3 += 2; + if (cplim > cplim2) + cplim = cplim2; + while (cp2 < cplim) + *cp2++ = *cp1++ & *cp3++; + if (cp2 < cplim2) + bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); +} + +/* + * Set up a routing table entry, normally + * for an interface. + */ +int +rtinit(ifa, cmd, flags) + register struct ifaddr *ifa; + int cmd, flags; +{ + register struct rtentry *rt; + register struct sockaddr *dst; + register struct sockaddr *deldst; + struct mbuf *m = 0; + struct rtentry *nrt = 0; + int error; + + dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; + /* + * If it's a delete, check that if it exists, it's on the correct + * interface or we might scrub a route to another ifa which would + * be confusing at best and possibly worse. + */ + if (cmd == RTM_DELETE) { + /* + * It's a delete, so it should already exist.. + * If it's a net, mask off the host bits + * (Assuming we have a mask) + */ + if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { + m = m_get(M_WAIT, MT_SONAME); + deldst = mtod(m, struct sockaddr *); + rt_maskedcopy(dst, deldst, ifa->ifa_netmask); + dst = deldst; + } + /* + * Get an rtentry that is in the routing tree and + * contains the correct info. (if this fails we can't get there). + * We set "report" to FALSE so that if it doesn't exist, + * it doesn't report an error or clone a route, etc. etc. + */ + rt = rtalloc1(dst, 0, 0UL); + if (rt) { + /* + * Ok so we found the rtentry. it has an extra reference + * for us at this stage. we won't need that so + * lop that off now. + */ + rt->rt_refcnt--; + if (rt->rt_ifa != ifa) { + /* + * If the interface in the rtentry doesn't match + * the interface we are using, then we don't + * want to delete it, so return an error. + * This seems to be the only point of + * this whole RTM_DELETE clause. + */ + if (m) + (void) m_free(m); + return (flags & RTF_HOST ? EHOSTUNREACH + : ENETUNREACH); + } + } + /* XXX */ +#if 0 + else { + /* + * One would think that as we are deleting, and we know + * it doesn't exist, we could just return at this point + * with an "ELSE" clause, but apparently not.. + */ + return (flags & RTF_HOST ? EHOSTUNREACH + : ENETUNREACH); + } +#endif + } + /* + * Do the actual request + */ + error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, + flags | ifa->ifa_flags, &nrt); + if (m) + (void) m_free(m); + /* + * If we are deleting, and we found an entry, then + * it's been removed from the tree.. now throw it away. + */ + if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { + /* + * notify any listenning routing agents of the change + */ + rt_newaddrmsg(cmd, ifa, error, nrt); + if (rt->rt_refcnt <= 0) { + rt->rt_refcnt++; /* need a 1->0 transition to free */ + rtfree(rt); + } + } + + /* + * We are adding, and we have a returned routing entry. + * We need to sanity check the result. + */ + if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { + /* + * We just wanted to add it.. we don't actually need a reference + */ + rt->rt_refcnt--; + /* + * If it came back with an unexpected interface, then it must + * have already existed or something. (XXX) + */ + if (rt->rt_ifa != ifa) { + printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, + rt->rt_ifa); + /* + * Ask that the route we got back be removed + * from the routing tables as we are trying + * to supersede it. + */ + if (rt->rt_ifa->ifa_rtrequest) + rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); + /* + * Remove the referenve to the it's ifaddr. + */ + IFAFREE(rt->rt_ifa); + /* + * And substitute in references to the ifaddr + * we are adding. + */ + rt->rt_ifa = ifa; + rt->rt_ifp = ifa->ifa_ifp; + ifa->ifa_refcnt++; + /* + * Now add it to the routing table + * XXX could we have just left it? + * as it might have been in the right place.. + */ + if (ifa->ifa_rtrequest) + ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); + } + /* + * notify any listenning routing agents of the change + */ + rt_newaddrmsg(cmd, ifa, error, nrt); + } + return (error); +} diff --git a/cpukit/libnetworking/net/route.h b/cpukit/libnetworking/net/route.h new file mode 100644 index 0000000000..69d76909fc --- /dev/null +++ b/cpukit/libnetworking/net/route.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)route.h 8.3 (Berkeley) 4/19/94 + * $Id$ + */ + +#ifndef _NET_ROUTE_H_ +#define _NET_ROUTE_H_ + +/* + * Kernel resident routing tables. + * + * The routing tables are initialized when interface addresses + * are set by making entries for all directly connected interfaces. + */ + +/* + * A route consists of a destination address and a reference + * to a routing entry. These are often held by protocols + * in their control blocks, e.g. inpcb. + */ +struct route { + struct rtentry *ro_rt; + struct sockaddr ro_dst; +}; + +/* + * These numbers are used by reliable protocols for determining + * retransmission behavior and are included in the routing structure. + */ +struct rt_metrics { + u_long rmx_locks; /* Kernel must leave these values alone */ + u_long rmx_mtu; /* MTU for this path */ + u_long rmx_hopcount; /* max hops expected */ + u_long rmx_expire; /* lifetime for route, e.g. redirect */ + u_long rmx_recvpipe; /* inbound delay-bandwidth product */ + u_long rmx_sendpipe; /* outbound delay-bandwidth product */ + u_long rmx_ssthresh; /* outbound gateway buffer limit */ + u_long rmx_rtt; /* estimated round trip time */ + u_long rmx_rttvar; /* estimated rtt variance */ + u_long rmx_pksent; /* packets sent using this route */ + u_long rmx_filler[4]; /* will be used for T/TCP later */ +}; + +/* + * rmx_rtt and rmx_rttvar are stored as microseconds; + * RTTTOPRHZ(rtt) converts to a value suitable for use + * by a protocol slowtimo counter. + */ +#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ +#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ)) + +/* + * XXX kernel function pointer `rt_output' is visible to applications. + */ +struct mbuf; + +/* + * We distinguish between routes to hosts and routes to networks, + * preferring the former if available. For each route we infer + * the interface to use from the gateway address supplied when + * the route was entered. Routes that forward packets through + * gateways are marked so that the output routines know to address the + * gateway rather than the ultimate destination. + */ +#ifndef RNF_NORMAL +#include <net/radix.h> +#endif +struct rtentry { + struct radix_node rt_nodes[2]; /* tree glue, and other values */ +#define rt_key(r) ((struct sockaddr *)((r)->rt_nodes->rn_key)) +#define rt_mask(r) ((struct sockaddr *)((r)->rt_nodes->rn_mask)) + struct sockaddr *rt_gateway; /* value */ + short rt_filler; /* was short flags field */ + short rt_refcnt; /* # held references */ + u_long rt_flags; /* up/down?, host/net */ + struct ifnet *rt_ifp; /* the answer: interface to use */ + struct ifaddr *rt_ifa; /* the answer: interface to use */ + struct sockaddr *rt_genmask; /* for generation of cloned routes */ + caddr_t rt_llinfo; /* pointer to link level info cache */ + struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ + struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ + int (*rt_output) __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); + /* output routine for this (rt,if) */ + struct rtentry *rt_parent; /* cloning parent of this route */ + void *rt_filler2; /* more filler */ +}; + +/* + * Following structure necessary for 4.3 compatibility; + * We should eventually move it to a compat file. + */ +struct ortentry { + u_long rt_hash; /* to speed lookups */ + struct sockaddr rt_dst; /* key */ + struct sockaddr rt_gateway; /* value */ + short rt_flags; /* up/down?, host/net */ + short rt_refcnt; /* # held references */ + u_long rt_use; /* raw # packets forwarded */ + struct ifnet *rt_ifp; /* the answer: interface to use */ +}; + +#define rt_use rt_rmx.rmx_pksent + +#define RTF_UP 0x1 /* route usable */ +#define RTF_GATEWAY 0x2 /* destination is a gateway */ +#define RTF_HOST 0x4 /* host entry (net otherwise) */ +#define RTF_REJECT 0x8 /* host or net unreachable */ +#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ +#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ +#define RTF_DONE 0x40 /* message confirmed */ +/* 0x80 unused */ +#define RTF_CLONING 0x100 /* generate new routes on use */ +#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ +#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ +#define RTF_STATIC 0x800 /* manually added */ +#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ +#define RTF_PROTO2 0x4000 /* protocol specific routing flag */ +#define RTF_PROTO1 0x8000 /* protocol specific routing flag */ + +#define RTF_PRCLONING 0x10000 /* protocol requires cloning */ +#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +#define RTF_PROTO3 0x40000 /* protocol specific routing flag */ +/* 0x80000 unused */ +#define RTF_PINNED 0x100000 /* future use */ +#define RTF_LOCAL 0x200000 /* route represents a local address */ +#define RTF_BROADCAST 0x400000 /* route represents a bcast address */ +#define RTF_MULTICAST 0x800000 /* route represents a mcast address */ + /* 0x1000000 and up unassigned */ + +/* + * Routing statistics. + */ +struct rtstat { + short rts_badredirect; /* bogus redirect calls */ + short rts_dynamic; /* routes created by redirects */ + short rts_newgateway; /* routes modified by redirects */ + short rts_unreach; /* lookups which failed */ + short rts_wildcard; /* lookups satisfied by a wildcard */ +}; +/* + * Structures for routing messages. + */ +struct rt_msghdr { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + pid_t rtm_pid; /* identify sender */ + int rtm_seq; /* for sender to identify action */ + int rtm_errno; /* why failed */ + int rtm_use; /* from rtentry */ + u_long rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + +#define RTM_VERSION 5 /* Up the ante and ignore older versions */ + +#define RTM_ADD 0x1 /* Add Route */ +#define RTM_DELETE 0x2 /* Delete Route */ +#define RTM_CHANGE 0x3 /* Change Metrics or flags */ +#define RTM_GET 0x4 /* Report Metrics */ +#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */ +#define RTM_REDIRECT 0x6 /* Told to use different route */ +#define RTM_MISS 0x7 /* Lookup failed on this address */ +#define RTM_LOCK 0x8 /* fix specified metrics */ +#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ +#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ +#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ +#define RTM_NEWADDR 0xc /* address being added to iface */ +#define RTM_DELADDR 0xd /* address being removed from iface */ +#define RTM_IFINFO 0xe /* iface going up/down etc. */ + +#define RTV_MTU 0x1 /* init or lock _mtu */ +#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ +#define RTV_EXPIRE 0x4 /* init or lock _hopcount */ +#define RTV_RPIPE 0x8 /* init or lock _recvpipe */ +#define RTV_SPIPE 0x10 /* init or lock _sendpipe */ +#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ +#define RTV_RTT 0x40 /* init or lock _rtt */ +#define RTV_RTTVAR 0x80 /* init or lock _rttvar */ + +/* + * Bitmask values for rtm_addr. + */ +#define RTA_DST 0x1 /* destination sockaddr present */ +#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ +#define RTA_NETMASK 0x4 /* netmask sockaddr present */ +#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ +#define RTA_IFP 0x10 /* interface name sockaddr present */ +#define RTA_IFA 0x20 /* interface addr sockaddr present */ +#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ +#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ + +/* + * Index offsets for sockaddr array for alternate internal encoding. + */ +#define RTAX_DST 0 /* destination sockaddr present */ +#define RTAX_GATEWAY 1 /* gateway sockaddr present */ +#define RTAX_NETMASK 2 /* netmask sockaddr present */ +#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ +#define RTAX_IFP 4 /* interface name sockaddr present */ +#define RTAX_IFA 5 /* interface addr sockaddr present */ +#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ +#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ +#define RTAX_MAX 8 /* size of array to allocate */ + +struct rt_addrinfo { + int rti_addrs; + struct sockaddr *rti_info[RTAX_MAX]; +}; + +struct route_cb { + int ip_count; + int ipx_count; + int ns_count; + int iso_count; + int any_count; +}; + +#ifdef KERNEL +#define RTFREE(rt) \ + if ((rt)->rt_refcnt <= 1) \ + rtfree(rt); \ + else \ + (rt)->rt_refcnt--; + +extern struct route_cb route_cb; +extern struct rtstat rtstat; +extern struct radix_node_head *rt_tables[AF_MAX+1]; + +void route_init __P((void)); +void rt_ifmsg __P((struct ifnet *)); +void rt_missmsg __P((int, struct rt_addrinfo *, int, int)); +void rt_newaddrmsg __P((int, struct ifaddr *, int, struct rtentry *)); +int rt_setgate __P((struct rtentry *, + struct sockaddr *, struct sockaddr *)); +void rtalloc __P((struct route *)); +void rtalloc_ign __P((struct route *, unsigned long)); +struct rtentry * + rtalloc1 __P((struct sockaddr *, int, unsigned long)); +void rtfree __P((struct rtentry *)); +int rtinit __P((struct ifaddr *, int, int)); +int rtioctl __P((int, caddr_t, struct proc *)); +void rtredirect __P((struct sockaddr *, struct sockaddr *, + struct sockaddr *, int, struct sockaddr *, struct rtentry **)); +int rtrequest __P((int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, struct rtentry **)); +#endif + +#endif diff --git a/cpukit/libnetworking/net/rtsock.c b/cpukit/libnetworking/net/rtsock.c new file mode 100644 index 0000000000..2a08181000 --- /dev/null +++ b/cpukit/libnetworking/net/rtsock.c @@ -0,0 +1,829 @@ +/* + * Copyright (c) 1988, 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)rtsock.c 8.5 (Berkeley) 11/2/94 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/raw_cb.h> + +static struct sockaddr route_dst = { 2, PF_ROUTE, }; +static struct sockaddr route_src = { 2, PF_ROUTE, }; +static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, }; +static struct sockproto route_proto = { PF_ROUTE, }; + +struct walkarg { + int w_tmemsize; + int w_op, w_arg; + caddr_t w_tmem; + struct sysctl_req *w_req; +}; + +static struct mbuf * + rt_msg1 __P((int, struct rt_addrinfo *)); +static int rt_msg2 __P((int, + struct rt_addrinfo *, caddr_t, struct walkarg *)); +static int rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); +static int sysctl_dumpentry __P((struct radix_node *rn, void *vw)); +static int sysctl_iflist __P((int af, struct walkarg *w)); +static int route_output __P((struct mbuf *, struct socket *)); +static int route_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +static void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *)); + +/* Sleazy use of local variables throughout file, warning!!!! */ +#define dst info.rti_info[RTAX_DST] +#define gate info.rti_info[RTAX_GATEWAY] +#define netmask info.rti_info[RTAX_NETMASK] +#define genmask info.rti_info[RTAX_GENMASK] +#define ifpaddr info.rti_info[RTAX_IFP] +#define ifaaddr info.rti_info[RTAX_IFA] +#define brdaddr info.rti_info[RTAX_BRD] + +/*ARGSUSED*/ +static int +route_usrreq(so, req, m, nam, control) + register struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register int error = 0; + register struct rawcb *rp = sotorawcb(so); + int s; + + if (req == PRU_ATTACH) { + MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); + so->so_pcb = (caddr_t)rp; + if (so->so_pcb) + bzero(so->so_pcb, sizeof(*rp)); + } + if (req == PRU_DETACH && rp) { + int af = rp->rcb_proto.sp_protocol; + if (af == AF_INET) + route_cb.ip_count--; + else if (af == AF_IPX) + route_cb.ipx_count--; + else if (af == AF_NS) + route_cb.ns_count--; + else if (af == AF_ISO) + route_cb.iso_count--; + route_cb.any_count--; + } + s = splnet(); + error = raw_usrreq(so, req, m, nam, control); + rp = sotorawcb(so); + if (req == PRU_ATTACH && rp) { + int af = rp->rcb_proto.sp_protocol; + if (error) { + free((caddr_t)rp, M_PCB); + splx(s); + return (error); + } + if (af == AF_INET) + route_cb.ip_count++; + else if (af == AF_IPX) + route_cb.ipx_count++; + else if (af == AF_NS) + route_cb.ns_count++; + else if (af == AF_ISO) + route_cb.iso_count++; + rp->rcb_faddr = &route_src; + route_cb.any_count++; + soisconnected(so); + so->so_options |= SO_USELOOPBACK; + } + splx(s); + return (error); +} + +/*ARGSUSED*/ +static int +route_output(m, so) + register struct mbuf *m; + struct socket *so; +{ + register struct rt_msghdr *rtm = 0; + register struct rtentry *rt = 0; + struct rtentry *saved_nrt = 0; + struct radix_node_head *rnh; + struct rt_addrinfo info; + int len, error = 0; + struct ifnet *ifp = 0; + struct ifaddr *ifa = 0; + +#define senderr(e) { error = e; goto flush;} + if (m == 0 || ((m->m_len < sizeof(long)) && + (m = m_pullup(m, sizeof(long))) == 0)) + return (ENOBUFS); + if ((m->m_flags & M_PKTHDR) == 0) + panic("route_output"); + len = m->m_pkthdr.len; + if (len < sizeof(*rtm) || + len != mtod(m, struct rt_msghdr *)->rtm_msglen) { + dst = 0; + senderr(EINVAL); + } + R_Malloc(rtm, struct rt_msghdr *, len); + if (rtm == 0) { + dst = 0; + senderr(ENOBUFS); + } + m_copydata(m, 0, len, (caddr_t)rtm); + if (rtm->rtm_version != RTM_VERSION) { + dst = 0; + senderr(EPROTONOSUPPORT); + } + info.rti_addrs = rtm->rtm_addrs; + if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) { + dst = 0; + senderr(EINVAL); + } + if (dst == 0 || (dst->sa_family >= AF_MAX) + || (gate != 0 && (gate->sa_family >= AF_MAX))) + senderr(EINVAL); + if (genmask) { + struct radix_node *t; + t = rn_addmask((caddr_t)genmask, 0, 1); + if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) + genmask = (struct sockaddr *)(t->rn_key); + else + senderr(ENOBUFS); + } + switch (rtm->rtm_type) { + + case RTM_ADD: + if (gate == 0) + senderr(EINVAL); + error = rtrequest(RTM_ADD, dst, gate, netmask, + rtm->rtm_flags, &saved_nrt); + if (error == 0 && saved_nrt) { + rt_setmetrics(rtm->rtm_inits, + &rtm->rtm_rmx, &saved_nrt->rt_rmx); + saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); + saved_nrt->rt_rmx.rmx_locks |= + (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); + saved_nrt->rt_refcnt--; + saved_nrt->rt_genmask = genmask; + } + break; + + case RTM_DELETE: + error = rtrequest(RTM_DELETE, dst, gate, netmask, + rtm->rtm_flags, &saved_nrt); + if (error == 0) { + if ((rt = saved_nrt)) + rt->rt_refcnt++; + goto report; + } + break; + + case RTM_GET: + case RTM_CHANGE: + case RTM_LOCK: + if ((rnh = rt_tables[dst->sa_family]) == 0) { + senderr(EAFNOSUPPORT); + } else if (rt = (struct rtentry *) + rnh->rnh_lookup(dst, netmask, rnh)) + rt->rt_refcnt++; + else + senderr(ESRCH); + switch(rtm->rtm_type) { + + case RTM_GET: + report: + dst = rt_key(rt); + gate = rt->rt_gateway; + netmask = rt_mask(rt); + genmask = rt->rt_genmask; + if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { + ifp = rt->rt_ifp; + if (ifp) { + ifpaddr = ifp->if_addrlist->ifa_addr; + ifaaddr = rt->rt_ifa->ifa_addr; + rtm->rtm_index = ifp->if_index; + } else { + ifpaddr = 0; + ifaaddr = 0; + } + } + len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0, + (struct walkarg *)0); + if (len > rtm->rtm_msglen) { + struct rt_msghdr *new_rtm; + R_Malloc(new_rtm, struct rt_msghdr *, len); + if (new_rtm == 0) + senderr(ENOBUFS); + Bcopy(rtm, new_rtm, rtm->rtm_msglen); + Free(rtm); rtm = new_rtm; + } + (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, + (struct walkarg *)0); + rtm->rtm_flags = rt->rt_flags; + rtm->rtm_rmx = rt->rt_rmx; + rtm->rtm_addrs = info.rti_addrs; + break; + + case RTM_CHANGE: + if (gate && (error = rt_setgate(rt, rt_key(rt), gate))) + senderr(error); + + /* + * If they tried to change things but didn't specify + * the required gateway, then just use the old one. + * This can happen if the user tries to change the + * flags on the default route without changing the + * default gateway. Changing flags still doesn't work. + */ + if ((rt->rt_flags & RTF_GATEWAY) && !gate) + gate = rt->rt_gateway; + + /* new gateway could require new ifaddr, ifp; + flags may also be different; ifp may be specified + by ll sockaddr when protocol address is ambiguous */ + if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && + (ifp = ifa->ifa_ifp) && (ifaaddr || gate)) + ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, + ifp); + else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || + (gate && (ifa = ifa_ifwithroute(rt->rt_flags, + rt_key(rt), gate)))) + ifp = ifa->ifa_ifp; + if (ifa) { + register struct ifaddr *oifa = rt->rt_ifa; + if (oifa != ifa) { + if (oifa && oifa->ifa_rtrequest) + oifa->ifa_rtrequest(RTM_DELETE, + rt, gate); + IFAFREE(rt->rt_ifa); + rt->rt_ifa = ifa; + ifa->ifa_refcnt++; + rt->rt_ifp = ifp; + } + } + rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, + &rt->rt_rmx); + if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) + rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); + if (genmask) + rt->rt_genmask = genmask; + /* + * Fall into + */ + case RTM_LOCK: + rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); + rt->rt_rmx.rmx_locks |= + (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); + break; + } + break; + + default: + senderr(EOPNOTSUPP); + } + +flush: + if (rtm) { + if (error) + rtm->rtm_errno = error; + else + rtm->rtm_flags |= RTF_DONE; + } + if (rt) + rtfree(rt); + { + register struct rawcb *rp = 0; + /* + * Check to see if we don't want our own messages. + */ + if ((so->so_options & SO_USELOOPBACK) == 0) { + if (route_cb.any_count <= 1) { + if (rtm) + Free(rtm); + m_freem(m); + return (error); + } + /* There is another listener, so construct message */ + rp = sotorawcb(so); + } + if (rtm) { + m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); + Free(rtm); + } + if (rp) + rp->rcb_proto.sp_family = 0; /* Avoid us */ + if (dst) + route_proto.sp_protocol = dst->sa_family; + raw_input(m, &route_proto, &route_src, &route_dst); + if (rp) + rp->rcb_proto.sp_family = PF_ROUTE; + } + return (error); +} + +static void +rt_setmetrics(which, in, out) + u_long which; + register struct rt_metrics *in, *out; +{ +#define metric(f, e) if (which & (f)) out->e = in->e; + metric(RTV_RPIPE, rmx_recvpipe); + metric(RTV_SPIPE, rmx_sendpipe); + metric(RTV_SSTHRESH, rmx_ssthresh); + metric(RTV_RTT, rmx_rtt); + metric(RTV_RTTVAR, rmx_rttvar); + metric(RTV_HOPCOUNT, rmx_hopcount); + metric(RTV_MTU, rmx_mtu); + metric(RTV_EXPIRE, rmx_expire); +#undef metric +} + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + + +/* + * Extract the addresses of the passed sockaddrs. + * Do a little sanity checking so as to avoid bad memory references. + * This data is derived straight from userland. + */ +static int +rt_xaddrs(cp, cplim, rtinfo) + register caddr_t cp, cplim; + register struct rt_addrinfo *rtinfo; +{ + register struct sockaddr *sa; + register int i; + + bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); + for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { + if ((rtinfo->rti_addrs & (1 << i)) == 0) + continue; + sa = (struct sockaddr *)cp; + /* + * It won't fit. + */ + if ( (cp + sa->sa_len) > cplim ) { + return (EINVAL); + } + + /* + * there are no more.. quit now + * If there are more bits, they are in error. + * I've seen this. route(1) can evidently generate these. + * This causes kernel to core dump. + * for compatibility, If we see this, point to a safe address. + */ + if (sa->sa_len == 0) { + rtinfo->rti_info[i] = &sa_zero; + return (0); /* should be EINVAL but for compat */ + } + + /* accept it */ + rtinfo->rti_info[i] = sa; + ADVANCE(cp, sa); + } + return (0); +} + +static struct mbuf * +rt_msg1(type, rtinfo) + int type; + register struct rt_addrinfo *rtinfo; +{ + register struct rt_msghdr *rtm; + register struct mbuf *m; + register int i; + register struct sockaddr *sa; + int len, dlen; + + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == 0) + return (m); + switch (type) { + + case RTM_DELADDR: + case RTM_NEWADDR: + len = sizeof(struct ifa_msghdr); + break; + + case RTM_IFINFO: + len = sizeof(struct if_msghdr); + break; + + default: + len = sizeof(struct rt_msghdr); + } + if (len > MHLEN) + panic("rt_msg1"); + m->m_pkthdr.len = m->m_len = len; + m->m_pkthdr.rcvif = 0; + rtm = mtod(m, struct rt_msghdr *); + bzero((caddr_t)rtm, len); + for (i = 0; i < RTAX_MAX; i++) { + if ((sa = rtinfo->rti_info[i]) == NULL) + continue; + rtinfo->rti_addrs |= (1 << i); + dlen = ROUNDUP(sa->sa_len); + m_copyback(m, len, dlen, (caddr_t)sa); + len += dlen; + } + if (m->m_pkthdr.len != len) { + m_freem(m); + return (NULL); + } + rtm->rtm_msglen = len; + rtm->rtm_version = RTM_VERSION; + rtm->rtm_type = type; + return (m); +} + +static int +rt_msg2(type, rtinfo, cp, w) + int type; + register struct rt_addrinfo *rtinfo; + caddr_t cp; + struct walkarg *w; +{ + register int i; + int len, dlen, second_time = 0; + caddr_t cp0; + + rtinfo->rti_addrs = 0; +again: + switch (type) { + + case RTM_DELADDR: + case RTM_NEWADDR: + len = sizeof(struct ifa_msghdr); + break; + + case RTM_IFINFO: + len = sizeof(struct if_msghdr); + break; + + default: + len = sizeof(struct rt_msghdr); + } + cp0 = cp; + if (cp0) + cp += len; + for (i = 0; i < RTAX_MAX; i++) { + register struct sockaddr *sa; + + if ((sa = rtinfo->rti_info[i]) == 0) + continue; + rtinfo->rti_addrs |= (1 << i); + dlen = ROUNDUP(sa->sa_len); + if (cp) { + bcopy((caddr_t)sa, cp, (unsigned)dlen); + cp += dlen; + } + len += dlen; + } + if (cp == 0 && w != NULL && !second_time) { + register struct walkarg *rw = w; + + if (rw->w_req) { + if (rw->w_tmemsize < len) { + if (rw->w_tmem) + free(rw->w_tmem, M_RTABLE); + rw->w_tmem = (caddr_t) + malloc(len, M_RTABLE, M_NOWAIT); + if (rw->w_tmem) + rw->w_tmemsize = len; + } + if (rw->w_tmem) { + cp = rw->w_tmem; + second_time = 1; + goto again; + } + } + } + if (cp) { + register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; + + rtm->rtm_version = RTM_VERSION; + rtm->rtm_type = type; + rtm->rtm_msglen = len; + } + return (len); +} + +/* + * This routine is called to generate a message from the routing + * socket indicating that a redirect has occured, a routing lookup + * has failed, or that a protocol has detected timeouts to a particular + * destination. + */ +void +rt_missmsg(type, rtinfo, flags, error) + int type, flags, error; + register struct rt_addrinfo *rtinfo; +{ + register struct rt_msghdr *rtm; + register struct mbuf *m; + struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; + + if (route_cb.any_count == 0) + return; + m = rt_msg1(type, rtinfo); + if (m == 0) + return; + rtm = mtod(m, struct rt_msghdr *); + rtm->rtm_flags = RTF_DONE | flags; + rtm->rtm_errno = error; + rtm->rtm_addrs = rtinfo->rti_addrs; + route_proto.sp_protocol = sa ? sa->sa_family : 0; + raw_input(m, &route_proto, &route_src, &route_dst); +} + +/* + * This routine is called to generate a message from the routing + * socket indicating that the status of a network interface has changed. + */ +void +rt_ifmsg(ifp) + register struct ifnet *ifp; +{ + register struct if_msghdr *ifm; + struct mbuf *m; + struct rt_addrinfo info; + + if (route_cb.any_count == 0) + return; + bzero((caddr_t)&info, sizeof(info)); + m = rt_msg1(RTM_IFINFO, &info); + if (m == 0) + return; + ifm = mtod(m, struct if_msghdr *); + ifm->ifm_index = ifp->if_index; + ifm->ifm_flags = (u_short)ifp->if_flags; + ifm->ifm_data = ifp->if_data; + ifm->ifm_addrs = 0; + route_proto.sp_protocol = 0; + raw_input(m, &route_proto, &route_src, &route_dst); +} + +/* + * This is called to generate messages from the routing socket + * indicating a network interface has had addresses associated with it. + * if we ever reverse the logic and replace messages TO the routing + * socket indicate a request to configure interfaces, then it will + * be unnecessary as the routing socket will automatically generate + * copies of it. + */ +void +rt_newaddrmsg(cmd, ifa, error, rt) + int cmd, error; + register struct ifaddr *ifa; + register struct rtentry *rt; +{ + struct rt_addrinfo info; + struct sockaddr *sa = 0; + int pass; + struct mbuf *m = 0; + struct ifnet *ifp = ifa->ifa_ifp; + + if (route_cb.any_count == 0) + return; + for (pass = 1; pass < 3; pass++) { + bzero((caddr_t)&info, sizeof(info)); + if ((cmd == RTM_ADD && pass == 1) || + (cmd == RTM_DELETE && pass == 2)) { + register struct ifa_msghdr *ifam; + int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; + + ifaaddr = sa = ifa->ifa_addr; + ifpaddr = ifp->if_addrlist->ifa_addr; + netmask = ifa->ifa_netmask; + brdaddr = ifa->ifa_dstaddr; + if ((m = rt_msg1(ncmd, &info)) == NULL) + continue; + ifam = mtod(m, struct ifa_msghdr *); + ifam->ifam_index = ifp->if_index; + ifam->ifam_metric = ifa->ifa_metric; + ifam->ifam_flags = ifa->ifa_flags; + ifam->ifam_addrs = info.rti_addrs; + } + if ((cmd == RTM_ADD && pass == 2) || + (cmd == RTM_DELETE && pass == 1)) { + register struct rt_msghdr *rtm; + + if (rt == 0) + continue; + netmask = rt_mask(rt); + dst = sa = rt_key(rt); + gate = rt->rt_gateway; + if ((m = rt_msg1(cmd, &info)) == NULL) + continue; + rtm = mtod(m, struct rt_msghdr *); + rtm->rtm_index = ifp->if_index; + rtm->rtm_flags |= rt->rt_flags; + rtm->rtm_errno = error; + rtm->rtm_addrs = info.rti_addrs; + } + route_proto.sp_protocol = sa ? sa->sa_family : 0; + raw_input(m, &route_proto, &route_src, &route_dst); + } +} + + +/* + * This is used in dumping the kernel table via sysctl(). + */ +int +sysctl_dumpentry(rn, vw) + struct radix_node *rn; + void *vw; +{ + register struct walkarg *w = vw; + register struct rtentry *rt = (struct rtentry *)rn; + int error = 0, size; + struct rt_addrinfo info; + + if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) + return 0; + bzero((caddr_t)&info, sizeof(info)); + dst = rt_key(rt); + gate = rt->rt_gateway; + netmask = rt_mask(rt); + genmask = rt->rt_genmask; + size = rt_msg2(RTM_GET, &info, 0, w); + if (w->w_req && w->w_tmem) { + register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; + + rtm->rtm_flags = rt->rt_flags; + rtm->rtm_use = rt->rt_use; + rtm->rtm_rmx = rt->rt_rmx; + rtm->rtm_index = rt->rt_ifp->if_index; + rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; + rtm->rtm_addrs = info.rti_addrs; + error = 0; + return (error); + } + return (error); +} + +int +sysctl_iflist(af, w) + int af; + register struct walkarg *w; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + struct rt_addrinfo info; + int len, error = 0; + + bzero((caddr_t)&info, sizeof(info)); + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if (w->w_arg && w->w_arg != ifp->if_index) + continue; + ifa = ifp->if_addrlist; + ifpaddr = ifa->ifa_addr; + len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); + ifpaddr = 0; + if (w->w_req && w->w_tmem) { + register struct if_msghdr *ifm; + + ifm = (struct if_msghdr *)w->w_tmem; + ifm->ifm_index = ifp->if_index; + ifm->ifm_flags = (u_short)ifp->if_flags; + ifm->ifm_data = ifp->if_data; + ifm->ifm_addrs = info.rti_addrs; + error =0; + if (error) + return (error); + } + while ((ifa = ifa->ifa_next) != 0) { + if (af && af != ifa->ifa_addr->sa_family) + continue; + ifaaddr = ifa->ifa_addr; + netmask = ifa->ifa_netmask; + brdaddr = ifa->ifa_dstaddr; + len = rt_msg2(RTM_NEWADDR, &info, 0, w); + if (w->w_req && w->w_tmem) { + register struct ifa_msghdr *ifam; + + ifam = (struct ifa_msghdr *)w->w_tmem; + ifam->ifam_index = ifa->ifa_ifp->if_index; + ifam->ifam_flags = ifa->ifa_flags; + ifam->ifam_metric = ifa->ifa_metric; + ifam->ifam_addrs = info.rti_addrs; + error = 0; + if (error) + return (error); + } + } + ifaaddr = netmask = brdaddr = 0; + } + return (0); +} + +static int +sysctl_rtsock SYSCTL_HANDLER_ARGS +{ + int *name = (int *)arg1; + u_int namelen = arg2; + register struct radix_node_head *rnh; + int i, s, error = EINVAL; + u_char af; + struct walkarg w; + + name ++; + namelen--; + if (req->newptr) + return (EPERM); + if (namelen != 3) + return (EINVAL); + af = name[0]; + Bzero(&w, sizeof(w)); + w.w_op = name[1]; + w.w_arg = name[2]; + w.w_req = req; + + s = splnet(); + switch (w.w_op) { + + case NET_RT_DUMP: + case NET_RT_FLAGS: + for (i = 1; i <= AF_MAX; i++) + if ((rnh = rt_tables[i]) && (af == 0 || af == i) && + (error = rnh->rnh_walktree(rnh, + sysctl_dumpentry, &w))) + break; + break; + + case NET_RT_IFLIST: + error = sysctl_iflist(af, &w); + } + splx(s); + if (w.w_tmem) + free(w.w_tmem, M_RTABLE); + return (error); +} + +SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock,""); + +/* + * Definitions of protocols supported in the ROUTE domain. + */ + +extern struct domain routedomain; /* or at least forward */ + +static struct protosw routesw[] = { +{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, + 0, route_output, raw_ctlinput, 0, + route_usrreq, + raw_init +} +}; + +struct domain routedomain = + { PF_ROUTE, "route", route_init, 0, 0, + routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; + +DOMAIN_SET(route); diff --git a/cpukit/libnetworking/netdb.h b/cpukit/libnetworking/netdb.h new file mode 100644 index 0000000000..ec274f851f --- /dev/null +++ b/cpukit/libnetworking/netdb.h @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1980, 1983, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +/* + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * From: Id: netdb.h,v 8.9 1996/11/19 08:39:29 vixie Exp $ + * $Id$ + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +#include <sys/cdefs.h> + +#ifndef _PATH_HEQUIV +# define _PATH_HEQUIV "/etc/hosts.equiv" +#endif +#define _PATH_HOSTS "/etc/hosts" +#define _PATH_NETWORKS "/etc/networks" +#define _PATH_PROTOCOLS "/etc/protocols" +#define _PATH_SERVICES "/etc/services" + +extern int h_errno; + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatibility */ +}; + +/* + * Assumption here is that a network number + * fits in an unsigned long -- probably a poor one. + */ +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + int n_addrtype; /* net address type */ + unsigned long n_net; /* network # */ +}; + +struct servent { + char *s_name; /* official service name */ + char **s_aliases; /* alias list */ + int s_port; /* port # */ + char *s_proto; /* protocol to use */ +}; + +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +__BEGIN_DECLS +void endhostent __P((void)); +void endnetent __P((void)); +void endprotoent __P((void)); +void endservent __P((void)); +struct hostent *gethostbyaddr __P((const char *, int, int)); +struct hostent *gethostbyname __P((const char *)); +struct hostent *gethostbyname2 __P((const char *, int)); +struct hostent *gethostent __P((void)); +struct netent *getnetbyaddr __P((unsigned long, int)); +struct netent *getnetbyname __P((const char *)); +struct netent *getnetent __P((void)); +struct protoent *getprotobyname __P((const char *)); +struct protoent *getprotobynumber __P((int)); +struct protoent *getprotoent __P((void)); +struct servent *getservbyname __P((const char *, const char *)); +struct servent *getservbyport __P((int, const char *)); +struct servent *getservent __P((void)); +void herror __P((const char *)); +__const char *hstrerror __P((int)); +void sethostent __P((int)); +/* void sethostfile __P((const char *)); */ +void setnetent __P((int)); +void setprotoent __P((int)); +void setservent __P((int)); + +/* + * PRIVATE functions specific to the FreeBSD implementation + */ + +/* DO NOT USE THESE, THEY ARE SUBJECT TO CHANGE AND ARE NOT PORTABLE!!! */ +void _sethosthtent __P((int)); +void _endhosthtent __P((void)); +void _sethostdnsent __P((int)); +void _endhostdnsent __P((void)); +void _setnethtent __P((int)); +void _endnethtent __P((void)); +void _setnetdnsent __P((int)); +void _endnetdnsent __P((void)); +struct hostent * _gethostbyhtname __P((const char *, int)); +struct hostent * _gethostbydnsname __P((const char *, int)); +struct hostent * _gethostbynisname __P((const char *, int)); +struct hostent * _gethostbyhtaddr __P((const char *, int, int)); +struct hostent * _gethostbydnsaddr __P((const char *, int, int)); +struct hostent * _gethostbynisaddr __P((const char *, int, int)); +struct netent * _getnetbyhtname __P((const char *)); +struct netent * _getnetbydnsname __P((const char *)); +struct netent * _getnetbynisname __P((const char *)); +struct netent * _getnetbyhtaddr __P((unsigned long, int)); +struct netent * _getnetbydnsaddr __P((unsigned long, int)); +struct netent * _getnetbynisaddr __P((unsigned long, int)); +void _map_v4v6_address __P((const char *src, char *dst)); +void _map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len)); +__END_DECLS + +#endif /* !_NETDB_H_ */ diff --git a/cpukit/libnetworking/netinet/icmp_var.h b/cpukit/libnetworking/netinet/icmp_var.h new file mode 100644 index 0000000000..7657f31acf --- /dev/null +++ b/cpukit/libnetworking/netinet/icmp_var.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_ICMP_VAR_H_ +#define _NETINET_ICMP_VAR_H_ + +/* + * Variables related to this implementation + * of the internet control message protocol. + */ +struct icmpstat { +/* statistics related to icmp packets generated */ + u_long icps_error; /* # of calls to icmp_error */ + u_long icps_oldshort; /* no error 'cuz old ip too short */ + u_long icps_oldicmp; /* no error 'cuz old was icmp */ + u_long icps_outhist[ICMP_MAXTYPE + 1]; +/* statistics related to input messages processed */ + u_long icps_badcode; /* icmp_code out of range */ + u_long icps_tooshort; /* packet < ICMP_MINLEN */ + u_long icps_checksum; /* bad checksum */ + u_long icps_badlen; /* calculated bound mismatch */ + u_long icps_reflect; /* number of responses */ + u_long icps_inhist[ICMP_MAXTYPE + 1]; + u_long icps_bmcastecho; /* b/mcast echo requests dropped */ + u_long icps_bmcasttstamp; /* b/mcast tstamp requests dropped */ +}; + +/* + * Names for ICMP sysctl objects + */ +#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ +#define ICMPCTL_STATS 2 /* statistics (read-only) */ +#define ICMPCTL_MAXID 3 + +#define ICMPCTL_NAMES { \ + { 0, 0 }, \ + { "maskrepl", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ +} + +#ifdef KERNEL +extern struct icmpstat icmpstat; +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/if_ether.c b/cpukit/libnetworking/netinet/if_ether.c new file mode 100644 index 0000000000..985ce6e7d9 --- /dev/null +++ b/cpukit/libnetworking/netinet/if_ether.c @@ -0,0 +1,638 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +/* + * Ethernet address resolution protocol. + * TODO: + * add "inuse/lock" bit (or ref. count) along with valid bit + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <net/netisr.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> + +#define SIN(s) ((struct sockaddr_in *)s) +#define SDL(s) ((struct sockaddr_dl *)s) + +SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); + +/* timer values */ +static int arpt_prune = (5*60*1); /* walk list every 5 minutes */ +static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ +static int arpt_down = 20; /* once declared down, don't send for 20 sec */ + +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, + &arpt_prune, 0, ""); +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, + &arpt_keep, 0, ""); +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW, + &arpt_down, 0, ""); + +#define rt_expire rt_rmx.rmx_expire + +struct llinfo_arp { + LIST_ENTRY(llinfo_arp) la_le; + struct rtentry *la_rt; + struct mbuf *la_hold; /* last packet until resolved/timeout */ + long la_asked; /* last time we QUERIED for this addr */ +#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */ +}; + +static LIST_HEAD(, llinfo_arp) llinfo_arp; + +struct ifqueue arpintrq = {0, 0, 0, 50}; +static int arp_inuse, arp_allocated; + +static int arp_maxtries = 5; +static int useloopback = 1; /* use loopback interface for local traffic */ +static int arp_proxyall = 0; + +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, + &arp_maxtries, 0, ""); +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, + &useloopback, 0, ""); +SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, + &arp_proxyall, 0, ""); + +static void arp_rtrequest __P((int, struct rtentry *, struct sockaddr *)); +static void arprequest __P((struct arpcom *, u_long *, u_long *, u_char *)); +void arpintr __P((void)); +static void arptfree __P((struct llinfo_arp *)); +static void arptimer __P((void *)); +static struct llinfo_arp + *arplookup __P((u_long, int, int)); +static void in_arpinput __P((struct mbuf *)); + +/* + * Timeout routine. Age arp_tab entries periodically. + */ +/* ARGSUSED */ +static void +arptimer(ignored_arg) + void *ignored_arg; +{ + int s = splnet(); + register struct llinfo_arp *la = llinfo_arp.lh_first; + struct llinfo_arp *ola; + + timeout(arptimer, (caddr_t)0, arpt_prune * hz); + while ((ola = la) != 0) { + register struct rtentry *rt = la->la_rt; + la = la->la_le.le_next; + if (rt->rt_expire && rt->rt_expire <= rtems_bsdnet_seconds_since_boot()) + arptfree(ola); /* timer has expired, clear */ + } + splx(s); +} + +/* + * Parallel to llc_rtrequest. + */ +static void +arp_rtrequest(req, rt, sa) + int req; + register struct rtentry *rt; + struct sockaddr *sa; +{ + register struct sockaddr *gate = rt->rt_gateway; + register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; + static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; + static int arpinit_done; + + if (!arpinit_done) { + arpinit_done = 1; + LIST_INIT(&llinfo_arp); + timeout(arptimer, (caddr_t)0, hz); + } + if (rt->rt_flags & RTF_GATEWAY) + return; + switch (req) { + + case RTM_ADD: + /* + * XXX: If this is a manually added route to interface + * such as older version of routed or gated might provide, + * restore cloning bit. + */ + if ((rt->rt_flags & RTF_HOST) == 0 && + SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) + rt->rt_flags |= RTF_CLONING; + if (rt->rt_flags & RTF_CLONING) { + /* + * Case 1: This route should come from a route to iface. + */ + rt_setgate(rt, rt_key(rt), + (struct sockaddr *)&null_sdl); + gate = rt->rt_gateway; + SDL(gate)->sdl_type = rt->rt_ifp->if_type; + SDL(gate)->sdl_index = rt->rt_ifp->if_index; + rt->rt_expire = rtems_bsdnet_seconds_since_boot(); + break; + } + /* Announce a new entry if requested. */ + if (rt->rt_flags & RTF_ANNOUNCE) + arprequest((struct arpcom *)rt->rt_ifp, + &SIN(rt_key(rt))->sin_addr.s_addr, + &SIN(rt_key(rt))->sin_addr.s_addr, + (u_char *)LLADDR(SDL(gate))); + /*FALLTHROUGH*/ + case RTM_RESOLVE: + if (gate->sa_family != AF_LINK || + gate->sa_len < sizeof(null_sdl)) { + log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); + break; + } + SDL(gate)->sdl_type = rt->rt_ifp->if_type; + SDL(gate)->sdl_index = rt->rt_ifp->if_index; + if (la != 0) + break; /* This happens on a route change */ + /* + * Case 2: This route may come from cloning, or a manual route + * add with a LL address. + */ + R_Malloc(la, struct llinfo_arp *, sizeof(*la)); + rt->rt_llinfo = (caddr_t)la; + if (la == 0) { + log(LOG_DEBUG, "arp_rtrequest: malloc failed\n"); + break; + } + arp_inuse++, arp_allocated++; + Bzero(la, sizeof(*la)); + la->la_rt = rt; + rt->rt_flags |= RTF_LLINFO; + LIST_INSERT_HEAD(&llinfo_arp, la, la_le); + + /* + * This keeps the multicast addresses from showing up + * in `arp -a' listings as unresolved. It's not actually + * functional. Then the same for broadcast. + */ + if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) { + ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr, + LLADDR(SDL(gate))); + SDL(gate)->sdl_alen = 6; + rt->rt_expire = 0; + } + if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { + memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6); + SDL(gate)->sdl_alen = 6; + rt->rt_expire = 0; + } + + if (SIN(rt_key(rt))->sin_addr.s_addr == + (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { + /* + * This test used to be + * if (loif.if_flags & IFF_UP) + * It allowed local traffic to be forced + * through the hardware by configuring the loopback down. + * However, it causes problems during network configuration + * for boards that can't receive packets they send. + * It is now necessary to clear "useloopback" and remove + * the route to force traffic out to the hardware. + */ + rt->rt_expire = 0; + Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr, + LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); + if (useloopback) + rt->rt_ifp = loif; + + } + break; + + case RTM_DELETE: + if (la == 0) + break; + arp_inuse--; + LIST_REMOVE(la, la_le); + rt->rt_llinfo = 0; + rt->rt_flags &= ~RTF_LLINFO; + if (la->la_hold) + m_freem(la->la_hold); + Free((caddr_t)la); + } +} + +/* + * Broadcast an ARP request. Caller specifies: + * - arp header source ip address + * - arp header target ip address + * - arp header source ethernet address + */ +static void +arprequest(ac, sip, tip, enaddr) + register struct arpcom *ac; + register u_long *sip, *tip; + register u_char *enaddr; +{ + register struct mbuf *m; + register struct ether_header *eh; + register struct ether_arp *ea; + struct sockaddr sa; + + if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) + return; + m->m_len = sizeof(*ea); + m->m_pkthdr.len = sizeof(*ea); + MH_ALIGN(m, sizeof(*ea)); + ea = mtod(m, struct ether_arp *); + eh = (struct ether_header *)sa.sa_data; + bzero((caddr_t)ea, sizeof (*ea)); + (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */ + ea->arp_hrd = htons(ARPHRD_ETHER); + ea->arp_pro = htons(ETHERTYPE_IP); + ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ + ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ + ea->arp_op = htons(ARPOP_REQUEST); + (void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha)); + (void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa)); + (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa)); + sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); + (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); +} + +/* + * Resolve an IP address into an ethernet address. If success, + * desten is filled in. If there is no entry in arptab, + * set one up and broadcast a request for the IP address. + * Hold onto this mbuf and resend it once the address + * is finally resolved. A return value of 1 indicates + * that desten has been filled in and the packet should be sent + * normally; a 0 return indicates that the packet has been + * taken over here, either now or for later transmission. + */ +int +arpresolve(ac, rt, m, dst, desten, rt0) + register struct arpcom *ac; + register struct rtentry *rt; + struct mbuf *m; + register struct sockaddr *dst; + register u_char *desten; + struct rtentry *rt0; +{ + register struct llinfo_arp *la; + struct sockaddr_dl *sdl; + + if (m->m_flags & M_BCAST) { /* broadcast */ + (void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr)); + return (1); + } + if (m->m_flags & M_MCAST) { /* multicast */ + ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); + return(1); + } + if (rt) + la = (struct llinfo_arp *)rt->rt_llinfo; + else { + la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); + if (la) + rt = la->la_rt; + } + if (la == 0 || rt == 0) { + log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n", + inet_ntoa(SIN(dst)->sin_addr)); + m_freem(m); + return (0); + } + sdl = SDL(rt->rt_gateway); + /* + * Check the address family and length is valid, the address + * is resolved; otherwise, try to resolve. + */ + if ((rt->rt_expire == 0 || rt->rt_expire > rtems_bsdnet_seconds_since_boot()) && + sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { + bcopy(LLADDR(sdl), desten, sdl->sdl_alen); + return 1; + } + /* + * There is an arptab entry, but no ethernet address + * response yet. Replace the held mbuf with this + * latest one. + */ + if (la->la_hold) + m_freem(la->la_hold); + la->la_hold = m; + if (rt->rt_expire) { + rt->rt_flags &= ~RTF_REJECT; + if (la->la_asked == 0 || rt->rt_expire != rtems_bsdnet_seconds_since_boot()) { + rt->rt_expire = rtems_bsdnet_seconds_since_boot(); + if (la->la_asked++ < arp_maxtries) + arprequest(ac, + &(SIN(rt->rt_ifa->ifa_addr)->sin_addr.s_addr), + &(SIN(dst)->sin_addr.s_addr), + ac->ac_enaddr); + else { + rt->rt_flags |= RTF_REJECT; + rt->rt_expire += arpt_down; + la->la_asked = 0; + } + + } + } + return (0); +} + +/* + * Common length and type checks are done here, + * then the protocol-specific routine is called. + */ +void +arpintr(void) +{ + register struct mbuf *m; + register struct arphdr *ar; + int s; + + while (arpintrq.ifq_head) { + s = splimp(); + IF_DEQUEUE(&arpintrq, m); + splx(s); + if (m == 0 || (m->m_flags & M_PKTHDR) == 0) + panic("arpintr"); + if (m->m_len >= sizeof(struct arphdr) && + (ar = mtod(m, struct arphdr *)) && + ntohs(ar->ar_hrd) == ARPHRD_ETHER && + m->m_len >= + sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) + + switch (ntohs(ar->ar_pro)) { + + case ETHERTYPE_IP: + in_arpinput(m); + continue; + } + m_freem(m); + } +} + +NETISR_SET(NETISR_ARP, arpintr); + +/* + * ARP for Internet protocols on 10 Mb/s Ethernet. + * Algorithm is that given in RFC 826. + * In addition, a sanity check is performed on the sender + * protocol address, to catch impersonators. + * We no longer handle negotiations for use of trailer protocol: + * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent + * along with IP replies if we wanted trailers sent to us, + * and also sent them in response to IP replies. + * This allowed either end to announce the desire to receive + * trailer packets. + * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, + * but formerly didn't normally send requests. + */ +static void +in_arpinput(m) + struct mbuf *m; +{ + register struct ether_arp *ea; + register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; + struct ether_header *eh; + register struct llinfo_arp *la = 0; + register struct rtentry *rt; + struct in_ifaddr *ia, *maybe_ia = 0; + struct sockaddr_dl *sdl; + struct sockaddr sa; + struct in_addr isaddr, itaddr, myaddr; + int op; + + ea = mtod(m, struct ether_arp *); + op = ntohs(ea->arp_op); + (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); + (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == &ac->ac_if) { + maybe_ia = ia; + if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || + (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) + break; + } + if (maybe_ia == 0) { + m_freem(m); + return; + } + myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; + if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, + sizeof (ea->arp_sha))) { + m_freem(m); /* it's from me, ignore it. */ + return; + } + if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, + sizeof (ea->arp_sha))) { + log(LOG_ERR, + "arp: ether address is broadcast for IP address %s!\n", + inet_ntoa(isaddr)); + m_freem(m); + return; + } + if (isaddr.s_addr == myaddr.s_addr) { + log(LOG_ERR, + "arp: %6D is using my IP address %s!\n", + ea->arp_sha, ":", inet_ntoa(isaddr)); + itaddr = myaddr; + goto reply; + } + la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); + if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { + if (sdl->sdl_alen && + bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) + log(LOG_INFO, "arp: %s moved from %6D to %6D\n", + inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":", + ea->arp_sha, ":"); + (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); + sdl->sdl_alen = sizeof(ea->arp_sha); + if (rt->rt_expire) + rt->rt_expire = rtems_bsdnet_seconds_since_boot() + arpt_keep; + rt->rt_flags &= ~RTF_REJECT; + la->la_asked = 0; + if (la->la_hold) { + (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold, + rt_key(rt), rt); + la->la_hold = 0; + } + } +reply: + if (op != ARPOP_REQUEST) { + m_freem(m); + return; + } + if (itaddr.s_addr == myaddr.s_addr) { + /* I am the target */ + (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); + (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); + } else { + la = arplookup(itaddr.s_addr, 0, SIN_PROXY); + if (la == NULL) { + struct sockaddr_in sin; + + if (!arp_proxyall) { + m_freem(m); + return; + } + + bzero(&sin, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_len = sizeof sin; + sin.sin_addr = itaddr; + + rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); + if (!rt) { + m_freem(m); + return; + } + /* + * Don't send proxies for nodes on the same interface + * as this one came out of, or we'll get into a fight + * over who claims what Ether address. + */ + if (rt->rt_ifp == &ac->ac_if) { + rtfree(rt); + m_freem(m); + return; + } + (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); + (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); + rtfree(rt); +#ifdef DEBUG_PROXY + printf("arp: proxying for %s\n", + inet_ntoa(itaddr)); +#endif + } else { + rt = la->la_rt; + (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); + sdl = SDL(rt->rt_gateway); + (void)memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha)); + } + } + + (void)memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa)); + (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa)); + ea->arp_op = htons(ARPOP_REPLY); + ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ + eh = (struct ether_header *)sa.sa_data; + (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_ARP); + sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); + (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); + return; +} + +/* + * Free an arp entry. + */ +static void +arptfree(la) + register struct llinfo_arp *la; +{ + register struct rtentry *rt = la->la_rt; + register struct sockaddr_dl *sdl; + if (rt == 0) + panic("arptfree"); + if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && + sdl->sdl_family == AF_LINK) { + sdl->sdl_alen = 0; + la->la_asked = 0; + rt->rt_flags &= ~RTF_REJECT; + return; + } + rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), + 0, (struct rtentry **)0); +} +/* + * Lookup or enter a new address in arptab. + */ +static struct llinfo_arp * +arplookup(addr, create, proxy) + u_long addr; + int create, proxy; +{ + register struct rtentry *rt; + static struct sockaddr_inarp sin = {sizeof(sin), AF_INET }; + const char *why = 0; + + sin.sin_addr.s_addr = addr; + sin.sin_other = proxy ? SIN_PROXY : 0; + rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); + if (rt == 0) + return (0); + rt->rt_refcnt--; + + if (rt->rt_flags & RTF_GATEWAY) + why = "host is not on local network"; + else if ((rt->rt_flags & RTF_LLINFO) == 0) + why = "could not allocate llinfo"; + else if (rt->rt_gateway->sa_family != AF_LINK) + why = "gateway route is not ours"; + + if (why && create) { + log(LOG_DEBUG, "arplookup %s failed: %s\n", + inet_ntoa(sin.sin_addr), why); + return 0; + } else if (why) { + return 0; + } + return ((struct llinfo_arp *)rt->rt_llinfo); +} + +void +arp_ifinit(ac, ifa) + struct arpcom *ac; + struct ifaddr *ifa; +{ + if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) + arprequest(ac, &(IA_SIN(ifa)->sin_addr.s_addr), + &(IA_SIN(ifa)->sin_addr.s_addr), ac->ac_enaddr); + ifa->ifa_rtrequest = arp_rtrequest; + ifa->ifa_flags |= RTF_CLONING; +} diff --git a/cpukit/libnetworking/netinet/if_ether.h b/cpukit/libnetworking/netinet/if_ether.h new file mode 100644 index 0000000000..22c8e97187 --- /dev/null +++ b/cpukit/libnetworking/netinet/if_ether.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)if_ether.h 8.3 (Berkeley) 5/2/95 + * $Id$ + */ + +#ifndef _NETINET_IF_ETHER_H_ +#define _NETINET_IF_ETHER_H_ + +#include <net/ethernet.h> + +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ +#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */ + +/* + * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have + * (type-ETHERTYPE_TRAIL)*512 bytes of data followed + * by an ETHER type (as given above) and then the (variable-length) header. + */ +#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */ +#define ETHERTYPE_NTRAILER 16 + +#define ETHERMTU (ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) +#define ETHERMIN (ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) + +#ifdef KERNEL +/* + * Macro to map an IP multicast address to an Ethernet multicast address. + * The high-order 25 bits of the Ethernet address are statically assigned, + * and the low-order 23 bits are taken from the low end of the IP address. + */ +#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \ + /* struct in_addr *ipaddr; */ \ + /* u_char enaddr[ETHER_ADDR_LEN]; */ \ +{ \ + (enaddr)[0] = 0x01; \ + (enaddr)[1] = 0x00; \ + (enaddr)[2] = 0x5e; \ + (enaddr)[3] = ((u_char *)ipaddr)[1] & 0x7f; \ + (enaddr)[4] = ((u_char *)ipaddr)[2]; \ + (enaddr)[5] = ((u_char *)ipaddr)[3]; \ +} +#endif + +/* + * Ethernet Address Resolution Protocol. + * + * See RFC 826 for protocol description. Structure below is adapted + * to resolving internet addresses. Field names used correspond to + * RFC 826. + */ +struct ether_arp { + struct arphdr ea_hdr; /* fixed-size header */ + u_char arp_sha[ETHER_ADDR_LEN]; /* sender hardware address */ + u_char arp_spa[4]; /* sender protocol address */ + u_char arp_tha[ETHER_ADDR_LEN]; /* target hardware address */ + u_char arp_tpa[4]; /* target protocol address */ +}; +#define arp_hrd ea_hdr.ar_hrd +#define arp_pro ea_hdr.ar_pro +#define arp_hln ea_hdr.ar_hln +#define arp_pln ea_hdr.ar_pln +#define arp_op ea_hdr.ar_op + + +/* + * Structure shared between the ethernet driver modules and + * the address resolution code. For example, each ec_softc or il_softc + * begins with this structure. + */ +struct arpcom { + /* + * The ifnet struct _must_ be at the head of this structure. + */ + struct ifnet ac_if; /* network-visible interface */ + u_char ac_enaddr[ETHER_ADDR_LEN]; /* ethernet hardware address */ + struct ether_multi *ac_multiaddrs; /* list of ether multicast addrs */ + int ac_multicnt; /* length of ac_multiaddrs list */ +}; + +struct sockaddr_inarp { + u_char sin_len; + u_char sin_family; + u_short sin_port; + struct in_addr sin_addr; + struct in_addr sin_srcaddr; + u_short sin_tos; + u_short sin_other; +#define SIN_PROXY 1 +}; +/* + * IP and ethernet specific routing flags + */ +#define RTF_USETRAILERS RTF_PROTO1 /* use trailers */ +#define RTF_ANNOUNCE RTF_PROTO2 /* announce new arp entry */ + +#ifdef KERNEL +extern u_char etherbroadcastaddr[ETHER_ADDR_LEN]; +extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN]; +extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN]; +extern struct ifqueue arpintrq; + +int arpresolve __P((struct arpcom *, struct rtentry *, struct mbuf *, + struct sockaddr *, u_char *, struct rtentry *)); +void arp_ifinit __P((struct arpcom *, struct ifaddr *)); +int ether_addmulti __P((struct ifreq *, struct arpcom *)); +int ether_delmulti __P((struct ifreq *, struct arpcom *)); + +/* + * Ethernet multicast address structure. There is one of these for each + * multicast address or range of multicast addresses that we are supposed + * to listen to on a particular interface. They are kept in a linked list, + * rooted in the interface's arpcom structure. (This really has nothing to + * do with ARP, or with the Internet address family, but this appears to be + * the minimally-disrupting place to put it.) + */ +struct ether_multi { + u_char enm_addrlo[ETHER_ADDR_LEN]; /* low or only address of range */ + u_char enm_addrhi[ETHER_ADDR_LEN]; /* high or only address of range */ + struct arpcom *enm_ac; /* back pointer to arpcom */ + u_int enm_refcount; /* no. claims to this addr/range */ + struct ether_multi *enm_next; /* ptr to next ether_multi */ +}; + +/* + * Structure used by macros below to remember position when stepping through + * all of the ether_multi records. + */ +struct ether_multistep { + struct ether_multi *e_enm; +}; + +/* + * Macro for looking up the ether_multi record for a given range of Ethernet + * multicast addresses connected to a given arpcom structure. If no matching + * record is found, "enm" returns NULL. + */ +#define ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm) \ + /* u_char addrlo[ETHER_ADDR_LEN]; */ \ + /* u_char addrhi[ETHER_ADDR_LEN]; */ \ + /* struct arpcom *ac; */ \ + /* struct ether_multi *enm; */ \ +{ \ + for ((enm) = (ac)->ac_multiaddrs; \ + (enm) != NULL && \ + (bcmp((enm)->enm_addrlo, (addrlo), ETHER_ADDR_LEN) != 0 || \ + bcmp((enm)->enm_addrhi, (addrhi), ETHER_ADDR_LEN) != 0); \ + (enm) = (enm)->enm_next); \ +} + +/* + * Macro to step through all of the ether_multi records, one at a time. + * The current position is remembered in "step", which the caller must + * provide. ETHER_FIRST_MULTI(), below, must be called to initialize "step" + * and get the first record. Both macros return a NULL "enm" when there + * are no remaining records. + */ +#define ETHER_NEXT_MULTI(step, enm) \ + /* struct ether_multistep step; */ \ + /* struct ether_multi *enm; */ \ +{ \ + if (((enm) = (step).e_enm) != NULL) \ + (step).e_enm = (enm)->enm_next; \ +} + +#define ETHER_FIRST_MULTI(step, ac, enm) \ + /* struct ether_multistep step; */ \ + /* struct arpcom *ac; */ \ + /* struct ether_multi *enm; */ \ +{ \ + (step).e_enm = (ac)->ac_multiaddrs; \ + ETHER_NEXT_MULTI((step), (enm)); \ +} + +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/igmp.c b/cpukit/libnetworking/netinet/igmp.c new file mode 100644 index 0000000000..2af8b7038e --- /dev/null +++ b/cpukit/libnetworking/netinet/igmp.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 1988 Stephen Deering. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Stephen Deering of Stanford University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)igmp.c 8.1 (Berkeley) 7/19/93 + * $Id$ + */ + +/* + * Internet Group Management Protocol (IGMP) routines. + * + * Written by Steve Deering, Stanford, May 1988. + * Modified by Rosen Sharma, Stanford, Aug 1994. + * Modified by Bill Fenner, Xerox PARC, Feb 1995. + * Modified to fully comply to IGMPv2 by Bill Fenner, Oct 1995. + * + * MULTICAST Revision: 3.5.1.4 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/igmp.h> +#include <netinet/igmp_var.h> + +static struct router_info * + find_rti __P((struct ifnet *ifp)); + +static struct igmpstat igmpstat; + +SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_RD, + &igmpstat, igmpstat, ""); + +static int igmp_timers_are_running; +static u_long igmp_all_hosts_group; +static u_long igmp_all_rtrs_group; +static struct mbuf *router_alert; +static struct router_info *Head; + +static void igmp_sendpkt(struct in_multi *, int, unsigned long); + +void +igmp_init() +{ + struct ipoption *ra; + + /* + * To avoid byte-swapping the same value over and over again. + */ + igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP); + igmp_all_rtrs_group = htonl(INADDR_ALLRTRS_GROUP); + + igmp_timers_are_running = 0; + + /* + * Construct a Router Alert option to use in outgoing packets + */ + MGET(router_alert, M_DONTWAIT, MT_DATA); + ra = mtod(router_alert, struct ipoption *); + ra->ipopt_dst.s_addr = 0; + ra->ipopt_list[0] = IPOPT_RA; /* Router Alert Option */ + ra->ipopt_list[1] = 0x04; /* 4 bytes long */ + ra->ipopt_list[2] = 0x00; + ra->ipopt_list[3] = 0x00; + router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1]; + + Head = (struct router_info *) 0; +} + +static struct router_info * +find_rti(ifp) + struct ifnet *ifp; +{ + register struct router_info *rti = Head; + +#ifdef IGMP_DEBUG + printf("[igmp.c, _find_rti] --> entering \n"); +#endif + while (rti) { + if (rti->rti_ifp == ifp) { +#ifdef IGMP_DEBUG + printf("[igmp.c, _find_rti] --> found old entry \n"); +#endif + return rti; + } + rti = rti->rti_next; + } + MALLOC(rti, struct router_info *, sizeof *rti, M_MRTABLE, M_NOWAIT); + rti->rti_ifp = ifp; + rti->rti_type = IGMP_V2_ROUTER; + rti->rti_time = 0; + rti->rti_next = Head; + Head = rti; +#ifdef IGMP_DEBUG + printf("[igmp.c, _find_rti] --> created an entry \n"); +#endif + return rti; +} + +void +igmp_input(m, iphlen) + register struct mbuf *m; + register int iphlen; +{ + register struct igmp *igmp; + register struct ip *ip; + register int igmplen; + register struct ifnet *ifp = m->m_pkthdr.rcvif; + register int minlen; + register struct in_multi *inm; + register struct in_ifaddr *ia; + struct in_multistep step; + struct router_info *rti; + + int timer; /** timer value in the igmp query header **/ + + ++igmpstat.igps_rcv_total; + + ip = mtod(m, struct ip *); + igmplen = ip->ip_len; + + /* + * Validate lengths + */ + if (igmplen < IGMP_MINLEN) { + ++igmpstat.igps_rcv_tooshort; + m_freem(m); + return; + } + minlen = iphlen + IGMP_MINLEN; + if ((m->m_flags & M_EXT || m->m_len < minlen) && + (m = m_pullup(m, minlen)) == 0) { + ++igmpstat.igps_rcv_tooshort; + return; + } + + /* + * Validate checksum + */ + m->m_data += iphlen; + m->m_len -= iphlen; + igmp = mtod(m, struct igmp *); + if (in_cksum(m, igmplen)) { + ++igmpstat.igps_rcv_badsum; + m_freem(m); + return; + } + m->m_data -= iphlen; + m->m_len += iphlen; + + ip = mtod(m, struct ip *); + timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE; + rti = find_rti(ifp); + + /* + * In the IGMPv2 specification, there are 3 states and a flag. + * + * In Non-Member state, we simply don't have a membership record. + * In Delaying Member state, our timer is running (inm->inm_timer) + * In Idle Member state, our timer is not running (inm->inm_timer==0) + * + * The flag is inm->inm_state, it is set to IGMP_OTHERMEMBER if + * we have heard a report from another member, or IGMP_IREPORTEDLAST + * if I sent the last report. + */ + switch (igmp->igmp_type) { + + case IGMP_MEMBERSHIP_QUERY: + ++igmpstat.igps_rcv_queries; + + if (ifp->if_flags & IFF_LOOPBACK) + break; + + if (igmp->igmp_code == 0) { + /* + * Old router. Remember that the querier on this + * interface is old, and set the timer to the + * value in RFC 1112. + */ + + rti->rti_type = IGMP_V1_ROUTER; + rti->rti_time = 0; + + timer = IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ; + + if (ip->ip_dst.s_addr != igmp_all_hosts_group || + igmp->igmp_group.s_addr != 0) { + ++igmpstat.igps_rcv_badqueries; + m_freem(m); + return; + } + } else { + /* + * New router. Simply do the new validity check. + */ + + if (igmp->igmp_group.s_addr != 0 && + !IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) { + ++igmpstat.igps_rcv_badqueries; + m_freem(m); + return; + } + } + + /* + * - Start the timers in all of our membership records + * that the query applies to for the interface on + * which the query arrived excl. those that belong + * to the "all-hosts" group (224.0.0.1). + * - Restart any timer that is already running but has + * a value longer than the requested timeout. + * - Use the value specified in the query message as + * the maximum timeout. + */ + IN_FIRST_MULTI(step, inm); + while (inm != NULL) { + if (inm->inm_ifp == ifp && + inm->inm_addr.s_addr != igmp_all_hosts_group && + (igmp->igmp_group.s_addr == 0 || + igmp->igmp_group.s_addr == inm->inm_addr.s_addr)) { + if (inm->inm_timer == 0 || + inm->inm_timer > timer) { + inm->inm_timer = + IGMP_RANDOM_DELAY(timer); + igmp_timers_are_running = 1; + } + } + IN_NEXT_MULTI(step, inm); + } + + break; + + case IGMP_V1_MEMBERSHIP_REPORT: + case IGMP_V2_MEMBERSHIP_REPORT: + /* + * For fast leave to work, we have to know that we are the + * last person to send a report for this group. Reports + * can potentially get looped back if we are a multicast + * router, so discard reports sourced by me. + */ + IFP_TO_IA(ifp, ia); + if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr) + break; + + ++igmpstat.igps_rcv_reports; + + if (ifp->if_flags & IFF_LOOPBACK) + break; + + if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) { + ++igmpstat.igps_rcv_badreports; + m_freem(m); + return; + } + + /* + * KLUDGE: if the IP source address of the report has an + * unspecified (i.e., zero) subnet number, as is allowed for + * a booting host, replace it with the correct subnet number + * so that a process-level multicast routing demon can + * determine which subnet it arrived from. This is necessary + * to compensate for the lack of any way for a process to + * determine the arrival interface of an incoming packet. + */ + if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) + if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet); + + /* + * If we belong to the group being reported, stop + * our timer for that group. + */ + IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm); + + if (inm != NULL) { + inm->inm_timer = 0; + ++igmpstat.igps_rcv_ourreports; + + inm->inm_state = IGMP_OTHERMEMBER; + } + + break; + } + + /* + * Pass all valid IGMP packets up to any process(es) listening + * on a raw IGMP socket. + */ + rip_input(m, iphlen); +} + +void +igmp_joingroup(inm) + struct in_multi *inm; +{ + int s = splnet(); + + if (inm->inm_addr.s_addr == igmp_all_hosts_group + || inm->inm_ifp->if_flags & IFF_LOOPBACK) { + inm->inm_timer = 0; + inm->inm_state = IGMP_OTHERMEMBER; + } else { + inm->inm_rti = find_rti(inm->inm_ifp); + igmp_sendpkt(inm, inm->inm_rti->rti_type, 0); + inm->inm_timer = IGMP_RANDOM_DELAY( + IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ); + inm->inm_state = IGMP_IREPORTEDLAST; + igmp_timers_are_running = 1; + } + splx(s); +} + +void +igmp_leavegroup(inm) + struct in_multi *inm; +{ + if (inm->inm_state == IGMP_IREPORTEDLAST && + inm->inm_addr.s_addr != igmp_all_hosts_group && + !(inm->inm_ifp->if_flags & IFF_LOOPBACK) && + inm->inm_rti->rti_type != IGMP_V1_ROUTER) + igmp_sendpkt(inm, IGMP_V2_LEAVE_GROUP, igmp_all_rtrs_group); +} + +void +igmp_fasttimo() +{ + register struct in_multi *inm; + struct in_multistep step; + int s; + + /* + * Quick check to see if any work needs to be done, in order + * to minimize the overhead of fasttimo processing. + */ + + if (!igmp_timers_are_running) + return; + + s = splnet(); + igmp_timers_are_running = 0; + IN_FIRST_MULTI(step, inm); + while (inm != NULL) { + if (inm->inm_timer == 0) { + /* do nothing */ + } else if (--inm->inm_timer == 0) { + igmp_sendpkt(inm, inm->inm_rti->rti_type, 0); + inm->inm_state = IGMP_IREPORTEDLAST; + } else { + igmp_timers_are_running = 1; + } + IN_NEXT_MULTI(step, inm); + } + splx(s); +} + +void +igmp_slowtimo() +{ + int s = splnet(); + register struct router_info *rti = Head; + +#ifdef IGMP_DEBUG + printf("[igmp.c,_slowtimo] -- > entering \n"); +#endif + while (rti) { + if (rti->rti_type == IGMP_V1_ROUTER) { + rti->rti_time++; + if (rti->rti_time >= IGMP_AGE_THRESHOLD) { + rti->rti_type = IGMP_V2_ROUTER; + } + } + rti = rti->rti_next; + } +#ifdef IGMP_DEBUG + printf("[igmp.c,_slowtimo] -- > exiting \n"); +#endif + splx(s); +} + +static struct route igmprt; + +static void +igmp_sendpkt(inm, type, addr) + struct in_multi *inm; + int type; + unsigned long addr; +{ + struct mbuf *m; + struct igmp *igmp; + struct ip *ip; + struct ip_moptions imo; + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == NULL) + return; + + m->m_pkthdr.rcvif = loif; + m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN; + MH_ALIGN(m, IGMP_MINLEN + sizeof(struct ip)); + m->m_data += sizeof(struct ip); + m->m_len = IGMP_MINLEN; + igmp = mtod(m, struct igmp *); + igmp->igmp_type = type; + igmp->igmp_code = 0; + igmp->igmp_group = inm->inm_addr; + igmp->igmp_cksum = 0; + igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN); + + m->m_data -= sizeof(struct ip); + m->m_len += sizeof(struct ip); + ip = mtod(m, struct ip *); + ip->ip_tos = 0; + ip->ip_len = sizeof(struct ip) + IGMP_MINLEN; + ip->ip_off = 0; + ip->ip_p = IPPROTO_IGMP; + ip->ip_src.s_addr = INADDR_ANY; + ip->ip_dst.s_addr = addr ? addr : igmp->igmp_group.s_addr; + + imo.imo_multicast_ifp = inm->inm_ifp; + imo.imo_multicast_ttl = 1; + imo.imo_multicast_vif = -1; + /* + * Request loopback of the report if we are acting as a multicast + * router, so that the process-level routing demon can hear it. + */ + imo.imo_multicast_loop = (ip_mrouter != NULL); + + /* + * XXX + * Do we have to worry about reentrancy here? Don't think so. + */ + ip_output(m, router_alert, &igmprt, 0, &imo); + + ++igmpstat.igps_snd_reports; +} diff --git a/cpukit/libnetworking/netinet/igmp.h b/cpukit/libnetworking/netinet/igmp.h new file mode 100644 index 0000000000..01d6d09179 --- /dev/null +++ b/cpukit/libnetworking/netinet/igmp.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1988 Stephen Deering. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Stephen Deering of Stanford University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)igmp.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_IGMP_H_ +#define _NETINET_IGMP_H_ + +/* + * Internet Group Management Protocol (IGMP) definitions. + * + * Written by Steve Deering, Stanford, May 1988. + * + * MULTICAST Revision: 3.5.1.2 + */ + +/* + * IGMP packet format. + */ +struct igmp { + u_char igmp_type; /* version & type of IGMP message */ + u_char igmp_code; /* subtype for routing msgs */ + u_short igmp_cksum; /* IP-style checksum */ + struct in_addr igmp_group; /* group address being reported */ +}; /* (zero for queries) */ + +#define IGMP_MINLEN 8 + +/* + * Message types, including version number. + */ +#define IGMP_MEMBERSHIP_QUERY 0x11 /* membership query */ +#define IGMP_V1_MEMBERSHIP_REPORT 0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMBERSHIP_REPORT 0x16 /* Ver. 2 membership report */ +#define IGMP_V2_LEAVE_GROUP 0x17 /* Leave-group message */ + +#define IGMP_DVMRP 0x13 /* DVMRP routing message */ +#define IGMP_PIM 0x14 /* PIM routing message */ + +#define IGMP_MTRACE_RESP 0x1e /* traceroute resp.(to sender)*/ +#define IGMP_MTRACE 0x1f /* mcast traceroute messages */ + +#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */ + /* query (in seconds) according */ + /* to RFC1112 */ + + +#define IGMP_TIMER_SCALE 10 /* denotes that the igmp code field */ + /* specifies time in 10th of seconds*/ + +/* + * The following four defininitions are for backwards compatibility. + * They should be removed as soon as all applications are updated to + * use the new constant names. + */ +#define IGMP_HOST_MEMBERSHIP_QUERY IGMP_MEMBERSHIP_QUERY +#define IGMP_HOST_MEMBERSHIP_REPORT IGMP_V1_MEMBERSHIP_REPORT +#define IGMP_HOST_NEW_MEMBERSHIP_REPORT IGMP_V2_MEMBERSHIP_REPORT +#define IGMP_HOST_LEAVE_MESSAGE IGMP_V2_LEAVE_GROUP + +#endif /* _NETINET_IGMP_H_ */ diff --git a/cpukit/libnetworking/netinet/igmp_var.h b/cpukit/libnetworking/netinet/igmp_var.h new file mode 100644 index 0000000000..f408bf2bc1 --- /dev/null +++ b/cpukit/libnetworking/netinet/igmp_var.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1988 Stephen Deering. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Stephen Deering of Stanford University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)igmp_var.h 8.1 (Berkeley) 7/19/93 + * $Id$ + */ + +#ifndef _NETINET_IGMP_VAR_H_ +#define _NETINET_IGMP_VAR_H_ + +/* + * Internet Group Management Protocol (IGMP), + * implementation-specific definitions. + * + * Written by Steve Deering, Stanford, May 1988. + * + * MULTICAST Revision: 3.5.1.3 + */ + +struct igmpstat { + u_int igps_rcv_total; /* total IGMP messages received */ + u_int igps_rcv_tooshort; /* received with too few bytes */ + u_int igps_rcv_badsum; /* received with bad checksum */ + u_int igps_rcv_queries; /* received membership queries */ + u_int igps_rcv_badqueries; /* received invalid queries */ + u_int igps_rcv_reports; /* received membership reports */ + u_int igps_rcv_badreports; /* received invalid reports */ + u_int igps_rcv_ourreports; /* received reports for our groups */ + u_int igps_snd_reports; /* sent membership reports */ +}; + +#ifdef KERNEL +extern struct igmpstat igmpstat; + +#define IGMP_RANDOM_DELAY(X) (random() % (X) + 1) + +/* + * States for IGMPv2's leave processing + */ +#define IGMP_OTHERMEMBER 0 +#define IGMP_IREPORTEDLAST 1 + +/* + * We must remember what version the subnet's querier is. + * We conveniently use the IGMP message type for the proper + * membership report to keep this state. + */ +#define IGMP_V1_ROUTER IGMP_V1_MEMBERSHIP_REPORT +#define IGMP_V2_ROUTER IGMP_V2_MEMBERSHIP_REPORT + +/* + * Revert to new router if we haven't heard from an old router in + * this amount of time. + */ +#define IGMP_AGE_THRESHOLD 540 + +void igmp_init __P((void)); +void igmp_input __P((struct mbuf *, int)); +void igmp_joingroup __P((struct in_multi *)); +void igmp_leavegroup __P((struct in_multi *)); +void igmp_fasttimo __P((void)); +void igmp_slowtimo __P((void)); +#endif + +/* + * Names for IGMP sysctl objects + */ +#define IGMPCTL_STATS 1 /* statistics (read-only) */ +#define IGMPCTL_MAXID 2 + +#define IGMPCTL_NAMES { \ + { 0, 0 }, \ + { "stats", CTLTYPE_STRUCT }, \ +} + +#endif + + diff --git a/cpukit/libnetworking/netinet/in.c b/cpukit/libnetworking/netinet/in.c new file mode 100644 index 0000000000..701406f207 --- /dev/null +++ b/cpukit/libnetworking/netinet/in.c @@ -0,0 +1,728 @@ +/* + * Copyright (c) 1982, 1986, 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in.c 8.4 (Berkeley) 1/9/95 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> + +#include <netinet/igmp_var.h> + +/* + * This structure is used to keep track of in_multi chains which belong to + * deleted interface addresses. + */ +static LIST_HEAD(, multi_kludge) in_mk; /* XXX BSS initialization */ + +struct multi_kludge { + LIST_ENTRY(multi_kludge) mk_entry; + struct ifnet *mk_ifp; + struct in_multihead mk_head; +}; + +static void in_socktrim __P((struct sockaddr_in *)); +static int in_ifinit __P((struct ifnet *, + struct in_ifaddr *, struct sockaddr_in *, int)); +static void in_ifscrub __P((struct ifnet *, struct in_ifaddr *)); + +static int subnetsarelocal = 0; +SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, + &subnetsarelocal, 0, ""); +/* + * Return 1 if an internet address is for a ``local'' host + * (one to which we have a connection). If subnetsarelocal + * is true, this includes other subnets of the local net. + * Otherwise, it includes only the directly-connected (sub)nets. + */ +int +in_localaddr(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + register struct in_ifaddr *ia; + + if (subnetsarelocal) { + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if ((i & ia->ia_netmask) == ia->ia_net) + return (1); + } else { + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if ((i & ia->ia_subnetmask) == ia->ia_subnet) + return (1); + } + return (0); +} + +/* + * Determine whether an IP address is in a reserved set of addresses + * that may not be forwarded, or whether datagrams to that destination + * may be forwarded. + */ +int +in_canforward(in) + struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + register u_long net; + + if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) + return (0); + if (IN_CLASSA(i)) { + net = i & IN_CLASSA_NET; + if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) + return (0); + } + return (1); +} + +/* + * Trim a mask in a sockaddr + */ +static void +in_socktrim(ap) +struct sockaddr_in *ap; +{ + register char *cplim = (char *) &ap->sin_addr; + register char *cp = (char *) (&ap->sin_addr + 1); + + ap->sin_len = 0; + while (--cp >= cplim) + if (*cp) { + (ap)->sin_len = cp - (char *) (ap) + 1; + break; + } +} + +static int in_interfaces; /* number of external internet interfaces */ + +/* + * Generic internet control operations (ioctl's). + * Ifp is 0 if not an interface-specific ioctl. + */ +/* ARGSUSED */ +int +in_control(so, cmd, data, ifp) + struct socket *so; + u_long cmd; + caddr_t data; + register struct ifnet *ifp; +{ + register struct ifreq *ifr = (struct ifreq *)data; + register struct in_ifaddr *ia = 0, *iap; + register struct ifaddr *ifa; + struct in_ifaddr *oia; + struct in_aliasreq *ifra = (struct in_aliasreq *)data; + struct sockaddr_in oldaddr; + int error, hostIsNew, maskIsNew, s; + u_long i; + struct multi_kludge *mk; + + /* + * Find address for this interface, if it exists. + * + * If an alias address was specified, find that one instead of + * the first one on the interface. + */ + if (ifp) + for (iap = in_ifaddr; iap; iap = iap->ia_next) + if (iap->ia_ifp == ifp) { + if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr == + iap->ia_addr.sin_addr.s_addr) { + ia = iap; + break; + } else if (ia == NULL) { + ia = iap; + if (ifr->ifr_addr.sa_family != AF_INET) + break; + } + } + + switch (cmd) { + + case SIOCAIFADDR: + case SIOCDIFADDR: + if (ifra->ifra_addr.sin_family == AF_INET) { + for (oia = ia; ia; ia = ia->ia_next) { + if (ia->ia_ifp == ifp && + ia->ia_addr.sin_addr.s_addr == + ifra->ifra_addr.sin_addr.s_addr) + break; + } + if ((ifp->if_flags & IFF_POINTOPOINT) + && (cmd == SIOCAIFADDR) + && (ifra->ifra_dstaddr.sin_addr.s_addr + == INADDR_ANY)) { + return EDESTADDRREQ; + } + } + if (cmd == SIOCDIFADDR && ia == 0) + return (EADDRNOTAVAIL); + /* FALLTHROUGH */ + case SIOCSIFADDR: + case SIOCSIFNETMASK: + case SIOCSIFDSTADDR: + if ((so->so_state & SS_PRIV) == 0) + return (EPERM); + + if (ifp == 0) + panic("in_control"); + if (ia == (struct in_ifaddr *)0) { + oia = (struct in_ifaddr *) + malloc(sizeof *oia, M_IFADDR, M_WAITOK); + if (oia == (struct in_ifaddr *)NULL) + return (ENOBUFS); + bzero((caddr_t)oia, sizeof *oia); + ia = in_ifaddr; + /* + * Protect from ipintr() traversing address list + * while we're modifying it. + */ + s = splnet(); + + if (ia) { + for ( ; ia->ia_next; ia = ia->ia_next) + continue; + ia->ia_next = oia; + } else + in_ifaddr = oia; + ia = oia; + ifa = ifp->if_addrlist; + if (ifa) { + for ( ; ifa->ifa_next; ifa = ifa->ifa_next) + continue; + ifa->ifa_next = (struct ifaddr *) ia; + } else + ifp->if_addrlist = (struct ifaddr *) ia; + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + ia->ia_ifa.ifa_dstaddr + = (struct sockaddr *)&ia->ia_dstaddr; + ia->ia_ifa.ifa_netmask + = (struct sockaddr *)&ia->ia_sockmask; + ia->ia_sockmask.sin_len = 8; + if (ifp->if_flags & IFF_BROADCAST) { + ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); + ia->ia_broadaddr.sin_family = AF_INET; + } + ia->ia_ifp = ifp; + if (!(ifp->if_flags & IFF_LOOPBACK)) + in_interfaces++; + splx(s); + } + break; + + case SIOCSIFBRDADDR: + if ((so->so_state & SS_PRIV) == 0) + return (EPERM); + /* FALLTHROUGH */ + + case SIOCGIFADDR: + case SIOCGIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCGIFBRDADDR: + if (ia == (struct in_ifaddr *)0) + return (EADDRNOTAVAIL); + break; + } + switch (cmd) { + + case SIOCGIFADDR: + *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; + break; + + case SIOCGIFBRDADDR: + if ((ifp->if_flags & IFF_BROADCAST) == 0) + return (EINVAL); + *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; + break; + + case SIOCGIFDSTADDR: + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; + break; + + case SIOCGIFNETMASK: + *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; + break; + + case SIOCSIFDSTADDR: + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + oldaddr = ia->ia_dstaddr; + ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; + if (ifp->if_ioctl && (error = (*ifp->if_ioctl) + (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { + ia->ia_dstaddr = oldaddr; + return (error); + } + if (ia->ia_flags & IFA_ROUTE) { + ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + ia->ia_ifa.ifa_dstaddr = + (struct sockaddr *)&ia->ia_dstaddr; + rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); + } + break; + + case SIOCSIFBRDADDR: + if ((ifp->if_flags & IFF_BROADCAST) == 0) + return (EINVAL); + ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; + break; + + case SIOCSIFADDR: + return (in_ifinit(ifp, ia, + (struct sockaddr_in *) &ifr->ifr_addr, 1)); + + case SIOCSIFNETMASK: + i = ifra->ifra_addr.sin_addr.s_addr; + ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i); + break; + + case SIOCAIFADDR: + maskIsNew = 0; + hostIsNew = 1; + error = 0; + if (ia->ia_addr.sin_family == AF_INET) { + if (ifra->ifra_addr.sin_len == 0) { + ifra->ifra_addr = ia->ia_addr; + hostIsNew = 0; + } else if (ifra->ifra_addr.sin_addr.s_addr == + ia->ia_addr.sin_addr.s_addr) + hostIsNew = 0; + } + if (ifra->ifra_mask.sin_len) { + in_ifscrub(ifp, ia); + ia->ia_sockmask = ifra->ifra_mask; + ia->ia_subnetmask = + ntohl(ia->ia_sockmask.sin_addr.s_addr); + maskIsNew = 1; + } + if ((ifp->if_flags & IFF_POINTOPOINT) && + (ifra->ifra_dstaddr.sin_family == AF_INET)) { + in_ifscrub(ifp, ia); + ia->ia_dstaddr = ifra->ifra_dstaddr; + maskIsNew = 1; /* We lie; but the effect's the same */ + } + if (ifra->ifra_addr.sin_family == AF_INET && + (hostIsNew || maskIsNew)) + error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); + if ((ifp->if_flags & IFF_BROADCAST) && + (ifra->ifra_broadaddr.sin_family == AF_INET)) + ia->ia_broadaddr = ifra->ifra_broadaddr; + return (error); + + case SIOCDIFADDR: + mk = malloc(sizeof *mk, M_IPMADDR, M_WAITOK); + if (!mk) + return ENOBUFS; + + in_ifscrub(ifp, ia); + /* + * Protect from ipintr() traversing address list + * while we're modifying it. + */ + s = splnet(); + + if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) + ifp->if_addrlist = ifa->ifa_next; + else { + while (ifa->ifa_next && + (ifa->ifa_next != (struct ifaddr *)ia)) + ifa = ifa->ifa_next; + if (ifa->ifa_next) + ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; + else + printf("Couldn't unlink inifaddr from ifp\n"); + } + oia = ia; + if (oia == (ia = in_ifaddr)) + in_ifaddr = ia->ia_next; + else { + while (ia->ia_next && (ia->ia_next != oia)) + ia = ia->ia_next; + if (ia->ia_next) + ia->ia_next = oia->ia_next; + else + printf("Didn't unlink inifadr from list\n"); + } + + if (!oia->ia_multiaddrs.lh_first) { + IFAFREE(&oia->ia_ifa); + FREE(mk, M_IPMADDR); + splx(s); + break; + } + + /* + * Multicast address kludge: + * If there were any multicast addresses attached to this + * interface address, either move them to another address + * on this interface, or save them until such time as this + * interface is reconfigured for IP. + */ + IFP_TO_IA(oia->ia_ifp, ia); + if (ia) { /* there is another address */ + struct in_multi *inm; + for(inm = oia->ia_multiaddrs.lh_first; inm; + inm = inm->inm_entry.le_next) { + IFAFREE(&inm->inm_ia->ia_ifa); + ia->ia_ifa.ifa_refcnt++; + inm->inm_ia = ia; + LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, + inm_entry); + } + FREE(mk, M_IPMADDR); + } else { /* last address on this if deleted, save */ + struct in_multi *inm; + + LIST_INIT(&mk->mk_head); + mk->mk_ifp = ifp; + + for(inm = oia->ia_multiaddrs.lh_first; inm; + inm = inm->inm_entry.le_next) { + LIST_INSERT_HEAD(&mk->mk_head, inm, inm_entry); + } + + if (mk->mk_head.lh_first) { + LIST_INSERT_HEAD(&in_mk, mk, mk_entry); + } else { + FREE(mk, M_IPMADDR); + } + } + + IFAFREE((&oia->ia_ifa)); + splx(s); + break; + + default: + if (ifp == 0 || ifp->if_ioctl == 0) + return (EOPNOTSUPP); + return ((*ifp->if_ioctl)(ifp, cmd, data)); + } + return (0); +} + +/* + * Delete any existing route for an interface. + */ +static void +in_ifscrub(ifp, ia) + register struct ifnet *ifp; + register struct in_ifaddr *ia; +{ + + if ((ia->ia_flags & IFA_ROUTE) == 0) + return; + if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + else + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); + ia->ia_flags &= ~IFA_ROUTE; +} + +/* + * Initialize an interface's internet address + * and routing table entry. + */ +static int +in_ifinit(ifp, ia, sin, scrub) + register struct ifnet *ifp; + register struct in_ifaddr *ia; + struct sockaddr_in *sin; + int scrub; +{ + register u_long i = ntohl(sin->sin_addr.s_addr); + struct sockaddr_in oldaddr; + int s = splimp(), flags = RTF_UP, error; + struct multi_kludge *mk; + + oldaddr = ia->ia_addr; + ia->ia_addr = *sin; + /* + * Give the interface a chance to initialize + * if this is its first address, + * and to validate the address if necessary. + */ + if (ifp->if_ioctl && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { + splx(s); + ia->ia_addr = oldaddr; + return (error); + } + splx(s); + if (scrub) { + ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; + in_ifscrub(ifp, ia); + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + } + if (IN_CLASSA(i)) + ia->ia_netmask = IN_CLASSA_NET; + else if (IN_CLASSB(i)) + ia->ia_netmask = IN_CLASSB_NET; + else + ia->ia_netmask = IN_CLASSC_NET; + /* + * The subnet mask usually includes at least the standard network part, + * but may may be smaller in the case of supernetting. + * If it is set, we believe it. + */ + if (ia->ia_subnetmask == 0) { + ia->ia_subnetmask = ia->ia_netmask; + ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); + } else + ia->ia_netmask &= ia->ia_subnetmask; + ia->ia_net = i & ia->ia_netmask; + ia->ia_subnet = i & ia->ia_subnetmask; + in_socktrim(&ia->ia_sockmask); + /* + * Add route for the network. + */ + ia->ia_ifa.ifa_metric = ifp->if_metric; + if (ifp->if_flags & IFF_BROADCAST) { + ia->ia_broadaddr.sin_addr.s_addr = + htonl(ia->ia_subnet | ~ia->ia_subnetmask); + ia->ia_netbroadcast.s_addr = + htonl(ia->ia_net | ~ ia->ia_netmask); + } else if (ifp->if_flags & IFF_LOOPBACK) { + ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; + flags |= RTF_HOST; + } else if (ifp->if_flags & IFF_POINTOPOINT) { + if (ia->ia_dstaddr.sin_family != AF_INET) + return (0); + flags |= RTF_HOST; + } + if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) + ia->ia_flags |= IFA_ROUTE; + + LIST_INIT(&ia->ia_multiaddrs); + /* + * If the interface supports multicast, join the "all hosts" + * multicast group on that interface. + */ + if (ifp->if_flags & IFF_MULTICAST) { + struct in_addr addr; + + /* + * Continuation of multicast address hack: + * If there was a multicast group list previously saved + * for this interface, then we re-attach it to the first + * address configured on the i/f. + */ + for(mk = in_mk.lh_first; mk; mk = mk->mk_entry.le_next) { + if(mk->mk_ifp == ifp) { + struct in_multi *inm; + + for(inm = mk->mk_head.lh_first; inm; + inm = inm->inm_entry.le_next) { + IFAFREE(&inm->inm_ia->ia_ifa); + ia->ia_ifa.ifa_refcnt++; + inm->inm_ia = ia; + LIST_INSERT_HEAD(&ia->ia_multiaddrs, + inm, inm_entry); + } + LIST_REMOVE(mk, mk_entry); + free(mk, M_IPMADDR); + break; + } + } + + addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + in_addmulti(&addr, ifp); + } + return (error); +} + + +/* + * Return 1 if the address might be a local broadcast address. + */ +int +in_broadcast(in, ifp) + struct in_addr in; + struct ifnet *ifp; +{ + register struct ifaddr *ifa; + u_long t; + + if (in.s_addr == INADDR_BROADCAST || + in.s_addr == INADDR_ANY) + return 1; + if ((ifp->if_flags & IFF_BROADCAST) == 0) + return 0; + t = ntohl(in.s_addr); + /* + * Look through the list of addresses for a match + * with a broadcast address. + */ +#define ia ((struct in_ifaddr *)ifa) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_INET && + (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || + in.s_addr == ia->ia_netbroadcast.s_addr || + /* + * Check for old-style (host 0) broadcast. + */ + t == ia->ia_subnet || t == ia->ia_net) && + /* + * Check for an all one subnetmask. These + * only exist when an interface gets a secondary + * address. + */ + ia->ia_subnetmask != (u_long)0xffffffff) + return 1; + return (0); +#undef ia +} +/* + * Add an address to the list of IP multicast addresses for a given interface. + */ +struct in_multi * +in_addmulti(ap, ifp) + register struct in_addr *ap; + register struct ifnet *ifp; +{ + register struct in_multi *inm; + struct ifreq ifr; + struct in_ifaddr *ia; + int s = splnet(); + + /* + * See if address already in list. + */ + IN_LOOKUP_MULTI(*ap, ifp, inm); + if (inm != NULL) { + /* + * Found it; just increment the reference count. + */ + ++inm->inm_refcount; + } + else { + /* + * New address; allocate a new multicast record + * and link it into the interface's multicast list. + */ + inm = (struct in_multi *)malloc(sizeof(*inm), + M_IPMADDR, M_NOWAIT); + if (inm == NULL) { + splx(s); + return (NULL); + } + inm->inm_addr = *ap; + inm->inm_ifp = ifp; + inm->inm_refcount = 1; + IFP_TO_IA(ifp, ia); + if (ia == NULL) { + free(inm, M_IPMADDR); + splx(s); + return (NULL); + } + inm->inm_ia = ia; + ia->ia_ifa.ifa_refcnt++; /* gain a reference */ + LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_entry); + + /* + * Ask the network driver to update its multicast reception + * filter appropriately for the new address. + */ + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap; + if ((ifp->if_ioctl == NULL) || + (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) { + LIST_REMOVE(inm, inm_entry); + IFAFREE(&ia->ia_ifa); /* release reference */ + free(inm, M_IPMADDR); + splx(s); + return (NULL); + } + /* + * Let IGMP know that we have joined a new IP multicast group. + */ + igmp_joingroup(inm); + } + splx(s); + return (inm); +} + +/* + * Delete a multicast address record. + */ +void +in_delmulti(inm) + register struct in_multi *inm; +{ + struct ifreq ifr; + int s = splnet(); + + if (--inm->inm_refcount == 0) { + /* + * No remaining claims to this record; let IGMP know that + * we are leaving the multicast group. + */ + igmp_leavegroup(inm); + /* + * Unlink from list. + */ + LIST_REMOVE(inm, inm_entry); + IFAFREE(&inm->inm_ia->ia_ifa); /* release reference */ + + /* + * Notify the network driver to update its multicast reception + * filter. + */ + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr = + inm->inm_addr; + (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI, + (caddr_t)&ifr); + free(inm, M_IPMADDR); + } + splx(s); +} diff --git a/cpukit/libnetworking/netinet/in.h b/cpukit/libnetworking/netinet/in.h new file mode 100644 index 0000000000..ba3cbb21cc --- /dev/null +++ b/cpukit/libnetworking/netinet/in.h @@ -0,0 +1,433 @@ +/* + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in.h 8.3 (Berkeley) 1/3/94 + * $Id$ + */ + +#ifndef _NETINET_IN_H_ +#define _NETINET_IN_H_ + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +/* + * Protocols (RFC 1700) + */ +#define IPPROTO_IP 0 /* dummy for IP */ +#define IPPROTO_ICMP 1 /* control message protocol */ +#define IPPROTO_IGMP 2 /* group mgmt protocol */ +#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ +#define IPPROTO_IPIP 4 /* IP encapsulation in IP */ +#define IPPROTO_TCP 6 /* tcp */ +#define IPPROTO_ST 7 /* Stream protocol II */ +#define IPPROTO_EGP 8 /* exterior gateway protocol */ +#define IPPROTO_PIGP 9 /* private interior gateway */ +#define IPPROTO_RCCMON 10 /* BBN RCC Monitoring */ +#define IPPROTO_NVPII 11 /* network voice protocol*/ +#define IPPROTO_PUP 12 /* pup */ +#define IPPROTO_ARGUS 13 /* Argus */ +#define IPPROTO_EMCON 14 /* EMCON */ +#define IPPROTO_XNET 15 /* Cross Net Debugger */ +#define IPPROTO_CHAOS 16 /* Chaos*/ +#define IPPROTO_UDP 17 /* user datagram protocol */ +#define IPPROTO_MUX 18 /* Multiplexing */ +#define IPPROTO_MEAS 19 /* DCN Measurement Subsystems */ +#define IPPROTO_HMP 20 /* Host Monitoring */ +#define IPPROTO_PRM 21 /* Packet Radio Measurement */ +#define IPPROTO_IDP 22 /* xns idp */ +#define IPPROTO_TRUNK1 23 /* Trunk-1 */ +#define IPPROTO_TRUNK2 24 /* Trunk-2 */ +#define IPPROTO_LEAF1 25 /* Leaf-1 */ +#define IPPROTO_LEAF2 26 /* Leaf-2 */ +#define IPPROTO_RDP 27 /* Reliable Data */ +#define IPPROTO_IRTP 28 /* Reliable Transaction */ +#define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ +#define IPPROTO_BLT 30 /* Bulk Data Transfer */ +#define IPPROTO_NSP 31 /* Network Services */ +#define IPPROTO_INP 32 /* Merit Internodal */ +#define IPPROTO_SEP 33 /* Sequential Exchange */ +#define IPPROTO_3PC 34 /* Third Party Connect */ +#define IPPROTO_IDPR 35 /* InterDomain Policy Routing */ +#define IPPROTO_XTP 36 /* XTP */ +#define IPPROTO_DDP 37 /* Datagram Delivery */ +#define IPPROTO_CMTP 38 /* Control Message Transport */ +#define IPPROTO_TPXX 39 /* TP++ Transport */ +#define IPPROTO_IL 40 /* IL transport protocol */ +#define IPPROTO_SIP 41 /* Simple Internet Protocol */ +#define IPPROTO_SDRP 42 /* Source Demand Routing */ +#define IPPROTO_SIPSR 43 /* SIP Source Route */ +#define IPPROTO_SIPFRAG 44 /* SIP Fragment */ +#define IPPROTO_IDRP 45 /* InterDomain Routing*/ +#define IPPROTO_RSVP 46 /* resource reservation */ +#define IPPROTO_GRE 47 /* General Routing Encap. */ +#define IPPROTO_MHRP 48 /* Mobile Host Routing */ +#define IPPROTO_BHA 49 /* BHA */ +#define IPPROTO_ESP 50 /* SIPP Encap Sec. Payload */ +#define IPPROTO_AH 51 /* SIPP Auth Header */ +#define IPPROTO_INLSP 52 /* Integ. Net Layer Security */ +#define IPPROTO_SWIPE 53 /* IP with encryption */ +#define IPPROTO_NHRP 54 /* Next Hop Resolution */ +/* 55-60: Unassigned */ +#define IPPROTO_AHIP 61 /* any host internal protocol */ +#define IPPROTO_CFTP 62 /* CFTP */ +#define IPPROTO_HELLO 63 /* "hello" routing protocol */ +#define IPPROTO_SATEXPAK 64 /* SATNET/Backroom EXPAK */ +#define IPPROTO_KRYPTOLAN 65 /* Kryptolan */ +#define IPPROTO_RVD 66 /* Remote Virtual Disk */ +#define IPPROTO_IPPC 67 /* Pluribus Packet Core */ +#define IPPROTO_ADFS 68 /* Any distributed FS */ +#define IPPROTO_SATMON 69 /* Satnet Monitoring */ +#define IPPROTO_VISA 70 /* VISA Protocol */ +#define IPPROTO_IPCV 71 /* Packet Core Utility */ +#define IPPROTO_CPNX 72 /* Comp. Prot. Net. Executive */ +#define IPPROTO_CPHB 73 /* Comp. Prot. HeartBeat */ +#define IPPROTO_WSN 74 /* Wang Span Network */ +#define IPPROTO_PVP 75 /* Packet Video Protocol */ +#define IPPROTO_BRSATMON 76 /* BackRoom SATNET Monitoring */ +#define IPPROTO_ND 77 /* Sun net disk proto (temp.) */ +#define IPPROTO_WBMON 78 /* WIDEBAND Monitoring */ +#define IPPROTO_WBEXPAK 79 /* WIDEBAND EXPAK */ +#define IPPROTO_EON 80 /* ISO cnlp */ +#define IPPROTO_VMTP 81 /* VMTP */ +#define IPPROTO_SVMTP 82 /* Secure VMTP */ +#define IPPROTO_VINES 83 /* Banyon VINES */ +#define IPPROTO_TTP 84 /* TTP */ +#define IPPROTO_IGP 85 /* NSFNET-IGP */ +#define IPPROTO_DGP 86 /* dissimilar gateway prot. */ +#define IPPROTO_TCF 87 /* TCF */ +#define IPPROTO_IGRP 88 /* Cisco/GXS IGRP */ +#define IPPROTO_OSPFIGP 89 /* OSPFIGP */ +#define IPPROTO_SRPC 90 /* Strite RPC protocol */ +#define IPPROTO_LARP 91 /* Locus Address Resoloution */ +#define IPPROTO_MTP 92 /* Multicast Transport */ +#define IPPROTO_AX25 93 /* AX.25 Frames */ +#define IPPROTO_IPEIP 94 /* IP encapsulated in IP */ +#define IPPROTO_MICP 95 /* Mobile Int.ing control */ +#define IPPROTO_SCCSP 96 /* Semaphore Comm. security */ +#define IPPROTO_ETHERIP 97 /* Ethernet IP encapsulation */ +#define IPPROTO_ENCAP 98 /* encapsulation header */ +#define IPPROTO_APES 99 /* any private encr. scheme */ +#define IPPROTO_GMTP 100 /* GMTP*/ +/* 101-254: Unassigned */ +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion */ +#define IPPROTO_DIVERT 254 /* divert pseudo-protocol */ +#define IPPROTO_RAW 255 /* raw IP packet */ +#define IPPROTO_MAX 256 + + +/* + * Local port number conventions: + * + * When a user does a bind(2) or connect(2) with a port number of zero, + * a non-conflicting local port address is chosen. + * The default range is IPPORT_RESERVED through + * IPPORT_USERRESERVED, although that is settable by sysctl. + * + * A user may set the IPPROTO_IP option IP_PORTRANGE to change this + * default assignment range. + * + * The value IP_PORTRANGE_DEFAULT causes the default behavior. + * + * The value IP_PORTRANGE_HIGH changes the range of candidate port numbers + * into the "high" range. These are reserved for client outbound connections + * which do not want to be filtered by any firewalls. + * + * The value IP_PORTRANGE_LOW changes the range to the "low" are + * that is (by convention) restricted to privileged processes. This + * convention is based on "vouchsafe" principles only. It is only secure + * if you trust the remote host to restrict these ports. + * + * The default range of ports and the high range can be changed by + * sysctl(3). (net.inet.ip.port{hi,low}{first,last}_auto) + * + * Changing those values has bad security implications if you are + * using a a stateless firewall that is allowing packets outside of that + * range in order to allow transparent outgoing connections. + * + * Such a firewall configuration will generally depend on the use of these + * default values. If you change them, you may find your Security + * Administrator looking for you with a heavy object. + */ + +/* + * Ports < IPPORT_RESERVED are reserved for + * privileged processes (e.g. root). (IP_PORTRANGE_LOW) + * Ports > IPPORT_USERRESERVED are reserved + * for servers, not necessarily privileged. (IP_PORTRANGE_DEFAULT) + */ +#define IPPORT_RESERVED 1024 +#define IPPORT_USERRESERVED 5000 + +/* + * Default local port range to use by setting IP_PORTRANGE_HIGH + */ +#define IPPORT_HIFIRSTAUTO 40000 +#define IPPORT_HILASTAUTO 44999 + +/* + * Scanning for a free reserved port return a value below IPPORT_RESERVED, + * but higher than IPPORT_RESERVEDSTART. Traditionally the start value was + * 512, but that conflicts with some well-known-services that firewalls may + * have a fit if we use. + */ +#define IPPORT_RESERVEDSTART 600 + +/* + * Internet address (a structure for historical reasons) + */ +struct in_addr { + u_long s_addr; +}; + +/* + * Definitions of bits in internet address integers. + * On subnets, the decomposition of addresses to host and net parts + * is done according to subnet mask, not the masks here. + */ +#define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST 0x00ffffff +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST 0x0000ffff +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST 0x000000ff + +#define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) +#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define IN_EXPERIMENTAL(i) (((long)(i) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000) + +#define INADDR_ANY (u_long)0x00000000 +#define INADDR_BROADCAST (u_long)0xffffffff /* must be masked */ +#ifndef KERNEL +#define INADDR_NONE 0xffffffff /* -1 return */ +#endif + +#define INADDR_UNSPEC_GROUP (u_long)0xe0000000 /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP (u_long)0xe0000001 /* 224.0.0.1 */ +#define INADDR_ALLRTRS_GROUP (u_long)0xe0000002 /* 224.0.0.2 */ +#define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff /* 224.0.0.255 */ + +#define IN_LOOPBACKNET 127 /* official! */ + +/* + * Socket address, internet style. + */ +struct sockaddr_in { + u_char sin_len; + u_char sin_family; + u_short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +/* + * Structure used to describe IP options. + * Used to store options internally, to pass them to a process, + * or to restore options retrieved earlier. + * The ip_dst is used for the first-hop gateway when using a source route + * (this gets put into the header proper). + */ +struct ip_opts { + struct in_addr ip_dst; /* first hop, 0 w/o src rt */ + char ip_opts[40]; /* actually variable in size */ +}; + +/* + * Options for use with [gs]etsockopt at the IP level. + * First word of comment is data type; bool is stored in int. + */ +#define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ +#define IP_HDRINCL 2 /* int; header is included with data */ +#define IP_TOS 3 /* int; IP type of service and preced. */ +#define IP_TTL 4 /* int; IP time to live */ +#define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ +#define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ +#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ +#define IP_RETOPTS 8 /* ip_opts; set/get IP options */ +#define IP_MULTICAST_IF 9 /* u_char; set/get IP multicast i/f */ +#define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ +#define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ +#define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ +#define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ +#define IP_MULTICAST_VIF 14 /* set/get IP mcast virt. iface */ +#define IP_RSVP_ON 15 /* enable RSVP in kernel */ +#define IP_RSVP_OFF 16 /* disable RSVP in kernel */ +#define IP_RSVP_VIF_ON 17 /* set RSVP per-vif socket */ +#define IP_RSVP_VIF_OFF 18 /* unset RSVP per-vif socket */ +#define IP_PORTRANGE 19 /* int; range to choose for unspec port */ +#define IP_RECVIF 20 /* bool; receive reception if w/dgram */ + +#define IP_FW_ADD 50 /* add a firewall rule to chain */ +#define IP_FW_DEL 51 /* delete a firewall rule from chain */ +#define IP_FW_FLUSH 52 /* flush firewall rule chain */ +#define IP_FW_ZERO 53 /* clear single/all firewall counter(s) */ +#define IP_FW_GET 54 /* get entire firewall rule chain */ +#define IP_NAT 55 /* set/get NAT opts */ + +/* + * Defaults and limits for options + */ +#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ +#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ +#define IP_MAX_MEMBERSHIPS 20 /* per socket */ + +/* + * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. + */ +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +/* + * Argument for IP_PORTRANGE: + * - which range to search when port is unspecified at bind() or connect() + */ +#define IP_PORTRANGE_DEFAULT 0 /* default range */ +#define IP_PORTRANGE_HIGH 1 /* "high" - request firewall bypass */ +#define IP_PORTRANGE_LOW 2 /* "low" - vouchsafe security */ + +/* + * Definitions for inet sysctl operations. + * + * Third level is protocol number. + * Fourth level is desired variable within that protocol. + */ +#define IPPROTO_MAXID (IPPROTO_IDP + 1) /* don't list to IPPROTO_MAX */ + +#define CTL_IPPROTO_NAMES { \ + { "ip", CTLTYPE_NODE }, \ + { "icmp", CTLTYPE_NODE }, \ + { "igmp", CTLTYPE_NODE }, \ + { "ggp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "tcp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { "egp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "pup", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "udp", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "idp", CTLTYPE_NODE }, \ +} + +/* + * Names for IP sysctl objects + */ +#define IPCTL_FORWARDING 1 /* act as router */ +#define IPCTL_SENDREDIRECTS 2 /* may send redirects when forwarding */ +#define IPCTL_DEFTTL 3 /* default TTL */ +#ifdef notyet +#define IPCTL_DEFMTU 4 /* default MTU */ +#endif +#define IPCTL_RTEXPIRE 5 /* cloned route expiration time */ +#define IPCTL_RTMINEXPIRE 6 /* min value for expiration time */ +#define IPCTL_RTMAXCACHE 7 /* trigger level for dynamic expire */ +#define IPCTL_SOURCEROUTE 8 /* may perform source routes */ +#define IPCTL_DIRECTEDBROADCAST 9 /* may re-broadcast received packets */ +#define IPCTL_INTRQMAXLEN 10 /* max length of netisr queue */ +#define IPCTL_INTRQDROPS 11 /* number of netisr q drops */ +#define IPCTL_ACCEPTSOURCEROUTE 13 /* may accept source routed packets */ +#define IPCTL_MAXID 13 + +#define IPCTL_NAMES { \ + { 0, 0 }, \ + { "forwarding", CTLTYPE_INT }, \ + { "redirect", CTLTYPE_INT }, \ + { "ttl", CTLTYPE_INT }, \ + { "mtu", CTLTYPE_INT }, \ + { "rtexpire", CTLTYPE_INT }, \ + { "rtminexpire", CTLTYPE_INT }, \ + { "rtmaxcache", CTLTYPE_INT }, \ + { "sourceroute", CTLTYPE_INT }, \ + { "directed-broadcast", CTLTYPE_INT }, \ + { "intr-queue-maxlen", CTLTYPE_INT }, \ + { "intr-queue-drops", CTLTYPE_INT }, \ + { "accept_sourceroute", CTLTYPE_INT }, \ +} + + +#ifdef KERNEL +struct ifnet; struct mbuf; /* forward declarations for Standard C */ + +int in_broadcast __P((struct in_addr, struct ifnet *)); +int in_canforward __P((struct in_addr)); +int in_cksum __P((struct mbuf *, int)); +int in_localaddr __P((struct in_addr)); +char *inet_ntoa __P((struct in_addr)); /* in libkern */ + +/* Firewall hooks */ +struct ip; +typedef int ip_fw_chk_t __P((struct ip**, int, struct ifnet*, int, struct mbuf**)); +typedef int ip_fw_ctl_t __P((int, struct mbuf**)); +extern ip_fw_chk_t *ip_fw_chk_ptr; +extern ip_fw_ctl_t *ip_fw_ctl_ptr; + +/* IP NAT hooks */ +typedef int ip_nat_t __P((struct ip**, struct mbuf**, struct ifnet*, int)); +typedef int ip_nat_ctl_t __P((int, struct mbuf**)); +extern ip_nat_t *ip_nat_ptr; +extern ip_nat_ctl_t *ip_nat_ctl_ptr; +#define IP_NAT_IN 0x00000001 +#define IP_NAT_OUT 0x00000002 + +#endif /* KERNEL */ + +#endif diff --git a/cpukit/libnetworking/netinet/in_cksum.c b/cpukit/libnetworking/netinet/in_cksum.c new file mode 100644 index 0000000000..f834d629d2 --- /dev/null +++ b/cpukit/libnetworking/netinet/in_cksum.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/mbuf.h> + +#if (defined(__GNUC__) && (defined(__mc68000__) || defined(__m68k__))) + +#define REDUCE { sum = (sum & 0xFFFF) + (sum >> 16); if (sum > 0xFFFF) sum -= 0xFFFF; } + +/* + * Motorola 68k version of Internet Protocol Checksum routine + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * August, 1998 + */ +int +in_cksum(m, len) + struct mbuf *m; + int len; +{ + unsigned short *w; + unsigned long sum = 0; + int mlen = 0; + int byte_swapped = 0; + union { + char c[2]; + u_short s; + } s_util; + + for ( ; m && len ; m = m->m_next) { + if (m->m_len == 0) + continue; + w = mtod(m, u_short *); + if (mlen == -1) { + /* + * The first byte of this mbuf is the continuation + * of a word spanning between this mbuf and the + * last mbuf. + * + * s_util.c[0] is already saved when scanning previous + * mbuf. + */ + s_util.c[1] = *(char *)w; + sum += s_util.s; + w = (u_short *)((char *)w + 1); + mlen = m->m_len - 1; + len--; + } else + mlen = m->m_len; + if (len < mlen) + mlen = len; + len -= mlen; + + /* + * Force to longword boundary. + */ + if (3 & (int)w) { + REDUCE; + if ((1 & (int) w) && (mlen > 0)) { + sum <<= 8; + s_util.c[0] = *(u_char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + if ((2 & (int) w) && (mlen >= 2)) { + sum += *w++; + mlen -= 2; + } + } + + /* + * Sum all the longwords in the buffer. + * See RFC 1071 -- Computing the Internet Checksum. + * It should work for all 68k family members. + */ + { + unsigned long tcnt = mlen, t1; + __asm__ volatile ( + "movel %2,%3\n\t" + "lsrl #6,%2 | count/64 = # loop traversals\n\t" + "andl #0x3c,%3 | Then find fractions of a chunk\n\t" + "negl %3\n\t | Each long uses 4 instruction bytes\n\t" + "andi #0xf,%%cc | Clear X (extended carry flag)\n\t" + "jmp %%pc@(lcsum2_lbl-.-2:b,%3) | Jump into loop\n" + "lcsum1_lbl: | Begin inner loop...\n\t" + "movel %1@+,%3 | 0: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 1: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 2: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 3: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 4: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 5: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 6: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 7: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 8: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | 9: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | A: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | B: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | C: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | D: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | E: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n\t" + "movel %1@+,%3 | F: Fetch 32-bit word\n\t" + "addxl %3,%0 | Add word + previous carry\n" + "lcsum2_lbl:\n\tdbf %2,lcsum1_lbl | (NB- dbra doesn't affect X)\n\t" + "movel %0,%3 | Fold 32 bit sum to 16 bits\n\t" + "swap %3 | (NB- swap doesn't affect X)\n\t" + "addxw %3,%0 |\n\t" + "moveq #0,%3 | Add in last carry\n\t" + "addxw %3,%0 |\n\t" + "andl #0xffff,%0 | Mask to 16-bit sum\n" : + "=d" (sum), "=a" (w), "=d" (tcnt) , "=d" (t1) : + "0" (sum), "1" (w), "2" (tcnt) : + "cc", "memory"); + } + mlen &= 3; + + /* + * Soak up the last 1, 2 or 3 bytes + */ + while ((mlen -= 2) >= 0) + sum += *w++; + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(char *)w; + sum += s_util.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(char *)w; + } + if (len) + sum = 0xDEAD; + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} + + +#else +/* + * Checksum routine for Internet Protocol family headers (Portable Version). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + */ + + +int +in_cksum(m, len) + register struct mbuf *m; + register int len; +{ + register u_short *w; + register int sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + union { + char c[2]; + u_short s; + } s_util; + union { + u_short s[2]; + long l; + } l_util; + + for (;m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + w = mtod(m, u_short *); + if (mlen == -1) { + /* + * The first byte of this mbuf is the continuation + * of a word spanning between this mbuf and the + * last mbuf. + * + * s_util.c[0] is already saved when scanning previous + * mbuf. + */ + s_util.c[1] = *(char *)w; + sum += s_util.s; + w = (u_short *)((char *)w + 1); + mlen = m->m_len - 1; + len--; + } else + mlen = m->m_len; + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to even boundary. + */ + if ((1 & (int) w) && (mlen > 0)) { + REDUCE; + sum <<= 8; + s_util.c[0] = *(u_char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + /* + * Unroll the loop to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; + sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; + sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; + w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + continue; + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(char *)w; + sum += s_util.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(char *)w; + } + if (len) + printf("cksum: out of data\n"); + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} +#endif diff --git a/cpukit/libnetworking/netinet/in_pcb.c b/cpukit/libnetworking/netinet/in_pcb.c new file mode 100644 index 0000000000..5241ddb6f8 --- /dev/null +++ b/cpukit/libnetworking/netinet/in_pcb.c @@ -0,0 +1,757 @@ +/* + * Copyright (c) 1982, 1986, 1991, 1993, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> + +struct in_addr zeroin_addr; + +static void in_pcbinshash __P((struct inpcb *)); +static void in_rtchange __P((struct inpcb *, int)); + +/* + * These configure the range of local port addresses assigned to + * "unspecified" outgoing connections/packets/whatever. + */ +static int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */ +static int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */ +static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ +static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ +static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 40000 */ +static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 44999 */ + +#define RANGECHK(var, min, max) \ + if ((var) < (min)) { (var) = (min); } \ + else if ((var) > (max)) { (var) = (max); } + +#if 0 +static int +sysctl_net_ipport_check SYSCTL_HANDLER_ARGS +{ + int error = sysctl_handle_int(oidp, + oidp->oid_arg1, oidp->oid_arg2, req); + if (!error) { + RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1); + RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1); + RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX); + RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX); + RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX); + RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX); + } + return error; +} +#endif + +#undef RANGECHK + +SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); + +SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, + &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", ""); +SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW, + &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", ""); +SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW, + &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", ""); +SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW, + &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", ""); +SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW, + &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", ""); +SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW, + &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", ""); + +int +in_pcballoc(so, pcbinfo) + struct socket *so; + struct inpcbinfo *pcbinfo; +{ + register struct inpcb *inp; + int s; + + MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_NOWAIT); + if (inp == NULL) + return (ENOBUFS); + bzero((caddr_t)inp, sizeof(*inp)); + inp->inp_pcbinfo = pcbinfo; + inp->inp_socket = so; + s = splnet(); + LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); + in_pcbinshash(inp); + splx(s); + so->so_pcb = (caddr_t)inp; + return (0); +} + +int +in_pcbbind(inp, nam) + register struct inpcb *inp; + struct mbuf *nam; +{ + register struct socket *so = inp->inp_socket; + unsigned short *lastport; + struct sockaddr_in *sin; + u_short lport = 0; + int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); + int error; + + if (in_ifaddr == 0) + return (EADDRNOTAVAIL); + if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) + return (EINVAL); + if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && + ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || + (so->so_options & SO_ACCEPTCONN) == 0)) + wild = 1; + if (nam) { + sin = mtod(nam, struct sockaddr_in *); + if (nam->m_len != sizeof (*sin)) + return (EINVAL); +#ifdef notdef + /* + * We should check the family, but old programs + * incorrectly fail to initialize it. + */ + if (sin->sin_family != AF_INET) + return (EAFNOSUPPORT); +#endif + lport = sin->sin_port; + if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { + /* + * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; + * allow complete duplication of binding if + * SO_REUSEPORT is set, or if SO_REUSEADDR is set + * and a multicast address is bound on both + * new and duplicated sockets. + */ + if (so->so_options & SO_REUSEADDR) + reuseport = SO_REUSEADDR|SO_REUSEPORT; + } else if (sin->sin_addr.s_addr != INADDR_ANY) { + sin->sin_port = 0; /* yech... */ + if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) + return (EADDRNOTAVAIL); + } + if (lport) { + struct inpcb *t; + + /* GROSS */ + if (ntohs(lport) < IPPORT_RESERVED && + (error = suser(p->p_ucred, &p->p_acflag))) + return (EACCES); + if (so->so_uid) { + t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, + 0, sin->sin_addr, lport, + INPLOOKUP_WILDCARD); + if (t && (so->so_uid != t->inp_socket->so_uid)) + return (EADDRINUSE); + } + t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, + sin->sin_addr, lport, wild); + if (t && (reuseport & t->inp_socket->so_options) == 0) + return (EADDRINUSE); + } + inp->inp_laddr = sin->sin_addr; + } + if (lport == 0) { + ushort first, last; + int count; + + inp->inp_flags |= INP_ANONPORT; + + if (inp->inp_flags & INP_HIGHPORT) { + first = ipport_hifirstauto; /* sysctl */ + last = ipport_hilastauto; + lastport = &inp->inp_pcbinfo->lasthi; + } else if (inp->inp_flags & INP_LOWPORT) { + if (error = suser(p->p_ucred, &p->p_acflag)) + return (EACCES); + first = ipport_lowfirstauto; /* 1023 */ + last = ipport_lowlastauto; /* 600 */ + lastport = &inp->inp_pcbinfo->lastlow; + } else { + first = ipport_firstauto; /* sysctl */ + last = ipport_lastauto; + lastport = &inp->inp_pcbinfo->lastport; + } + /* + * Simple check to ensure all ports are not used up causing + * a deadlock here. + * + * We split the two cases (up and down) so that the direction + * is not being tested on each round of the loop. + */ + if (first > last) { + /* + * counting down + */ + count = first - last; + + do { + if (count-- <= 0) /* completely used? */ + return (EADDRNOTAVAIL); + --*lastport; + if (*lastport > first || *lastport < last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup(inp->inp_pcbinfo, + zeroin_addr, 0, inp->inp_laddr, lport, wild)); + } else { + /* + * counting up + */ + count = last - first; + + do { + if (count-- <= 0) /* completely used? */ + return (EADDRNOTAVAIL); + ++*lastport; + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup(inp->inp_pcbinfo, + zeroin_addr, 0, inp->inp_laddr, lport, wild)); + } + } + inp->inp_lport = lport; + in_pcbrehash(inp); + return (0); +} + +/* + * Transform old in_pcbconnect() into an inner subroutine for new + * in_pcbconnect(): Do some validity-checking on the remote + * address (in mbuf 'nam') and then determine local host address + * (i.e., which interface) to use to access that remote host. + * + * This preserves definition of in_pcbconnect(), while supporting a + * slightly different version for T/TCP. (This is more than + * a bit of a kludge, but cleaning up the internal interfaces would + * have forced minor changes in every protocol). + */ + +int +in_pcbladdr(inp, nam, plocal_sin) + register struct inpcb *inp; + struct mbuf *nam; + struct sockaddr_in **plocal_sin; +{ + struct in_ifaddr *ia; + register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); + + if (nam->m_len != sizeof (*sin)) + return (EINVAL); + if (sin->sin_family != AF_INET) + return (EAFNOSUPPORT); + if (sin->sin_port == 0) + return (EADDRNOTAVAIL); + if (in_ifaddr) { + /* + * If the destination address is INADDR_ANY, + * use the primary local address. + * If the supplied address is INADDR_BROADCAST, + * and the primary interface supports broadcast, + * choose the broadcast address for that interface. + */ +#define satosin(sa) ((struct sockaddr_in *)(sa)) +#define sintosa(sin) ((struct sockaddr *)(sin)) +#define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) + if (sin->sin_addr.s_addr == INADDR_ANY) + sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; + else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && + (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) + sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; + } + if (inp->inp_laddr.s_addr == INADDR_ANY) { + register struct route *ro; + + ia = (struct in_ifaddr *)0; + /* + * If route is known or can be allocated now, + * our src addr is taken from the i/f, else punt. + */ + ro = &inp->inp_route; + if (ro->ro_rt && + (satosin(&ro->ro_dst)->sin_addr.s_addr != + sin->sin_addr.s_addr || + inp->inp_socket->so_options & SO_DONTROUTE)) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } + if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ + (ro->ro_rt == (struct rtentry *)0 || + ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + /* No route yet, so try to acquire one */ + ro->ro_dst.sa_family = AF_INET; + ro->ro_dst.sa_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = + sin->sin_addr; + rtalloc(ro); + } + /* + * If we found a route, use the address + * corresponding to the outgoing interface + * unless it is the loopback (in case a route + * to our address on another net goes to loopback). + */ + if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) + ia = ifatoia(ro->ro_rt->rt_ifa); + if (ia == 0) { + u_short fport = sin->sin_port; + + sin->sin_port = 0; + ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); + if (ia == 0) + ia = ifatoia(ifa_ifwithnet(sintosa(sin))); + sin->sin_port = fport; + if (ia == 0) + ia = in_ifaddr; + if (ia == 0) + return (EADDRNOTAVAIL); + } + /* + * If the destination address is multicast and an outgoing + * interface has been set as a multicast option, use the + * address of that interface as our source address. + */ + if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && + inp->inp_moptions != NULL) { + struct ip_moptions *imo; + struct ifnet *ifp; + + imo = inp->inp_moptions; + if (imo->imo_multicast_ifp != NULL) { + ifp = imo->imo_multicast_ifp; + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) + break; + if (ia == 0) + return (EADDRNOTAVAIL); + } + } + /* + * Don't do pcblookup call here; return interface in plocal_sin + * and exit to caller, that will do the lookup. + */ + *plocal_sin = &ia->ia_addr; + + } + return(0); +} + +/* + * Outer subroutine: + * Connect from a socket to a specified address. + * Both address and port must be specified in argument sin. + * If don't have a local address for this socket yet, + * then pick one. + */ +int +in_pcbconnect(inp, nam) + register struct inpcb *inp; + struct mbuf *nam; +{ + struct sockaddr_in *ifaddr; + register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); + int error; + + /* + * Call inner routine, to assign local interface address. + */ + if (error = in_pcbladdr(inp, nam, &ifaddr)) + return(error); + + if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, + inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, + inp->inp_lport, 0) != NULL) + return (EADDRINUSE); + if (inp->inp_laddr.s_addr == INADDR_ANY) { + if (inp->inp_lport == 0) + (void)in_pcbbind(inp, (struct mbuf *)0); + inp->inp_laddr = ifaddr->sin_addr; + } + inp->inp_faddr = sin->sin_addr; + inp->inp_fport = sin->sin_port; + in_pcbrehash(inp); + return (0); +} + +void +in_pcbdisconnect(inp) + struct inpcb *inp; +{ + + inp->inp_faddr.s_addr = INADDR_ANY; + inp->inp_fport = 0; + in_pcbrehash(inp); + if (inp->inp_socket->so_state & SS_NOFDREF) + in_pcbdetach(inp); +} + +void +in_pcbdetach(inp) + struct inpcb *inp; +{ + struct socket *so = inp->inp_socket; + int s; + + so->so_pcb = 0; + sofree(so); + if (inp->inp_options) + (void)m_free(inp->inp_options); + if (inp->inp_route.ro_rt) + rtfree(inp->inp_route.ro_rt); + ip_freemoptions(inp->inp_moptions); + s = splnet(); + LIST_REMOVE(inp, inp_hash); + LIST_REMOVE(inp, inp_list); + splx(s); + FREE(inp, M_PCB); +} + +void +in_setsockaddr(inp, nam) + register struct inpcb *inp; + struct mbuf *nam; +{ + register struct sockaddr_in *sin; + + nam->m_len = sizeof (*sin); + sin = mtod(nam, struct sockaddr_in *); + bzero((caddr_t)sin, sizeof (*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_port = inp->inp_lport; + sin->sin_addr = inp->inp_laddr; +} + +void +in_setpeeraddr(inp, nam) + struct inpcb *inp; + struct mbuf *nam; +{ + register struct sockaddr_in *sin; + + nam->m_len = sizeof (*sin); + sin = mtod(nam, struct sockaddr_in *); + bzero((caddr_t)sin, sizeof (*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_port = inp->inp_fport; + sin->sin_addr = inp->inp_faddr; +} + +/* + * Pass some notification to all connections of a protocol + * associated with address dst. The local address and/or port numbers + * may be specified to limit the search. The "usual action" will be + * taken, depending on the ctlinput cmd. The caller must filter any + * cmds that are uninteresting (e.g., no error in the map). + * Call the protocol specific routine (if any) to report + * any errors for each matching socket. + * + * Must be called at splnet. + */ +void +in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) + struct inpcbhead *head; + struct sockaddr *dst; + u_int fport_arg, lport_arg; + struct in_addr laddr; + int cmd; + void (*notify) __P((struct inpcb *, int)); +{ + register struct inpcb *inp, *oinp; + struct in_addr faddr; + u_short fport = fport_arg, lport = lport_arg; + int errnum, s; + + if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) + return; + faddr = ((struct sockaddr_in *)dst)->sin_addr; + if (faddr.s_addr == INADDR_ANY) + return; + + /* + * Redirects go to all references to the destination, + * and use in_rtchange to invalidate the route cache. + * Dead host indications: notify all references to the destination. + * Otherwise, if we have knowledge of the local port and address, + * deliver only to that socket. + */ + if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { + fport = 0; + lport = 0; + laddr.s_addr = 0; + if (cmd != PRC_HOSTDEAD) + notify = in_rtchange; + } + errnum = inetctlerrmap[cmd]; + s = splnet(); + for (inp = head->lh_first; inp != NULL;) { + if (inp->inp_faddr.s_addr != faddr.s_addr || + inp->inp_socket == 0 || + (lport && inp->inp_lport != lport) || + (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || + (fport && inp->inp_fport != fport)) { + inp = inp->inp_list.le_next; + continue; + } + oinp = inp; + inp = inp->inp_list.le_next; + if (notify) + (*notify)(oinp, errnum); + } + splx(s); +} + +/* + * Check for alternatives when higher level complains + * about service problems. For now, invalidate cached + * routing information. If the route was created dynamically + * (by a redirect), time to try a default gateway again. + */ +void +in_losing(inp) + struct inpcb *inp; +{ + register struct rtentry *rt; + struct rt_addrinfo info; + + if ((rt = inp->inp_route.ro_rt)) { + inp->inp_route.ro_rt = 0; + bzero((caddr_t)&info, sizeof(info)); + info.rti_info[RTAX_DST] = + (struct sockaddr *)&inp->inp_route.ro_dst; + info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; + info.rti_info[RTAX_NETMASK] = rt_mask(rt); + rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); + if (rt->rt_flags & RTF_DYNAMIC) + (void) rtrequest(RTM_DELETE, rt_key(rt), + rt->rt_gateway, rt_mask(rt), rt->rt_flags, + (struct rtentry **)0); + else + /* + * A new route can be allocated + * the next time output is attempted. + */ + rtfree(rt); + } +} + +/* + * After a routing change, flush old routing + * and allocate a (hopefully) better one. + */ +static void +in_rtchange(inp, errnum) + register struct inpcb *inp; + int errnum; +{ + if (inp->inp_route.ro_rt) { + rtfree(inp->inp_route.ro_rt); + inp->inp_route.ro_rt = 0; + /* + * A new route can be allocated the next time + * output is attempted. + */ + } +} + +struct inpcb * +in_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay) + struct inpcbinfo *pcbinfo; + struct in_addr faddr, laddr; + u_int fport_arg, lport_arg; + int wild_okay; +{ + register struct inpcb *inp, *match = NULL; + int matchwild = 3, wildcard; + u_short fport = fport_arg, lport = lport_arg; + int s; + + s = splnet(); + + for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { + if (inp->inp_lport != lport) + continue; + wildcard = 0; + if (inp->inp_faddr.s_addr != INADDR_ANY) { + if (faddr.s_addr == INADDR_ANY) + wildcard++; + else if (inp->inp_faddr.s_addr != faddr.s_addr || + inp->inp_fport != fport) + continue; + } else { + if (faddr.s_addr != INADDR_ANY) + wildcard++; + } + if (inp->inp_laddr.s_addr != INADDR_ANY) { + if (laddr.s_addr == INADDR_ANY) + wildcard++; + else if (inp->inp_laddr.s_addr != laddr.s_addr) + continue; + } else { + if (laddr.s_addr != INADDR_ANY) + wildcard++; + } + if (wildcard && wild_okay == 0) + continue; + if (wildcard < matchwild) { + match = inp; + matchwild = wildcard; + if (matchwild == 0) { + break; + } + } + } + splx(s); + return (match); +} + +/* + * Lookup PCB in hash list. + */ +struct inpcb * +in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) + struct inpcbinfo *pcbinfo; + struct in_addr faddr, laddr; + u_int fport_arg, lport_arg; + int wildcard; +{ + struct inpcbhead *head; + register struct inpcb *inp; + u_short fport = fport_arg, lport = lport_arg; + int s; + + s = splnet(); + /* + * First look for an exact match. + */ + head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; + for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { + if (inp->inp_faddr.s_addr == faddr.s_addr && + inp->inp_laddr.s_addr == laddr.s_addr && + inp->inp_fport == fport && + inp->inp_lport == lport) + goto found; + } + if (wildcard) { + struct inpcb *local_wild = NULL; + + head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; + for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { + if (inp->inp_faddr.s_addr == INADDR_ANY && + inp->inp_fport == 0 && inp->inp_lport == lport) { + if (inp->inp_laddr.s_addr == laddr.s_addr) + goto found; + else if (inp->inp_laddr.s_addr == INADDR_ANY) + local_wild = inp; + } + } + if (local_wild != NULL) { + inp = local_wild; + goto found; + } + } + splx(s); + return (NULL); + +found: + /* + * Move PCB to head of this hash chain so that it can be + * found more quickly in the future. + * XXX - this is a pessimization on machines with few + * concurrent connections. + */ + if (inp != head->lh_first) { + LIST_REMOVE(inp, inp_hash); + LIST_INSERT_HEAD(head, inp, inp_hash); + } + splx(s); + return (inp); +} + +/* + * Insert PCB into hash chain. Must be called at splnet. + */ +static void +in_pcbinshash(inp) + struct inpcb *inp; +{ + struct inpcbhead *head; + + head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, + inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; + + LIST_INSERT_HEAD(head, inp, inp_hash); +} + +void +in_pcbrehash(inp) + struct inpcb *inp; +{ + struct inpcbhead *head; + int s; + + s = splnet(); + LIST_REMOVE(inp, inp_hash); + + head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, + inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; + + LIST_INSERT_HEAD(head, inp, inp_hash); + splx(s); +} diff --git a/cpukit/libnetworking/netinet/in_pcb.h b/cpukit/libnetworking/netinet/in_pcb.h new file mode 100644 index 0000000000..9390cfda6c --- /dev/null +++ b/cpukit/libnetworking/netinet/in_pcb.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_pcb.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_IN_PCB_H_ +#define _NETINET_IN_PCB_H_ + +#include <sys/queue.h> + +/* + * Common structure pcb for internet protocol implementation. + * Here are stored pointers to local and foreign host table + * entries, local and foreign socket numbers, and pointers + * up (to a socket structure) and down (to a protocol-specific) + * control block. + */ +LIST_HEAD(inpcbhead, inpcb); + +struct inpcb { + LIST_ENTRY(inpcb) inp_list; /* list for all PCBs of this proto */ + LIST_ENTRY(inpcb) inp_hash; /* hash list */ + struct inpcbinfo *inp_pcbinfo; /* PCB list info */ + struct in_addr inp_faddr; /* foreign host table entry */ + struct in_addr inp_laddr; /* local host table entry */ + u_short inp_fport; /* foreign port */ + u_short inp_lport; /* local port */ + caddr_t inp_ppcb; /* pointer to per-protocol pcb */ + struct socket *inp_socket; /* back pointer to socket */ + struct mbuf *inp_options; /* IP options */ + struct route inp_route; /* placeholder for routing entry */ + int inp_flags; /* generic IP/datagram flags */ + u_char inp_ip_tos; /* type of service proto */ + u_char inp_ip_ttl; /* time to live proto */ + u_char inp_ip_p; /* protocol proto */ + u_char pad[1]; /* alignment */ + struct ip_moptions *inp_moptions; /* IP multicast options */ +#if 0 /* Someday, perhaps... */ + struct ip inp_ip; /* header prototype; should have more */ +#endif +}; + +struct inpcbinfo { + struct inpcbhead *listhead; + struct inpcbhead *hashbase; + unsigned long hashmask; + unsigned short lastport; + unsigned short lastlow; + unsigned short lasthi; +}; + +#define INP_PCBHASH(faddr, lport, fport, mask) \ + (((faddr) ^ ((faddr) >> 16) ^ (lport) ^ (fport)) & (mask)) + +/* flags in inp_flags: */ +#define INP_RECVOPTS 0x01 /* receive incoming IP options */ +#define INP_RECVRETOPTS 0x02 /* receive IP options for reply */ +#define INP_RECVDSTADDR 0x04 /* receive IP dst address */ +#define INP_HDRINCL 0x08 /* user supplies entire IP header */ +#define INP_HIGHPORT 0x10 /* user wants "high" port binding */ +#define INP_LOWPORT 0x20 /* user wants "low" port binding */ +#define INP_ANONPORT 0x40 /* port chosen for user */ +#define INP_RECVIF 0x80 /* receive incoming interface */ +#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ + INP_RECVIF) + +#define INPLOOKUP_WILDCARD 1 + +#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) + +#ifdef KERNEL +void in_losing __P((struct inpcb *)); +int in_pcballoc __P((struct socket *, struct inpcbinfo *)); +int in_pcbbind __P((struct inpcb *, struct mbuf *)); +int in_pcbconnect __P((struct inpcb *, struct mbuf *)); +void in_pcbdetach __P((struct inpcb *)); +void in_pcbdisconnect __P((struct inpcb *)); +int in_pcbladdr __P((struct inpcb *, struct mbuf *, + struct sockaddr_in **)); +struct inpcb * + in_pcblookup __P((struct inpcbinfo *, + struct in_addr, u_int, struct in_addr, u_int, int)); +struct inpcb * + in_pcblookuphash __P((struct inpcbinfo *, + struct in_addr, u_int, struct in_addr, u_int, int)); +void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *, + u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int))); +void in_pcbrehash __P((struct inpcb *)); +void in_setpeeraddr __P((struct inpcb *, struct mbuf *)); +void in_setsockaddr __P((struct inpcb *, struct mbuf *)); +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/in_proto.c b/cpukit/libnetworking/netinet/in_proto.c new file mode 100644 index 0000000000..3fa845955e --- /dev/null +++ b/cpukit/libnetworking/netinet/in_proto.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_proto.c 8.2 (Berkeley) 2/9/95 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/radix.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/in_pcb.h> +#include <netinet/igmp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +#endif +#include <netinet/udp.h> +#include <netinet/udp_var.h> +/* + * TCP/IP protocol family: IP, ICMP, UDP, TCP. + */ + +#ifdef IPXIP +#include <netipx/ipx.h> +#include <netipx/ipx_ip.h> +#endif + +#ifdef NSIP +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + +#ifdef TPIP +void tpip_input(), tpip_ctlinput(), tp_init(), tp_slowtimo(), tp_drain(); +int tp_ctloutput(), tp_usrreq(); +#endif + +#ifdef EON +void eoninput(), eonctlinput(), eonprotoinit(); +#endif /* EON */ + +extern struct domain inetdomain; + +struct protosw inetsw[] = { +{ 0, &inetdomain, 0, 0, + 0, 0, 0, 0, + 0, + ip_init, 0, ip_slowtimo, ip_drain +}, +{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR, + udp_input, 0, udp_ctlinput, ip_ctloutput, + udp_usrreq, + udp_init +}, +{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, + PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD, + tcp_input, 0, tcp_ctlinput, tcp_ctloutput, + 0, + tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, + &tcp_usrreqs +}, +{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR, + rip_input, 0, 0, rip_ctloutput, + rip_usrreq, + 0, 0, 0, 0, +}, +{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR, + icmp_input, 0, 0, rip_ctloutput, + rip_usrreq +}, +{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR, + igmp_input, 0, 0, rip_ctloutput, + rip_usrreq, + igmp_init, igmp_fasttimo, igmp_slowtimo +}, +{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR, + rsvp_input, 0, 0, rip_ctloutput, + rip_usrreq, + 0, 0, 0, 0, +}, +{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR, + ipip_input, 0, 0, rip_ctloutput, + rip_usrreq, + 0, 0, 0, 0, +}, +#ifdef IPDIVERT +{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, + div_input, 0, 0, ip_ctloutput, + div_usrreq, + div_init, 0, 0, 0, +}, +#endif +#ifdef TPIP +{ SOCK_SEQPACKET,&inetdomain, IPPROTO_TP, PR_CONNREQUIRED|PR_WANTRCVD, + tpip_input, 0, tpip_ctlinput, tp_ctloutput, + tp_usrreq, + tp_init, 0, tp_slowtimo, tp_drain, +}, +#endif +/* EON (ISO CLNL over IP) */ +#ifdef EON +{ SOCK_RAW, &inetdomain, IPPROTO_EON, 0, + eoninput, 0, eonctlinput, 0, + 0, + eonprotoinit, 0, 0, 0, +}, +#endif +#ifdef IPXIP +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, + ipxip_input, 0, ipxip_ctlinput, 0, + rip_usrreq, + 0, 0, 0, 0, +}, +#endif +#ifdef NSIP +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, + idpip_input, 0, nsip_ctlinput, 0, + rip_usrreq, + 0, 0, 0, 0, +}, +#endif + /* raw wildcard */ +{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR, + rip_input, 0, 0, rip_ctloutput, + rip_usrreq, + rip_init, 0, 0, 0, +}, +}; + +extern int in_inithead(void **, int); + +struct domain inetdomain = + { AF_INET, "internet", 0, 0, 0, + inetsw, &inetsw[sizeof(inetsw)/sizeof(inetsw[0])], 0, + in_inithead, 32, sizeof(struct sockaddr_in) + }; + +DOMAIN_SET(inet); + +SYSCTL_NODE(_net, PF_INET, inet, CTLFLAG_RW, 0, + "Internet Family"); + +SYSCTL_NODE(_net_inet, IPPROTO_IP, ip, CTLFLAG_RW, 0, "IP"); +SYSCTL_NODE(_net_inet, IPPROTO_ICMP, icmp, CTLFLAG_RW, 0, "ICMP"); +SYSCTL_NODE(_net_inet, IPPROTO_UDP, udp, CTLFLAG_RW, 0, "UDP"); +SYSCTL_NODE(_net_inet, IPPROTO_TCP, tcp, CTLFLAG_RW, 0, "TCP"); +SYSCTL_NODE(_net_inet, IPPROTO_IGMP, igmp, CTLFLAG_RW, 0, "IGMP"); +#ifdef IPDIVERT +SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, div, CTLFLAG_RW, 0, "DIVERT"); +#endif + diff --git a/cpukit/libnetworking/netinet/in_rmx.c b/cpukit/libnetworking/netinet/in_rmx.c new file mode 100644 index 0000000000..ba1793b3b4 --- /dev/null +++ b/cpukit/libnetworking/netinet/in_rmx.c @@ -0,0 +1,384 @@ +/* + * Copyright 1994, 1995 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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. + * + * $Id$ + */ + +/* + * This code does two things necessary for the enhanced TCP metrics to + * function in a useful manner: + * 1) It marks all non-host routes as `cloning', thus ensuring that + * every actual reference to such a route actually gets turned + * into a reference to a host route to the specific destination + * requested. + * 2) When such routes lose all their references, it arranges for them + * to be deleted in some random collection of circumstances, so that + * a large quantity of stale routing data is not kept in kernel memory + * indefinitely. See in_rtqtimo() below for the exact mechanism. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/mbuf.h> +#include <sys/syslog.h> + +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> + +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +#include <netinet/tcp.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> + +extern int in_inithead __P((void **head, int off)); + +#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ + +/* + * Do what we need to do when inserting a route. + */ +static struct radix_node * +in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, + struct radix_node *treenodes) +{ + struct rtentry *rt = (struct rtentry *)treenodes; + struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); + struct radix_node *ret; + + /* + * For IP, all unicast non-host routes are automatically cloning. + */ + if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) + rt->rt_flags |= RTF_MULTICAST; + + if(!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { + rt->rt_flags |= RTF_PRCLONING; + } + + /* + * A little bit of help for both IP output and input: + * For host routes, we make sure that RTF_BROADCAST + * is set for anything that looks like a broadcast address. + * This way, we can avoid an expensive call to in_broadcast() + * in ip_output() most of the time (because the route passed + * to ip_output() is almost always a host route). + * + * We also do the same for local addresses, with the thought + * that this might one day be used to speed up ip_input(). + * + * We also mark routes to multicast addresses as such, because + * it's easy to do and might be useful (but this is much more + * dubious since it's so easy to inspect the address). (This + * is done above.) + */ + if (rt->rt_flags & RTF_HOST) { + if (in_broadcast(sin->sin_addr, rt->rt_ifp)) { + rt->rt_flags |= RTF_BROADCAST; + } else { +#define satosin(sa) ((struct sockaddr_in *)sa) + if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr + == sin->sin_addr.s_addr) + rt->rt_flags |= RTF_LOCAL; +#undef satosin + } + } + + /* + * We also specify a send and receive pipe size for every + * route added, to help TCP a bit. TCP doesn't actually + * want a true pipe size, which would be prohibitive in memory + * costs and is hard to compute anyway; it simply uses these + * values to size its buffers. So, we fill them in with the + * same values that TCP would have used anyway, and allow the + * installing program or the link layer to override these values + * as it sees fit. This will hopefully allow TCP more + * opportunities to save its ssthresh value. + */ + if (!rt->rt_rmx.rmx_sendpipe && !(rt->rt_rmx.rmx_locks & RTV_SPIPE)) + rt->rt_rmx.rmx_sendpipe = tcp_sendspace; + + if (!rt->rt_rmx.rmx_recvpipe && !(rt->rt_rmx.rmx_locks & RTV_RPIPE)) + rt->rt_rmx.rmx_recvpipe = tcp_recvspace; + + if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) + && rt->rt_ifp) + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; + + ret = rn_addroute(v_arg, n_arg, head, treenodes); + if (ret == NULL && rt->rt_flags & RTF_HOST) { + struct rtentry *rt2; + /* + * We are trying to add a host route, but can't. + * Find out if it is because of an + * ARP entry and delete it if so. + */ + rt2 = rtalloc1((struct sockaddr *)sin, 0, + RTF_CLONING | RTF_PRCLONING); + if (rt2) { + if (rt2->rt_flags & RTF_LLINFO && + rt2->rt_flags & RTF_HOST && + rt2->rt_gateway && + rt2->rt_gateway->sa_family == AF_LINK) { + rtrequest(RTM_DELETE, + (struct sockaddr *)rt_key(rt2), + rt2->rt_gateway, + rt_mask(rt2), rt2->rt_flags, 0); + ret = rn_addroute(v_arg, n_arg, head, + treenodes); + } + RTFREE(rt2); + } + } + return ret; +} + +/* + * This code is the inverse of in_clsroute: on first reference, if we + * were managing the route, stop doing so and set the expiration timer + * back off again. + */ +static struct radix_node * +in_matroute(void *v_arg, struct radix_node_head *head) +{ + struct radix_node *rn = rn_match(v_arg, head); + struct rtentry *rt = (struct rtentry *)rn; + + if(rt && rt->rt_refcnt == 0) { /* this is first reference */ + if(rt->rt_flags & RTPRF_OURS) { + rt->rt_flags &= ~RTPRF_OURS; + rt->rt_rmx.rmx_expire = 0; + } + } + return rn; +} + +static int rtq_reallyold = 60*60; + /* one hour is ``really old'' */ +SYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire, + CTLFLAG_RW, &rtq_reallyold , 0, ""); + +static int rtq_minreallyold = 10; + /* never automatically crank down to less */ +SYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire, + CTLFLAG_RW, &rtq_minreallyold , 0, ""); + +static int rtq_toomany = 128; + /* 128 cached routes is ``too many'' */ +SYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache, + CTLFLAG_RW, &rtq_toomany , 0, ""); + + +/* + * On last reference drop, mark the route as belong to us so that it can be + * timed out. + */ +static void +in_clsroute(struct radix_node *rn, struct radix_node_head *head) +{ + struct rtentry *rt = (struct rtentry *)rn; + + if(!(rt->rt_flags & RTF_UP)) + return; /* prophylactic measures */ + + if((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) + return; + + if((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) + != RTF_WASCLONED) + return; + + /* + * As requested by David Greenman: + * If rtq_reallyold is 0, just delete the route without + * waiting for a timeout cycle to kill it. + */ + if(rtq_reallyold != 0) { + rt->rt_flags |= RTPRF_OURS; + rt->rt_rmx.rmx_expire = rtems_bsdnet_seconds_since_boot() + rtq_reallyold; + } else { + rtrequest(RTM_DELETE, + (struct sockaddr *)rt_key(rt), + rt->rt_gateway, rt_mask(rt), + rt->rt_flags, 0); + } +} + +struct rtqk_arg { + struct radix_node_head *rnh; + int draining; + int killed; + int found; + int updating; + time_t nextstop; +}; + +/* + * Get rid of old routes. When draining, this deletes everything, even when + * the timeout is not expired yet. When updating, this makes sure that + * nothing has a timeout longer than the current value of rtq_reallyold. + */ +static int +in_rtqkill(struct radix_node *rn, void *rock) +{ + struct rtqk_arg *ap = rock; + struct rtentry *rt = (struct rtentry *)rn; + int err; + + if(rt->rt_flags & RTPRF_OURS) { + ap->found++; + + if(ap->draining || rt->rt_rmx.rmx_expire <= rtems_bsdnet_seconds_since_boot()) { + if(rt->rt_refcnt > 0) + panic("rtqkill route really not free"); + + err = rtrequest(RTM_DELETE, + (struct sockaddr *)rt_key(rt), + rt->rt_gateway, rt_mask(rt), + rt->rt_flags, 0); + if(err) { + log(LOG_WARNING, "in_rtqkill: error %d\n", err); + } else { + ap->killed++; + } + } else { + if(ap->updating + && (rt->rt_rmx.rmx_expire - rtems_bsdnet_seconds_since_boot() + > rtq_reallyold)) { + rt->rt_rmx.rmx_expire = rtems_bsdnet_seconds_since_boot() + + rtq_reallyold; + } + ap->nextstop = lmin(ap->nextstop, + rt->rt_rmx.rmx_expire); + } + } + + return 0; +} + +#define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */ +static int rtq_timeout = RTQ_TIMEOUT; + +static void +in_rtqtimo(void *rock) +{ + struct radix_node_head *rnh = rock; + struct rtqk_arg arg; + struct timeval atv; + static time_t last_adjusted_timeout = 0; + int s; + + arg.found = arg.killed = 0; + arg.rnh = rnh; + arg.nextstop = rtems_bsdnet_seconds_since_boot() + rtq_timeout; + arg.draining = arg.updating = 0; + s = splnet(); + rnh->rnh_walktree(rnh, in_rtqkill, &arg); + splx(s); + + /* + * Attempt to be somewhat dynamic about this: + * If there are ``too many'' routes sitting around taking up space, + * then crank down the timeout, and see if we can't make some more + * go away. However, we make sure that we will never adjust more + * than once in rtq_timeout seconds, to keep from cranking down too + * hard. + */ + if((arg.found - arg.killed > rtq_toomany) + && (rtems_bsdnet_seconds_since_boot() - last_adjusted_timeout >= rtq_timeout) + && rtq_reallyold > rtq_minreallyold) { + rtq_reallyold = 2*rtq_reallyold / 3; + if(rtq_reallyold < rtq_minreallyold) { + rtq_reallyold = rtq_minreallyold; + } + + last_adjusted_timeout = rtems_bsdnet_seconds_since_boot(); +#ifdef DIAGNOSTIC + log(LOG_DEBUG, "in_rtqtimo: adjusted rtq_reallyold to %d\n", + rtq_reallyold); +#endif + arg.found = arg.killed = 0; + arg.updating = 1; + s = splnet(); + rnh->rnh_walktree(rnh, in_rtqkill, &arg); + splx(s); + } + + atv.tv_usec = 0; + atv.tv_sec = arg.nextstop; + timeout(in_rtqtimo, rock, hzto(&atv)); +} + +void +in_rtqdrain(void) +{ + struct radix_node_head *rnh = rt_tables[AF_INET]; + struct rtqk_arg arg; + int s; + arg.found = arg.killed = 0; + arg.rnh = rnh; + arg.nextstop = 0; + arg.draining = 1; + arg.updating = 0; + s = splnet(); + rnh->rnh_walktree(rnh, in_rtqkill, &arg); + splx(s); +} + +/* + * Initialize our routing tree. + */ +int +in_inithead(void **head, int off) +{ + struct radix_node_head *rnh; + + if(!rn_inithead(head, off)) + return 0; + + if(head != (void **)&rt_tables[AF_INET]) /* BOGUS! */ + return 1; /* only do this for the real routing table */ + + rnh = *head; + rnh->rnh_addaddr = in_addroute; + rnh->rnh_matchaddr = in_matroute; + rnh->rnh_close = in_clsroute; + in_rtqtimo(rnh); /* kick off timeout first time */ + return 1; +} + diff --git a/cpukit/libnetworking/netinet/in_systm.h b/cpukit/libnetworking/netinet/in_systm.h new file mode 100644 index 0000000000..d72e9b4665 --- /dev/null +++ b/cpukit/libnetworking/netinet/in_systm.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_systm.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_IN_SYSTM_H_ +#define _NETINET_IN_SYSTM_H_ + +/* + * Miscellaneous internetwork + * definitions for kernel. + */ + +/* + * Network types. + * + * Internally the system keeps counters in the headers with the bytes + * swapped so that VAX instructions will work on them. It reverses + * the bytes before transmission at each protocol level. The n_ types + * represent the types with the bytes in ``high-ender'' order. + */ +typedef u_short n_short; /* short as received from the net */ +typedef u_long n_long; /* long as received from the net */ + +typedef u_long n_time; /* ms since 00:00 GMT, byte rev */ + +#ifdef KERNEL +n_time iptime __P((void)); +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/in_var.h b/cpukit/libnetworking/netinet/in_var.h new file mode 100644 index 0000000000..e7a54d5e85 --- /dev/null +++ b/cpukit/libnetworking/netinet/in_var.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 1985, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_var.h 8.2 (Berkeley) 1/9/95 + * $Id$ + */ + +#ifndef _NETINET_IN_VAR_H_ +#define _NETINET_IN_VAR_H_ + +#include <sys/queue.h> + +/* + * Interface address, Internet version. One of these structures + * is allocated for each interface with an Internet address. + * The ifaddr structure contains the protocol-independent part + * of the structure and is assumed to be first. + */ +struct in_ifaddr { + struct ifaddr ia_ifa; /* protocol-independent info */ +#define ia_ifp ia_ifa.ifa_ifp +#define ia_flags ia_ifa.ifa_flags + /* ia_{,sub}net{,mask} in host order */ + u_long ia_net; /* network number of interface */ + u_long ia_netmask; /* mask of net part */ + u_long ia_subnet; /* subnet number, including net */ + u_long ia_subnetmask; /* mask of subnet part */ + struct in_addr ia_netbroadcast; /* to recognize net broadcasts */ + struct in_ifaddr *ia_next; /* next in list of internet addresses */ + struct sockaddr_in ia_addr; /* reserve space for interface name */ + struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */ +#define ia_broadaddr ia_dstaddr + struct sockaddr_in ia_sockmask; /* reserve space for general netmask */ + LIST_HEAD(in_multihead, in_multi) ia_multiaddrs; + /* list of multicast addresses */ +}; + +struct in_aliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr_in ifra_addr; + struct sockaddr_in ifra_broadaddr; +#define ifra_dstaddr ifra_broadaddr + struct sockaddr_in ifra_mask; +}; +/* + * Given a pointer to an in_ifaddr (ifaddr), + * return a pointer to the addr as a sockaddr_in. + */ +#define IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr)) +#define IA_DSTSIN(ia) (&(((struct in_ifaddr *)(ia))->ia_dstaddr)) + +#define IN_LNAOF(in, ifa) \ + ((ntohl((in).s_addr) & ~((struct in_ifaddr *)(ifa)->ia_subnetmask)) + + +#ifdef KERNEL +extern struct in_ifaddr *in_ifaddr; +extern struct ifqueue ipintrq; /* ip packet input queue */ +extern struct in_addr zeroin_addr; +extern u_char inetctlerrmap[]; +extern int rtq_reallyold; /* XXX */ +extern int rtq_minreallyold; /* XXX */ +extern int rtq_toomany; /* XXX */ + +/* + * Macro for finding the interface (ifnet structure) corresponding to one + * of our IP addresses. + */ +#define INADDR_TO_IFP(addr, ifp) \ + /* struct in_addr addr; */ \ + /* struct ifnet *ifp; */ \ +{ \ + register struct in_ifaddr *ia; \ +\ + for (ia = in_ifaddr; \ + ia != NULL && ((ia->ia_ifp->if_flags & IFF_POINTOPOINT)? \ + IA_DSTSIN(ia):IA_SIN(ia))->sin_addr.s_addr != (addr).s_addr; \ + ia = ia->ia_next) \ + continue; \ + if (ia == NULL) \ + for (ia = in_ifaddr; \ + ia != NULL; \ + ia = ia->ia_next) \ + if (ia->ia_ifp->if_flags & IFF_POINTOPOINT && \ + IA_SIN(ia)->sin_addr.s_addr == (addr).s_addr) \ + break; \ + (ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \ +} + +/* + * Macro for finding the internet address structure (in_ifaddr) corresponding + * to a given interface (ifnet structure). + */ +#define IFP_TO_IA(ifp, ia) \ + /* struct ifnet *ifp; */ \ + /* struct in_ifaddr *ia; */ \ +{ \ + for ((ia) = in_ifaddr; \ + (ia) != NULL && (ia)->ia_ifp != (ifp); \ + (ia) = (ia)->ia_next) \ + continue; \ +} +#endif + +/* + * This information should be part of the ifnet structure but we don't wish + * to change that - as it might break a number of things + */ + +struct router_info { + struct ifnet *rti_ifp; + int rti_type; /* type of router which is querier on this interface */ + int rti_time; /* # of slow timeouts since last old query */ + struct router_info *rti_next; +}; + +/* + * Internet multicast address structure. There is one of these for each IP + * multicast group to which this host belongs on a given network interface. + * They are kept in a linked list, rooted in the interface's in_ifaddr + * structure. + */ +struct in_multi { + LIST_ENTRY(in_multi) inm_entry; /* list glue */ + struct in_addr inm_addr; /* IP multicast address */ + struct ifnet *inm_ifp; /* back pointer to ifnet */ + struct in_ifaddr *inm_ia; /* back pointer to in_ifaddr */ + u_int inm_refcount; /* no. membership claims by sockets */ + u_int inm_timer; /* IGMP membership report timer */ + u_int inm_state; /* state of the membership */ + struct router_info *inm_rti; /* router info*/ +}; + +#ifdef KERNEL +/* + * Structure used by macros below to remember position when stepping through + * all of the in_multi records. + */ +struct in_multistep { + struct in_ifaddr *i_ia; + struct in_multi *i_inm; +}; + +/* + * Macro for looking up the in_multi record for a given IP multicast address + * on a given interface. If no matching record is found, "inm" returns NULL. + */ +#define IN_LOOKUP_MULTI(addr, ifp, inm) \ + /* struct in_addr addr; */ \ + /* struct ifnet *ifp; */ \ + /* struct in_multi *inm; */ \ +{ \ + register struct in_ifaddr *ia; \ +\ + IFP_TO_IA((ifp), ia); \ + if (ia == NULL) \ + (inm) = NULL; \ + else \ + for ((inm) = ia->ia_multiaddrs.lh_first; \ + (inm) != NULL && (inm)->inm_addr.s_addr != (addr).s_addr; \ + (inm) = inm->inm_entry.le_next) \ + continue; \ +} + +/* + * Macro to step through all of the in_multi records, one at a time. + * The current position is remembered in "step", which the caller must + * provide. IN_FIRST_MULTI(), below, must be called to initialize "step" + * and get the first record. Both macros return a NULL "inm" when there + * are no remaining records. + */ +#define IN_NEXT_MULTI(step, inm) \ + /* struct in_multistep step; */ \ + /* struct in_multi *inm; */ \ +{ \ + if (((inm) = (step).i_inm) != NULL) \ + (step).i_inm = (inm)->inm_entry.le_next; \ + else \ + while ((step).i_ia != NULL) { \ + (inm) = (step).i_ia->ia_multiaddrs.lh_first; \ + (step).i_ia = (step).i_ia->ia_next; \ + if ((inm) != NULL) { \ + (step).i_inm = (inm)->inm_entry.le_next; \ + break; \ + } \ + } \ +} + +#define IN_FIRST_MULTI(step, inm) \ + /* struct in_multistep step; */ \ + /* struct in_multi *inm; */ \ +{ \ + (step).i_ia = in_ifaddr; \ + (step).i_inm = NULL; \ + IN_NEXT_MULTI((step), (inm)); \ +} + +struct in_multi *in_addmulti __P((struct in_addr *, struct ifnet *)); +void in_delmulti __P((struct in_multi *)); +int in_control __P((struct socket *, u_long, caddr_t, struct ifnet *)); +void in_rtqdrain __P((void)); +void ip_input __P((struct mbuf *)); + +#endif /* KERNEL */ + +#endif /* _NETINET_IN_VAR_H_ */ diff --git a/cpukit/libnetworking/netinet/ip.h b/cpukit/libnetworking/netinet/ip.h new file mode 100644 index 0000000000..e7f824ca6f --- /dev/null +++ b/cpukit/libnetworking/netinet/ip.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip.h 8.2 (Berkeley) 6/1/94 + * $Id$ + */ + +#ifndef _NETINET_IP_H_ +#define _NETINET_IP_H_ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +/* + * Structure of an internet header, naked of options. + * + * We declare ip_len and ip_off to be short, rather than u_short + * pragmatically since otherwise unsigned comparisons can result + * against negative integers quite easily, and fail in subtle ways. + */ +struct ip { +#ifdef _IP_VHL + u_char ip_vhl; /* version << 4 | header length >> 2 */ +#else +#if BYTE_ORDER == LITTLE_ENDIAN + u_char ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ +#endif +#endif /* not _IP_VHL */ + u_char ip_tos; /* type of service */ + u_short ip_len; /* total length */ + u_short ip_id; /* identification */ + u_short ip_off; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + +#ifdef _IP_VHL +#define IP_MAKE_VHL(v, hl) ((v) << 4 | (hl)) +#define IP_VHL_HL(vhl) ((vhl) & 0x0f) +#define IP_VHL_V(vhl) ((vhl) >> 4) +#define IP_VHL_BORING 0x45 +#endif + +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for IP type of service (ip_tos) + */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_MINCOST 0x02 + +/* + * Definitions for IP precedence (also in ip_tos) (hopefully unused) + */ +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ +#define IPOPT_RA 148 /* router alert */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +/* + * Time stamp option structure. + */ +struct ip_timestamp { + u_char ipt_code; /* IPOPT_TS */ + u_char ipt_len; /* size of structure (variable) */ + u_char ipt_ptr; /* index of current entry */ +#if BYTE_ORDER == LITTLE_ENDIAN + u_char ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char ipt_oflw:4, /* overflow counter */ + ipt_flg:4; /* flags, see below */ +#endif + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +}; + +#include <machine/in_cksum.h> + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + +#endif diff --git a/cpukit/libnetworking/netinet/ip_divert.c b/cpukit/libnetworking/netinet/ip_divert.c new file mode 100644 index 0000000000..2955e811ad --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_divert.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/systm.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> + +/* + * Divert sockets + */ + +/* + * Allocate enough space to hold a full IP packet + */ +#define DIVSNDQ (65536 + 100) +#define DIVRCVQ (65536 + 100) + +/* Global variables */ + +/* + * ip_input() and ip_output() set this secret value before calling us to + * let us know which divert port to divert a packet to; this is done so + * we can use the existing prototype for struct protosw's pr_input(). + * This is stored in host order. + */ +u_short ip_divert_port; + +/* + * We set this value to a non-zero port number when we want the call to + * ip_fw_chk() in ip_input() or ip_output() to ignore ``divert <port>'' + * chain entries. This is stored in host order. + */ +u_short ip_divert_ignore; + +/* Internal variables */ + +static struct inpcbhead divcb; +static struct inpcbinfo divcbinfo; + +static u_long div_sendspace = DIVSNDQ; /* XXX sysctl ? */ +static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */ + +/* Optimization: have this preinitialized */ +static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET }; + +/* Internal functions */ + +static int div_output(struct socket *so, + struct mbuf *m, struct mbuf *addr, struct mbuf *control); + +/* + * Initialize divert connection block queue. + */ +void +div_init(void) +{ + LIST_INIT(&divcb); + divcbinfo.listhead = &divcb; + /* + * XXX We don't use the hash list for divert IP, but it's easier + * to allocate a one entry hash list than it is to check all + * over the place for hashbase == NULL. + */ + divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask); +} + +/* + * Setup generic address and protocol structures + * for div_input routine, then pass them along with + * mbuf chain. ip->ip_len is assumed to have had + * the header length (hlen) subtracted out already. + * We tell whether the packet was incoming or outgoing + * by seeing if hlen == 0, which is a hack. + */ +void +div_input(struct mbuf *m, int hlen) +{ + struct ip *ip; + struct inpcb *inp; + struct socket *sa; + + /* Sanity check */ + if (ip_divert_port == 0) + panic("div_input: port is 0"); + + /* Assure header */ + if (m->m_len < sizeof(struct ip) && + (m = m_pullup(m, sizeof(struct ip))) == 0) { + return; + } + ip = mtod(m, struct ip *); + + /* Record divert port */ + divsrc.sin_port = htons(ip_divert_port); + + /* Restore packet header fields */ + ip->ip_len += hlen; + HTONS(ip->ip_len); + HTONS(ip->ip_off); + + /* Record receive interface address, if any */ + divsrc.sin_addr.s_addr = 0; + if (hlen) { + struct ifaddr *ifa; + +#ifdef DIAGNOSTIC + /* Sanity check */ + if (!(m->m_flags & M_PKTHDR)) + panic("div_input: no pkt hdr"); +#endif + + /* More fields affected by ip_input() */ + HTONS(ip->ip_id); + + /* Find IP address for recieve interface */ + for (ifa = m->m_pkthdr.rcvif->if_addrlist; + ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + divsrc.sin_addr = + ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; + break; + } + } + + /* Put packet on socket queue, if any */ + sa = NULL; + for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { + if (inp->inp_lport == htons(ip_divert_port)) + sa = inp->inp_socket; + } + if (sa) { + if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, + m, (struct mbuf *)0) == 0) + m_freem(m); + else + sorwakeup(sa); + } else { + m_freem(m); + ipstat.ips_noproto++; + ipstat.ips_delivered--; + } +} + +/* + * Deliver packet back into the IP processing machinery. + * + * If no address specified, or address is 0.0.0.0, send to ip_output(); + * otherwise, send to ip_input() and mark as having been received on + * the interface with that address. + * + * If no address specified, or dest port is 0, allow packet to divert + * back to this socket; otherwise, don't. + */ +static int +div_output(so, m, addr, control) + struct socket *so; + register struct mbuf *m; + struct mbuf *addr, *control; +{ + register struct inpcb *const inp = sotoinpcb(so); + register struct ip *const ip = mtod(m, struct ip *); + struct sockaddr_in *sin = NULL; + int error = 0; + + if (control) + m_freem(control); /* XXX */ + if (addr) + sin = mtod(addr, struct sockaddr_in *); + + /* Loopback avoidance option */ + ip_divert_ignore = ntohs(inp->inp_lport); + + /* Reinject packet into the system as incoming or outgoing */ + if (!sin || sin->sin_addr.s_addr == 0) { + /* Don't allow both user specified and setsockopt options, + and don't allow packet length sizes that will crash */ + if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) || + ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { + error = EINVAL; + goto cantsend; + } + + /* Convert fields to host order for ip_output() */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + + /* Send packet to output processing */ + ipstat.ips_rawout++; /* XXX */ + error = ip_output(m, inp->inp_options, &inp->inp_route, + (so->so_options & SO_DONTROUTE) | + IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions); + } else { + struct ifaddr *ifa; + + /* Find receive interface with the given IP address */ + sin->sin_port = 0; + if ((ifa = ifa_ifwithaddr((struct sockaddr *) sin)) == 0) { + error = EADDRNOTAVAIL; + goto cantsend; + } + m->m_pkthdr.rcvif = ifa->ifa_ifp; + + /* Send packet to input processing */ + ip_input(m); + } + + /* Reset for next time (and other packets) */ + ip_divert_ignore = 0; + return error; + +cantsend: + ip_divert_ignore = 0; + m_freem(m); + return error; +} + +/*ARGSUSED*/ +int +div_usrreq(so, req, m, nam, control) + register struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register int error = 0; + register struct inpcb *inp = sotoinpcb(so); + int s; + + if (inp == NULL && req != PRU_ATTACH) { + error = EINVAL; + goto release; + } + switch (req) { + + case PRU_ATTACH: + if (inp) + panic("div_attach"); + if ((so->so_state & SS_PRIV) == 0) { + error = EACCES; + break; + } + s = splnet(); + error = in_pcballoc(so, &divcbinfo); + splx(s); + if (error) + break; + error = soreserve(so, div_sendspace, div_recvspace); + if (error) + break; + inp = (struct inpcb *)so->so_pcb; + inp->inp_ip_p = (int)nam; /* XXX */ + inp->inp_flags |= INP_HDRINCL; + /* The socket is always "connected" because + we always know "where" to send the packet */ + so->so_state |= SS_ISCONNECTED; + break; + + case PRU_DISCONNECT: + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + break; + } + /* FALLTHROUGH */ + case PRU_ABORT: + soisdisconnected(so); + /* FALLTHROUGH */ + case PRU_DETACH: + if (inp == 0) + panic("div_detach"); + in_pcbdetach(inp); + break; + + case PRU_BIND: + s = splnet(); + error = in_pcbbind(inp, nam); + splx(s); + break; + + /* + * Mark the connection as being incapable of further input. + */ + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_SEND: + /* Packet must have a header (but that's about it) */ + if (m->m_len < sizeof (struct ip) || + (m = m_pullup(m, sizeof (struct ip))) == 0) { + ipstat.ips_toosmall++; + error = EINVAL; + break; + } + + /* Send packet */ + error = div_output(so, m, nam, control); + m = NULL; + break; + + case PRU_SOCKADDR: + in_setsockaddr(inp, nam); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + /* + * Not supported. + */ + case PRU_CONNECT: + case PRU_CONNECT2: + case PRU_CONTROL: + case PRU_RCVOOB: + case PRU_RCVD: + case PRU_LISTEN: + case PRU_ACCEPT: + case PRU_SENDOOB: + case PRU_PEERADDR: + error = EOPNOTSUPP; + break; + + default: + panic("div_usrreq"); + } +release: + if (m) + m_freem(m); + return (error); +} diff --git a/cpukit/libnetworking/netinet/ip_fw.c b/cpukit/libnetworking/netinet/ip_fw.c new file mode 100644 index 0000000000..aeb09b0bbe --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_fw.c @@ -0,0 +1,1069 @@ +/* + * Copyright (c) 1996 Alex Nash + * Copyright (c) 1993 Daniel Boulet + * Copyright (c) 1994 Ugen J.S.Antsilevich + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + * + * $Id$ + */ + +/* + * Implement IP packet firewall + */ + +#ifndef IPFIREWALL_MODULE +#include "opt_ipfw.h" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/queue.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/ip_fw.h> +#include <netinet/tcp.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#include <netinet/udp.h> + +static int fw_debug = 1; +#ifdef IPFIREWALL_VERBOSE +static int fw_verbose = 1; +#else +static int fw_verbose = 0; +#endif +#ifdef IPFIREWALL_VERBOSE_LIMIT +static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; +#else +static int fw_verbose_limit = 0; +#endif + +LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; + +#ifdef SYSCTL_NODE +SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); +#endif + +#define dprintf(a) if (!fw_debug); else printf a + +#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ + (ntohl(a.s_addr)>>16)&0xFF,\ + (ntohl(a.s_addr)>>8)&0xFF,\ + (ntohl(a.s_addr))&0xFF); + +#define dprint_ip(a) if (!fw_debug); else print_ip(a) + +static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl)); +static int del_entry __P((struct ip_fw_head *chainptr, u_short number)); +static int zero_entry __P((struct mbuf *m)); +static struct ip_fw *check_ipfw_struct __P((struct ip_fw *m)); +static struct ip_fw *check_ipfw_mbuf __P((struct mbuf *fw)); +static int ipopts_match __P((struct ip *ip, struct ip_fw *f)); +static int port_match __P((u_short *portptr, int nports, u_short port, + int range_flag)); +static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f)); +static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); +static void ipfw_report __P((struct ip_fw *f, struct ip *ip, + struct ifnet *rif, struct ifnet *oif)); + +#ifdef IPFIREWALL_MODULE +static ip_fw_chk_t *old_chk_ptr; +static ip_fw_ctl_t *old_ctl_ptr; +#endif + +static int ip_fw_chk __P((struct ip **pip, int hlen, + struct ifnet *oif, int ignport, struct mbuf **m)); +static int ip_fw_ctl __P((int stage, struct mbuf **mm)); + +static char err_prefix[] = "ip_fw_ctl:"; + +/* + * Returns 1 if the port is matched by the vector, 0 otherwise + */ +static inline int +port_match(u_short *portptr, int nports, u_short port, int range_flag) +{ + if (!nports) + return 1; + if (range_flag) { + if (portptr[0] <= port && port <= portptr[1]) { + return 1; + } + nports -= 2; + portptr += 2; + } + while (nports-- > 0) { + if (*portptr++ == port) { + return 1; + } + } + return 0; +} + +static int +tcpflg_match(struct tcphdr *tcp, struct ip_fw *f) +{ + u_char flg_set, flg_clr; + + if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) && + (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK))) + return 1; + + flg_set = tcp->th_flags & f->fw_tcpf; + flg_clr = tcp->th_flags & f->fw_tcpnf; + + if (flg_set != f->fw_tcpf) + return 0; + if (flg_clr) + return 0; + + return 1; +} + +static int +icmptype_match(struct icmp *icmp, struct ip_fw *f) +{ + int type; + + if (!(f->fw_flg & IP_FW_F_ICMPBIT)) + return(1); + + type = icmp->icmp_type; + + /* check for matching type in the bitmap */ + if (type < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 && + (f->fw_icmptypes[type / (sizeof(unsigned) * 8)] & + (1U << (type % (8 * sizeof(unsigned)))))) + return(1); + + return(0); /* no match */ +} + +static int +ipopts_match(struct ip *ip, struct ip_fw *f) +{ + register u_char *cp; + int opt, optlen, cnt; + u_char opts, nopts, nopts_sve; + + cp = (u_char *)(ip + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + opts = f->fw_ipopt; + nopts = nopts_sve = f->fw_ipnopt; + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= 0 || optlen > cnt) { + return 0; /*XXX*/ + } + } + switch (opt) { + + default: + break; + + case IPOPT_LSRR: + opts &= ~IP_FW_IPOPT_LSRR; + nopts &= ~IP_FW_IPOPT_LSRR; + break; + + case IPOPT_SSRR: + opts &= ~IP_FW_IPOPT_SSRR; + nopts &= ~IP_FW_IPOPT_SSRR; + break; + + case IPOPT_RR: + opts &= ~IP_FW_IPOPT_RR; + nopts &= ~IP_FW_IPOPT_RR; + break; + case IPOPT_TS: + opts &= ~IP_FW_IPOPT_TS; + nopts &= ~IP_FW_IPOPT_TS; + break; + } + if (opts == nopts) + break; + } + if (opts == 0 && nopts == nopts_sve) + return 1; + else + return 0; +} + +static inline int +iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname) +{ + /* Check by name or by IP address */ + if (byname) { + /* Check unit number (-1 is wildcard) */ + if (ifu->fu_via_if.unit != -1 + && ifp->if_unit != ifu->fu_via_if.unit) + return(0); + /* Check name */ + if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN)) + return(0); + return(1); + } else if (ifu->fu_via_ip.s_addr != 0) { /* Zero == wildcard */ + struct ifaddr *ia; + + for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { + if (ia->ifa_addr == NULL) + continue; + if (ia->ifa_addr->sa_family != AF_INET) + continue; + if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *) + (ia->ifa_addr))->sin_addr.s_addr) + continue; + return(1); + } + return(0); + } + return(1); +} + +static void +ipfw_report(struct ip_fw *f, struct ip *ip, + struct ifnet *rif, struct ifnet *oif) +{ + static int counter; + struct tcphdr *const tcp = (struct tcphdr *) ((u_long *) ip+ ip->ip_hl); + struct udphdr *const udp = (struct udphdr *) ((u_long *) ip+ ip->ip_hl); + struct icmp *const icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl); + int count; + + count = f ? f->fw_pcnt : ++counter; + if (fw_verbose_limit != 0 && count > fw_verbose_limit) + return; + + /* Print command name */ + printf("ipfw: %d ", f ? f->fw_number : -1); + if (!f) + printf("Refuse"); + else + switch (f->fw_flg & IP_FW_F_COMMAND) { + case IP_FW_F_DENY: + printf("Deny"); + break; + case IP_FW_F_REJECT: + if (f->fw_reject_code == IP_FW_REJECT_RST) + printf("Reset"); + else + printf("Unreach"); + break; + case IP_FW_F_ACCEPT: + printf("Accept"); + break; + case IP_FW_F_COUNT: + printf("Count"); + break; + case IP_FW_F_DIVERT: + printf("Divert %d", f->fw_divert_port); + break; + case IP_FW_F_TEE: + printf("Tee %d", f->fw_divert_port); + break; + case IP_FW_F_SKIPTO: + printf("SkipTo %d", f->fw_skipto_rule); + break; + default: + printf("UNKNOWN"); + break; + } + printf(" "); + + switch (ip->ip_p) { + case IPPROTO_TCP: + printf("TCP "); + print_ip(ip->ip_src); + if ((ip->ip_off & IP_OFFMASK) == 0) + printf(":%d ", ntohs(tcp->th_sport)); + else + printf(" "); + print_ip(ip->ip_dst); + if ((ip->ip_off & IP_OFFMASK) == 0) + printf(":%d", ntohs(tcp->th_dport)); + break; + case IPPROTO_UDP: + printf("UDP "); + print_ip(ip->ip_src); + if ((ip->ip_off & IP_OFFMASK) == 0) + printf(":%d ", ntohs(udp->uh_sport)); + else + printf(" "); + print_ip(ip->ip_dst); + if ((ip->ip_off & IP_OFFMASK) == 0) + printf(":%d", ntohs(udp->uh_dport)); + break; + case IPPROTO_ICMP: + printf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code); + print_ip(ip->ip_src); + printf(" "); + print_ip(ip->ip_dst); + break; + default: + printf("P:%d ", ip->ip_p); + print_ip(ip->ip_src); + printf(" "); + print_ip(ip->ip_dst); + break; + } + if (oif) + printf(" out via %s%d", oif->if_name, oif->if_unit); + else if (rif) + printf(" in via %s%d", rif->if_name, rif->if_unit); + if ((ip->ip_off & IP_OFFMASK)) + printf(" Fragment = %d",ip->ip_off & IP_OFFMASK); + printf("\n"); + if (fw_verbose_limit != 0 && count == fw_verbose_limit) + printf("ipfw: limit reached on rule #%d\n", + f ? f->fw_number : -1); +} + +/* + * Parameters: + * + * ip Pointer to packet header (struct ip *) + * hlen Packet header length + * oif Outgoing interface, or NULL if packet is incoming + * ignport Ignore all divert/tee rules to this port (if non-zero) + * *m The packet; we set to NULL when/if we nuke it. + * + * Return value: + * + * 0 The packet is to be accepted and routed normally OR + * the packet was denied/rejected and has been dropped; + * in the latter case, *m is equal to NULL upon return. + * port Divert the packet to port. + */ + +static int +ip_fw_chk(struct ip **pip, int hlen, + struct ifnet *oif, int ignport, struct mbuf **m) +{ + struct ip_fw_chain *chain; + struct ip_fw *rule = NULL; + struct ip *ip = *pip; + struct ifnet *const rif = (*m)->m_pkthdr.rcvif; + u_short offset = (ip->ip_off & IP_OFFMASK); + u_short src_port, dst_port; + + /* + * Go down the chain, looking for enlightment + */ + for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) { + register struct ip_fw *const f = chain->rule; + + /* Check direction inbound */ + if (!oif && !(f->fw_flg & IP_FW_F_IN)) + continue; + + /* Check direction outbound */ + if (oif && !(f->fw_flg & IP_FW_F_OUT)) + continue; + + /* Fragments */ + if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK)) + continue; + + /* If src-addr doesn't match, not this rule. */ + if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr + & f->fw_smsk.s_addr) != f->fw_src.s_addr)) + continue; + + /* If dest-addr doesn't match, not this rule. */ + if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr + & f->fw_dmsk.s_addr) != f->fw_dst.s_addr)) + continue; + + /* Interface check */ + if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { + struct ifnet *const iface = oif ? oif : rif; + + /* Backwards compatibility hack for "via" */ + if (!iface || !iface_match(iface, + &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME)) + continue; + } else { + /* Check receive interface */ + if ((f->fw_flg & IP_FW_F_IIFACE) + && (!rif || !iface_match(rif, + &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME))) + continue; + /* Check outgoing interface */ + if ((f->fw_flg & IP_FW_F_OIFACE) + && (!oif || !iface_match(oif, + &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME))) + continue; + } + + /* Check IP options */ + if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f)) + continue; + + /* Check protocol; if wildcard, match */ + if (f->fw_prot == IPPROTO_IP) + goto got_match; + + /* If different, don't match */ + if (ip->ip_p != f->fw_prot) + continue; + +#define PULLUP_TO(len) do { \ + if ((*m)->m_len < (len) \ + && (*m = m_pullup(*m, (len))) == 0) { \ + goto bogusfrag; \ + } \ + *pip = ip = mtod(*m, struct ip *); \ + offset = (ip->ip_off & IP_OFFMASK); \ + } while (0) + + /* Protocol specific checks */ + switch (ip->ip_p) { + case IPPROTO_TCP: + { + struct tcphdr *tcp; + + if (offset == 1) /* cf. RFC 1858 */ + goto bogusfrag; + if (offset != 0) { + /* + * TCP flags and ports aren't available in this + * packet -- if this rule specified either one, + * we consider the rule a non-match. + */ + if (f->fw_nports != 0 || + f->fw_tcpf != f->fw_tcpnf) + continue; + + break; + } + PULLUP_TO(hlen + 14); + tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl); + if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f)) + continue; + src_port = ntohs(tcp->th_sport); + dst_port = ntohs(tcp->th_dport); + goto check_ports; + } + + case IPPROTO_UDP: + { + struct udphdr *udp; + + if (offset != 0) { + /* + * Port specification is unavailable -- if this + * rule specifies a port, we consider the rule + * a non-match. + */ + if (f->fw_nports != 0) + continue; + + break; + } + PULLUP_TO(hlen + 4); + udp = (struct udphdr *) ((u_long *)ip + ip->ip_hl); + src_port = ntohs(udp->uh_sport); + dst_port = ntohs(udp->uh_dport); +check_ports: + if (!port_match(&f->fw_pts[0], + IP_FW_GETNSRCP(f), src_port, + f->fw_flg & IP_FW_F_SRNG)) + continue; + if (!port_match(&f->fw_pts[IP_FW_GETNSRCP(f)], + IP_FW_GETNDSTP(f), dst_port, + f->fw_flg & IP_FW_F_DRNG)) + continue; + break; + } + + case IPPROTO_ICMP: + { + struct icmp *icmp; + + if (offset != 0) /* Type isn't valid */ + break; + PULLUP_TO(hlen + 2); + icmp = (struct icmp *) ((u_long *)ip + ip->ip_hl); + if (!icmptype_match(icmp, f)) + continue; + break; + } +#undef PULLUP_TO + +bogusfrag: + if (fw_verbose) + ipfw_report(NULL, ip, rif, oif); + goto dropit; + } + +got_match: + /* Ignore divert/tee rule if socket port is "ignport" */ + switch (f->fw_flg & IP_FW_F_COMMAND) { + case IP_FW_F_DIVERT: + case IP_FW_F_TEE: + if (f->fw_divert_port == ignport) + continue; /* ignore this rule */ + break; + } + + /* Update statistics */ + f->fw_pcnt += 1; + f->fw_bcnt += ip->ip_len; + f->timestamp = rtems_bsdnet_seconds_since_boot(); + + /* Log to console if desired */ + if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose) + ipfw_report(f, ip, rif, oif); + + /* Take appropriate action */ + switch (f->fw_flg & IP_FW_F_COMMAND) { + case IP_FW_F_ACCEPT: + return(0); + case IP_FW_F_COUNT: + continue; + case IP_FW_F_DIVERT: + return(f->fw_divert_port); + case IP_FW_F_TEE: + /* + * XXX someday tee packet here, but beware that you + * can't use m_copym() or m_copypacket() because + * the divert input routine modifies the mbuf + * (and these routines only increment reference + * counts in the case of mbuf clusters), so need + * to write custom routine. + */ + continue; + case IP_FW_F_SKIPTO: +#ifdef DIAGNOSTIC + while (chain->chain.le_next + && chain->chain.le_next->rule->fw_number + < f->fw_skipto_rule) +#else + while (chain->chain.le_next->rule->fw_number + < f->fw_skipto_rule) +#endif + chain = chain->chain.le_next; + continue; + } + + /* Deny/reject this packet using this rule */ + rule = f; + break; + } + +#ifdef DIAGNOSTIC + /* Rule 65535 should always be there and should always match */ + if (!chain) + panic("ip_fw: chain"); +#endif + + /* + * At this point, we're going to drop the packet. + * Send a reject notice if all of the following are true: + * + * - The packet matched a reject rule + * - The packet is not an ICMP packet + * - The packet is not a multicast or broadcast packet + */ + if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT + && ip->ip_p != IPPROTO_ICMP + && !((*m)->m_flags & (M_BCAST|M_MCAST)) + && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + switch (rule->fw_reject_code) { + case IP_FW_REJECT_RST: + { + struct tcphdr *const tcp = + (struct tcphdr *) ((u_long *)ip + ip->ip_hl); + struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip; + + if (offset != 0 || (tcp->th_flags & TH_RST)) + break; + ti.ti_i = *((struct ipovly *) ip); + ti.ti_t = *tcp; + bcopy(&ti, ip, sizeof(ti)); + NTOHL(tip->ti_seq); + NTOHL(tip->ti_ack); + tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2); + if (tcp->th_flags & TH_ACK) { + tcp_respond(NULL, tip, *m, + (tcp_seq)0, ntohl(tcp->th_ack), TH_RST); + } else { + if (tcp->th_flags & TH_SYN) + tip->ti_len++; + tcp_respond(NULL, tip, *m, tip->ti_seq + + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK); + } + *m = NULL; + break; + } + default: /* Send an ICMP unreachable using code */ + icmp_error(*m, ICMP_UNREACH, + rule->fw_reject_code, 0L, 0); + *m = NULL; + break; + } + } + +dropit: + /* + * Finally, drop the packet. + */ + if (*m) { + m_freem(*m); + *m = NULL; + } + return(0); +} + +static int +add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) +{ + struct ip_fw *ftmp = 0; + struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0; + u_short nbr = 0; + int s; + + fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT); + ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT); + if (!fwc || !ftmp) { + dprintf(("%s malloc said no\n", err_prefix)); + if (fwc) free(fwc, M_IPFW); + if (ftmp) free(ftmp, M_IPFW); + return (ENOSPC); + } + + bcopy(frwl, ftmp, sizeof(struct ip_fw)); + ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; + ftmp->fw_pcnt = 0L; + ftmp->fw_bcnt = 0L; + fwc->rule = ftmp; + + s = splnet(); + + if (!chainptr->lh_first) { + LIST_INSERT_HEAD(chainptr, fwc, chain); + splx(s); + return(0); + } else if (ftmp->fw_number == (u_short)-1) { + if (fwc) free(fwc, M_IPFW); + if (ftmp) free(ftmp, M_IPFW); + splx(s); + dprintf(("%s bad rule number\n", err_prefix)); + return (EINVAL); + } + + /* If entry number is 0, find highest numbered rule and add 100 */ + if (ftmp->fw_number == 0) { + for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) { + if (fcp->rule->fw_number != (u_short)-1) + nbr = fcp->rule->fw_number; + else + break; + } + if (nbr < (u_short)-1 - 100) + nbr += 100; + ftmp->fw_number = nbr; + } + + /* Got a valid number; now insert it, keeping the list ordered */ + for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) { + if (fcp->rule->fw_number > ftmp->fw_number) { + if (fcpl) { + LIST_INSERT_AFTER(fcpl, fwc, chain); + } else { + LIST_INSERT_HEAD(chainptr, fwc, chain); + } + break; + } else { + fcpl = fcp; + } + } + + splx(s); + return (0); +} + +static int +del_entry(struct ip_fw_head *chainptr, u_short number) +{ + struct ip_fw_chain *fcp; + int s; + + s = splnet(); + + fcp = chainptr->lh_first; + if (number != (u_short)-1) { + for (; fcp; fcp = fcp->chain.le_next) { + if (fcp->rule->fw_number == number) { + LIST_REMOVE(fcp, chain); + splx(s); + free(fcp->rule, M_IPFW); + free(fcp, M_IPFW); + return 0; + } + } + } + + splx(s); + return (EINVAL); +} + +static int +zero_entry(struct mbuf *m) +{ + struct ip_fw *frwl; + struct ip_fw_chain *fcp; + int s; + + if (m) { + if (m->m_len != sizeof(struct ip_fw)) + return(EINVAL); + frwl = mtod(m, struct ip_fw *); + } + else + frwl = NULL; + + /* + * It's possible to insert multiple chain entries with the + * same number, so we don't stop after finding the first + * match if zeroing a specific entry. + */ + s = splnet(); + for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) + if (!frwl || frwl->fw_number == fcp->rule->fw_number) { + fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; + fcp->rule->timestamp = 0; + } + splx(s); + + if (fw_verbose) { + if (frwl) + printf("ipfw: Entry %d cleared.\n", frwl->fw_number); + else + printf("ipfw: Accounting cleared.\n"); + } + + return(0); +} + +static struct ip_fw * +check_ipfw_mbuf(struct mbuf *m) +{ + /* Check length */ + if (m->m_len != sizeof(struct ip_fw)) { + dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len, + (int)sizeof(struct ip_fw))); + return (NULL); + } + return(check_ipfw_struct(mtod(m, struct ip_fw *))); +} + +static struct ip_fw * +check_ipfw_struct(struct ip_fw *frwl) +{ + /* Check for invalid flag bits */ + if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) { + dprintf(("%s undefined flag bits set (flags=%x)\n", + err_prefix, frwl->fw_flg)); + return (NULL); + } + /* Must apply to incoming or outgoing (or both) */ + if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) { + dprintf(("%s neither in nor out\n", err_prefix)); + return (NULL); + } + /* Empty interface name is no good */ + if (((frwl->fw_flg & IP_FW_F_IIFNAME) + && !*frwl->fw_in_if.fu_via_if.name) + || ((frwl->fw_flg & IP_FW_F_OIFNAME) + && !*frwl->fw_out_if.fu_via_if.name)) { + dprintf(("%s empty interface name\n", err_prefix)); + return (NULL); + } + /* Sanity check interface matching */ + if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { + ; /* allow "via" backwards compatibility */ + } else if ((frwl->fw_flg & IP_FW_F_IN) + && (frwl->fw_flg & IP_FW_F_OIFACE)) { + dprintf(("%s outgoing interface check on incoming\n", + err_prefix)); + return (NULL); + } + /* Sanity check port ranges */ + if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) { + dprintf(("%s src range set but n_src_p=%d\n", + err_prefix, IP_FW_GETNSRCP(frwl))); + return (NULL); + } + if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) { + dprintf(("%s dst range set but n_dst_p=%d\n", + err_prefix, IP_FW_GETNDSTP(frwl))); + return (NULL); + } + if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) { + dprintf(("%s too many ports (%d+%d)\n", + err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl))); + return (NULL); + } + /* + * Protocols other than TCP/UDP don't use port range + */ + if ((frwl->fw_prot != IPPROTO_TCP) && + (frwl->fw_prot != IPPROTO_UDP) && + (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) { + dprintf(("%s port(s) specified for non TCP/UDP rule\n", + err_prefix)); + return(NULL); + } + + /* + * Rather than modify the entry to make such entries work, + * we reject this rule and require user level utilities + * to enforce whatever policy they deem appropriate. + */ + if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || + (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) { + dprintf(("%s rule never matches\n", err_prefix)); + return(NULL); + } + + if ((frwl->fw_flg & IP_FW_F_FRAG) && + (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) { + if (frwl->fw_nports) { + dprintf(("%s cannot mix 'frag' and ports\n", err_prefix)); + return(NULL); + } + if (frwl->fw_prot == IPPROTO_TCP && + frwl->fw_tcpf != frwl->fw_tcpnf) { + dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix)); + return(NULL); + } + } + + /* Check command specific stuff */ + switch (frwl->fw_flg & IP_FW_F_COMMAND) + { + case IP_FW_F_REJECT: + if (frwl->fw_reject_code >= 0x100 + && !(frwl->fw_prot == IPPROTO_TCP + && frwl->fw_reject_code == IP_FW_REJECT_RST)) { + dprintf(("%s unknown reject code\n", err_prefix)); + return(NULL); + } + break; + case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ + case IP_FW_F_TEE: + if (frwl->fw_divert_port == 0) { + dprintf(("%s can't divert to port 0\n", err_prefix)); + return (NULL); + } + break; + case IP_FW_F_DENY: + case IP_FW_F_ACCEPT: + case IP_FW_F_COUNT: + case IP_FW_F_SKIPTO: + break; + default: + dprintf(("%s invalid command\n", err_prefix)); + return(NULL); + } + + return frwl; +} + +static int +ip_fw_ctl(int stage, struct mbuf **mm) +{ + int error; + struct mbuf *m; + + if (stage == IP_FW_GET) { + struct ip_fw_chain *fcp = ip_fw_chain.lh_first; + *mm = m = m_get(M_WAIT, MT_SOOPTS); + for (; fcp; fcp = fcp->chain.le_next) { + memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule)); + m->m_len = sizeof *(fcp->rule); + m->m_next = m_get(M_WAIT, MT_SOOPTS); + m = m->m_next; + m->m_len = 0; + } + return (0); + } + m = *mm; + /* only allow get calls if secure mode > 2 */ + if (securelevel > 2) { + if (m) (void)m_free(m); + return(EPERM); + } + if (stage == IP_FW_FLUSH) { + while (ip_fw_chain.lh_first != NULL && + ip_fw_chain.lh_first->rule->fw_number != (u_short)-1) { + struct ip_fw_chain *fcp = ip_fw_chain.lh_first; + int s = splnet(); + LIST_REMOVE(ip_fw_chain.lh_first, chain); + splx(s); + free(fcp->rule, M_IPFW); + free(fcp, M_IPFW); + } + if (m) (void)m_free(m); + return (0); + } + if (stage == IP_FW_ZERO) { + error = zero_entry(m); + if (m) (void)m_free(m); + return (error); + } + if (m == NULL) { + printf("%s NULL mbuf ptr\n", err_prefix); + return (EINVAL); + } + + if (stage == IP_FW_ADD) { + struct ip_fw *frwl = check_ipfw_mbuf(m); + + if (!frwl) + error = EINVAL; + else + error = add_entry(&ip_fw_chain, frwl); + if (m) (void)m_free(m); + return error; + } + if (stage == IP_FW_DEL) { + if (m->m_len != sizeof(struct ip_fw)) { + dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len, + (int)sizeof(struct ip_fw))); + error = EINVAL; + } else if (mtod(m, struct ip_fw *)->fw_number == (u_short)-1) { + dprintf(("%s can't delete rule 65535\n", err_prefix)); + error = EINVAL; + } else + error = del_entry(&ip_fw_chain, + mtod(m, struct ip_fw *)->fw_number); + if (m) (void)m_free(m); + return error; + } + + dprintf(("%s unknown request %d\n", err_prefix, stage)); + if (m) (void)m_free(m); + return (EINVAL); +} + +void +ip_fw_init(void) +{ + struct ip_fw default_rule; + + ip_fw_chk_ptr = ip_fw_chk; + ip_fw_ctl_ptr = ip_fw_ctl; + LIST_INIT(&ip_fw_chain); + + bzero(&default_rule, sizeof default_rule); + default_rule.fw_prot = IPPROTO_IP; + default_rule.fw_number = (u_short)-1; +#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT + default_rule.fw_flg |= IP_FW_F_ACCEPT; +#else + default_rule.fw_flg |= IP_FW_F_DENY; +#endif + default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT; + if (check_ipfw_struct(&default_rule) == NULL || + add_entry(&ip_fw_chain, &default_rule)) + panic(__FUNCTION__); + + printf("IP packet filtering initialized, " +#ifdef IPDIVERT + "divert enabled, "); +#else + "divert disabled, "); +#endif +#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT + printf("default to accept, "); +#endif +#ifndef IPFIREWALL_VERBOSE + printf("logging disabled\n"); +#else + if (fw_verbose_limit == 0) + printf("unlimited logging\n"); + else + printf("logging limited to %d packets/entry\n", + fw_verbose_limit); +#endif +} + +#ifdef IPFIREWALL_MODULE + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +MOD_MISC(ipfw); + +static int +ipfw_load(struct lkm_table *lkmtp, int cmd) +{ + int s=splnet(); + + old_chk_ptr = ip_fw_chk_ptr; + old_ctl_ptr = ip_fw_ctl_ptr; + + ip_fw_init(); + splx(s); + return 0; +} + +static int +ipfw_unload(struct lkm_table *lkmtp, int cmd) +{ + int s=splnet(); + + ip_fw_chk_ptr = old_chk_ptr; + ip_fw_ctl_ptr = old_ctl_ptr; + + while (ip_fw_chain.lh_first != NULL) { + struct ip_fw_chain *fcp = ip_fw_chain.lh_first; + LIST_REMOVE(ip_fw_chain.lh_first, chain); + free(fcp->rule, M_IPFW); + free(fcp, M_IPFW); + } + + splx(s); + printf("IP firewall unloaded\n"); + return 0; +} + +int +ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver) +{ + DISPATCH(lkmtp, cmd, ver, ipfw_load, ipfw_unload, lkm_nullcmd); +} +#endif diff --git a/cpukit/libnetworking/netinet/ip_fw.h b/cpukit/libnetworking/netinet/ip_fw.h new file mode 100644 index 0000000000..cab7f4ac93 --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_fw.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 1993 Daniel Boulet + * Copyright (c) 1994 Ugen J.S.Antsilevich + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + * + * $Id$ + */ + +#ifndef _IP_FW_H +#define _IP_FW_H + +#include <net/if.h> + +/* + * This union structure identifies an interface, either explicitly + * by name or implicitly by IP address. The flags IP_FW_F_IIFNAME + * and IP_FW_F_OIFNAME say how to interpret this structure. An + * interface unit number of -1 matches any unit number, while an + * IP address of 0.0.0.0 indicates matches any interface. + * + * The receive and transmit interfaces are only compared against the + * the packet if the corresponding bit (IP_FW_F_IIFACE or IP_FW_F_OIFACE) + * is set. Note some packets lack a receive or transmit interface + * (in which case the missing "interface" never matches). + */ + +union ip_fw_if { + struct in_addr fu_via_ip; /* Specified by IP address */ + struct { /* Specified by interface name */ +#define FW_IFNLEN IFNAMSIZ + char name[FW_IFNLEN]; + short unit; /* -1 means match any unit */ + } fu_via_if; +}; + +/* + * Format of an IP firewall descriptor + * + * fw_src, fw_dst, fw_smsk, fw_dmsk are always stored in network byte order. + * fw_flg and fw_n*p are stored in host byte order (of course). + * Port numbers are stored in HOST byte order. + * Warning: setsockopt() will fail if sizeof(struct ip_fw) > MLEN (108) + */ + +struct ip_fw { + u_long fw_pcnt,fw_bcnt; /* Packet and byte counters */ + struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ + struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ + u_short fw_number; /* Rule number */ + u_short fw_flg; /* Flags word */ +#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ + u_short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ + u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */ + u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */ +#define IP_FW_ICMPTYPES_DIM (32 / (sizeof(unsigned) * 8)) + unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */ + long timestamp; /* timestamp (tv_sec) of last match */ + union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */ + union { + u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */ + u_short fu_skipto_rule; /* SKIPTO command rule number */ + u_short fu_reject_code; /* REJECT response code */ + } fw_un; + u_char fw_prot; /* IP protocol */ + u_char fw_nports; /* N'of src ports and # of dst ports */ + /* in ports array (dst ports follow */ + /* src ports; max of 10 ports in all; */ + /* count of 0 means match all ports) */ +}; + +#define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) +#define IP_FW_SETNSRCP(rule, n) do { \ + (rule)->fw_nports &= ~0x0f; \ + (rule)->fw_nports |= (n); \ + } while (0) +#define IP_FW_GETNDSTP(rule) ((rule)->fw_nports >> 4) +#define IP_FW_SETNDSTP(rule, n) do { \ + (rule)->fw_nports &= ~0xf0; \ + (rule)->fw_nports |= (n) << 4;\ + } while (0) + +#define fw_divert_port fw_un.fu_divert_port +#define fw_skipto_rule fw_un.fu_skipto_rule +#define fw_reject_code fw_un.fu_reject_code + +struct ip_fw_chain { + LIST_ENTRY(ip_fw_chain) chain; + struct ip_fw *rule; +}; + +/* + * Values for "flags" field . + */ +#define IP_FW_F_IN 0x0001 /* Check inbound packets */ +#define IP_FW_F_OUT 0x0002 /* Check outbound packets */ +#define IP_FW_F_IIFACE 0x0004 /* Apply inbound interface test */ +#define IP_FW_F_OIFACE 0x0008 /* Apply outbound interface test */ + +#define IP_FW_F_COMMAND 0x0070 /* Mask for type of chain entry: */ +#define IP_FW_F_DENY 0x0000 /* This is a deny rule */ +#define IP_FW_F_REJECT 0x0010 /* Deny and send a response packet */ +#define IP_FW_F_ACCEPT 0x0020 /* This is an accept rule */ +#define IP_FW_F_COUNT 0x0030 /* This is a count rule */ +#define IP_FW_F_DIVERT 0x0040 /* This is a divert rule */ +#define IP_FW_F_TEE 0x0050 /* This is a tee rule */ +#define IP_FW_F_SKIPTO 0x0060 /* This is a skipto rule */ + +#define IP_FW_F_PRN 0x0080 /* Print if this rule matches */ + +#define IP_FW_F_SRNG 0x0100 /* The first two src ports are a min * + * and max range (stored in host byte * + * order). */ + +#define IP_FW_F_DRNG 0x0200 /* The first two dst ports are a min * + * and max range (stored in host byte * + * order). */ + +#define IP_FW_F_IIFNAME 0x0400 /* In interface by name/unit (not IP) */ +#define IP_FW_F_OIFNAME 0x0800 /* Out interface by name/unit (not IP) */ + +#define IP_FW_F_INVSRC 0x1000 /* Invert sense of src check */ +#define IP_FW_F_INVDST 0x2000 /* Invert sense of dst check */ + +#define IP_FW_F_FRAG 0x4000 /* Fragment */ + +#define IP_FW_F_ICMPBIT 0x8000 /* ICMP type bitmap is valid */ + +#define IP_FW_F_MASK 0xFFFF /* All possible flag bits mask */ + +/* + * For backwards compatibility with rules specifying "via iface" but + * not restricted to only "in" or "out" packets, we define this combination + * of bits to represent this configuration. + */ + +#define IF_FW_F_VIAHACK (IP_FW_F_IN|IP_FW_F_OUT|IP_FW_F_IIFACE|IP_FW_F_OIFACE) + +/* + * Definitions for REJECT response codes. + * Values less than 256 correspond to ICMP unreachable codes. + */ +#define IP_FW_REJECT_RST 0x0100 /* TCP packets: send RST */ + +/* + * Definitions for IP option names. + */ +#define IP_FW_IPOPT_LSRR 0x01 +#define IP_FW_IPOPT_SSRR 0x02 +#define IP_FW_IPOPT_RR 0x04 +#define IP_FW_IPOPT_TS 0x08 + +/* + * Definitions for TCP flags. + */ +#define IP_FW_TCPF_FIN TH_FIN +#define IP_FW_TCPF_SYN TH_SYN +#define IP_FW_TCPF_RST TH_RST +#define IP_FW_TCPF_PSH TH_PUSH +#define IP_FW_TCPF_ACK TH_ACK +#define IP_FW_TCPF_URG TH_URG +#define IP_FW_TCPF_ESTAB 0x40 + +/* + * Main firewall chains definitions and global var's definitions. + */ +#ifdef KERNEL + +/* + * Function definitions. + */ +void ip_fw_init(void); + +#endif /* KERNEL */ + +#endif /* _IP_FW_H */ diff --git a/cpukit/libnetworking/netinet/ip_icmp.c b/cpukit/libnetworking/netinet/ip_icmp.c new file mode 100644 index 0000000000..a18dacca99 --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_icmp.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/route.h> + +#define _IP_VHL +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/ip_var.h> +#include <netinet/icmp_var.h> + +/* + * ICMP routines: error generation, receive packet processing, and + * routines to turnaround packets back to the originator, and + * host table maintenance routines. + */ + + struct icmpstat icmpstat; +SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD, + &icmpstat, icmpstat, ""); + +static int icmpmaskrepl = 0; +SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, + &icmpmaskrepl, 0, ""); + +static int icmpbmcastecho = 1; +SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho, + 0, ""); + +#ifdef ICMPPRINTFS +int icmpprintfs = 0; +#endif + +static void icmp_reflect __P((struct mbuf *)); +static void icmp_send __P((struct mbuf *, struct mbuf *)); +static int ip_next_mtu __P((int, int)); + +extern struct protosw inetsw[]; + +/* + * Generate an error packet of type error + * in response to bad packet ip. + */ +void +icmp_error(n, type, code, dest, destifp) + struct mbuf *n; + int type, code; + n_long dest; + struct ifnet *destifp; +{ + register struct ip *oip = mtod(n, struct ip *), *nip; + register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; + register struct icmp *icp; + register struct mbuf *m; + unsigned icmplen; + +#ifdef ICMPPRINTFS + if (icmpprintfs) + printf("icmp_error(%p, %x, %d)\n", oip, type, code); +#endif + if (type != ICMP_REDIRECT) + icmpstat.icps_error++; + /* + * Don't send error if not the first fragment of message. + * Don't error if the old packet protocol was ICMP + * error message, only known informational types. + */ + if (oip->ip_off &~ (IP_MF|IP_DF)) + goto freeit; + if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && + n->m_len >= oiplen + ICMP_MINLEN && + !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { + icmpstat.icps_oldicmp++; + goto freeit; + } + /* Don't send error in response to a multicast or broadcast packet */ + if (n->m_flags & (M_BCAST|M_MCAST)) + goto freeit; + /* + * First, formulate icmp message + */ + m = m_gethdr(M_DONTWAIT, MT_HEADER); + if (m == NULL) + goto freeit; + icmplen = oiplen + min(8, oip->ip_len); + m->m_len = icmplen + ICMP_MINLEN; + MH_ALIGN(m, m->m_len); + icp = mtod(m, struct icmp *); + if ((u_int)type > ICMP_MAXTYPE) + panic("icmp_error"); + icmpstat.icps_outhist[type]++; + icp->icmp_type = type; + if (type == ICMP_REDIRECT) + icp->icmp_gwaddr.s_addr = dest; + else { + icp->icmp_void = 0; + /* + * The following assignments assume an overlay with the + * zeroed icmp_void field. + */ + if (type == ICMP_PARAMPROB) { + icp->icmp_pptr = code; + code = 0; + } else if (type == ICMP_UNREACH && + code == ICMP_UNREACH_NEEDFRAG && destifp) { + icp->icmp_nextmtu = htons(destifp->if_mtu); + } + } + + icp->icmp_code = code; + bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); + nip = &icp->icmp_ip; + nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); + + /* + * Now, copy old ip header (without options) + * in front of icmp message. + */ + if (m->m_data - sizeof(struct ip) < m->m_pktdat) + panic("icmp len"); + m->m_data -= sizeof(struct ip); + m->m_len += sizeof(struct ip); + m->m_pkthdr.len = m->m_len; + m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; + nip = mtod(m, struct ip *); + bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); + nip->ip_len = m->m_len; + nip->ip_vhl = IP_VHL_BORING; + nip->ip_p = IPPROTO_ICMP; + nip->ip_tos = 0; + icmp_reflect(m); + +freeit: + m_freem(n); +} + +static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; +static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; +static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; + +/* + * Process a received ICMP message. + */ +void +icmp_input(m, hlen) + register struct mbuf *m; + int hlen; +{ + register struct icmp *icp; + register struct ip *ip = mtod(m, struct ip *); + int icmplen = ip->ip_len; + register int i; + struct in_ifaddr *ia; + void (*ctlfunc) __P((int, struct sockaddr *, void *)); + int code; + + /* + * Locate icmp structure in mbuf, and check + * that not corrupted and of at least minimum length. + */ +#ifdef ICMPPRINTFS + if (icmpprintfs) { + char buf[4 * sizeof "123"]; + strcpy(buf, inet_ntoa(ip->ip_src)); + printf("icmp_input from %s to %s, len %d\n", + buf, inet_ntoa(ip->ip_dst), icmplen); + } +#endif + if (icmplen < ICMP_MINLEN) { + icmpstat.icps_tooshort++; + goto freeit; + } + i = hlen + min(icmplen, ICMP_ADVLENMIN); + if (m->m_len < i && (m = m_pullup(m, i)) == 0) { + icmpstat.icps_tooshort++; + return; + } + ip = mtod(m, struct ip *); + m->m_len -= hlen; + m->m_data += hlen; + icp = mtod(m, struct icmp *); + if (in_cksum(m, icmplen)) { + icmpstat.icps_checksum++; + goto freeit; + } + m->m_len += hlen; + m->m_data -= hlen; + +#ifdef ICMPPRINTFS + if (icmpprintfs) + printf("icmp_input, type %d code %d\n", icp->icmp_type, + icp->icmp_code); +#endif + + /* + * Message type specific processing. + */ + if (icp->icmp_type > ICMP_MAXTYPE) + goto raw; + icmpstat.icps_inhist[icp->icmp_type]++; + code = icp->icmp_code; + switch (icp->icmp_type) { + + case ICMP_UNREACH: + switch (code) { + case ICMP_UNREACH_NET: + case ICMP_UNREACH_HOST: + case ICMP_UNREACH_PROTOCOL: + case ICMP_UNREACH_PORT: + case ICMP_UNREACH_SRCFAIL: + code += PRC_UNREACH_NET; + break; + + case ICMP_UNREACH_NEEDFRAG: + code = PRC_MSGSIZE; + break; + + case ICMP_UNREACH_NET_UNKNOWN: + case ICMP_UNREACH_NET_PROHIB: + case ICMP_UNREACH_TOSNET: + code = PRC_UNREACH_NET; + break; + + case ICMP_UNREACH_HOST_UNKNOWN: + case ICMP_UNREACH_ISOLATED: + case ICMP_UNREACH_HOST_PROHIB: + case ICMP_UNREACH_TOSHOST: + code = PRC_UNREACH_HOST; + break; + + case ICMP_UNREACH_FILTER_PROHIB: + case ICMP_UNREACH_HOST_PRECEDENCE: + case ICMP_UNREACH_PRECEDENCE_CUTOFF: + code = PRC_UNREACH_PORT; + break; + + default: + goto badcode; + } + goto deliver; + + case ICMP_TIMXCEED: + if (code > 1) + goto badcode; + code += PRC_TIMXCEED_INTRANS; + goto deliver; + + case ICMP_PARAMPROB: + if (code > 1) + goto badcode; + code = PRC_PARAMPROB; + goto deliver; + + case ICMP_SOURCEQUENCH: + if (code) + goto badcode; + code = PRC_QUENCH; + deliver: + /* + * Problem with datagram; advise higher level routines. + */ + if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || + IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { + icmpstat.icps_badlen++; + goto freeit; + } + NTOHS(icp->icmp_ip.ip_len); + /* Discard ICMP's in response to multicast packets */ + if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) + goto badcode; +#ifdef ICMPPRINTFS + if (icmpprintfs) + printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); +#endif + icmpsrc.sin_addr = icp->icmp_ip.ip_dst; +#if 1 + /* + * MTU discovery: + * If we got a needfrag and there is a host route to the + * original destination, and the MTU is not locked, then + * set the MTU in the route to the suggested new value + * (if given) and then notify as usual. The ULPs will + * notice that the MTU has changed and adapt accordingly. + * If no new MTU was suggested, then we guess a new one + * less than the current value. If the new MTU is + * unreasonably small (arbitrarily set at 296), then + * we reset the MTU to the interface value and enable the + * lock bit, indicating that we are no longer doing MTU + * discovery. + */ + if (code == PRC_MSGSIZE) { + struct rtentry *rt; + int mtu; + + rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, + RTF_CLONING | RTF_PRCLONING); + if (rt && (rt->rt_flags & RTF_HOST) + && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { + mtu = ntohs(icp->icmp_nextmtu); + if (!mtu) + mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, + 1); +#ifdef DEBUG_MTUDISC + printf("MTU for %s reduced to %d\n", + inet_ntoa(icmpsrc.sin_addr), mtu); +#endif + if (mtu < 296) { + /* rt->rt_rmx.rmx_mtu = + rt->rt_ifp->if_mtu; */ + rt->rt_rmx.rmx_locks |= RTV_MTU; + } else if (rt->rt_rmx.rmx_mtu > mtu) { + rt->rt_rmx.rmx_mtu = mtu; + } + } + if (rt) + RTFREE(rt); + } + +#endif + ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; + if (ctlfunc) + (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, + (void *)&icp->icmp_ip); + break; + + badcode: + icmpstat.icps_badcode++; + break; + + case ICMP_ECHO: + if (!icmpbmcastecho + && (m->m_flags & (M_MCAST | M_BCAST)) != 0 + && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + icmpstat.icps_bmcastecho++; + break; + } + icp->icmp_type = ICMP_ECHOREPLY; + goto reflect; + + case ICMP_TSTAMP: + if (!icmpbmcastecho + && (m->m_flags & (M_MCAST | M_BCAST)) != 0 + && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + icmpstat.icps_bmcasttstamp++; + break; + } + if (icmplen < ICMP_TSLEN) { + icmpstat.icps_badlen++; + break; + } + icp->icmp_type = ICMP_TSTAMPREPLY; + icp->icmp_rtime = iptime(); + icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ + goto reflect; + + case ICMP_MASKREQ: +#define satosin(sa) ((struct sockaddr_in *)(sa)) + if (icmpmaskrepl == 0) + break; + /* + * We are not able to respond with all ones broadcast + * unless we receive it over a point-to-point interface. + */ + if (icmplen < ICMP_MASKLEN) + break; + switch (ip->ip_dst.s_addr) { + + case INADDR_BROADCAST: + case INADDR_ANY: + icmpdst.sin_addr = ip->ip_src; + break; + + default: + icmpdst.sin_addr = ip->ip_dst; + } + ia = (struct in_ifaddr *)ifaof_ifpforaddr( + (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); + if (ia == 0) + break; + if (ia->ia_ifp == 0) + break; + icp->icmp_type = ICMP_MASKREPLY; + icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; + if (ip->ip_src.s_addr == 0) { + if (ia->ia_ifp->if_flags & IFF_BROADCAST) + ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; + else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) + ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; + } +reflect: + ip->ip_len += hlen; /* since ip_input deducts this */ + icmpstat.icps_reflect++; + icmpstat.icps_outhist[icp->icmp_type]++; + icmp_reflect(m); + return; + + case ICMP_REDIRECT: + if (code > 3) + goto badcode; + if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || + IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { + icmpstat.icps_badlen++; + break; + } + /* + * Short circuit routing redirects to force + * immediate change in the kernel's routing + * tables. The message is also handed to anyone + * listening on a raw socket (e.g. the routing + * daemon for use in updating its tables). + */ + icmpgw.sin_addr = ip->ip_src; + icmpdst.sin_addr = icp->icmp_gwaddr; +#ifdef ICMPPRINTFS + if (icmpprintfs) { + char buf[4 * sizeof "123"]; + strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst)); + + printf("redirect dst %s to %s\n", + buf, inet_ntoa(icp->icmp_gwaddr)); + } +#endif + icmpsrc.sin_addr = icp->icmp_ip.ip_dst; + rtredirect((struct sockaddr *)&icmpsrc, + (struct sockaddr *)&icmpdst, + (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, + (struct sockaddr *)&icmpgw, (struct rtentry **)0); + pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); + break; + + /* + * No kernel processing for the following; + * just fall through to send to raw listener. + */ + case ICMP_ECHOREPLY: + case ICMP_ROUTERADVERT: + case ICMP_ROUTERSOLICIT: + case ICMP_TSTAMPREPLY: + case ICMP_IREQREPLY: + case ICMP_MASKREPLY: + default: + break; + } + +raw: + rip_input(m, hlen); + return; + +freeit: + m_freem(m); +} + +/* + * Reflect the ip packet back to the source + */ +static void +icmp_reflect(m) + struct mbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + register struct in_ifaddr *ia; + struct in_addr t; + struct mbuf *opts = 0; + int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip); + + if (!in_canforward(ip->ip_src) && + ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != + (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { + m_freem(m); /* Bad return address */ + goto done; /* Ip_output() will check for broadcast */ + } + t = ip->ip_dst; + ip->ip_dst = ip->ip_src; + /* + * If the incoming packet was addressed directly to us, + * use dst as the src for the reply. Otherwise (broadcast + * or anonymous), use the address which corresponds + * to the incoming interface. + */ + for (ia = in_ifaddr; ia; ia = ia->ia_next) { + if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) + break; + if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) && + t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) + break; + } + icmpdst.sin_addr = t; + if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif) + ia = (struct in_ifaddr *)ifaof_ifpforaddr( + (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); + /* + * The following happens if the packet was not addressed to us, + * and was received on an interface with no IP address. + */ + if (ia == (struct in_ifaddr *)0) + ia = in_ifaddr; + t = IA_SIN(ia)->sin_addr; + ip->ip_src = t; + ip->ip_ttl = MAXTTL; + + if (optlen > 0) { + register u_char *cp; + int opt, cnt; + u_int len; + + /* + * Retrieve any source routing from the incoming packet; + * add on any record-route or timestamp options. + */ + cp = (u_char *) (ip + 1); + if ((opts = ip_srcroute()) == 0 && + (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { + opts->m_len = sizeof(struct in_addr); + mtod(opts, struct in_addr *)->s_addr = 0; + } + if (opts) { +#ifdef ICMPPRINTFS + if (icmpprintfs) + printf("icmp_reflect optlen %d rt %d => ", + optlen, opts->m_len); +#endif + for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + len = 1; + else { + len = cp[IPOPT_OLEN]; + if (len <= 0 || len > cnt) + break; + } + /* + * Should check for overflow, but it "can't happen" + */ + if (opt == IPOPT_RR || opt == IPOPT_TS || + opt == IPOPT_SECURITY) { + bcopy((caddr_t)cp, + mtod(opts, caddr_t) + opts->m_len, len); + opts->m_len += len; + } + } + /* Terminate & pad, if necessary */ + cnt = opts->m_len % 4; + if (cnt) { + for (; cnt < 4; cnt++) { + *(mtod(opts, caddr_t) + opts->m_len) = + IPOPT_EOL; + opts->m_len++; + } + } +#ifdef ICMPPRINTFS + if (icmpprintfs) + printf("%d\n", opts->m_len); +#endif + } + /* + * Now strip out original options by copying rest of first + * mbuf's data back, and adjust the IP length. + */ + ip->ip_len -= optlen; + ip->ip_vhl = IP_VHL_BORING; + m->m_len -= optlen; + if (m->m_flags & M_PKTHDR) + m->m_pkthdr.len -= optlen; + optlen += sizeof(struct ip); + bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), + (unsigned)(m->m_len - sizeof(struct ip))); + } + m->m_flags &= ~(M_BCAST|M_MCAST); + icmp_send(m, opts); +done: + if (opts) + (void)m_free(opts); +} + +/* + * Send an icmp packet back to the ip level, + * after supplying a checksum. + */ +static void +icmp_send(m, opts) + register struct mbuf *m; + struct mbuf *opts; +{ + register struct ip *ip = mtod(m, struct ip *); + register int hlen; + register struct icmp *icp; + struct route ro; + + hlen = IP_VHL_HL(ip->ip_vhl) << 2; + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + icp->icmp_cksum = 0; + icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); + m->m_data -= hlen; + m->m_len += hlen; +#ifdef ICMPPRINTFS + if (icmpprintfs) { + char buf[4 * sizeof "123"]; + strcpy(buf, inet_ntoa(ip->ip_dst)); + printf("icmp_send dst %s src %s\n", + buf, inet_ntoa(ip->ip_src)); + } +#endif + bzero(&ro, sizeof ro); + (void) ip_output(m, opts, &ro, 0, NULL); + if (ro.ro_rt) + RTFREE(ro.ro_rt); +} + +n_time +iptime() +{ + struct timeval atv; + u_long t; + + microtime(&atv); + t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; + return (htonl(t)); +} + +#if 1 +/* + * Return the next larger or smaller MTU plateau (table from RFC 1191) + * given current value MTU. If DIR is less than zero, a larger plateau + * is returned; otherwise, a smaller value is returned. + */ +static int +ip_next_mtu(mtu, dir) + int mtu; + int dir; +{ + static int mtutab[] = { + 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, + 68, 0 + }; + int i; + + for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) { + if (mtu >= mtutab[i]) + break; + } + + if (dir < 0) { + if (i == 0) { + return 0; + } else { + return mtutab[i - 1]; + } + } else { + if (mtutab[i] == 0) { + return 0; + } else if(mtu > mtutab[i]) { + return mtutab[i]; + } else { + return mtutab[i + 1]; + } + } +} +#endif diff --git a/cpukit/libnetworking/netinet/ip_icmp.h b/cpukit/libnetworking/netinet/ip_icmp.h new file mode 100644 index 0000000000..9d07a682de --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_icmp.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +/* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. + */ + +/* + * Internal of an ICMP Router Advertisement + */ +struct icmp_ra_addr { + u_int32_t ira_addr; + u_int32_t ira_preference; +}; + +/* + * Structure of an icmp header. + */ +struct icmp { + u_char icmp_type; /* type of message, see below */ + u_char icmp_code; /* type sub code */ + u_short icmp_cksum; /* ones complement cksum of struct */ + union { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + n_short icd_id; + n_short icd_seq; + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + n_short ipm_void; + n_short ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + u_char irt_num_addrs; + u_char irt_wpa; + u_int16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + u_long id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enough to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#ifndef _IP_VHL +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ +#else +#define ICMP_ADVLEN(p) (8 + (IP_VHL_HL((p)->icmp_ip.ip_vhl) << 2) + 8) + /* N.B.: must separately check that header length >= 5 */ +#endif + +/* + * Definition of type and code field values. + */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */ +#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */ +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +#ifdef KERNEL +void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); +void icmp_input __P((struct mbuf *, int)); +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/ip_input.c b/cpukit/libnetworking/netinet/ip_input.c new file mode 100644 index 0000000000..7dbed785ba --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_input.c @@ -0,0 +1,1488 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 + * $Id$ + * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ + */ + +#define _IP_VHL + +#include "opt_ipfw.h" + +#include <stddef.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <net/netisr.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <machine/in_cksum.h> + +#include <sys/socketvar.h> + +#ifdef IPFIREWALL +#include <netinet/ip_fw.h> +#endif + +int rsvp_on = 0; +static int ip_rsvp_on; +struct socket *ip_rsvpd; + +static int ipforwarding = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, + &ipforwarding, 0, ""); + +static int ipsendredirects = 1; /* XXX */ +SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, + &ipsendredirects, 0, ""); + +int ip_defttl = IPDEFTTL; +SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, + &ip_defttl, 0, ""); + +static int ip_dosourceroute = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, + &ip_dosourceroute, 0, ""); + +static int ip_acceptsourceroute = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, + CTLFLAG_RW, &ip_acceptsourceroute, 0, ""); +#ifdef DIAGNOSTIC +static int ipprintfs = 0; +#endif + +extern struct domain inetdomain; +extern struct protosw inetsw[]; +u_char ip_protox[IPPROTO_MAX]; +static int ipqmaxlen = IFQ_MAXLEN; +struct in_ifaddr *in_ifaddr; /* first inet address */ +struct ifqueue ipintrq; +SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD, + &ipintrq.ifq_maxlen, 0, ""); +SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, + &ipintrq.ifq_drops, 0, ""); + +struct ipstat ipstat; + +/* Packet reassembly stuff */ +#define IPREASS_NHASH_LOG2 6 +#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) +#define IPREASS_HMASK (IPREASS_NHASH - 1) +#define IPREASS_HASH(x,y) \ + ((((x) & 0xF | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) + +static struct ipq ipq[IPREASS_NHASH]; +static int nipq = 0; /* total # of reass queues */ +static int maxnipq; + +#ifdef IPCTL_DEFMTU +SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, + &ip_mtu, 0, ""); +#endif + +#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 +#undef COMPAT_IPFW +#define COMPAT_IPFW 1 +#else +#undef COMPAT_IPFW +#endif + +#ifdef COMPAT_IPFW +/* Firewall hooks */ +ip_fw_chk_t *ip_fw_chk_ptr; +ip_fw_ctl_t *ip_fw_ctl_ptr; + +/* IP Network Address Translation (NAT) hooks */ +ip_nat_t *ip_nat_ptr; +ip_nat_ctl_t *ip_nat_ctl_ptr; +#endif + +/* + * We need to save the IP options in case a protocol wants to respond + * to an incoming packet over the same route if the packet got here + * using IP source routing. This allows connection establishment and + * maintenance when the remote end is on a network that is not known + * to us. + */ +static int ip_nhops = 0; +static struct ip_srcrt { + struct in_addr dst; /* final destination */ + char nop; /* one NOP to align */ + char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ + struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; +} ip_srcrt; + +#ifdef IPDIVERT +/* + * Shared variable between ip_input() and ip_reass() to communicate + * about which packets, once assembled from fragments, get diverted, + * and to which port. + */ +static u_short frag_divert_port; +#endif + +static void save_rte __P((u_char *, struct in_addr)); +static void ip_deq __P((struct ipasfrag *)); +static int ip_dooptions __P((struct mbuf *)); +static void ip_enq __P((struct ipasfrag *, struct ipasfrag *)); +static void ip_forward __P((struct mbuf *, int)); +static void ip_freef __P((struct ipq *)); +static struct ip * + ip_reass __P((struct ipasfrag *, struct ipq *, struct ipq *)); +static struct in_ifaddr * + ip_rtaddr __P((struct in_addr)); +void ipintr __P((void)); +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void +ip_init() +{ + register struct protosw *pr; + register int i; + + pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); + if (pr == 0) + panic("ip_init"); + for (i = 0; i < IPPROTO_MAX; i++) + ip_protox[i] = pr - inetsw; + for (pr = inetdomain.dom_protosw; + pr < inetdomain.dom_protoswNPROTOSW; pr++) + if (pr->pr_domain->dom_family == PF_INET && + pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) + ip_protox[pr->pr_protocol] = pr - inetsw; + + for (i = 0; i < IPREASS_NHASH; i++) + ipq[i].next = ipq[i].prev = &ipq[i]; + + maxnipq = nmbclusters/4; + + ip_id = rtems_bsdnet_seconds_since_boot() & 0xffff; + ipintrq.ifq_maxlen = ipqmaxlen; +#ifdef IPFIREWALL + ip_fw_init(); +#endif +#ifdef IPNAT + ip_nat_init(); +#endif + +} + +static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; +static struct route ipforward_rt; + +/* + * Ip input routine. Checksum and byte swap header. If fragmented + * try to reassemble. Process options. Pass to next level. + */ +void +ip_input(struct mbuf *m) +{ + struct ip *ip; + struct ipq *fp; + struct in_ifaddr *ia; + int i, hlen; + u_short sum; + +#ifdef DIAGNOSTIC + if ((m->m_flags & M_PKTHDR) == 0) + panic("ip_input no HDR"); +#endif + /* + * If no IP addresses have been set yet but the interfaces + * are receiving, can't do anything with incoming packets yet. + */ + if (in_ifaddr == NULL) + goto bad; + ipstat.ips_total++; + + if (m->m_pkthdr.len < sizeof(struct ip)) + goto tooshort; + +#ifdef DIAGNOSTIC + if (m->m_len < sizeof(struct ip)) + panic("ipintr mbuf too short"); +#endif + + if (m->m_len < sizeof (struct ip) && + (m = m_pullup(m, sizeof (struct ip))) == 0) { + ipstat.ips_toosmall++; + return; + } + ip = mtod(m, struct ip *); + + if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { + ipstat.ips_badvers++; + goto bad; + } + + hlen = IP_VHL_HL(ip->ip_vhl) << 2; + if (hlen < sizeof(struct ip)) { /* minimum header length */ + ipstat.ips_badhlen++; + goto bad; + } + if (hlen > m->m_len) { + if ((m = m_pullup(m, hlen)) == 0) { + ipstat.ips_badhlen++; + return; + } + ip = mtod(m, struct ip *); + } + if (hlen == sizeof(struct ip)) { + sum = in_cksum_hdr(ip); + } else { + sum = in_cksum(m, hlen); + } + if (sum) { + ipstat.ips_badsum++; + goto bad; + } + + /* + * Convert fields to host representation. + */ + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) { + ipstat.ips_badlen++; + goto bad; + } + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + + /* + * Check that the amount of data in the buffers + * is as at least much as the IP header would have us expect. + * Trim mbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_pkthdr.len < ip->ip_len) { +tooshort: + ipstat.ips_tooshort++; + goto bad; + } + if (m->m_pkthdr.len > ip->ip_len) { + if (m->m_len == m->m_pkthdr.len) { + m->m_len = ip->ip_len; + m->m_pkthdr.len = ip->ip_len; + } else + m_adj(m, ip->ip_len - m->m_pkthdr.len); + } + /* + * IpHack's section. + * Right now when no processing on packet has done + * and it is still fresh out of network we do our black + * deals with it. + * - Firewall: deny/allow/divert + * - Xlate: translate packet's addr/port (NAT). + * - Wrap: fake packet's addr/port <unimpl.> + * - Encapsulate: put it in another IP and send out. <unimp.> + */ + +#ifdef COMPAT_IPFW + if (ip_fw_chk_ptr) { +#ifdef IPDIVERT + u_short port; + + port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, ip_divert_ignore, &m); + ip_divert_ignore = 0; + if (port) { /* Divert packet */ + frag_divert_port = port; + goto ours; + } +#else + /* If ipfw says divert, we have to just drop packet */ + if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, 0, &m)) { + m_freem(m); + m = NULL; + } +#endif + if (!m) + return; + } + + if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) + return; +#endif + + /* + * Process options and, if not destined for us, + * ship it on. ip_dooptions returns 1 when an + * error was detected (causing an icmp message + * to be sent and the original packet to be freed). + */ + ip_nhops = 0; /* for source routed packets */ + if (hlen > sizeof (struct ip) && ip_dooptions(m)) + return; + + /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no + * matter if it is destined to another node, or whether it is + * a multicast one, RSVP wants it! and prevents it from being forwarded + * anywhere else. Also checks if the rsvp daemon is running before + * grabbing the packet. + */ + if (rsvp_on && ip->ip_p==IPPROTO_RSVP) + goto ours; + + /* + * Check our list of addresses, to see if the packet is for us. + */ + for (ia = in_ifaddr; ia; ia = ia->ia_next) { +#define satosin(sa) ((struct sockaddr_in *)(sa)) + + if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) + goto ours; +#ifdef BOOTP_COMPAT + if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) + goto ours; +#endif + if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { + if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == + ip->ip_dst.s_addr) + goto ours; + if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) + goto ours; + } + } + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + struct in_multi *inm; + if (ip_mrouter) { + /* + * If we are acting as a multicast router, all + * incoming multicast packets are passed to the + * kernel-level multicast forwarding function. + * The packet is returned (relatively) intact; if + * ip_mforward() returns a non-zero value, the packet + * must be discarded, else it may be accepted below. + * + * (The IP ident field is put in the same byte order + * as expected when ip_mforward() is called from + * ip_output().) + */ + ip->ip_id = htons(ip->ip_id); + if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { + ipstat.ips_cantforward++; + m_freem(m); + return; + } + ip->ip_id = ntohs(ip->ip_id); + + /* + * The process-level routing demon needs to receive + * all multicast IGMP packets, whether or not this + * host belongs to their destination groups. + */ + if (ip->ip_p == IPPROTO_IGMP) + goto ours; + ipstat.ips_forward++; + } + /* + * See if we belong to the destination multicast group on the + * arrival interface. + */ + IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); + if (inm == NULL) { + ipstat.ips_cantforward++; + m_freem(m); + return; + } + goto ours; + } + if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) + goto ours; + if (ip->ip_dst.s_addr == INADDR_ANY) + goto ours; + + /* + * Not for us; forward if possible and desirable. + */ + if (ipforwarding == 0) { + ipstat.ips_cantforward++; + m_freem(m); + } else + ip_forward(m, 0); + return; + +ours: + + /* + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) + */ + if (ip->ip_off &~ (IP_DF | IP_RF)) { + if (m->m_flags & M_EXT) { /* XXX */ + if ((m = m_pullup(m, sizeof (struct ip))) == 0) { + ipstat.ips_toosmall++; +#ifdef IPDIVERT + frag_divert_port = 0; +#endif + return; + } + ip = mtod(m, struct ip *); + } + sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); + /* + * Look for queue of fragments + * of this datagram. + */ + for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + + fp = 0; + + /* check if there's a place for the new queue */ + if (nipq > maxnipq) { + /* + * drop something from the tail of the current queue + * before proceeding further + */ + if (ipq[sum].prev == &ipq[sum]) { /* gak */ + for (i = 0; i < IPREASS_NHASH; i++) { + if (ipq[i].prev != &ipq[i]) { + ip_freef(ipq[i].prev); + break; + } + } + } else + ip_freef(ipq[sum].prev); + } +found: + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + ((struct ipasfrag *)ip)->ipf_mff &= ~1; + if (ip->ip_off & IP_MF) + ((struct ipasfrag *)ip)->ipf_mff |= 1; + ip->ip_off <<= 3; + + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]); + if (ip == 0) + return; + ipstat.ips_reassembled++; + m = dtom(ip); +#ifdef IPDIVERT + if (frag_divert_port) { + ip->ip_len += hlen; + HTONS(ip->ip_len); + HTONS(ip->ip_off); + HTONS(ip->ip_id); + ip->ip_sum = 0; + ip->ip_sum = in_cksum_hdr(ip); + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + NTOHS(ip->ip_len); + ip->ip_len -= hlen; + } +#endif + } else + if (fp) + ip_freef(fp); + } else + ip->ip_len -= hlen; + +#ifdef IPDIVERT + /* + * Divert reassembled packets to the divert protocol if required + */ + if (frag_divert_port) { + ipstat.ips_delivered++; + ip_divert_port = frag_divert_port; + frag_divert_port = 0; + (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen); + return; + } + + /* Don't let packets divert themselves */ + if (ip->ip_p == IPPROTO_DIVERT) { + ipstat.ips_noproto++; + goto bad; + } +#endif + + /* + * Switch out to protocol's input routine. + */ + ipstat.ips_delivered++; + (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); + return; +bad: + m_freem(m); +} + +/* + * IP software interrupt routine - to go away sometime soon + */ +void +ipintr(void) +{ + int s; + struct mbuf *m; + + while(1) { + s = splimp(); + IF_DEQUEUE(&ipintrq, m); + splx(s); + if (m == 0) + return; + ip_input(m); + } +} + +NETISR_SET(NETISR_IP, ipintr); + +/* + * Take incoming datagram fragment and try to + * reassemble it into whole datagram. If a chain for + * reassembly of this datagram already exists, then it + * is given as fp; otherwise have to make a chain. + */ +static struct ip * +ip_reass(ip, fp, where) + register struct ipasfrag *ip; + register struct ipq *fp; + struct ipq *where; +{ + register struct mbuf *m = dtom(ip); + register struct ipasfrag *q; + struct mbuf *t; + int hlen = ip->ip_hl << 2; + int i, next; + + /* + * Presence of header sizes in mbufs + * would confuse code below. + */ + m->m_data += hlen; + m->m_len -= hlen; + + /* + * If first fragment to arrive, create a reassembly queue. + */ + if (fp == 0) { + if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) + goto dropfrag; + fp = mtod(t, struct ipq *); + insque(fp, where); + nipq++; + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; + fp->ipq_src = ((struct ip *)ip)->ip_src; + fp->ipq_dst = ((struct ip *)ip)->ip_dst; +#ifdef IPDIVERT + fp->ipq_divert = 0; +#endif + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) + if (q->ip_off > ip->ip_off) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (q->ipf_prev != (struct ipasfrag *)fp) { + i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; + if (i > 0) { + if (i >= ip->ip_len) + goto dropfrag; + m_adj(dtom(ip), i); + ip->ip_off += i; + ip->ip_len -= i; + } + } + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { + struct mbuf *m0; + + i = (ip->ip_off + ip->ip_len) - q->ip_off; + if (i < q->ip_len) { + q->ip_len -= i; + q->ip_off += i; + m_adj(dtom(q), i); + break; + } + m0 = dtom(q); + q = q->ipf_next; + ip_deq(q->ipf_prev); + m_freem(m0); + } + +insert: + +#ifdef IPDIVERT + /* + * Any fragment diverting causes the whole packet to divert + */ + if (frag_divert_port != 0) + fp->ipq_divert = frag_divert_port; + frag_divert_port = 0; +#endif + + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(ip, q->ipf_prev); + next = 0; + for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { + if (q->ip_off != next) + return (0); + next += q->ip_len; + } + if (q->ipf_prev->ipf_mff & 1) + return (0); + + /* + * Reassembly is complete. Make sure the packet is a sane size. + */ + if (next + (IP_VHL_HL(((struct ip *)fp->ipq_next)->ip_vhl) << 2) + > IP_MAXPACKET) { + ipstat.ips_toolong++; + ip_freef(fp); + return (0); + } + + /* + * Concatenate fragments. + */ + q = fp->ipq_next; + m = dtom(q); + t = m->m_next; + m->m_next = 0; + m_cat(m, t); + q = q->ipf_next; + while (q != (struct ipasfrag *)fp) { + t = dtom(q); + q = q->ipf_next; + m_cat(m, t); + } + +#ifdef IPDIVERT + /* + * Record divert port for packet, if any + */ + frag_divert_port = fp->ipq_divert; +#endif + + /* + * Create header for new ip packet by + * modifying header of first packet; + * dequeue and discard fragment reassembly header. + * Make header visible. + */ + ip = fp->ipq_next; + ip->ip_len = next; + ip->ipf_mff &= ~1; + ((struct ip *)ip)->ip_src = fp->ipq_src; + ((struct ip *)ip)->ip_dst = fp->ipq_dst; + remque(fp); + nipq--; + (void) m_free(dtom(fp)); + m = dtom(ip); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); + /* some debugging cruft by sklower, below, will go away soon */ + if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ + register int plen = 0; + for (t = m; m; m = m->m_next) + plen += m->m_len; + t->m_pkthdr.len = plen; + } + return ((struct ip *)ip); + +dropfrag: + ipstat.ips_fragdropped++; + m_freem(m); + return (0); +} + +/* + * Free a fragment reassembly header and all + * associated datagrams. + */ +static void +ip_freef(fp) + struct ipq *fp; +{ + register struct ipasfrag *q, *p; + + for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { + p = q->ipf_next; + ip_deq(q); + m_freem(dtom(q)); + } + remque(fp); + (void) m_free(dtom(fp)); + nipq--; +} + +/* + * Put an ip fragment on a reassembly chain. + * Like insque, but pointers in middle of structure. + */ +static void +ip_enq(p, prev) + register struct ipasfrag *p, *prev; +{ + + p->ipf_prev = prev; + p->ipf_next = prev->ipf_next; + prev->ipf_next->ipf_prev = p; + prev->ipf_next = p; +} + +/* + * To ip_enq as remque is to insque. + */ +static void +ip_deq(p) + register struct ipasfrag *p; +{ + + p->ipf_prev->ipf_next = p->ipf_next; + p->ipf_next->ipf_prev = p->ipf_prev; +} + +/* + * IP timer processing; + * if a timer expires on a reassembly + * queue, discard it. + */ +void +ip_slowtimo() +{ + register struct ipq *fp; + int s = splnet(); + int i; + + for (i = 0; i < IPREASS_NHASH; i++) { + fp = ipq[i].next; + if (fp == 0) + continue; + while (fp != &ipq[i]) { + --fp->ipq_ttl; + fp = fp->next; + if (fp->prev->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef(fp->prev); + } + } + } + splx(s); +} + +/* + * Drain off all datagram fragments. + */ +void +ip_drain() +{ + int i; + + for (i = 0; i < IPREASS_NHASH; i++) { + while (ipq[i].next != &ipq[i]) { + ipstat.ips_fragdropped++; + ip_freef(ipq[i].next); + } + } + in_rtqdrain(); +} + +/* + * Do option processing on a datagram, + * possibly discarding it if bad options are encountered, + * or forwarding it if source-routed. + * Returns 1 if packet has been forwarded/freed, + * 0 if the packet should be processed further. + */ +static int +ip_dooptions(m) + struct mbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + register u_char *cp; + register struct ip_timestamp *ipt; + register struct in_ifaddr *ia; + int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; + struct in_addr *sin, dst; + n_time ntime; + + dst = ip->ip_dst; + cp = (u_char *)(ip + 1); + cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= 0 || optlen > cnt) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + } + switch (opt) { + + default: + break; + + /* + * Source routing with record. + * Find interface with current destination address. + * If none on this machine then drop if strictly routed, + * or do nothing if loosely routed. + * Record interface address and bring up next address + * component. If strictly routed make sure next + * address is on directly accessible net. + */ + case IPOPT_LSRR: + case IPOPT_SSRR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = ip->ip_dst; + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)&ipaddr); + if (ia == 0) { + if (opt == IPOPT_SSRR) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + if (!ip_dosourceroute) + goto nosourcerouting; + /* + * Loose routing, and not at next destination + * yet; nothing to do except forward. + */ + break; + } + off--; /* 0 origin */ + if (off > optlen - sizeof(struct in_addr)) { + /* + * End of source route. Should be for us. + */ + if (!ip_acceptsourceroute) + goto nosourcerouting; + save_rte(cp, ip->ip_src); + break; + } + + if (!ip_dosourceroute) { + char buf[4*sizeof "123"]; + +nosourcerouting: + strcpy(buf, inet_ntoa(ip->ip_dst)); + log(LOG_WARNING, + "attempted source route from %s to %s\n", + inet_ntoa(ip->ip_src), buf); + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + + /* + * locate outgoing interface + */ + (void)memcpy(&ipaddr.sin_addr, cp + off, + sizeof(ipaddr.sin_addr)); + + if (opt == IPOPT_SSRR) { +#define INA struct in_ifaddr * +#define SA struct sockaddr * + if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) + ia = (INA)ifa_ifwithnet((SA)&ipaddr); + } else + ia = ip_rtaddr(ipaddr.sin_addr); + if (ia == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + ip->ip_dst = ipaddr.sin_addr; + (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), + sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); + break; + + case IPOPT_RR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + /* + * If no space remains, ignore. + */ + off--; /* 0 origin */ + if (off > optlen - sizeof(struct in_addr)) + break; + (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, + sizeof(ipaddr.sin_addr)); + /* + * locate outgoing interface; if we're the destination, + * use the incoming interface (should be same). + */ + if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && + (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), + sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + break; + + case IPOPT_TS: + code = cp - (u_char *)ip; + ipt = (struct ip_timestamp *)cp; + if (ipt->ipt_len < 5) + goto bad; + if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { + if (++ipt->ipt_oflw == 0) + goto bad; + break; + } + sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); + switch (ipt->ipt_flg) { + + case IPOPT_TS_TSONLY: + break; + + case IPOPT_TS_TSANDADDR: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == 0) + continue; + (void)memcpy(sin, &IA_SIN(ia)->sin_addr, + sizeof(struct in_addr)); + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + case IPOPT_TS_PRESPEC: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + (void)memcpy(&ipaddr.sin_addr, sin, + sizeof(struct in_addr)); + if (ifa_ifwithaddr((SA)&ipaddr) == 0) + continue; + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + default: + goto bad; + } + ntime = iptime(); + (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, + sizeof(n_time)); + ipt->ipt_ptr += sizeof(n_time); + } + } + if (forward && ipforwarding) { + ip_forward(m, 1); + return (1); + } + return (0); +bad: + ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */ + icmp_error(m, type, code, 0, 0); + ipstat.ips_badoptions++; + return (1); +} + +/* + * Given address of next destination (final or next hop), + * return internet address info of interface to be used to get there. + */ +static struct in_ifaddr * +ip_rtaddr(dst) + struct in_addr dst; +{ + register struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; + + if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { + if (ipforward_rt.ro_rt) { + RTFREE(ipforward_rt.ro_rt); + ipforward_rt.ro_rt = 0; + } + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = dst; + + rtalloc_ign(&ipforward_rt, RTF_PRCLONING); + } + if (ipforward_rt.ro_rt == 0) + return ((struct in_ifaddr *)0); + return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); +} + +/* + * Save incoming source route for use in replies, + * to be picked up later by ip_srcroute if the receiver is interested. + */ +void +save_rte(option, dst) + u_char *option; + struct in_addr dst; +{ + unsigned olen; + + olen = option[IPOPT_OLEN]; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf("save_rte: olen %d\n", olen); +#endif + if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) + return; + bcopy(option, ip_srcrt.srcopt, olen); + ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); + ip_srcrt.dst = dst; +} + +/* + * Retrieve incoming source route for use in replies, + * in the same form used by setsockopt. + * The first hop is placed before the options, will be removed later. + */ +struct mbuf * +ip_srcroute() +{ + register struct in_addr *p, *q; + register struct mbuf *m; + + if (ip_nhops == 0) + return ((struct mbuf *)0); + m = m_get(M_DONTWAIT, MT_SOOPTS); + if (m == 0) + return ((struct mbuf *)0); + +#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) + + /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ + m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + + OPTSIZ; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); +#endif + + /* + * First save first hop for return route + */ + p = &ip_srcrt.route[ip_nhops - 1]; + *(mtod(m, struct in_addr *)) = *p--; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); +#endif + + /* + * Copy option fields and padding (nop) to mbuf. + */ + ip_srcrt.nop = IPOPT_NOP; + ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; + (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), + &ip_srcrt.nop, OPTSIZ); + q = (struct in_addr *)(mtod(m, caddr_t) + + sizeof(struct in_addr) + OPTSIZ); +#undef OPTSIZ + /* + * Record return path as an IP source route, + * reversing the path (pointers are now aligned). + */ + while (p >= ip_srcrt.route) { +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" %lx", ntohl(q->s_addr)); +#endif + *q++ = *p--; + } + /* + * Last hop goes to final destination. + */ + *q = ip_srcrt.dst; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" %lx\n", ntohl(q->s_addr)); +#endif + return (m); +} + +/* + * Strip out IP options, at higher + * level protocol in the kernel. + * Second argument is buffer to which options + * will be moved, and return value is their length. + * XXX should be deleted; last arg currently ignored. + */ +void +ip_stripoptions(m, mopt) + register struct mbuf *m; + struct mbuf *mopt; +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register caddr_t opts; + int olen; + + olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); + opts = (caddr_t)(ip + 1); + i = m->m_len - (sizeof (struct ip) + olen); + bcopy(opts + olen, opts, (unsigned)i); + m->m_len -= olen; + if (m->m_flags & M_PKTHDR) + m->m_pkthdr.len -= olen; + ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); +} + +u_char inetctlerrmap[PRC_NCMDS] = { + 0, 0, 0, 0, + 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, + EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, + EMSGSIZE, EHOSTUNREACH, 0, 0, + 0, 0, 0, 0, + ENOPROTOOPT +}; + +/* + * Forward a packet. If some error occurs return the sender + * an icmp packet. Note we can't always generate a meaningful + * icmp message because icmp doesn't have a large enough repertoire + * of codes and types. + * + * If not forwarding, just drop the packet. This could be confusing + * if ipforwarding was zero but some routing protocol was advancing + * us as a gateway to somewhere. However, we must let the routing + * protocol deal with that. + * + * The srcrt parameter indicates whether the packet is being forwarded + * via a source route. + */ +static void +ip_forward(m, srcrt) + struct mbuf *m; + int srcrt; +{ + register struct ip *ip = mtod(m, struct ip *); + register struct sockaddr_in *sin; + register struct rtentry *rt; + int error, type = 0, code = 0; + struct mbuf *mcopy; + n_long dest; + struct ifnet *destifp; + + dest = 0; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf("forward: src %lx dst %lx ttl %x\n", + ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl); +#endif + + + if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { + ipstat.ips_cantforward++; + m_freem(m); + return; + } + HTONS(ip->ip_id); + if (ip->ip_ttl <= IPTTLDEC) { + icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); + return; + } + ip->ip_ttl -= IPTTLDEC; + + sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; + if ((rt = ipforward_rt.ro_rt) == 0 || + ip->ip_dst.s_addr != sin->sin_addr.s_addr) { + if (ipforward_rt.ro_rt) { + RTFREE(ipforward_rt.ro_rt); + ipforward_rt.ro_rt = 0; + } + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = ip->ip_dst; + + rtalloc_ign(&ipforward_rt, RTF_PRCLONING); + if (ipforward_rt.ro_rt == 0) { + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); + return; + } + rt = ipforward_rt.ro_rt; + } + + /* + * Save at most 64 bytes of the packet in case + * we need to generate an ICMP message to the src. + */ + mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); + + /* + * If forwarding packet using same interface that it came in on, + * perhaps should send a redirect to sender to shortcut a hop. + * Only send redirect if source is sending directly to us, + * and if packet was not source routed (or has any options). + * Also, don't send redirect if forwarding using a default route + * or a route modified by a redirect. + */ +#define satosin(sa) ((struct sockaddr_in *)(sa)) + if (rt->rt_ifp == m->m_pkthdr.rcvif && + (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && + satosin(rt_key(rt))->sin_addr.s_addr != 0 && + ipsendredirects && !srcrt) { +#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) + u_long src = ntohl(ip->ip_src.s_addr); + + if (RTA(rt) && + (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { + if (rt->rt_flags & RTF_GATEWAY) + dest = satosin(rt->rt_gateway)->sin_addr.s_addr; + else + dest = ip->ip_dst.s_addr; + /* Router requirements says to only send host redirects */ + type = ICMP_REDIRECT; + code = ICMP_REDIRECT_HOST; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf("redirect (%d) to %lx\n", code, (u_long)dest); +#endif + } + } + + error = ip_output(m, (struct mbuf *)0, &ipforward_rt, + IP_FORWARDING, 0); + if (error) + ipstat.ips_cantforward++; + else { + ipstat.ips_forward++; + if (type) + ipstat.ips_redirectsent++; + else { + if (mcopy) + m_freem(mcopy); + return; + } + } + if (mcopy == NULL) + return; + destifp = NULL; + + switch (error) { + + case 0: /* forwarded, but need redirect */ + /* type, code set above */ + break; + + case ENETUNREACH: /* shouldn't happen, checked above */ + case EHOSTUNREACH: + case ENETDOWN: + case EHOSTDOWN: + default: + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + break; + + case EMSGSIZE: + type = ICMP_UNREACH; + code = ICMP_UNREACH_NEEDFRAG; + if (ipforward_rt.ro_rt) + destifp = ipforward_rt.ro_rt->rt_ifp; + ipstat.ips_cantfrag++; + break; + + case ENOBUFS: + type = ICMP_SOURCEQUENCH; + code = 0; + break; + } + icmp_error(mcopy, type, code, dest, destifp); +} + +void +ip_savecontrol(inp, mp, ip, m) + register struct inpcb *inp; + register struct mbuf **mp; + register struct ip *ip; + register struct mbuf *m; +{ + if (inp->inp_socket->so_options & SO_TIMESTAMP) { + struct timeval tv; + + microtime(&tv); + *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), + SCM_TIMESTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } + if (inp->inp_flags & INP_RECVDSTADDR) { + *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, + sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } +#ifdef notyet + /* XXX + * Moving these out of udp_input() made them even more broken + * than they already were. + */ + /* options were tossed already */ + if (inp->inp_flags & INP_RECVOPTS) { + *mp = sbcreatecontrol((caddr_t) opts_deleted_above, + sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } + /* ip_srcroute doesn't do what we want here, need to fix */ + if (inp->inp_flags & INP_RECVRETOPTS) { + *mp = sbcreatecontrol((caddr_t) ip_srcroute(), + sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } +#endif + if (inp->inp_flags & INP_RECVIF) { + struct sockaddr_dl sdl; + + sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data[0]); + sdl.sdl_family = AF_LINK; + sdl.sdl_index = m->m_pkthdr.rcvif ? + m->m_pkthdr.rcvif->if_index : 0; + sdl.sdl_nlen = sdl.sdl_alen = sdl.sdl_slen = 0; + *mp = sbcreatecontrol((caddr_t) &sdl, sdl.sdl_len, + IP_RECVIF, IPPROTO_IP); + if (*mp) + mp = &(*mp)->m_next; + } +} + +int +ip_rsvp_init(struct socket *so) +{ + if (so->so_type != SOCK_RAW || + so->so_proto->pr_protocol != IPPROTO_RSVP) + return EOPNOTSUPP; + + if (ip_rsvpd != NULL) + return EADDRINUSE; + + ip_rsvpd = so; + /* + * This may seem silly, but we need to be sure we don't over-increment + * the RSVP counter, in case something slips up. + */ + if (!ip_rsvp_on) { + ip_rsvp_on = 1; + rsvp_on++; + } + + return 0; +} + +int +ip_rsvp_done(void) +{ + ip_rsvpd = NULL; + /* + * This may seem silly, but we need to be sure we don't over-decrement + * the RSVP counter, in case something slips up. + */ + if (ip_rsvp_on) { + ip_rsvp_on = 0; + rsvp_on--; + } + return 0; +} diff --git a/cpukit/libnetworking/netinet/ip_mroute.c b/cpukit/libnetworking/netinet/ip_mroute.c new file mode 100644 index 0000000000..98f1e5d399 --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_mroute.c @@ -0,0 +1,2302 @@ +/* + * IP multicast forwarding procedures + * + * Written by David Waitzman, BBN Labs, August 1988. + * Modified by Steve Deering, Stanford, February 1989. + * Modified by Mark J. Steiglitz, Stanford, May, 1991 + * Modified by Van Jacobson, LBL, January 1993 + * Modified by Ajit Thyagarajan, PARC, August 1993 + * Modified by Bill Fenner, PARC, April 1995 + * + * MROUTING Revision: 3.5 + * $Id$ + */ + +#include "opt_mrouting.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/ioctl.h> +#include <sys/syslog.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/igmp.h> +#include <netinet/igmp_var.h> +#include <netinet/ip_mroute.h> +#include <netinet/udp.h> + +#ifndef NTOHL +#if BYTE_ORDER != BIG_ENDIAN +#define NTOHL(d) ((d) = ntohl((d))) +#define NTOHS(d) ((d) = ntohs((u_short)(d))) +#define HTONL(d) ((d) = htonl((d))) +#define HTONS(d) ((d) = htons((u_short)(d))) +#else +#define NTOHL(d) +#define NTOHS(d) +#define HTONL(d) +#define HTONS(d) +#endif +#endif + +#ifndef MROUTING +extern u_long _ip_mcast_src __P((int vifi)); +extern int _ip_mforward __P((struct ip *ip, struct ifnet *ifp, + struct mbuf *m, struct ip_moptions *imo)); +extern int _ip_mrouter_done __P((void)); +extern int _ip_mrouter_get __P((int cmd, struct socket *so, + struct mbuf **m)); +extern int _ip_mrouter_set __P((int cmd, struct socket *so, + struct mbuf *m)); +extern int _mrt_ioctl __P((int req, caddr_t data, struct proc *p)); + +/* + * Dummy routines and globals used when multicast routing is not compiled in. + */ + +struct socket *ip_mrouter = NULL; +static u_int ip_mrtproto = 0; +static struct mrtstat mrtstat; +u_int rsvpdebug = 0; + +int +_ip_mrouter_set(cmd, so, m) + int cmd; + struct socket *so; + struct mbuf *m; +{ + return(EOPNOTSUPP); +} + +int (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = _ip_mrouter_set; + + +int +_ip_mrouter_get(cmd, so, m) + int cmd; + struct socket *so; + struct mbuf **m; +{ + return(EOPNOTSUPP); +} + +int (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = _ip_mrouter_get; + +int +_ip_mrouter_done() +{ + return(0); +} + +int (*ip_mrouter_done)(void) = _ip_mrouter_done; + +int +_ip_mforward(ip, ifp, m, imo) + struct ip *ip; + struct ifnet *ifp; + struct mbuf *m; + struct ip_moptions *imo; +{ + return(0); +} + +int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, + struct ip_moptions *) = _ip_mforward; + +int +_mrt_ioctl(int req, caddr_t data, struct proc *p) +{ + return EOPNOTSUPP; +} + +int (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl; + +void +rsvp_input(m, iphlen) /* XXX must fixup manually */ + struct mbuf *m; + int iphlen; +{ + /* Can still get packets with rsvp_on = 0 if there is a local member + * of the group to which the RSVP packet is addressed. But in this + * case we want to throw the packet away. + */ + if (!rsvp_on) { + m_freem(m); + return; + } + + if (ip_rsvpd != NULL) { + if (rsvpdebug) + printf("rsvp_input: Sending packet up old-style socket\n"); + rip_input(m, iphlen); + return; + } + /* Drop the packet */ + m_freem(m); +} + +void ipip_input(struct mbuf *m, int iphlen) { /* XXX must fixup manually */ + rip_input(m, iphlen); +} + +int (*legal_vif_num)(int) = 0; + +/* + * This should never be called, since IP_MULTICAST_VIF should fail, but + * just in case it does get called, the code a little lower in ip_output + * will assign the packet a local address. + */ +u_long +_ip_mcast_src(int vifi) { return INADDR_ANY; } +u_long (*ip_mcast_src)(int) = _ip_mcast_src; + +int +ip_rsvp_vif_init(so, m) + struct socket *so; + struct mbuf *m; +{ + return(EINVAL); +} + +int +ip_rsvp_vif_done(so, m) + struct socket *so; + struct mbuf *m; +{ + return(EINVAL); +} + +void +ip_rsvp_force_done(so) + struct socket *so; +{ + return; +} + +#else /* MROUTING */ + +#define M_HASCL(m) ((m)->m_flags & M_EXT) + +#define INSIZ sizeof(struct in_addr) +#define same(a1, a2) \ + (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0) + +#define MT_MRTABLE MT_RTABLE /* since nothing else uses it */ + +/* + * Globals. All but ip_mrouter and ip_mrtproto could be static, + * except for netstat or debugging purposes. + */ +#ifndef MROUTE_LKM +struct socket *ip_mrouter = NULL; +struct mrtstat mrtstat; + +int ip_mrtproto = IGMP_DVMRP; /* for netstat only */ +#else /* MROUTE_LKM */ +extern void X_ipip_input __P((struct mbuf *m, int iphlen)); +extern struct mrtstat mrtstat; +static int ip_mrtproto; +#endif + +#define NO_RTE_FOUND 0x1 +#define RTE_FOUND 0x2 + +static struct mbuf *mfctable[MFCTBLSIZ]; +static u_char nexpire[MFCTBLSIZ]; +static struct vif viftable[MAXVIFS]; +static u_int mrtdebug = 0; /* debug level */ +#define DEBUG_MFC 0x02 +#define DEBUG_FORWARD 0x04 +#define DEBUG_EXPIRE 0x08 +#define DEBUG_XMIT 0x10 +static u_int tbfdebug = 0; /* tbf debug level */ +static u_int rsvpdebug = 0; /* rsvp debug level */ + +#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ +#define UPCALL_EXPIRE 6 /* number of timeouts */ + +/* + * Define the token bucket filter structures + * tbftable -> each vif has one of these for storing info + */ + +static struct tbf tbftable[MAXVIFS]; +#define TBF_REPROCESS (hz / 100) /* 100x / second */ + +/* + * 'Interfaces' associated with decapsulator (so we can tell + * packets that went through it from ones that get reflected + * by a broken gateway). These interfaces are never linked into + * the system ifnet list & no routes point to them. I.e., packets + * can't be sent this way. They only exist as a placeholder for + * multicast source verification. + */ +static struct ifnet multicast_decap_if[MAXVIFS]; + +#define ENCAP_TTL 64 +#define ENCAP_PROTO IPPROTO_IPIP /* 4 */ + +/* prototype IP hdr for encapsulated packets */ +static struct ip multicast_encap_iphdr = { +#if BYTE_ORDER == LITTLE_ENDIAN + sizeof(struct ip) >> 2, IPVERSION, +#else + IPVERSION, sizeof(struct ip) >> 2, +#endif + 0, /* tos */ + sizeof(struct ip), /* total length */ + 0, /* id */ + 0, /* frag offset */ + ENCAP_TTL, ENCAP_PROTO, + 0, /* checksum */ +}; + +/* + * Private variables. + */ +static vifi_t numvifs = 0; +static int have_encap_tunnel = 0; + +/* + * one-back cache used by ipip_input to locate a tunnel's vif + * given a datagram's src ip address. + */ +static u_long last_encap_src; +static struct vif *last_encap_vif; + +static u_long X_ip_mcast_src __P((int vifi)); +static int X_ip_mforward __P((struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo)); +static int X_ip_mrouter_done __P((void)); +static int X_ip_mrouter_get __P((int cmd, struct socket *so, struct mbuf **m)); +static int X_ip_mrouter_set __P((int cmd, struct socket *so, struct mbuf *m)); +static int X_legal_vif_num __P((int vif)); +static int X_mrt_ioctl __P((int cmd, caddr_t data)); + +static int get_sg_cnt(struct sioc_sg_req *); +static int get_vif_cnt(struct sioc_vif_req *); +static int ip_mrouter_init(struct socket *, struct mbuf *); +static int add_vif(struct vifctl *); +static int del_vif(vifi_t *); +static int add_mfc(struct mfcctl *); +static int del_mfc(struct mfcctl *); +static int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *); +static int get_version(struct mbuf *); +static int get_assert(struct mbuf *); +static int set_assert(int *); +static void expire_upcalls(void *); +static int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *, + vifi_t); +static void phyint_send(struct ip *, struct vif *, struct mbuf *); +static void encap_send(struct ip *, struct vif *, struct mbuf *); +static void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long); +static void tbf_queue(struct vif *, struct mbuf *); +static void tbf_process_q(struct vif *); +static void tbf_reprocess_q(void *); +static int tbf_dq_sel(struct vif *, struct ip *); +static void tbf_send_packet(struct vif *, struct mbuf *); +static void tbf_update_tokens(struct vif *); +static int priority(struct vif *, struct ip *); +void multiencap_decap(struct mbuf *); + +/* + * whether or not special PIM assert processing is enabled. + */ +static int pim_assert; +/* + * Rate limit for assert notification messages, in usec + */ +#define ASSERT_MSG_TIME 3000000 + +/* + * Hash function for a source, group entry + */ +#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \ + ((g) >> 20) ^ ((g) >> 10) ^ (g)) + +/* + * Find a route for a given origin IP address and Multicast group address + * Type of service parameter to be added in the future!!! + */ + +#define MFCFIND(o, g, rt) { \ + register struct mbuf *_mb_rt = mfctable[MFCHASH(o,g)]; \ + register struct mfc *_rt = NULL; \ + rt = NULL; \ + ++mrtstat.mrts_mfc_lookups; \ + while (_mb_rt) { \ + _rt = mtod(_mb_rt, struct mfc *); \ + if ((_rt->mfc_origin.s_addr == o) && \ + (_rt->mfc_mcastgrp.s_addr == g) && \ + (_mb_rt->m_act == NULL)) { \ + rt = _rt; \ + break; \ + } \ + _mb_rt = _mb_rt->m_next; \ + } \ + if (rt == NULL) { \ + ++mrtstat.mrts_mfc_misses; \ + } \ +} + + +/* + * Macros to compute elapsed time efficiently + * Borrowed from Van Jacobson's scheduling code + */ +#define TV_DELTA(a, b, delta) { \ + register int xxs; \ + \ + delta = (a).tv_usec - (b).tv_usec; \ + if ((xxs = (a).tv_sec - (b).tv_sec)) { \ + switch (xxs) { \ + case 2: \ + delta += 1000000; \ + /* fall through */ \ + case 1: \ + delta += 1000000; \ + break; \ + default: \ + delta += (1000000 * xxs); \ + } \ + } \ +} + +#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ + (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) + +#ifdef UPCALL_TIMING +u_long upcall_data[51]; +static void collate(struct timeval *); +#endif /* UPCALL_TIMING */ + + +/* + * Handle MRT setsockopt commands to modify the multicast routing tables. + */ +static int +X_ip_mrouter_set(cmd, so, m) + int cmd; + struct socket *so; + struct mbuf *m; +{ + if (cmd != MRT_INIT && so != ip_mrouter) return EACCES; + + switch (cmd) { + case MRT_INIT: return ip_mrouter_init(so, m); + case MRT_DONE: return ip_mrouter_done(); + case MRT_ADD_VIF: return add_vif (mtod(m, struct vifctl *)); + case MRT_DEL_VIF: return del_vif (mtod(m, vifi_t *)); + case MRT_ADD_MFC: return add_mfc (mtod(m, struct mfcctl *)); + case MRT_DEL_MFC: return del_mfc (mtod(m, struct mfcctl *)); + case MRT_ASSERT: return set_assert(mtod(m, int *)); + default: return EOPNOTSUPP; + } +} + +#ifndef MROUTE_LKM +int (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = X_ip_mrouter_set; +#endif + +/* + * Handle MRT getsockopt commands + */ +static int +X_ip_mrouter_get(cmd, so, m) + int cmd; + struct socket *so; + struct mbuf **m; +{ + struct mbuf *mb; + + if (so != ip_mrouter) return EACCES; + + *m = mb = m_get(M_WAIT, MT_SOOPTS); + + switch (cmd) { + case MRT_VERSION: return get_version(mb); + case MRT_ASSERT: return get_assert(mb); + default: return EOPNOTSUPP; + } +} + +#ifndef MROUTE_LKM +int (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = X_ip_mrouter_get; +#endif + +/* + * Handle ioctl commands to obtain information from the cache + */ +static int +X_mrt_ioctl(cmd, data) + int cmd; + caddr_t data; +{ + int error = 0; + + switch (cmd) { + case (SIOCGETVIFCNT): + return (get_vif_cnt((struct sioc_vif_req *)data)); + break; + case (SIOCGETSGCNT): + return (get_sg_cnt((struct sioc_sg_req *)data)); + break; + default: + return (EINVAL); + break; + } + return error; +} + +#ifndef MROUTE_LKM +int (*mrt_ioctl)(int, caddr_t) = X_mrt_ioctl; +#endif + +/* + * returns the packet, byte, rpf-failure count for the source group provided + */ +static int +get_sg_cnt(req) + register struct sioc_sg_req *req; +{ + register struct mfc *rt; + int s; + + s = splnet(); + MFCFIND(req->src.s_addr, req->grp.s_addr, rt); + splx(s); + if (rt != NULL) { + req->pktcnt = rt->mfc_pkt_cnt; + req->bytecnt = rt->mfc_byte_cnt; + req->wrong_if = rt->mfc_wrong_if; + } else + req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; + + return 0; +} + +/* + * returns the input and output packet and byte counts on the vif provided + */ +static int +get_vif_cnt(req) + register struct sioc_vif_req *req; +{ + register vifi_t vifi = req->vifi; + + if (vifi >= numvifs) return EINVAL; + + req->icount = viftable[vifi].v_pkt_in; + req->ocount = viftable[vifi].v_pkt_out; + req->ibytes = viftable[vifi].v_bytes_in; + req->obytes = viftable[vifi].v_bytes_out; + + return 0; +} + +/* + * Enable multicast routing + */ +static int +ip_mrouter_init(so, m) + struct socket *so; + struct mbuf *m; +{ + int *v; + + if (mrtdebug) + log(LOG_DEBUG,"ip_mrouter_init: so_type = %d, pr_protocol = %d\n", + so->so_type, so->so_proto->pr_protocol); + + if (so->so_type != SOCK_RAW || + so->so_proto->pr_protocol != IPPROTO_IGMP) return EOPNOTSUPP; + + if (!m || (m->m_len != sizeof(int *))) + return ENOPROTOOPT; + + v = mtod(m, int *); + if (*v != 1) + return ENOPROTOOPT; + + if (ip_mrouter != NULL) return EADDRINUSE; + + ip_mrouter = so; + + bzero((caddr_t)mfctable, sizeof(mfctable)); + bzero((caddr_t)nexpire, sizeof(nexpire)); + + pim_assert = 0; + + timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); + + if (mrtdebug) + log(LOG_DEBUG, "ip_mrouter_init\n"); + + return 0; +} + +/* + * Disable multicast routing + */ +static int +X_ip_mrouter_done() +{ + vifi_t vifi; + int i; + struct ifnet *ifp; + struct ifreq ifr; + struct mbuf *mb_rt; + struct mbuf *m; + struct rtdetq *rte; + int s; + + s = splnet(); + + /* + * For each phyint in use, disable promiscuous reception of all IP + * multicasts. + */ + for (vifi = 0; vifi < numvifs; vifi++) { + if (viftable[vifi].v_lcl_addr.s_addr != 0 && + !(viftable[vifi].v_flags & VIFF_TUNNEL)) { + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr + = INADDR_ANY; + ifp = viftable[vifi].v_ifp; + (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); + } + } + bzero((caddr_t)tbftable, sizeof(tbftable)); + bzero((caddr_t)viftable, sizeof(viftable)); + numvifs = 0; + pim_assert = 0; + + untimeout(expire_upcalls, (caddr_t)NULL); + + /* + * Free all multicast forwarding cache entries. + */ + for (i = 0; i < MFCTBLSIZ; i++) { + mb_rt = mfctable[i]; + while (mb_rt) { + if (mb_rt->m_act != NULL) { + while (mb_rt->m_act) { + m = mb_rt->m_act; + mb_rt->m_act = m->m_act; + rte = mtod(m, struct rtdetq *); + m_freem(rte->m); + m_free(m); + } + } + mb_rt = m_free(mb_rt); + } + } + + bzero((caddr_t)mfctable, sizeof(mfctable)); + + /* + * Reset de-encapsulation cache + */ + last_encap_src = 0; + last_encap_vif = NULL; + have_encap_tunnel = 0; + + ip_mrouter = NULL; + + splx(s); + + if (mrtdebug) + log(LOG_DEBUG, "ip_mrouter_done\n"); + + return 0; +} + +#ifndef MROUTE_LKM +int (*ip_mrouter_done)(void) = X_ip_mrouter_done; +#endif + +static int +get_version(mb) + struct mbuf *mb; +{ + int *v; + + v = mtod(mb, int *); + + *v = 0x0305; /* XXX !!!! */ + mb->m_len = sizeof(int); + + return 0; +} + +/* + * Set PIM assert processing global + */ +static int +set_assert(i) + int *i; +{ + if ((*i != 1) && (*i != 0)) + return EINVAL; + + pim_assert = *i; + + return 0; +} + +/* + * Get PIM assert processing global + */ +static int +get_assert(m) + struct mbuf *m; +{ + int *i; + + i = mtod(m, int *); + + *i = pim_assert; + + return 0; +} + +/* + * Add a vif to the vif table + */ +static int +add_vif(vifcp) + register struct vifctl *vifcp; +{ + register struct vif *vifp = viftable + vifcp->vifc_vifi; + static struct sockaddr_in sin = {sizeof sin, AF_INET}; + struct ifaddr *ifa; + struct ifnet *ifp; + struct ifreq ifr; + int error, s; + struct tbf *v_tbf = tbftable + vifcp->vifc_vifi; + + if (vifcp->vifc_vifi >= MAXVIFS) return EINVAL; + if (vifp->v_lcl_addr.s_addr != 0) return EADDRINUSE; + + /* Find the interface with an address in AF_INET family */ + sin.sin_addr = vifcp->vifc_lcl_addr; + ifa = ifa_ifwithaddr((struct sockaddr *)&sin); + if (ifa == 0) return EADDRNOTAVAIL; + ifp = ifa->ifa_ifp; + + if (vifcp->vifc_flags & VIFF_TUNNEL) { + if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) { + /* + * An encapsulating tunnel is wanted. Tell ipip_input() to + * start paying attention to encapsulated packets. + */ + if (have_encap_tunnel == 0) { + have_encap_tunnel = 1; + for (s = 0; s < MAXVIFS; ++s) { + multicast_decap_if[s].if_name = "mdecap"; + multicast_decap_if[s].if_unit = s; + } + } + /* + * Set interface to fake encapsulator interface + */ + ifp = &multicast_decap_if[vifcp->vifc_vifi]; + /* + * Prepare cached route entry + */ + bzero(&vifp->v_route, sizeof(vifp->v_route)); + } else { + log(LOG_ERR, "source routed tunnels not supported\n"); + return EOPNOTSUPP; + } + } else { + /* Make sure the interface supports multicast */ + if ((ifp->if_flags & IFF_MULTICAST) == 0) + return EOPNOTSUPP; + + /* Enable promiscuous reception of all IP multicasts from the if */ + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; + s = splnet(); + error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); + splx(s); + if (error) + return error; + } + + s = splnet(); + /* define parameters for the tbf structure */ + vifp->v_tbf = v_tbf; + GET_TIME(vifp->v_tbf->tbf_last_pkt_t); + vifp->v_tbf->tbf_n_tok = 0; + vifp->v_tbf->tbf_q_len = 0; + vifp->v_tbf->tbf_max_q_len = MAXQSIZE; + vifp->v_tbf->tbf_q = vifp->v_tbf->tbf_t = NULL; + + vifp->v_flags = vifcp->vifc_flags; + vifp->v_threshold = vifcp->vifc_threshold; + vifp->v_lcl_addr = vifcp->vifc_lcl_addr; + vifp->v_rmt_addr = vifcp->vifc_rmt_addr; + vifp->v_ifp = ifp; + /* scaling up here allows division by 1024 in critical code */ + vifp->v_rate_limit= vifcp->vifc_rate_limit * 1024 / 1000; + vifp->v_rsvp_on = 0; + vifp->v_rsvpd = NULL; + /* initialize per vif pkt counters */ + vifp->v_pkt_in = 0; + vifp->v_pkt_out = 0; + vifp->v_bytes_in = 0; + vifp->v_bytes_out = 0; + splx(s); + + /* Adjust numvifs up if the vifi is higher than numvifs */ + if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1; + + if (mrtdebug) + log(LOG_DEBUG, "add_vif #%d, lcladdr %x, %s %x, thresh %x, rate %d\n", + vifcp->vifc_vifi, + ntohl(vifcp->vifc_lcl_addr.s_addr), + (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask", + ntohl(vifcp->vifc_rmt_addr.s_addr), + vifcp->vifc_threshold, + vifcp->vifc_rate_limit); + + return 0; +} + +/* + * Delete a vif from the vif table + */ +static int +del_vif(vifip) + vifi_t *vifip; +{ + register struct vif *vifp = viftable + *vifip; + register vifi_t vifi; + register struct mbuf *m; + struct ifnet *ifp; + struct ifreq ifr; + int s; + + if (*vifip >= numvifs) return EINVAL; + if (vifp->v_lcl_addr.s_addr == 0) return EADDRNOTAVAIL; + + s = splnet(); + + if (!(vifp->v_flags & VIFF_TUNNEL)) { + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; + ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY; + ifp = vifp->v_ifp; + (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); + } + + if (vifp == last_encap_vif) { + last_encap_vif = 0; + last_encap_src = 0; + } + + /* + * Free packets queued at the interface + */ + while (vifp->v_tbf->tbf_q) { + m = vifp->v_tbf->tbf_q; + vifp->v_tbf->tbf_q = m->m_act; + m_freem(m); + } + + bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf))); + bzero((caddr_t)vifp, sizeof (*vifp)); + + /* Adjust numvifs down */ + for (vifi = numvifs; vifi > 0; vifi--) + if (viftable[vifi-1].v_lcl_addr.s_addr != 0) break; + numvifs = vifi; + + splx(s); + + if (mrtdebug) + log(LOG_DEBUG, "del_vif %d, numvifs %d\n", *vifip, numvifs); + + return 0; +} + +/* + * Add an mfc entry + */ +static int +add_mfc(mfccp) + struct mfcctl *mfccp; +{ + struct mfc *rt; + register struct mbuf *mb_rt; + u_long hash; + struct mbuf *mb_ntry; + struct rtdetq *rte; + register u_short nstl; + int s; + int i; + + MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt); + + /* If an entry already exists, just update the fields */ + if (rt) { + if (mrtdebug & DEBUG_MFC) + log(LOG_DEBUG,"add_mfc update o %x g %x p %x\n", + ntohl(mfccp->mfcc_origin.s_addr), + ntohl(mfccp->mfcc_mcastgrp.s_addr), + mfccp->mfcc_parent); + + s = splnet(); + rt->mfc_parent = mfccp->mfcc_parent; + for (i = 0; i < numvifs; i++) + rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; + splx(s); + return 0; + } + + /* + * Find the entry for which the upcall was made and update + */ + s = splnet(); + hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); + for (mb_rt = mfctable[hash], nstl = 0; mb_rt; mb_rt = mb_rt->m_next) { + + rt = mtod(mb_rt, struct mfc *); + if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && + (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) && + (mb_rt->m_act != NULL)) { + + if (nstl++) + log(LOG_ERR, "add_mfc %s o %x g %x p %x dbx %x\n", + "multiple kernel entries", + ntohl(mfccp->mfcc_origin.s_addr), + ntohl(mfccp->mfcc_mcastgrp.s_addr), + mfccp->mfcc_parent, mb_rt->m_act); + + if (mrtdebug & DEBUG_MFC) + log(LOG_DEBUG,"add_mfc o %x g %x p %x dbg %x\n", + ntohl(mfccp->mfcc_origin.s_addr), + ntohl(mfccp->mfcc_mcastgrp.s_addr), + mfccp->mfcc_parent, mb_rt->m_act); + + rt->mfc_origin = mfccp->mfcc_origin; + rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; + rt->mfc_parent = mfccp->mfcc_parent; + for (i = 0; i < numvifs; i++) + rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; + /* initialize pkt counters per src-grp */ + rt->mfc_pkt_cnt = 0; + rt->mfc_byte_cnt = 0; + rt->mfc_wrong_if = 0; + rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; + + rt->mfc_expire = 0; /* Don't clean this guy up */ + nexpire[hash]--; + + /* free packets Qed at the end of this entry */ + while (mb_rt->m_act) { + mb_ntry = mb_rt->m_act; + rte = mtod(mb_ntry, struct rtdetq *); +/* #ifdef RSVP_ISI */ + ip_mdq(rte->m, rte->ifp, rt, -1); +/* #endif */ + mb_rt->m_act = mb_ntry->m_act; + m_freem(rte->m); +#ifdef UPCALL_TIMING + collate(&(rte->t)); +#endif /* UPCALL_TIMING */ + m_free(mb_ntry); + } + } + } + + /* + * It is possible that an entry is being inserted without an upcall + */ + if (nstl == 0) { + if (mrtdebug & DEBUG_MFC) + log(LOG_DEBUG,"add_mfc no upcall h %d o %x g %x p %x\n", + hash, ntohl(mfccp->mfcc_origin.s_addr), + ntohl(mfccp->mfcc_mcastgrp.s_addr), + mfccp->mfcc_parent); + + for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { + + rt = mtod(mb_rt, struct mfc *); + if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && + (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) { + + rt->mfc_origin = mfccp->mfcc_origin; + rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; + rt->mfc_parent = mfccp->mfcc_parent; + for (i = 0; i < numvifs; i++) + rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; + /* initialize pkt counters per src-grp */ + rt->mfc_pkt_cnt = 0; + rt->mfc_byte_cnt = 0; + rt->mfc_wrong_if = 0; + rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; + if (rt->mfc_expire) + nexpire[hash]--; + rt->mfc_expire = 0; + } + } + if (mb_rt == NULL) { + /* no upcall, so make a new entry */ + MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); + if (mb_rt == NULL) { + splx(s); + return ENOBUFS; + } + + rt = mtod(mb_rt, struct mfc *); + + /* insert new entry at head of hash chain */ + rt->mfc_origin = mfccp->mfcc_origin; + rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp; + rt->mfc_parent = mfccp->mfcc_parent; + for (i = 0; i < numvifs; i++) + rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; + /* initialize pkt counters per src-grp */ + rt->mfc_pkt_cnt = 0; + rt->mfc_byte_cnt = 0; + rt->mfc_wrong_if = 0; + rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0; + rt->mfc_expire = 0; + + /* link into table */ + mb_rt->m_next = mfctable[hash]; + mfctable[hash] = mb_rt; + mb_rt->m_act = NULL; + } + } + splx(s); + return 0; +} + +#ifdef UPCALL_TIMING +/* + * collect delay statistics on the upcalls + */ +static void collate(t) +register struct timeval *t; +{ + register u_long d; + register struct timeval tp; + register u_long delta; + + GET_TIME(tp); + + if (TV_LT(*t, tp)) + { + TV_DELTA(tp, *t, delta); + + d = delta >> 10; + if (d > 50) + d = 50; + + ++upcall_data[d]; + } +} +#endif /* UPCALL_TIMING */ + +/* + * Delete an mfc entry + */ +static int +del_mfc(mfccp) + struct mfcctl *mfccp; +{ + struct in_addr origin; + struct in_addr mcastgrp; + struct mfc *rt; + struct mbuf *mb_rt; + struct mbuf **nptr; + u_long hash; + int s; + + origin = mfccp->mfcc_origin; + mcastgrp = mfccp->mfcc_mcastgrp; + hash = MFCHASH(origin.s_addr, mcastgrp.s_addr); + + if (mrtdebug & DEBUG_MFC) + log(LOG_DEBUG,"del_mfc orig %x mcastgrp %x\n", + ntohl(origin.s_addr), ntohl(mcastgrp.s_addr)); + + s = splnet(); + + nptr = &mfctable[hash]; + while ((mb_rt = *nptr) != NULL) { + rt = mtod(mb_rt, struct mfc *); + if (origin.s_addr == rt->mfc_origin.s_addr && + mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr && + mb_rt->m_act == NULL) + break; + + nptr = &mb_rt->m_next; + } + if (mb_rt == NULL) { + splx(s); + return EADDRNOTAVAIL; + } + + MFREE(mb_rt, *nptr); + + splx(s); + + return 0; +} + +/* + * Send a message to mrouted on the multicast routing socket + */ +static int +socket_send(s, mm, src) + struct socket *s; + struct mbuf *mm; + struct sockaddr_in *src; +{ + if (s) { + if (sbappendaddr(&s->so_rcv, + (struct sockaddr *)src, + mm, (struct mbuf *)0) != 0) { + sorwakeup(s); + return 0; + } + } + m_freem(mm); + return -1; +} + +/* + * IP multicast forwarding function. This function assumes that the packet + * pointed to by "ip" has arrived on (or is about to be sent to) the interface + * pointed to by "ifp", and the packet is to be relayed to other networks + * that have members of the packet's destination IP multicast group. + * + * The packet is returned unscathed to the caller, unless it is + * erroneous, in which case a non-zero return value tells the caller to + * discard it. + */ + +#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */ +#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */ + +static int +X_ip_mforward(ip, ifp, m, imo) + register struct ip *ip; + struct ifnet *ifp; + struct mbuf *m; + struct ip_moptions *imo; +{ + register struct mfc *rt; + register u_char *ipoptions; + static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; + static int srctun = 0; + register struct mbuf *mm; + int s; + vifi_t vifi; + struct vif *vifp; + + if (mrtdebug & DEBUG_FORWARD) + log(LOG_DEBUG, "ip_mforward: src %x, dst %x, ifp %x\n", + ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), ifp); + + if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 || + (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) { + /* + * Packet arrived via a physical interface or + * an encapsulated tunnel. + */ + } else { + /* + * Packet arrived through a source-route tunnel. + * Source-route tunnels are no longer supported. + */ + if ((srctun++ % 1000) == 0) + log(LOG_ERR, "ip_mforward: received source-routed packet from %x\n", + ntohl(ip->ip_src.s_addr)); + + return 1; + } + + if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) { + if (ip->ip_ttl < 255) + ip->ip_ttl++; /* compensate for -1 in *_send routines */ + if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { + vifp = viftable + vifi; + printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s%d)\n", + ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi, + (vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "", + vifp->v_ifp->if_name, vifp->v_ifp->if_unit); + } + return (ip_mdq(m, ifp, NULL, vifi)); + } + if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { + printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n", + ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr)); + if(!imo) + printf("In fact, no options were specified at all\n"); + } + + /* + * Don't forward a packet with time-to-live of zero or one, + * or a packet destined to a local-only group. + */ + if (ip->ip_ttl <= 1 || + ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP) + return 0; + + /* + * Determine forwarding vifs from the forwarding cache table + */ + s = splnet(); + MFCFIND(ip->ip_src.s_addr, ip->ip_dst.s_addr, rt); + + /* Entry exists, so forward if necessary */ + if (rt != NULL) { + splx(s); + return (ip_mdq(m, ifp, rt, -1)); + } else { + /* + * If we don't have a route for packet's origin, + * Make a copy of the packet & + * send message to routing daemon + */ + + register struct mbuf *mb_rt; + register struct mbuf *mb_ntry; + register struct mbuf *mb0; + register struct rtdetq *rte; + register struct mbuf *rte_m; + register u_long hash; + register int npkts; + int hlen = ip->ip_hl << 2; +#ifdef UPCALL_TIMING + struct timeval tp; + + GET_TIME(tp); +#endif + + mrtstat.mrts_no_route++; + if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) + log(LOG_DEBUG, "ip_mforward: no rte s %x g %x\n", + ntohl(ip->ip_src.s_addr), + ntohl(ip->ip_dst.s_addr)); + + /* + * Allocate mbufs early so that we don't do extra work if we are + * just going to fail anyway. Make sure to pullup the header so + * that other people can't step on it. + */ + MGET(mb_ntry, M_DONTWAIT, MT_DATA); + if (mb_ntry == NULL) { + splx(s); + return ENOBUFS; + } + mb0 = m_copy(m, 0, M_COPYALL); + if (mb0 && (M_HASCL(mb0) || mb0->m_len < hlen)) + mb0 = m_pullup(mb0, hlen); + if (mb0 == NULL) { + m_free(mb_ntry); + splx(s); + return ENOBUFS; + } + + /* is there an upcall waiting for this packet? */ + hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); + for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) { + rt = mtod(mb_rt, struct mfc *); + if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && + (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && + (mb_rt->m_act != NULL)) + break; + } + + if (mb_rt == NULL) { + int i; + struct igmpmsg *im; + + /* no upcall, so make a new entry */ + MGET(mb_rt, M_DONTWAIT, MT_MRTABLE); + if (mb_rt == NULL) { + m_free(mb_ntry); + m_freem(mb0); + splx(s); + return ENOBUFS; + } + /* Make a copy of the header to send to the user level process */ + mm = m_copy(mb0, 0, hlen); + if (mm == NULL) { + m_free(mb_ntry); + m_freem(mb0); + m_free(mb_rt); + splx(s); + return ENOBUFS; + } + + /* + * Send message to routing daemon to install + * a route into the kernel table + */ + k_igmpsrc.sin_addr = ip->ip_src; + + im = mtod(mm, struct igmpmsg *); + im->im_msgtype = IGMPMSG_NOCACHE; + im->im_mbz = 0; + + mrtstat.mrts_upcalls++; + + if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) { + log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n"); + ++mrtstat.mrts_upq_sockfull; + m_free(mb_ntry); + m_freem(mb0); + m_free(mb_rt); + splx(s); + return ENOBUFS; + } + + rt = mtod(mb_rt, struct mfc *); + + /* insert new entry at head of hash chain */ + rt->mfc_origin.s_addr = ip->ip_src.s_addr; + rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; + rt->mfc_expire = UPCALL_EXPIRE; + nexpire[hash]++; + for (i = 0; i < numvifs; i++) + rt->mfc_ttls[i] = 0; + rt->mfc_parent = -1; + + /* link into table */ + mb_rt->m_next = mfctable[hash]; + mfctable[hash] = mb_rt; + mb_rt->m_act = NULL; + + rte_m = mb_rt; + } else { + /* determine if q has overflowed */ + for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act) + npkts++; + + if (npkts > MAX_UPQ) { + mrtstat.mrts_upq_ovflw++; + m_free(mb_ntry); + m_freem(mb0); + splx(s); + return 0; + } + } + + mb_ntry->m_act = NULL; + rte = mtod(mb_ntry, struct rtdetq *); + + rte->m = mb0; + rte->ifp = ifp; +#ifdef UPCALL_TIMING + rte->t = tp; +#endif + + /* Add this entry to the end of the queue */ + rte_m->m_act = mb_ntry; + + splx(s); + + return 0; + } +} + +#ifndef MROUTE_LKM +int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, + struct ip_moptions *) = X_ip_mforward; +#endif + +/* + * Clean up the cache entry if upcall is not serviced + */ +static void +expire_upcalls(void *unused) +{ + struct mbuf *mb_rt, *m, **nptr; + struct rtdetq *rte; + struct mfc *mfc; + int i; + int s; + + s = splnet(); + for (i = 0; i < MFCTBLSIZ; i++) { + if (nexpire[i] == 0) + continue; + nptr = &mfctable[i]; + for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) { + mfc = mtod(mb_rt, struct mfc *); + + /* + * Skip real cache entries + * Make sure it wasn't marked to not expire (shouldn't happen) + * If it expires now + */ + if (mb_rt->m_act != NULL && + mfc->mfc_expire != 0 && + --mfc->mfc_expire == 0) { + if (mrtdebug & DEBUG_EXPIRE) + log(LOG_DEBUG, "expire_upcalls: expiring (%x %x)\n", + ntohl(mfc->mfc_origin.s_addr), + ntohl(mfc->mfc_mcastgrp.s_addr)); + /* + * drop all the packets + * free the mbuf with the pkt, if, timing info + */ + while (mb_rt->m_act) { + m = mb_rt->m_act; + mb_rt->m_act = m->m_act; + + rte = mtod(m, struct rtdetq *); + m_freem(rte->m); + m_free(m); + } + ++mrtstat.mrts_cache_cleanups; + nexpire[i]--; + + MFREE(mb_rt, *nptr); + } else { + nptr = &mb_rt->m_next; + } + } + } + splx(s); + timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT); +} + +/* + * Packet forwarding routine once entry in the cache is made + */ +static int +ip_mdq(m, ifp, rt, xmt_vif) + register struct mbuf *m; + register struct ifnet *ifp; + register struct mfc *rt; + register vifi_t xmt_vif; +{ + register struct ip *ip = mtod(m, struct ip *); + register vifi_t vifi; + register struct vif *vifp; + register int plen = ntohs(ip->ip_len); + +/* + * Macro to send packet on vif. Since RSVP packets don't get counted on + * input, they shouldn't get counted on output, so statistics keeping is + * seperate. + */ +#define MC_SEND(ip,vifp,m) { \ + if ((vifp)->v_flags & VIFF_TUNNEL) \ + encap_send((ip), (vifp), (m)); \ + else \ + phyint_send((ip), (vifp), (m)); \ +} + + /* + * If xmt_vif is not -1, send on only the requested vif. + * + * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) + */ + if (xmt_vif < numvifs) { + MC_SEND(ip, viftable + xmt_vif, m); + return 1; + } + + /* + * Don't forward if it didn't arrive from the parent vif for its origin. + */ + vifi = rt->mfc_parent; + if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) { + /* came in the wrong interface */ + if (mrtdebug & DEBUG_FORWARD) + log(LOG_DEBUG, "wrong if: ifp %x vifi %d vififp %x\n", + ifp, vifi, viftable[vifi].v_ifp); + ++mrtstat.mrts_wrong_if; + ++rt->mfc_wrong_if; + /* + * If we are doing PIM assert processing, and we are forwarding + * packets on this interface, and it is a broadcast medium + * interface (and not a tunnel), send a message to the routing daemon. + */ + if (pim_assert && rt->mfc_ttls[vifi] && + (ifp->if_flags & IFF_BROADCAST) && + !(viftable[vifi].v_flags & VIFF_TUNNEL)) { + struct sockaddr_in k_igmpsrc; + struct mbuf *mm; + struct igmpmsg *im; + int hlen = ip->ip_hl << 2; + struct timeval now; + register u_long delta; + + GET_TIME(now); + + TV_DELTA(rt->mfc_last_assert, now, delta); + + if (delta > ASSERT_MSG_TIME) { + mm = m_copy(m, 0, hlen); + if (mm && (M_HASCL(mm) || mm->m_len < hlen)) + mm = m_pullup(mm, hlen); + if (mm == NULL) { + return ENOBUFS; + } + + rt->mfc_last_assert = now; + + im = mtod(mm, struct igmpmsg *); + im->im_msgtype = IGMPMSG_WRONGVIF; + im->im_mbz = 0; + im->im_vif = vifi; + + k_igmpsrc.sin_addr = im->im_src; + + socket_send(ip_mrouter, mm, &k_igmpsrc); + } + } + return 0; + } + + /* If I sourced this packet, it counts as output, else it was input. */ + if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) { + viftable[vifi].v_pkt_out++; + viftable[vifi].v_bytes_out += plen; + } else { + viftable[vifi].v_pkt_in++; + viftable[vifi].v_bytes_in += plen; + } + rt->mfc_pkt_cnt++; + rt->mfc_byte_cnt += plen; + + /* + * For each vif, decide if a copy of the packet should be forwarded. + * Forward if: + * - the ttl exceeds the vif's threshold + * - there are group members downstream on interface + */ + for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) + if ((rt->mfc_ttls[vifi] > 0) && + (ip->ip_ttl > rt->mfc_ttls[vifi])) { + vifp->v_pkt_out++; + vifp->v_bytes_out += plen; + MC_SEND(ip, vifp, m); + } + + return 0; +} + +/* + * check if a vif number is legal/ok. This is used by ip_output, to export + * numvifs there, + */ +static int +X_legal_vif_num(vif) + int vif; +{ + if (vif >= 0 && vif < numvifs) + return(1); + else + return(0); +} + +#ifndef MROUTE_LKM +int (*legal_vif_num)(int) = X_legal_vif_num; +#endif + +/* + * Return the local address used by this vif + */ +static u_long +X_ip_mcast_src(vifi) + int vifi; +{ + if (vifi >= 0 && vifi < numvifs) + return viftable[vifi].v_lcl_addr.s_addr; + else + return INADDR_ANY; +} + +#ifndef MROUTE_LKM +u_long (*ip_mcast_src)(int) = X_ip_mcast_src; +#endif + +static void +phyint_send(ip, vifp, m) + struct ip *ip; + struct vif *vifp; + struct mbuf *m; +{ + register struct mbuf *mb_copy; + register int hlen = ip->ip_hl << 2; + + /* + * Make a new reference to the packet; make sure that + * the IP header is actually copied, not just referenced, + * so that ip_output() only scribbles on the copy. + */ + mb_copy = m_copy(m, 0, M_COPYALL); + if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < hlen)) + mb_copy = m_pullup(mb_copy, hlen); + if (mb_copy == NULL) + return; + + if (vifp->v_rate_limit <= 0) + tbf_send_packet(vifp, mb_copy); + else + tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len); +} + +static void +encap_send(ip, vifp, m) + register struct ip *ip; + register struct vif *vifp; + register struct mbuf *m; +{ + register struct mbuf *mb_copy; + register struct ip *ip_copy; + register int i, len = ip->ip_len; + + /* + * copy the old packet & pullup it's IP header into the + * new mbuf so we can modify it. Try to fill the new + * mbuf since if we don't the ethernet driver will. + */ + MGETHDR(mb_copy, M_DONTWAIT, MT_HEADER); + if (mb_copy == NULL) + return; + mb_copy->m_data += max_linkhdr; + mb_copy->m_len = sizeof(multicast_encap_iphdr); + + if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) { + m_freem(mb_copy); + return; + } + i = MHLEN - M_LEADINGSPACE(mb_copy); + if (i > len) + i = len; + mb_copy = m_pullup(mb_copy, i); + if (mb_copy == NULL) + return; + mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr); + + /* + * fill in the encapsulating IP header. + */ + ip_copy = mtod(mb_copy, struct ip *); + *ip_copy = multicast_encap_iphdr; + ip_copy->ip_id = htons(ip_id++); + ip_copy->ip_len += len; + ip_copy->ip_src = vifp->v_lcl_addr; + ip_copy->ip_dst = vifp->v_rmt_addr; + + /* + * turn the encapsulated IP header back into a valid one. + */ + ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr)); + --ip->ip_ttl; + HTONS(ip->ip_len); + HTONS(ip->ip_off); + ip->ip_sum = 0; + mb_copy->m_data += sizeof(multicast_encap_iphdr); + ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2); + mb_copy->m_data -= sizeof(multicast_encap_iphdr); + + if (vifp->v_rate_limit <= 0) + tbf_send_packet(vifp, mb_copy); + else + tbf_control(vifp, mb_copy, ip, ip_copy->ip_len); +} + +/* + * De-encapsulate a packet and feed it back through ip input (this + * routine is called whenever IP gets a packet with proto type + * ENCAP_PROTO and a local destination address). + */ +void +#ifdef MROUTE_LKM +X_ipip_input(m, iphlen) +#else +ipip_input(m, iphlen) +#endif + register struct mbuf *m; + int iphlen; +{ + struct ifnet *ifp = m->m_pkthdr.rcvif; + register struct ip *ip = mtod(m, struct ip *); + register int hlen = ip->ip_hl << 2; + register int s; + register struct ifqueue *ifq; + register struct vif *vifp; + + if (!have_encap_tunnel) { + rip_input(m, iphlen); + return; + } + /* + * dump the packet if it's not to a multicast destination or if + * we don't have an encapsulating tunnel with the source. + * Note: This code assumes that the remote site IP address + * uniquely identifies the tunnel (i.e., that this site has + * at most one tunnel with the remote site). + */ + if (! IN_MULTICAST(ntohl(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr))) { + ++mrtstat.mrts_bad_tunnel; + m_freem(m); + return; + } + if (ip->ip_src.s_addr != last_encap_src) { + register struct vif *vife; + + vifp = viftable; + vife = vifp + numvifs; + last_encap_src = ip->ip_src.s_addr; + last_encap_vif = 0; + for ( ; vifp < vife; ++vifp) + if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) { + if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT)) + == VIFF_TUNNEL) + last_encap_vif = vifp; + break; + } + } + if ((vifp = last_encap_vif) == 0) { + last_encap_src = 0; + mrtstat.mrts_cant_tunnel++; /*XXX*/ + m_freem(m); + if (mrtdebug) + log(LOG_DEBUG, "ip_mforward: no tunnel with %x\n", + ntohl(ip->ip_src.s_addr)); + return; + } + ifp = vifp->v_ifp; + + if (hlen > IP_HDR_LEN) + ip_stripoptions(m, (struct mbuf *) 0); + m->m_data += IP_HDR_LEN; + m->m_len -= IP_HDR_LEN; + m->m_pkthdr.len -= IP_HDR_LEN; + m->m_pkthdr.rcvif = ifp; + + ifq = &ipintrq; + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + m_freem(m); + } else { + IF_ENQUEUE(ifq, m); + /* + * normally we would need a "schednetisr(NETISR_IP)" + * here but we were called by ip_input and it is going + * to loop back & try to dequeue the packet we just + * queued as soon as we return so we avoid the + * unnecessary software interrrupt. + */ + } + splx(s); +} + +/* + * Token bucket filter module + */ + +static void +tbf_control(vifp, m, ip, p_len) + register struct vif *vifp; + register struct mbuf *m; + register struct ip *ip; + register u_long p_len; +{ + register struct tbf *t = vifp->v_tbf; + + if (p_len > MAX_BKT_SIZE) { + /* drop if packet is too large */ + mrtstat.mrts_pkt2large++; + m_freem(m); + return; + } + + tbf_update_tokens(vifp); + + /* if there are enough tokens, + * and the queue is empty, + * send this packet out + */ + + if (t->tbf_q_len == 0) { + /* queue empty, send packet if enough tokens */ + if (p_len <= t->tbf_n_tok) { + t->tbf_n_tok -= p_len; + tbf_send_packet(vifp, m); + } else { + /* queue packet and timeout till later */ + tbf_queue(vifp, m); + timeout(tbf_reprocess_q, (caddr_t)vifp, TBF_REPROCESS); + } + } else if (t->tbf_q_len < t->tbf_max_q_len) { + /* finite queue length, so queue pkts and process queue */ + tbf_queue(vifp, m); + tbf_process_q(vifp); + } else { + /* queue length too much, try to dq and queue and process */ + if (!tbf_dq_sel(vifp, ip)) { + mrtstat.mrts_q_overflow++; + m_freem(m); + return; + } else { + tbf_queue(vifp, m); + tbf_process_q(vifp); + } + } + return; +} + +/* + * adds a packet to the queue at the interface + */ +static void +tbf_queue(vifp, m) + register struct vif *vifp; + register struct mbuf *m; +{ + register int s = splnet(); + register struct tbf *t = vifp->v_tbf; + + if (t->tbf_t == NULL) { + /* Queue was empty */ + t->tbf_q = m; + } else { + /* Insert at tail */ + t->tbf_t->m_act = m; + } + + /* Set new tail pointer */ + t->tbf_t = m; + +#ifdef DIAGNOSTIC + /* Make sure we didn't get fed a bogus mbuf */ + if (m->m_act) + panic("tbf_queue: m_act"); +#endif + m->m_act = NULL; + + t->tbf_q_len++; + + splx(s); +} + + +/* + * processes the queue at the interface + */ +static void +tbf_process_q(vifp) + register struct vif *vifp; +{ + register struct mbuf *m; + register int len; + register int s = splnet(); + register struct tbf *t = vifp->v_tbf; + + /* loop through the queue at the interface and send as many packets + * as possible + */ + while (t->tbf_q_len > 0) { + m = t->tbf_q; + + len = mtod(m, struct ip *)->ip_len; + + /* determine if the packet can be sent */ + if (len <= t->tbf_n_tok) { + /* if so, + * reduce no of tokens, dequeue the packet, + * send the packet. + */ + t->tbf_n_tok -= len; + + t->tbf_q = m->m_act; + if (--t->tbf_q_len == 0) + t->tbf_t = NULL; + + m->m_act = NULL; + tbf_send_packet(vifp, m); + + } else break; + } + splx(s); +} + +static void +tbf_reprocess_q(xvifp) + void *xvifp; +{ + register struct vif *vifp = xvifp; + if (ip_mrouter == NULL) + return; + + tbf_update_tokens(vifp); + + tbf_process_q(vifp); + + if (vifp->v_tbf->tbf_q_len) + timeout(tbf_reprocess_q, (caddr_t)vifp, TBF_REPROCESS); +} + +/* function that will selectively discard a member of the queue + * based on the precedence value and the priority + */ +static int +tbf_dq_sel(vifp, ip) + register struct vif *vifp; + register struct ip *ip; +{ + register int s = splnet(); + register u_int p; + register struct mbuf *m, *last; + register struct mbuf **np; + register struct tbf *t = vifp->v_tbf; + + p = priority(vifp, ip); + + np = &t->tbf_q; + last = NULL; + while ((m = *np) != NULL) { + if (p > priority(vifp, mtod(m, struct ip *))) { + *np = m->m_act; + /* If we're removing the last packet, fix the tail pointer */ + if (m == t->tbf_t) + t->tbf_t = last; + m_freem(m); + /* it's impossible for the queue to be empty, but + * we check anyway. */ + if (--t->tbf_q_len == 0) + t->tbf_t = NULL; + splx(s); + mrtstat.mrts_drop_sel++; + return(1); + } + np = &m->m_act; + last = m; + } + splx(s); + return(0); +} + +static void +tbf_send_packet(vifp, m) + register struct vif *vifp; + register struct mbuf *m; +{ + struct ip_moptions imo; + int error; + static struct route ro; + int s = splnet(); + + if (vifp->v_flags & VIFF_TUNNEL) { + /* If tunnel options */ + ip_output(m, (struct mbuf *)0, &vifp->v_route, + IP_FORWARDING, (struct ip_moptions *)0); + } else { + imo.imo_multicast_ifp = vifp->v_ifp; + imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1; + imo.imo_multicast_loop = 1; + imo.imo_multicast_vif = -1; + + /* + * Re-entrancy should not be a problem here, because + * the packets that we send out and are looped back at us + * should get rejected because they appear to come from + * the loopback interface, thus preventing looping. + */ + error = ip_output(m, (struct mbuf *)0, &ro, + IP_FORWARDING, &imo); + + if (mrtdebug & DEBUG_XMIT) + log(LOG_DEBUG, "phyint_send on vif %d err %d\n", + vifp - viftable, error); + } + splx(s); +} + +/* determine the current time and then + * the elapsed time (between the last time and time now) + * in milliseconds & update the no. of tokens in the bucket + */ +static void +tbf_update_tokens(vifp) + register struct vif *vifp; +{ + struct timeval tp; + register u_long tm; + register int s = splnet(); + register struct tbf *t = vifp->v_tbf; + + GET_TIME(tp); + + TV_DELTA(tp, t->tbf_last_pkt_t, tm); + + /* + * This formula is actually + * "time in seconds" * "bytes/second". + * + * (tm / 1000000) * (v_rate_limit * 1000 * (1000/1024) / 8) + * + * The (1000/1024) was introduced in add_vif to optimize + * this divide into a shift. + */ + t->tbf_n_tok += tm * vifp->v_rate_limit / 1024 / 8; + t->tbf_last_pkt_t = tp; + + if (t->tbf_n_tok > MAX_BKT_SIZE) + t->tbf_n_tok = MAX_BKT_SIZE; + + splx(s); +} + +static int +priority(vifp, ip) + register struct vif *vifp; + register struct ip *ip; +{ + register int prio; + + /* temporary hack; may add general packet classifier some day */ + + /* + * The UDP port space is divided up into four priority ranges: + * [0, 16384) : unclassified - lowest priority + * [16384, 32768) : audio - highest priority + * [32768, 49152) : whiteboard - medium priority + * [49152, 65536) : video - low priority + */ + if (ip->ip_p == IPPROTO_UDP) { + struct udphdr *udp = (struct udphdr *)(((char *)ip) + (ip->ip_hl << 2)); + switch (ntohs(udp->uh_dport) & 0xc000) { + case 0x4000: + prio = 70; + break; + case 0x8000: + prio = 60; + break; + case 0xc000: + prio = 55; + break; + default: + prio = 50; + break; + } + if (tbfdebug > 1) + log(LOG_DEBUG, "port %x prio%d\n", ntohs(udp->uh_dport), prio); + } else { + prio = 50; + } + return prio; +} + +/* + * End of token bucket filter modifications + */ + +int +ip_rsvp_vif_init(so, m) + struct socket *so; + struct mbuf *m; +{ + int i; + register int s; + + if (rsvpdebug) + printf("ip_rsvp_vif_init: so_type = %d, pr_protocol = %d\n", + so->so_type, so->so_proto->pr_protocol); + + if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) + return EOPNOTSUPP; + + /* Check mbuf. */ + if (m == NULL || m->m_len != sizeof(int)) { + return EINVAL; + } + i = *(mtod(m, int *)); + + if (rsvpdebug) + printf("ip_rsvp_vif_init: vif = %d rsvp_on = %d\n",i,rsvp_on); + + s = splnet(); + + /* Check vif. */ + if (!legal_vif_num(i)) { + splx(s); + return EADDRNOTAVAIL; + } + + /* Check if socket is available. */ + if (viftable[i].v_rsvpd != NULL) { + splx(s); + return EADDRINUSE; + } + + viftable[i].v_rsvpd = so; + /* This may seem silly, but we need to be sure we don't over-increment + * the RSVP counter, in case something slips up. + */ + if (!viftable[i].v_rsvp_on) { + viftable[i].v_rsvp_on = 1; + rsvp_on++; + } + + splx(s); + return 0; +} + +int +ip_rsvp_vif_done(so, m) + struct socket *so; + struct mbuf *m; +{ + int i; + register int s; + + if (rsvpdebug) + printf("ip_rsvp_vif_done: so_type = %d, pr_protocol = %d\n", + so->so_type, so->so_proto->pr_protocol); + + if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) + return EOPNOTSUPP; + + /* Check mbuf. */ + if (m == NULL || m->m_len != sizeof(int)) { + return EINVAL; + } + i = *(mtod(m, int *)); + + s = splnet(); + + /* Check vif. */ + if (!legal_vif_num(i)) { + splx(s); + return EADDRNOTAVAIL; + } + + if (rsvpdebug) + printf("ip_rsvp_vif_done: v_rsvpd = %p so = %p\n", + viftable[i].v_rsvpd, so); + + viftable[i].v_rsvpd = NULL; + /* This may seem silly, but we need to be sure we don't over-decrement + * the RSVP counter, in case something slips up. + */ + if (viftable[i].v_rsvp_on) { + viftable[i].v_rsvp_on = 0; + rsvp_on--; + } + + splx(s); + return 0; +} + +void +ip_rsvp_force_done(so) + struct socket *so; +{ + int vifi; + register int s; + + /* Don't bother if it is not the right type of socket. */ + if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) + return; + + s = splnet(); + + /* The socket may be attached to more than one vif...this + * is perfectly legal. + */ + for (vifi = 0; vifi < numvifs; vifi++) { + if (viftable[vifi].v_rsvpd == so) { + viftable[vifi].v_rsvpd = NULL; + /* This may seem silly, but we need to be sure we don't + * over-decrement the RSVP counter, in case something slips up. + */ + if (viftable[vifi].v_rsvp_on) { + viftable[vifi].v_rsvp_on = 0; + rsvp_on--; + } + } + } + + splx(s); + return; +} + +void +rsvp_input(m, iphlen) + struct mbuf *m; + int iphlen; +{ + int vifi; + register struct ip *ip = mtod(m, struct ip *); + static struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET }; + register int s; + struct ifnet *ifp; + + if (rsvpdebug) + printf("rsvp_input: rsvp_on %d\n",rsvp_on); + + /* Can still get packets with rsvp_on = 0 if there is a local member + * of the group to which the RSVP packet is addressed. But in this + * case we want to throw the packet away. + */ + if (!rsvp_on) { + m_freem(m); + return; + } + + /* If the old-style non-vif-associated socket is set, then use + * it and ignore the new ones. + */ + if (ip_rsvpd != NULL) { + if (rsvpdebug) + printf("rsvp_input: Sending packet up old-style socket\n"); + rip_input(m, iphlen); + return; + } + + s = splnet(); + + if (rsvpdebug) + printf("rsvp_input: check vifs\n"); + +#ifdef DIAGNOSTIC + if (!(m->m_flags & M_PKTHDR)) + panic("rsvp_input no hdr"); +#endif + + ifp = m->m_pkthdr.rcvif; + /* Find which vif the packet arrived on. */ + for (vifi = 0; vifi < numvifs; vifi++) { + if (viftable[vifi].v_ifp == ifp) + break; + } + + if (vifi == numvifs) { + /* Can't find vif packet arrived on. Drop packet. */ + if (rsvpdebug) + printf("rsvp_input: Can't find vif for packet...dropping it.\n"); + m_freem(m); + splx(s); + return; + } + + if (rsvpdebug) + printf("rsvp_input: check socket\n"); + + if (viftable[vifi].v_rsvpd == NULL) { + /* drop packet, since there is no specific socket for this + * interface */ + if (rsvpdebug) + printf("rsvp_input: No socket defined for vif %d\n",vifi); + m_freem(m); + splx(s); + return; + } + rsvp_src.sin_addr = ip->ip_src; + + if (rsvpdebug && m) + printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n", + m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); + + if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) + if (rsvpdebug) + printf("rsvp_input: Failed to append to socket\n"); + else + if (rsvpdebug) + printf("rsvp_input: send packet up\n"); + + splx(s); +} + +#ifdef MROUTE_LKM +#include <sys/conf.h> +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +MOD_MISC("ip_mroute_mod") + +static int +ip_mroute_mod_handle(struct lkm_table *lkmtp, int cmd) +{ + int i; + struct lkm_misc *args = lkmtp->private.lkm_misc; + int err = 0; + + switch(cmd) { + static int (*old_ip_mrouter_cmd)(); + static int (*old_ip_mrouter_done)(); + static int (*old_ip_mforward)(); + static int (*old_mrt_ioctl)(); + static void (*old_proto4_input)(); + static int (*old_legal_vif_num)(); + extern struct protosw inetsw[]; + + case LKM_E_LOAD: + if(lkmexists(lkmtp) || ip_mrtproto) + return(EEXIST); + old_ip_mrouter_cmd = ip_mrouter_cmd; + ip_mrouter_cmd = X_ip_mrouter_cmd; + old_ip_mrouter_done = ip_mrouter_done; + ip_mrouter_done = X_ip_mrouter_done; + old_ip_mforward = ip_mforward; + ip_mforward = X_ip_mforward; + old_mrt_ioctl = mrt_ioctl; + mrt_ioctl = X_mrt_ioctl; + old_proto4_input = inetsw[ip_protox[ENCAP_PROTO]].pr_input; + inetsw[ip_protox[ENCAP_PROTO]].pr_input = X_ipip_input; + old_legal_vif_num = legal_vif_num; + legal_vif_num = X_legal_vif_num; + ip_mrtproto = IGMP_DVMRP; + + printf("\nIP multicast routing loaded\n"); + break; + + case LKM_E_UNLOAD: + if (ip_mrouter) + return EINVAL; + + ip_mrouter_cmd = old_ip_mrouter_cmd; + ip_mrouter_done = old_ip_mrouter_done; + ip_mforward = old_ip_mforward; + mrt_ioctl = old_mrt_ioctl; + inetsw[ip_protox[ENCAP_PROTO]].pr_input = old_proto4_input; + legal_vif_num = old_legal_vif_num; + ip_mrtproto = 0; + break; + + default: + err = EINVAL; + break; + } + + return(err); +} + +int +ip_mroute_mod(struct lkm_table *lkmtp, int cmd, int ver) { + DISPATCH(lkmtp, cmd, ver, ip_mroute_mod_handle, ip_mroute_mod_handle, + nosys); +} + +#endif /* MROUTE_LKM */ +#endif /* MROUTING */ diff --git a/cpukit/libnetworking/netinet/ip_mroute.h b/cpukit/libnetworking/netinet/ip_mroute.h new file mode 100644 index 0000000000..5ddd6799d2 --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_mroute.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 1989 Stephen Deering. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Stephen Deering of Stanford University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_mroute.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_IP_MROUTE_H_ +#define _NETINET_IP_MROUTE_H_ + +/* + * Definitions for IP multicast forwarding. + * + * Written by David Waitzman, BBN Labs, August 1988. + * Modified by Steve Deering, Stanford, February 1989. + * Modified by Ajit Thyagarajan, PARC, August 1993. + * Modified by Ajit Thyagarajan, PARC, August 1994. + * + * MROUTING Revision: 3.3.1.3 + */ + + +/* + * Multicast Routing set/getsockopt commands. + */ +#define MRT_INIT 100 /* initialize forwarder */ +#define MRT_DONE 101 /* shut down forwarder */ +#define MRT_ADD_VIF 102 /* create virtual interface */ +#define MRT_DEL_VIF 103 /* delete virtual interface */ +#define MRT_ADD_MFC 104 /* insert forwarding cache entry */ +#define MRT_DEL_MFC 105 /* delete forwarding cache entry */ +#define MRT_VERSION 106 /* get kernel version number */ +#define MRT_ASSERT 107 /* enable PIM assert processing */ + + +#define GET_TIME(t) microtime(&t) + +/* + * Types and macros for handling bitmaps with one bit per virtual interface. + */ +#define MAXVIFS 32 +typedef u_long vifbitmap_t; +typedef u_short vifi_t; /* type of a vif index */ +#define ALL_VIFS (vifi_t)-1 + +#define VIFM_SET(n, m) ((m) |= (1 << (n))) +#define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) +#define VIFM_ISSET(n, m) ((m) & (1 << (n))) +#define VIFM_CLRALL(m) ((m) = 0x00000000) +#define VIFM_COPY(mfrom, mto) ((mto) = (mfrom)) +#define VIFM_SAME(m1, m2) ((m1) == (m2)) + + +/* + * Argument structure for MRT_ADD_VIF. + * (MRT_DEL_VIF takes a single vifi_t argument.) + */ +struct vifctl { + vifi_t vifc_vifi; /* the index of the vif to be added */ + u_char vifc_flags; /* VIFF_ flags defined below */ + u_char vifc_threshold; /* min ttl required to forward on vif */ + u_int vifc_rate_limit; /* max rate */ + struct in_addr vifc_lcl_addr; /* local interface address */ + struct in_addr vifc_rmt_addr; /* remote address (tunnels only) */ +}; + +#define VIFF_TUNNEL 0x1 /* vif represents a tunnel end-point */ +#define VIFF_SRCRT 0x2 /* tunnel uses IP source routing */ + +/* + * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC + * (mfcc_tos to be added at a future point) + */ +struct mfcctl { + struct in_addr mfcc_origin; /* ip origin of mcasts */ + struct in_addr mfcc_mcastgrp; /* multicast group associated*/ + vifi_t mfcc_parent; /* incoming vif */ + u_char mfcc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ +}; + +/* + * The kernel's multicast routing statistics. + */ +struct mrtstat { + u_long mrts_mfc_lookups; /* # forw. cache hash table hits */ + u_long mrts_mfc_misses; /* # forw. cache hash table misses */ + u_long mrts_upcalls; /* # calls to mrouted */ + u_long mrts_no_route; /* no route for packet's origin */ + u_long mrts_bad_tunnel; /* malformed tunnel options */ + u_long mrts_cant_tunnel; /* no room for tunnel options */ + u_long mrts_wrong_if; /* arrived on wrong interface */ + u_long mrts_upq_ovflw; /* upcall Q overflow */ + u_long mrts_cache_cleanups; /* # entries with no upcalls */ + u_long mrts_drop_sel; /* pkts dropped selectively */ + u_long mrts_q_overflow; /* pkts dropped - Q overflow */ + u_long mrts_pkt2large; /* pkts dropped - size > BKT SIZE */ + u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ +}; + +/* + * Argument structure used by mrouted to get src-grp pkt counts + */ +struct sioc_sg_req { + struct in_addr src; + struct in_addr grp; + u_long pktcnt; + u_long bytecnt; + u_long wrong_if; +}; + +/* + * Argument structure used by mrouted to get vif pkt counts + */ +struct sioc_vif_req { + vifi_t vifi; /* vif number */ + u_long icount; /* Input packet count on vif */ + u_long ocount; /* Output packet count on vif */ + u_long ibytes; /* Input byte count on vif */ + u_long obytes; /* Output byte count on vif */ +}; + + +/* + * The kernel's virtual-interface structure. + */ +struct vif { + u_char v_flags; /* VIFF_ flags defined above */ + u_char v_threshold; /* min ttl required to forward on vif*/ + u_int v_rate_limit; /* max rate */ + struct tbf *v_tbf; /* token bucket structure at intf. */ + struct in_addr v_lcl_addr; /* local interface address */ + struct in_addr v_rmt_addr; /* remote address (tunnels only) */ + struct ifnet *v_ifp; /* pointer to interface */ + u_long v_pkt_in; /* # pkts in on interface */ + u_long v_pkt_out; /* # pkts out on interface */ + u_long v_bytes_in; /* # bytes in on interface */ + u_long v_bytes_out; /* # bytes out on interface */ + struct route v_route; /* cached route if this is a tunnel */ + u_int v_rsvp_on; /* RSVP listening on this vif */ + struct socket *v_rsvpd; /* RSVP daemon socket */ +}; + +/* + * The kernel's multicast forwarding cache entry structure + * (A field for the type of service (mfc_tos) is to be added + * at a future point) + */ +struct mfc { + struct in_addr mfc_origin; /* IP origin of mcasts */ + struct in_addr mfc_mcastgrp; /* multicast group associated*/ + vifi_t mfc_parent; /* incoming vif */ + u_char mfc_ttls[MAXVIFS]; /* forwarding ttls on vifs */ + u_long mfc_pkt_cnt; /* pkt count for src-grp */ + u_long mfc_byte_cnt; /* byte count for src-grp */ + u_long mfc_wrong_if; /* wrong if for src-grp */ + int mfc_expire; /* time to clean entry up */ + struct timeval mfc_last_assert; /* last time I sent an assert*/ +}; + +/* + * Struct used to communicate from kernel to multicast router + * note the convenient similarity to an IP packet + */ +struct igmpmsg { + u_long unused1; + u_long unused2; + u_char im_msgtype; /* what type of message */ +#define IGMPMSG_NOCACHE 1 +#define IGMPMSG_WRONGVIF 2 + u_char im_mbz; /* must be zero */ + u_char im_vif; /* vif rec'd on */ + u_char unused3; + struct in_addr im_src, im_dst; +}; + +/* + * Argument structure used for pkt info. while upcall is made + */ +struct rtdetq { + struct mbuf *m; /* A copy of the packet */ + struct ifnet *ifp; /* Interface pkt came in on */ + vifi_t xmt_vif; /* Saved copy of imo_multicast_vif */ +#ifdef UPCALL_TIMING + struct timeval t; /* Timestamp */ +#endif /* UPCALL_TIMING */ +}; + +#define MFCTBLSIZ 256 +#if (MFCTBLSIZ & (MFCTBLSIZ - 1)) == 0 /* from sys:route.h */ +#define MFCHASHMOD(h) ((h) & (MFCTBLSIZ - 1)) +#else +#define MFCHASHMOD(h) ((h) % MFCTBLSIZ) +#endif + +#define MAX_UPQ 4 /* max. no of pkts in upcall Q */ + +/* + * Token Bucket filter code + */ +#define MAX_BKT_SIZE 10000 /* 10K bytes size */ +#define MAXQSIZE 10 /* max # of pkts in queue */ + +/* + * the token bucket filter at each vif + */ +struct tbf +{ + struct timeval tbf_last_pkt_t; /* arr. time of last pkt */ + u_long tbf_n_tok; /* no of tokens in bucket */ + u_long tbf_q_len; /* length of queue at this vif */ + u_long tbf_max_q_len; /* max. queue length */ + struct mbuf *tbf_q; /* Packet queue */ + struct mbuf *tbf_t; /* tail-insertion pointer */ +}; + +#ifdef KERNEL + +extern int (*ip_mrouter_set) __P((int, struct socket *, struct mbuf *)); +extern int (*ip_mrouter_get) __P((int, struct socket *, struct mbuf **)); +extern int (*ip_mrouter_done) __P((void)); +#ifdef MROUTING +extern int (*mrt_ioctl) __P((int, caddr_t)); +#else +extern int (*mrt_ioctl) __P((int, caddr_t, struct proc *)); +#endif + +#endif /* KERNEL */ + +#endif /* _NETINET_IP_MROUTE_H_ */ diff --git a/cpukit/libnetworking/netinet/ip_output.c b/cpukit/libnetworking/netinet/ip_output.c new file mode 100644 index 0000000000..810f6c7479 --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_output.c @@ -0,0 +1,1307 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 + * $Id$ + */ + +#define _IP_VHL + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/errno.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> + +#ifdef vax +#include <machine/mtpr.h> +#endif +#include <machine/in_cksum.h> + +#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 +#undef COMPAT_IPFW +#define COMPAT_IPFW 1 +#else +#undef COMPAT_IPFW +#endif + +u_short ip_id; + +static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); +static void ip_mloopback + __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); +static int ip_getmoptions + __P((int, struct ip_moptions *, struct mbuf **)); +static int ip_optcopy __P((struct ip *, struct ip *)); +static int ip_pcbopts __P((struct mbuf **, struct mbuf *)); +static int ip_setmoptions + __P((int, struct ip_moptions **, struct mbuf *)); + +extern struct protosw inetsw[]; + +/* + * IP output. The packet in mbuf chain m contains a skeletal IP + * header (with len, off, ttl, proto, tos, src, dst). + * The mbuf chain containing the packet will be freed. + * The mbuf opt, if present, will not be freed. + */ +int +ip_output(m0, opt, ro, flags, imo) + struct mbuf *m0; + struct mbuf *opt; + struct route *ro; + int flags; + struct ip_moptions *imo; +{ + struct ip *ip, *mhip; + struct ifnet *ifp; + struct mbuf *m = m0; + int hlen = sizeof (struct ip); + int len, off, error = 0; + struct sockaddr_in *dst; + struct in_ifaddr *ia; + int isbroadcast; + +#ifdef DIAGNOSTIC + if ((m->m_flags & M_PKTHDR) == 0) + panic("ip_output no HDR"); + if (!ro) + panic("ip_output no route, proto = %d", + mtod(m, struct ip *)->ip_p); +#endif + if (opt) { + m = ip_insertoptions(m, opt, &len); + hlen = len; + } + ip = mtod(m, struct ip *); + /* + * Fill in IP header. + */ + if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { + ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2); + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); + ipstat.ips_localout++; + } else { + hlen = IP_VHL_HL(ip->ip_vhl) << 2; + } + + dst = (struct sockaddr_in *)&ro->ro_dst; + /* + * If there is a cached route, + * check that it is to the same destination + * and is still up. If not, free it and try again. + */ + if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || + dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } + if (ro->ro_rt == 0) { + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + dst->sin_addr = ip->ip_dst; + } + /* + * If routing to interface only, + * short circuit routing lookup. + */ +#define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) +#define sintosa(sin) ((struct sockaddr *)(sin)) + if (flags & IP_ROUTETOIF) { + if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 && + (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) { + ipstat.ips_noroute++; + error = ENETUNREACH; + goto bad; + } + ifp = ia->ia_ifp; + ip->ip_ttl = 1; + isbroadcast = in_broadcast(dst->sin_addr, ifp); + } else { + /* + * If this is the case, we probably don't want to allocate + * a protocol-cloned route since we didn't get one from the + * ULP. This lets TCP do its thing, while not burdening + * forwarding or ICMP with the overhead of cloning a route. + * Of course, we still want to do any cloning requested by + * the link layer, as this is probably required in all cases + * for correct operation (as it is for ARP). + */ + if (ro->ro_rt == 0) + rtalloc_ign(ro, RTF_PRCLONING); + if (ro->ro_rt == 0) { + ipstat.ips_noroute++; + error = EHOSTUNREACH; + goto bad; + } + ia = ifatoia(ro->ro_rt->rt_ifa); + ifp = ro->ro_rt->rt_ifp; + ro->ro_rt->rt_use++; + if (ro->ro_rt->rt_flags & RTF_GATEWAY) + dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; + if (ro->ro_rt->rt_flags & RTF_HOST) + isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST); + else + isbroadcast = in_broadcast(dst->sin_addr, ifp); + } + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + struct in_multi *inm; + + m->m_flags |= M_MCAST; + /* + * IP destination address is multicast. Make sure "dst" + * still points to the address in "ro". (It may have been + * changed to point to a gateway address, above.) + */ + dst = (struct sockaddr_in *)&ro->ro_dst; + /* + * See if the caller provided any multicast options + */ + if (imo != NULL) { + ip->ip_ttl = imo->imo_multicast_ttl; + if (imo->imo_multicast_ifp != NULL) + ifp = imo->imo_multicast_ifp; + if (imo->imo_multicast_vif != -1) + ip->ip_src.s_addr = + ip_mcast_src(imo->imo_multicast_vif); + } else + ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; + /* + * Confirm that the outgoing interface supports multicast. + */ + if ((imo == NULL) || (imo->imo_multicast_vif == -1)) { + if ((ifp->if_flags & IFF_MULTICAST) == 0) { + ipstat.ips_noroute++; + error = ENETUNREACH; + goto bad; + } + } + /* + * If source address not specified yet, use address + * of outgoing interface. + */ + if (ip->ip_src.s_addr == INADDR_ANY) { + register struct in_ifaddr *ia; + + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) { + ip->ip_src = IA_SIN(ia)->sin_addr; + break; + } + } + + IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); + if (inm != NULL && + (imo == NULL || imo->imo_multicast_loop)) { + /* + * If we belong to the destination multicast group + * on the outgoing interface, and the caller did not + * forbid loopback, loop back a copy. + */ + ip_mloopback(ifp, m, dst, hlen); + } + else { + /* + * If we are acting as a multicast router, perform + * multicast forwarding as if the packet had just + * arrived on the interface to which we are about + * to send. The multicast forwarding function + * recursively calls this function, using the + * IP_FORWARDING flag to prevent infinite recursion. + * + * Multicasts that are looped back by ip_mloopback(), + * above, will be forwarded by the ip_input() routine, + * if necessary. + */ + if (ip_mrouter && (flags & IP_FORWARDING) == 0) { + /* + * Check if rsvp daemon is running. If not, don't + * set ip_moptions. This ensures that the packet + * is multicast and not just sent down one link + * as prescribed by rsvpd. + */ + if (!rsvp_on) + imo = NULL; + if (ip_mforward(ip, ifp, m, imo) != 0) { + m_freem(m); + goto done; + } + } + } + + /* + * Multicasts with a time-to-live of zero may be looped- + * back, above, but must not be transmitted on a network. + * Also, multicasts addressed to the loopback interface + * are not sent -- the above call to ip_mloopback() will + * loop back a copy if this host actually belongs to the + * destination group on the loopback interface. + */ + if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) { + m_freem(m); + goto done; + } + + goto sendit; + } +#ifndef notdef + /* + * If source address not specified yet, use address + * of outgoing interface. + */ + if (ip->ip_src.s_addr == INADDR_ANY) + ip->ip_src = IA_SIN(ia)->sin_addr; +#endif + /* + * Verify that we have any chance at all of being able to queue + * the packet or packet fragments + */ + if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >= + ifp->if_snd.ifq_maxlen) { + error = ENOBUFS; + goto bad; + } + + /* + * Look for broadcast address and + * and verify user is allowed to send + * such a packet. + */ + if (isbroadcast) { + if ((ifp->if_flags & IFF_BROADCAST) == 0) { + error = EADDRNOTAVAIL; + goto bad; + } + if ((flags & IP_ALLOWBROADCAST) == 0) { + error = EACCES; + goto bad; + } + /* don't allow broadcast messages to be fragmented */ + if ((u_short)ip->ip_len > ifp->if_mtu) { + error = EMSGSIZE; + goto bad; + } + m->m_flags |= M_BCAST; + } else { + m->m_flags &= ~M_BCAST; + } + +sendit: + /* + * IpHack's section. + * - Xlate: translate packet's addr/port (NAT). + * - Firewall: deny/allow/etc. + * - Wrap: fake packet's addr/port <unimpl.> + * - Encapsulate: put it in another IP and send out. <unimp.> + */ + +#ifdef COMPAT_IPFW + if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) { + error = EACCES; + goto done; + } + + /* + * Check with the firewall... + */ + if (ip_fw_chk_ptr) { +#ifdef IPDIVERT + ip_divert_port = (*ip_fw_chk_ptr)(&ip, + hlen, ifp, ip_divert_ignore, &m); + ip_divert_ignore = 0; + if (ip_divert_port) { /* Divert packet */ + (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0); + goto done; + } +#else + /* If ipfw says divert, we have to just drop packet */ + if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, 0, &m)) { + m_freem(m); + goto done; + } +#endif + if (!m) { + error = EACCES; + goto done; + } + } +#endif /* COMPAT_IPFW */ + + /* + * If small enough for interface, can just send directly. + */ + if ((u_short)ip->ip_len <= ifp->if_mtu) { + ip->ip_len = htons((u_short)ip->ip_len); + ip->ip_off = htons((u_short)ip->ip_off); + ip->ip_sum = 0; + if (ip->ip_vhl == IP_VHL_BORING) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(m, hlen); + } + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst, ro->ro_rt); + goto done; + } + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = EMSGSIZE; + /* + * This case can happen if the user changed the MTU + * of an interface after enabling IP on it. Because + * most netifs don't keep track of routes pointing to + * them, there is no way for one to update all its + * routes when the MTU is changed. + */ + if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST)) + && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) + && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) { + ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu; + } + ipstat.ips_cantfrag++; + goto bad; + } + len = (ifp->if_mtu - hlen) &~ 7; + if (len < 8) { + error = EMSGSIZE; + goto bad; + } + + { + int mhlen, firstlen = len; + struct mbuf **mnext = &m->m_nextpkt; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == 0) { + error = ENOBUFS; + ipstat.ips_odropped++; + goto sendorfree; + } + m->m_data += max_linkhdr; + mhip = mtod(m, struct ip *); + *mhip = *ip; + if (hlen > sizeof (struct ip)) { + mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2); + } + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= (u_short)ip->ip_len) + len = (u_short)ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_short)(len + mhlen)); + m->m_next = m_copy(m0, off, len); + if (m->m_next == 0) { + (void) m_free(m); + error = ENOBUFS; /* ??? */ + ipstat.ips_odropped++; + goto sendorfree; + } + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = (struct ifnet *)0; + mhip->ip_off = htons((u_short)mhip->ip_off); + mhip->ip_sum = 0; + if (mhip->ip_vhl == IP_VHL_BORING) { + mhip->ip_sum = in_cksum_hdr(mhip); + } else { + mhip->ip_sum = in_cksum(m, mhlen); + } + *mnext = m; + mnext = &m->m_nextpkt; + ipstat.ips_ofragments++; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m = m0; + m_adj(m, hlen + firstlen - (u_short)ip->ip_len); + m->m_pkthdr.len = hlen + firstlen; + ip->ip_len = htons((u_short)m->m_pkthdr.len); + ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; + if (ip->ip_vhl == IP_VHL_BORING) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(m, hlen); + } +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = 0; + if (error == 0) + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst, ro->ro_rt); + else + m_freem(m); + } + + if (error == 0) + ipstat.ips_fragmented++; + } +done: + return (error); +bad: + m_freem(m0); + goto done; +} + +/* + * Insert IP options into preformed packet. + * Adjust IP destination as required for IP source routing, + * as indicated by a non-zero in_addr at the start of the options. + * + * XXX This routine assumes that the packet has no options in place. + */ +static struct mbuf * +ip_insertoptions(m, opt, phlen) + register struct mbuf *m; + struct mbuf *opt; + int *phlen; +{ + register struct ipoption *p = mtod(opt, struct ipoption *); + struct mbuf *n; + register struct ip *ip = mtod(m, struct ip *); + unsigned optlen; + + optlen = opt->m_len - sizeof(p->ipopt_dst); + if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) + return (m); /* XXX should fail */ + if (p->ipopt_dst.s_addr) + ip->ip_dst = p->ipopt_dst; + if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { + MGETHDR(n, M_DONTWAIT, MT_HEADER); + if (n == 0) + return (m); + n->m_pkthdr.len = m->m_pkthdr.len + optlen; + m->m_len -= sizeof(struct ip); + m->m_data += sizeof(struct ip); + n->m_next = m; + m = n; + m->m_len = optlen + sizeof(struct ip); + m->m_data += max_linkhdr; + (void)memcpy(mtod(m, void *), ip, sizeof(struct ip)); + } else { + m->m_data -= optlen; + m->m_len += optlen; + m->m_pkthdr.len += optlen; + ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); + } + ip = mtod(m, struct ip *); + bcopy(p->ipopt_list, ip + 1, optlen); + *phlen = sizeof(struct ip) + optlen; + ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2); + ip->ip_len += optlen; + return (m); +} + +/* + * Copy options from ip to jp, + * omitting those not copied during fragmentation. + */ +static int +ip_optcopy(ip, jp) + struct ip *ip, *jp; +{ + register u_char *cp, *dp; + int opt, optlen, cnt; + + cp = (u_char *)(ip + 1); + dp = (u_char *)(jp + 1); + cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) { + /* Preserve for IP mcast tunnel's LSRR alignment. */ + *dp++ = IPOPT_NOP; + optlen = 1; + continue; + } else + optlen = cp[IPOPT_OLEN]; + /* bogus lengths should have been caught by ip_dooptions */ + if (optlen > cnt) + optlen = cnt; + if (IPOPT_COPIED(opt)) { + bcopy(cp, dp, optlen); + dp += optlen; + } + } + for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) + *dp++ = IPOPT_EOL; + return (optlen); +} + +/* + * IP socket option processing. + */ +int +ip_ctloutput(op, so, level, optname, mp) + int op; + struct socket *so; + int level, optname; + struct mbuf **mp; +{ + register struct inpcb *inp = sotoinpcb(so); + register struct mbuf *m = *mp; + register int optval = 0; + int error = 0; + + if (level != IPPROTO_IP) { + error = EINVAL; + if (op == PRCO_SETOPT && *mp) + (void) m_free(*mp); + } else switch (op) { + + case PRCO_SETOPT: + switch (optname) { + case IP_OPTIONS: +#ifdef notyet + case IP_RETOPTS: + return (ip_pcbopts(optname, &inp->inp_options, m)); +#else + return (ip_pcbopts(&inp->inp_options, m)); +#endif + + case IP_TOS: + case IP_TTL: + case IP_RECVOPTS: + case IP_RECVRETOPTS: + case IP_RECVDSTADDR: + case IP_RECVIF: + if (m == 0 || m->m_len != sizeof(int)) + error = EINVAL; + else { + optval = *mtod(m, int *); + switch (optname) { + + case IP_TOS: + inp->inp_ip_tos = optval; + break; + + case IP_TTL: + inp->inp_ip_ttl = optval; + break; +#define OPTSET(bit) \ + if (optval) \ + inp->inp_flags |= bit; \ + else \ + inp->inp_flags &= ~bit; + + case IP_RECVOPTS: + OPTSET(INP_RECVOPTS); + break; + + case IP_RECVRETOPTS: + OPTSET(INP_RECVRETOPTS); + break; + + case IP_RECVDSTADDR: + OPTSET(INP_RECVDSTADDR); + break; + + case IP_RECVIF: + OPTSET(INP_RECVIF); + break; + } + } + break; +#undef OPTSET + + case IP_MULTICAST_IF: + case IP_MULTICAST_VIF: + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + error = ip_setmoptions(optname, &inp->inp_moptions, m); + break; + + case IP_PORTRANGE: + if (m == 0 || m->m_len != sizeof(int)) + error = EINVAL; + else { + optval = *mtod(m, int *); + + switch (optval) { + + case IP_PORTRANGE_DEFAULT: + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags &= ~(INP_HIGHPORT); + break; + + case IP_PORTRANGE_HIGH: + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags |= INP_HIGHPORT; + break; + + case IP_PORTRANGE_LOW: + inp->inp_flags &= ~(INP_HIGHPORT); + inp->inp_flags |= INP_LOWPORT; + break; + + default: + error = EINVAL; + break; + } + } + break; + + default: + error = ENOPROTOOPT; + break; + } + if (m) + (void)m_free(m); + break; + + case PRCO_GETOPT: + switch (optname) { + case IP_OPTIONS: + case IP_RETOPTS: + *mp = m = m_get(M_WAIT, MT_SOOPTS); + if (inp->inp_options) { + m->m_len = inp->inp_options->m_len; + bcopy(mtod(inp->inp_options, void *), + mtod(m, void *), m->m_len); + } else + m->m_len = 0; + break; + + case IP_TOS: + case IP_TTL: + case IP_RECVOPTS: + case IP_RECVRETOPTS: + case IP_RECVDSTADDR: + case IP_RECVIF: + *mp = m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof(int); + switch (optname) { + + case IP_TOS: + optval = inp->inp_ip_tos; + break; + + case IP_TTL: + optval = inp->inp_ip_ttl; + break; + +#define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) + + case IP_RECVOPTS: + optval = OPTBIT(INP_RECVOPTS); + break; + + case IP_RECVRETOPTS: + optval = OPTBIT(INP_RECVRETOPTS); + break; + + case IP_RECVDSTADDR: + optval = OPTBIT(INP_RECVDSTADDR); + break; + + case IP_RECVIF: + optval = OPTBIT(INP_RECVIF); + break; + } + *mtod(m, int *) = optval; + break; + + case IP_MULTICAST_IF: + case IP_MULTICAST_VIF: + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + error = ip_getmoptions(optname, inp->inp_moptions, mp); + break; + + case IP_PORTRANGE: + *mp = m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof(int); + + if (inp->inp_flags & INP_HIGHPORT) + optval = IP_PORTRANGE_HIGH; + else if (inp->inp_flags & INP_LOWPORT) + optval = IP_PORTRANGE_LOW; + else + optval = 0; + + *mtod(m, int *) = optval; + break; + + default: + error = ENOPROTOOPT; + break; + } + break; + } + return (error); +} + +/* + * Set up IP options in pcb for insertion in output packets. + * Store in mbuf with pointer in pcbopt, adding pseudo-option + * with destination address if source routed. + */ +static int +#ifdef notyet +ip_pcbopts(optname, pcbopt, m) + int optname; +#else +ip_pcbopts(pcbopt, m) +#endif + struct mbuf **pcbopt; + register struct mbuf *m; +{ + register int cnt, optlen; + register u_char *cp; + u_char opt; + + /* turn off any old options */ + if (*pcbopt) + (void)m_free(*pcbopt); + *pcbopt = 0; + if (m == (struct mbuf *)0 || m->m_len == 0) { + /* + * Only turning off any previous options. + */ + if (m) + (void)m_free(m); + return (0); + } + +#ifndef vax + if (m->m_len % sizeof(long)) + goto bad; +#endif + /* + * IP first-hop destination address will be stored before + * actual options; move other options back + * and clear it when none present. + */ + if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) + goto bad; + cnt = m->m_len; + m->m_len += sizeof(struct in_addr); + cp = mtod(m, u_char *) + sizeof(struct in_addr); + ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); + bzero(mtod(m, caddr_t), sizeof(struct in_addr)); + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= IPOPT_OLEN || optlen > cnt) + goto bad; + } + switch (opt) { + + default: + break; + + case IPOPT_LSRR: + case IPOPT_SSRR: + /* + * user process specifies route as: + * ->A->B->C->D + * D must be our final destination (but we can't + * check that since we may not have connected yet). + * A is first hop destination, which doesn't appear in + * actual IP option, but is stored before the options. + */ + if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) + goto bad; + m->m_len -= sizeof(struct in_addr); + cnt -= sizeof(struct in_addr); + optlen -= sizeof(struct in_addr); + cp[IPOPT_OLEN] = optlen; + /* + * Move first hop before start of options. + */ + bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), + sizeof(struct in_addr)); + /* + * Then copy rest of options back + * to close up the deleted entry. + */ + ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + + sizeof(struct in_addr)), + (caddr_t)&cp[IPOPT_OFFSET+1], + (unsigned)cnt + sizeof(struct in_addr)); + break; + } + } + if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) + goto bad; + *pcbopt = m; + return (0); + +bad: + (void)m_free(m); + return (EINVAL); +} + +/* + * Set the IP multicast options in response to user setsockopt(). + */ +static int +ip_setmoptions(optname, imop, m) + int optname; + struct ip_moptions **imop; + struct mbuf *m; +{ + register int error = 0; + u_char loop; + register int i; + struct in_addr addr; + register struct ip_mreq *mreq; + register struct ifnet *ifp; + register struct ip_moptions *imo = *imop; + struct route ro; + register struct sockaddr_in *dst; + int s; + + if (imo == NULL) { + /* + * No multicast option buffer attached to the pcb; + * allocate one and initialize to default values. + */ + imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, + M_WAITOK); + + if (imo == NULL) + return (ENOBUFS); + *imop = imo; + imo->imo_multicast_ifp = NULL; + imo->imo_multicast_vif = -1; + imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; + imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; + imo->imo_num_memberships = 0; + } + + switch (optname) { + /* store an index number for the vif you wanna use in the send */ + case IP_MULTICAST_VIF: + if (!legal_vif_num) { + error = EOPNOTSUPP; + break; + } + if (m == NULL || m->m_len != sizeof(int)) { + error = EINVAL; + break; + } + i = *(mtod(m, int *)); + if (!legal_vif_num(i) && (i != -1)) { + error = EINVAL; + break; + } + imo->imo_multicast_vif = i; + break; + + case IP_MULTICAST_IF: + /* + * Select the interface for outgoing multicast packets. + */ + if (m == NULL || m->m_len != sizeof(struct in_addr)) { + error = EINVAL; + break; + } + addr = *(mtod(m, struct in_addr *)); + /* + * INADDR_ANY is used to remove a previous selection. + * When no interface is selected, a default one is + * chosen every time a multicast packet is sent. + */ + if (addr.s_addr == INADDR_ANY) { + imo->imo_multicast_ifp = NULL; + break; + } + /* + * The selected interface is identified by its local + * IP address. Find the interface and confirm that + * it supports multicasting. + */ + s = splimp(); + INADDR_TO_IFP(addr, ifp); + if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { + splx(s); + error = EADDRNOTAVAIL; + break; + } + imo->imo_multicast_ifp = ifp; + splx(s); + break; + + case IP_MULTICAST_TTL: + /* + * Set the IP time-to-live for outgoing multicast packets. + */ + if (m == NULL || m->m_len != 1) { + error = EINVAL; + break; + } + imo->imo_multicast_ttl = *(mtod(m, u_char *)); + break; + + case IP_MULTICAST_LOOP: + /* + * Set the loopback flag for outgoing multicast packets. + * Must be zero or one. + */ + if (m == NULL || m->m_len != 1 || + (loop = *(mtod(m, u_char *))) > 1) { + error = EINVAL; + break; + } + imo->imo_multicast_loop = loop; + break; + + case IP_ADD_MEMBERSHIP: + /* + * Add a multicast group membership. + * Group must be a valid IP multicast address. + */ + if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { + error = EINVAL; + break; + } + mreq = mtod(m, struct ip_mreq *); + if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { + error = EINVAL; + break; + } + s = splimp(); + /* + * If no interface address was provided, use the interface of + * the route to the given multicast address. + */ + if (mreq->imr_interface.s_addr == INADDR_ANY) { + bzero((caddr_t)&ro, sizeof(ro)); + dst = (struct sockaddr_in *)&ro.ro_dst; + dst->sin_len = sizeof(*dst); + dst->sin_family = AF_INET; + dst->sin_addr = mreq->imr_multiaddr; + rtalloc(&ro); + if (ro.ro_rt == NULL) { + error = EADDRNOTAVAIL; + splx(s); + break; + } + ifp = ro.ro_rt->rt_ifp; + rtfree(ro.ro_rt); + } + else { + INADDR_TO_IFP(mreq->imr_interface, ifp); + } + + /* + * See if we found an interface, and confirm that it + * supports multicast. + */ + if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { + error = EADDRNOTAVAIL; + splx(s); + break; + } + /* + * See if the membership already exists or if all the + * membership slots are full. + */ + for (i = 0; i < imo->imo_num_memberships; ++i) { + if (imo->imo_membership[i]->inm_ifp == ifp && + imo->imo_membership[i]->inm_addr.s_addr + == mreq->imr_multiaddr.s_addr) + break; + } + if (i < imo->imo_num_memberships) { + error = EADDRINUSE; + splx(s); + break; + } + if (i == IP_MAX_MEMBERSHIPS) { + error = ETOOMANYREFS; + splx(s); + break; + } + /* + * Everything looks good; add a new record to the multicast + * address list for the given interface. + */ + if ((imo->imo_membership[i] = + in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { + error = ENOBUFS; + splx(s); + break; + } + ++imo->imo_num_memberships; + splx(s); + break; + + case IP_DROP_MEMBERSHIP: + /* + * Drop a multicast group membership. + * Group must be a valid IP multicast address. + */ + if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { + error = EINVAL; + break; + } + mreq = mtod(m, struct ip_mreq *); + if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { + error = EINVAL; + break; + } + + s = splimp(); + /* + * If an interface address was specified, get a pointer + * to its ifnet structure. + */ + if (mreq->imr_interface.s_addr == INADDR_ANY) + ifp = NULL; + else { + INADDR_TO_IFP(mreq->imr_interface, ifp); + if (ifp == NULL) { + error = EADDRNOTAVAIL; + splx(s); + break; + } + } + /* + * Find the membership in the membership array. + */ + for (i = 0; i < imo->imo_num_memberships; ++i) { + if ((ifp == NULL || + imo->imo_membership[i]->inm_ifp == ifp) && + imo->imo_membership[i]->inm_addr.s_addr == + mreq->imr_multiaddr.s_addr) + break; + } + if (i == imo->imo_num_memberships) { + error = EADDRNOTAVAIL; + splx(s); + break; + } + /* + * Give up the multicast address record to which the + * membership points. + */ + in_delmulti(imo->imo_membership[i]); + /* + * Remove the gap in the membership array. + */ + for (++i; i < imo->imo_num_memberships; ++i) + imo->imo_membership[i-1] = imo->imo_membership[i]; + --imo->imo_num_memberships; + splx(s); + break; + + default: + error = EOPNOTSUPP; + break; + } + + /* + * If all options have default values, no need to keep the mbuf. + */ + if (imo->imo_multicast_ifp == NULL && + imo->imo_multicast_vif == -1 && + imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && + imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && + imo->imo_num_memberships == 0) { + free(*imop, M_IPMOPTS); + *imop = NULL; + } + + return (error); +} + +/* + * Return the IP multicast options in response to user getsockopt(). + */ +static int +ip_getmoptions(optname, imo, mp) + int optname; + register struct ip_moptions *imo; + register struct mbuf **mp; +{ + u_char *ttl; + u_char *loop; + struct in_addr *addr; + struct in_ifaddr *ia; + + *mp = m_get(M_WAIT, MT_SOOPTS); + + switch (optname) { + + case IP_MULTICAST_VIF: + if (imo != NULL) + *(mtod(*mp, int *)) = imo->imo_multicast_vif; + else + *(mtod(*mp, int *)) = -1; + (*mp)->m_len = sizeof(int); + return(0); + + case IP_MULTICAST_IF: + addr = mtod(*mp, struct in_addr *); + (*mp)->m_len = sizeof(struct in_addr); + if (imo == NULL || imo->imo_multicast_ifp == NULL) + addr->s_addr = INADDR_ANY; + else { + IFP_TO_IA(imo->imo_multicast_ifp, ia); + addr->s_addr = (ia == NULL) ? INADDR_ANY + : IA_SIN(ia)->sin_addr.s_addr; + } + return (0); + + case IP_MULTICAST_TTL: + ttl = mtod(*mp, u_char *); + (*mp)->m_len = 1; + *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL + : imo->imo_multicast_ttl; + return (0); + + case IP_MULTICAST_LOOP: + loop = mtod(*mp, u_char *); + (*mp)->m_len = 1; + *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP + : imo->imo_multicast_loop; + return (0); + + default: + return (EOPNOTSUPP); + } +} + +/* + * Discard the IP multicast options. + */ +void +ip_freemoptions(imo) + register struct ip_moptions *imo; +{ + register int i; + + if (imo != NULL) { + for (i = 0; i < imo->imo_num_memberships; ++i) + in_delmulti(imo->imo_membership[i]); + free(imo, M_IPMOPTS); + } +} + +/* + * Routine called from ip_output() to loop back a copy of an IP multicast + * packet to the input queue of a specified interface. Note that this + * calls the output routine of the loopback "driver", but with an interface + * pointer that might NOT be a loopback interface -- evil, but easier than + * replicating that code here. + */ +static void +ip_mloopback(ifp, m, dst, hlen) + struct ifnet *ifp; + register struct mbuf *m; + register struct sockaddr_in *dst; + int hlen; +{ + register struct ip *ip; + struct mbuf *copym; + + copym = m_copy(m, 0, M_COPYALL); + if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen)) + copym = m_pullup(copym, hlen); + if (copym != NULL) { + /* + * We don't bother to fragment if the IP length is greater + * than the interface's MTU. Can this possibly matter? + */ + ip = mtod(copym, struct ip *); + ip->ip_len = htons((u_short)ip->ip_len); + ip->ip_off = htons((u_short)ip->ip_off); + ip->ip_sum = 0; + if (ip->ip_vhl == IP_VHL_BORING) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(copym, hlen); + } + /* + * NB: + * It's not clear whether there are any lingering + * reentrancy problems in other areas which might + * be exposed by using ip_input directly (in + * particular, everything which modifies the packet + * in-place). Yet another option is using the + * protosw directly to deliver the looped back + * packet. For the moment, we'll err on the side + * of safety by continuing to abuse looutput(). + */ +#ifdef notdef + copym->m_pkthdr.rcvif = ifp; + ip_input(copym) +#else + (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL); +#endif + } +} diff --git a/cpukit/libnetworking/netinet/ip_var.h b/cpukit/libnetworking/netinet/ip_var.h new file mode 100644 index 0000000000..cc7908e9a3 --- /dev/null +++ b/cpukit/libnetworking/netinet/ip_var.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_var.h 8.2 (Berkeley) 1/9/95 + * $Id$ + */ + +#ifndef _NETINET_IP_VAR_H_ +#define _NETINET_IP_VAR_H_ + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +struct ipovly { + caddr_t ih_next, ih_prev; /* for protocol sequence q's */ + u_char ih_x1; /* (unused) */ + u_char ih_pr; /* protocol */ + u_short ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +}; + +/* + * Ip reassembly queue structure. Each fragment + * being reassembled is attached to one of these structures. + * They are timed out after ipq_ttl drops to 0, and may also + * be reclaimed if memory becomes tight. + */ +struct ipq { + struct ipq *next,*prev; /* to other reass headers */ + u_char ipq_ttl; /* time for reass q to live */ + u_char ipq_p; /* protocol of this fragment */ + u_short ipq_id; /* sequence id for reassembly */ + struct ipasfrag *ipq_next,*ipq_prev; + /* to ip headers of fragments */ + struct in_addr ipq_src,ipq_dst; +#ifdef IPDIVERT + u_short ipq_divert; /* divert protocol port */ +#endif +}; + +/* + * Ip header, when holding a fragment. + * + * Note: ipf_next must be at same offset as ipq_next above + */ +struct ipasfrag { +#if BYTE_ORDER == LITTLE_ENDIAN + u_char ip_hl:4, + ip_v:4; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char ip_v:4, + ip_hl:4; +#endif + u_char ipf_mff; /* XXX overlays ip_tos: use low bit + * to avoid destroying tos; + * copied from (ip_off&IP_MF) */ + u_short ip_len; + u_short ip_id; + u_short ip_off; + u_char ip_ttl; + u_char ip_p; + u_short ip_sum; + struct ipasfrag *ipf_next; /* next fragment */ + struct ipasfrag *ipf_prev; /* previous fragment */ +}; + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + char ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +/* + * Structure attached to inpcb.ip_moptions and + * passed to ip_output when IP multicast options are in use. + */ +struct ip_moptions { + struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ + u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ + u_char imo_multicast_loop; /* 1 => hear sends if a member */ + u_short imo_num_memberships; /* no. memberships this socket */ + struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS]; + u_long imo_multicast_vif; /* vif num outgoing multicasts */ +}; + +struct ipstat { + u_long ips_total; /* total packets received */ + u_long ips_badsum; /* checksum bad */ + u_long ips_tooshort; /* packet too short */ + u_long ips_toosmall; /* not enough data */ + u_long ips_badhlen; /* ip header length < data size */ + u_long ips_badlen; /* ip length < ip header length */ + u_long ips_fragments; /* fragments received */ + u_long ips_fragdropped; /* frags dropped (dups, out of space) */ + u_long ips_fragtimeout; /* fragments timed out */ + u_long ips_forward; /* packets forwarded */ + u_long ips_cantforward; /* packets rcvd for unreachable dest */ + u_long ips_redirectsent; /* packets forwarded on same net */ + u_long ips_noproto; /* unknown or unsupported protocol */ + u_long ips_delivered; /* datagrams delivered to upper level*/ + u_long ips_localout; /* total ip packets generated here */ + u_long ips_odropped; /* lost packets due to nobufs, etc. */ + u_long ips_reassembled; /* total packets reassembled ok */ + u_long ips_fragmented; /* datagrams successfully fragmented */ + u_long ips_ofragments; /* output fragments created */ + u_long ips_cantfrag; /* don't fragment flag was set, etc. */ + u_long ips_badoptions; /* error in option processing */ + u_long ips_noroute; /* packets discarded due to no route */ + u_long ips_badvers; /* ip version != 4 */ + u_long ips_rawout; /* total raw ip packets generated */ + u_long ips_toolong; /* ip length > max ip packet size */ +}; + +#ifdef KERNEL +/* flags passed to ip_output as last parameter */ +#define IP_FORWARDING 0x1 /* most of ip header exists */ +#define IP_RAWOUTPUT 0x2 /* raw ip header exists */ +#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ +#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ + +struct inpcb; +struct route; + +extern struct ipstat ipstat; +extern u_short ip_id; /* ip packet ctr, for ids */ +extern int ip_defttl; /* default IP ttl */ +extern u_char ip_protox[]; +extern struct socket *ip_rsvpd; /* reservation protocol daemon */ +extern struct socket *ip_mrouter; /* multicast routing daemon */ +extern int (*legal_vif_num) __P((int)); +extern u_long (*ip_mcast_src) __P((int)); +extern int rsvp_on; + +int ip_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +void ip_drain __P((void)); +void ip_freemoptions __P((struct ip_moptions *)); +void ip_init __P((void)); +extern int (*ip_mforward) __P((struct ip *, struct ifnet *, struct mbuf *, + struct ip_moptions *)); +int ip_output __P((struct mbuf *, + struct mbuf *, struct route *, int, struct ip_moptions *)); +void ip_savecontrol __P((struct inpcb *, struct mbuf **, struct ip *, + struct mbuf *)); +void ip_slowtimo __P((void)); +struct mbuf * + ip_srcroute __P((void)); +void ip_stripoptions __P((struct mbuf *, struct mbuf *)); +int rip_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +void rip_init __P((void)); +void rip_input __P((struct mbuf *, int)); +int rip_output __P((struct mbuf *, struct socket *, u_long)); +int rip_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +void ipip_input __P((struct mbuf *, int)); +void rsvp_input __P((struct mbuf *, int)); +int ip_rsvp_init __P((struct socket *)); +int ip_rsvp_done __P((void)); +int ip_rsvp_vif_init __P((struct socket *, struct mbuf *)); +int ip_rsvp_vif_done __P((struct socket *, struct mbuf *)); +void ip_rsvp_force_done __P((struct socket *)); + +#ifdef IPDIVERT +void div_init __P((void)); +void div_input __P((struct mbuf *, int)); +int div_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +extern u_short ip_divert_port; +extern u_short ip_divert_ignore; +#endif /* IPDIVERT */ + +#endif /* KERNEL */ + +#endif /* _NETINET_IP_VAR_H_ */ diff --git a/cpukit/libnetworking/netinet/raw_ip.c b/cpukit/libnetworking/netinet/raw_ip.c new file mode 100644 index 0000000000..44d58f1844 --- /dev/null +++ b/cpukit/libnetworking/netinet/raw_ip.c @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/systm.h> + +#include <net/if.h> +#include <net/route.h> + +#define _IP_VHL +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/ip_mroute.h> + +#include <netinet/ip_fw.h> + +#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 +#undef COMPAT_IPFW +#define COMPAT_IPFW 1 +#else +#undef COMPAT_IPFW +#endif + +static struct inpcbhead ripcb; +static struct inpcbinfo ripcbinfo; + +/* + * Nominal space allocated to a raw ip socket. + */ +#define RIPSNDQ 8192 +#define RIPRCVQ 8192 + +/* + * Raw interface to IP protocol. + */ + +/* + * Initialize raw connection block q. + */ +void +rip_init() +{ + LIST_INIT(&ripcb); + ripcbinfo.listhead = &ripcb; + /* + * XXX We don't use the hash list for raw IP, but it's easier + * to allocate a one entry hash list than it is to check all + * over the place for hashbase == NULL. + */ + ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask); +} + +static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; +/* + * Setup generic address and protocol structures + * for raw_input routine, then pass them along with + * mbuf chain. + */ +void +rip_input(m, iphlen) + struct mbuf *m; + int iphlen; +{ + register struct ip *ip = mtod(m, struct ip *); + register struct inpcb *inp; + struct inpcb *last = 0; + struct mbuf *opts = 0; + + ripsrc.sin_addr = ip->ip_src; + for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { + if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p) + continue; + if (inp->inp_laddr.s_addr && + inp->inp_laddr.s_addr != ip->ip_dst.s_addr) + continue; + if (inp->inp_faddr.s_addr && + inp->inp_faddr.s_addr != ip->ip_src.s_addr) + continue; + if (last) { + struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + if (n) { + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, n); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&ripsrc, n, + opts) == 0) { + /* should notify about lost packet */ + m_freem(n); + if (opts) + m_freem(opts); + } else + sorwakeup(last->inp_socket); + opts = 0; + } + } + last = inp; + } + if (last) { + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, m); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&ripsrc, m, opts) == 0) { + m_freem(m); + if (opts) + m_freem(opts); + } else + sorwakeup(last->inp_socket); + } else { + m_freem(m); + ipstat.ips_noproto++; + ipstat.ips_delivered--; + } +} + +/* + * Generate IP header and pass packet to ip_output. + * Tack on options user may have setup with control call. + */ +int +rip_output(m, so, dst) + register struct mbuf *m; + struct socket *so; + u_long dst; +{ + register struct ip *ip; + register struct inpcb *inp = sotoinpcb(so); + int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; + + /* + * If the user handed us a complete IP packet, use it. + * Otherwise, allocate an mbuf for a header and fill it in. + */ + if ((inp->inp_flags & INP_HDRINCL) == 0) { + if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { + m_freem(m); + return(EMSGSIZE); + } + M_PREPEND(m, sizeof(struct ip), M_WAIT); + ip = mtod(m, struct ip *); + ip->ip_tos = 0; + ip->ip_off = 0; + ip->ip_p = inp->inp_ip_p; + ip->ip_len = m->m_pkthdr.len; + ip->ip_src = inp->inp_laddr; + ip->ip_dst.s_addr = dst; + ip->ip_ttl = MAXTTL; + } else { + if (m->m_pkthdr.len > IP_MAXPACKET) { + m_freem(m); + return(EMSGSIZE); + } + ip = mtod(m, struct ip *); + /* don't allow both user specified and setsockopt options, + and don't allow packet length sizes that will crash */ + if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) + && inp->inp_options) + || (ip->ip_len > m->m_pkthdr.len) + || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) { + m_freem(m); + return EINVAL; + } + if (ip->ip_id == 0) + ip->ip_id = htons(ip_id++); + /* XXX prevent ip_output from overwriting header fields */ + flags |= IP_RAWOUTPUT; + ipstat.ips_rawout++; + } + return (ip_output(m, inp->inp_options, &inp->inp_route, flags, + inp->inp_moptions)); +} + +/* + * Raw IP socket option processing. + */ +int +rip_ctloutput(op, so, level, optname, m) + int op; + struct socket *so; + int level, optname; + struct mbuf **m; +{ + register struct inpcb *inp = sotoinpcb(so); + register int error; + + if (level != IPPROTO_IP) { + if (op == PRCO_SETOPT && *m) + (void)m_free(*m); + return (EINVAL); + } + + switch (optname) { + + case IP_HDRINCL: + error = 0; + if (op == PRCO_SETOPT) { + if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) + error = EINVAL; + else if (*mtod(*m, int *)) + inp->inp_flags |= INP_HDRINCL; + else + inp->inp_flags &= ~INP_HDRINCL; + if (*m) + (void)m_free(*m); + } else { + *m = m_get(M_WAIT, MT_SOOPTS); + (*m)->m_len = sizeof (int); + *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; + } + return (error); + +#ifdef COMPAT_IPFW + case IP_FW_GET: + if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) { + if (*m) (void)m_free(*m); + return(EINVAL); + } + return (*ip_fw_ctl_ptr)(optname, m); + + case IP_FW_ADD: + case IP_FW_DEL: + case IP_FW_FLUSH: + case IP_FW_ZERO: + if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) { + if (*m) (void)m_free(*m); + return(EINVAL); + } + return (*ip_fw_ctl_ptr)(optname, m); + + case IP_NAT: + if (ip_nat_ctl_ptr == NULL) { + if (*m) (void)m_free(*m); + return(EINVAL); + } + return (*ip_nat_ctl_ptr)(op, m); + +#endif + case IP_RSVP_ON: + return ip_rsvp_init(so); + break; + + case IP_RSVP_OFF: + return ip_rsvp_done(); + break; + + case IP_RSVP_VIF_ON: + return ip_rsvp_vif_init(so, *m); + + case IP_RSVP_VIF_OFF: + return ip_rsvp_vif_done(so, *m); + + case MRT_INIT: + case MRT_DONE: + case MRT_ADD_VIF: + case MRT_DEL_VIF: + case MRT_ADD_MFC: + case MRT_DEL_MFC: + case MRT_VERSION: + case MRT_ASSERT: + if (op == PRCO_SETOPT) { + error = ip_mrouter_set(optname, so, *m); + if (*m) + (void)m_free(*m); + } else if (op == PRCO_GETOPT) { + error = ip_mrouter_get(optname, so, m); + } else + error = EINVAL; + return (error); + } + return (ip_ctloutput(op, so, level, optname, m)); +} + +static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */ +static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */ + +/*ARGSUSED*/ +int +rip_usrreq(so, req, m, nam, control) + register struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register int error = 0; + register struct inpcb *inp = sotoinpcb(so); + int s; + + if (req == PRU_CONTROL) + return (in_control(so, (u_long)m, (caddr_t)nam, + (struct ifnet *)control)); + + switch (req) { + + case PRU_ATTACH: + if (inp) + panic("rip_attach"); + if ((so->so_state & SS_PRIV) == 0) { + error = EACCES; + break; + } + s = splnet(); + error = in_pcballoc(so, &ripcbinfo); + splx(s); + if (error) + break; + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + break; + inp = (struct inpcb *)so->so_pcb; + inp->inp_ip_p = (int)nam; + break; + + case PRU_DISCONNECT: + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + break; + } + /* FALLTHROUGH */ + case PRU_ABORT: + soisdisconnected(so); + /* FALLTHROUGH */ + case PRU_DETACH: + if (inp == 0) + panic("rip_detach"); + if (so == ip_mrouter) + ip_mrouter_done(); + ip_rsvp_force_done(so); + if (so == ip_rsvpd) + ip_rsvp_done(); + in_pcbdetach(inp); + break; + + case PRU_BIND: + { + struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); + + if (nam->m_len != sizeof(*addr)) { + error = EINVAL; + break; + } + if ((ifnet == 0) || + ((addr->sin_family != AF_INET) && + (addr->sin_family != AF_IMPLINK)) || + (addr->sin_addr.s_addr && + ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { + error = EADDRNOTAVAIL; + break; + } + inp->inp_laddr = addr->sin_addr; + break; + } + case PRU_CONNECT: + { + struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); + + if (nam->m_len != sizeof(*addr)) { + error = EINVAL; + break; + } + if (ifnet == 0) { + error = EADDRNOTAVAIL; + break; + } + if ((addr->sin_family != AF_INET) && + (addr->sin_family != AF_IMPLINK)) { + error = EAFNOSUPPORT; + break; + } + inp->inp_faddr = addr->sin_addr; + soisconnected(so); + break; + } + + case PRU_CONNECT2: + error = EOPNOTSUPP; + break; + + /* + * Mark the connection as being incapable of further input. + */ + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + /* + * Ship a packet out. The appropriate raw output + * routine handles any massaging necessary. + */ + case PRU_SEND: + { + register u_long dst; + + if (so->so_state & SS_ISCONNECTED) { + if (nam) { + error = EISCONN; + break; + } + dst = inp->inp_faddr.s_addr; + } else { + if (nam == NULL) { + error = ENOTCONN; + break; + } + dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; + } + error = rip_output(m, so, dst); + m = NULL; + break; + } + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + /* + * Not supported. + */ + case PRU_RCVOOB: + case PRU_RCVD: + case PRU_LISTEN: + case PRU_ACCEPT: + case PRU_SENDOOB: + error = EOPNOTSUPP; + break; + + case PRU_SOCKADDR: + in_setsockaddr(inp, nam); + break; + + case PRU_PEERADDR: + in_setpeeraddr(inp, nam); + break; + + default: + panic("rip_usrreq"); + } + if (m != NULL) + m_freem(m); + return (error); +} diff --git a/cpukit/libnetworking/netinet/tcp.h b/cpukit/libnetworking/netinet/tcp.h new file mode 100644 index 0000000000..3585917aa3 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_TCP_H_ +#define _NETINET_TCP_H_ + +typedef u_long tcp_seq; +typedef u_long tcp_cc; /* connection count per rfc1644 */ + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +struct tcphdr { + u_short th_sport; /* source port */ + u_short th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#if BYTE_ORDER == LITTLE_ENDIAN + u_char th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#endif + u_char th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + + u_short th_win; /* window */ + u_short th_sum; /* checksum */ + u_short th_urp; /* urgent pointer */ +}; + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 +#define TCPOPT_WINDOW 3 +#define TCPOLEN_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + +#define TCPOPT_CC 11 /* CC options: RFC-1644 */ +#define TCPOPT_CCNEW 12 +#define TCPOPT_CCECHO 13 +#define TCPOLEN_CC 6 +#define TCPOLEN_CC_APPA (TCPOLEN_CC+2) +#define TCPOPT_CC_HDR(ccopt) \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|(ccopt)<<8|TCPOLEN_CC) + +/* + * Default maximum segment size for TCP. + * With an IP MSS of 576, this is 536, + * but 512 is probably more convenient. + * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + */ +#define TCP_MSS 512 + +#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ +#define TTCP_CLIENT_SND_WND 4096 /* dflt send window for T/TCP client */ + +#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ + +#define TCP_MAXHLEN (0xf<<2) /* max length of header in bytes */ +#define TCP_MAXOLEN (TCP_MAXHLEN - sizeof(struct tcphdr)) + /* max space left for options */ + +/* + * User-settable options (used with setsockopt). + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_MAXSEG 0x02 /* set maximum segment size */ +#define TCP_NOPUSH 0x04 /* don't push last block of write */ +#define TCP_NOOPT 0x08 /* don't use TCP options */ + +#endif diff --git a/cpukit/libnetworking/netinet/tcp_debug.c b/cpukit/libnetworking/netinet/tcp_debug.c new file mode 100644 index 0000000000..b90ff79ac8 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_debug.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_debug.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#ifdef TCPDEBUG +/* load symbolic names */ +#define PRUREQUESTS +#define TCPSTATES +#define TCPTIMERS +#define TANAMES +#endif + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <net/route.h> +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_debug.h> + +#ifdef TCPDEBUG +static int tcpconsdebug = 0; +#endif + +static struct tcp_debug tcp_debug[TCP_NDEBUG]; +static int tcp_debx; + +/* + * Tcp debug routines + */ +void +tcp_trace(act, ostate, tp, ti, req) + short act, ostate; + struct tcpcb *tp; + struct tcpiphdr *ti; + int req; +{ + tcp_seq seq, ack; + int len, flags; + struct tcp_debug *td = &tcp_debug[tcp_debx++]; + + if (tcp_debx == TCP_NDEBUG) + tcp_debx = 0; + td->td_time = iptime(); + td->td_act = act; + td->td_ostate = ostate; + td->td_tcb = (caddr_t)tp; + if (tp) + td->td_cb = *tp; + else + bzero((caddr_t)&td->td_cb, sizeof (*tp)); + if (ti) + td->td_ti = *ti; + else + bzero((caddr_t)&td->td_ti, sizeof (*ti)); + td->td_req = req; +#ifdef TCPDEBUG + if (tcpconsdebug == 0) + return; + if (tp) + printf("%p %s:", tp, tcpstates[ostate]); + else + printf("???????? "); + printf("%s ", tanames[act]); + switch (act) { + + case TA_INPUT: + case TA_OUTPUT: + case TA_DROP: + if (ti == 0) + break; + seq = ti->ti_seq; + ack = ti->ti_ack; + len = ti->ti_len; + if (act == TA_OUTPUT) { + seq = ntohl(seq); + ack = ntohl(ack); + len = ntohs((u_short)len); + } + if (act == TA_OUTPUT) + len -= sizeof (struct tcphdr); + if (len) + printf("[%x..%x)", seq, seq+len); + else + printf("%x", seq); + printf("@%x, urp=%x", ack, ti->ti_urp); + flags = ti->ti_flags; + if (flags) { + char *cp = "<"; +#define pf(f) { \ + if (ti->ti_flags & TH_##f) { \ + printf("%s%s", cp, #f); \ + cp = ","; \ + } \ +} + pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG); + printf(">"); + } + break; + + case TA_USER: + printf("%s", prurequests[req&0xff]); + if ((req & 0xff) == PRU_SLOWTIMO) + printf("<%s>", tcptimers[req>>8]); + break; + } + if (tp) + printf(" -> %s", tcpstates[tp->t_state]); + /* print out internal state of tp !?! */ + printf("\n"); + if (tp == 0) + return; + printf("\trcv_(nxt,wnd,up) (%x,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n", + tp->rcv_nxt, tp->rcv_wnd, tp->rcv_up, tp->snd_una, tp->snd_nxt, + tp->snd_max); + printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n", + tp->snd_wl1, tp->snd_wl2, tp->snd_wnd); +#endif /* TCPDEBUG */ +} diff --git a/cpukit/libnetworking/netinet/tcp_debug.h b/cpukit/libnetworking/netinet/tcp_debug.h new file mode 100644 index 0000000000..a33743b077 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_debug.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_debug.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_TCP_DEBUG_H_ +#define _NETINET_TCP_DEBUG_H_ + +struct tcp_debug { + n_time td_time; + short td_act; + short td_ostate; + caddr_t td_tcb; + struct tcpiphdr td_ti; + short td_req; + struct tcpcb td_cb; +}; + +#define TA_INPUT 0 +#define TA_OUTPUT 1 +#define TA_USER 2 +#define TA_RESPOND 3 +#define TA_DROP 4 + +#ifdef TANAMES +static char *tanames[] = + { "input", "output", "user", "respond", "drop" }; +#endif + +#define TCP_NDEBUG 100 + +#ifndef KERNEL +/* XXX common variables for broken applications. */ +struct tcp_debug tcp_debug[TCP_NDEBUG]; +int tcp_debx; +#endif + +#endif /* !_NETINET_TCP_DEBUG_H_ */ diff --git a/cpukit/libnetworking/netinet/tcp_fsm.h b/cpukit/libnetworking/netinet/tcp_fsm.h new file mode 100644 index 0000000000..3f2c12f54f --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_fsm.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_fsm.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_TCP_FSM_H_ +#define _NETINET_TCP_FSM_H_ + +/* + * TCP FSM state definitions. + * Per RFC793, September, 1981. + */ + +#define TCP_NSTATES 11 + +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) + +#ifdef TCPOUTFLAGS +/* + * Flags used when sending segments in tcp_output. + * Basic flags (TH_RST,TH_ACK,TH_SYN,TH_FIN) are totally + * determined by state, with the proviso that TH_FIN is sent only + * if all data queued for output is included in the segment. + */ +static u_char tcp_outflags[TCP_NSTATES] = { + TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, + TH_ACK, TH_ACK, + TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, +}; +#endif + +#ifdef KPROF +int tcp_acounts[TCP_NSTATES][PRU_NREQ]; +#endif + +#ifdef TCPSTATES +char *tcpstates[] = { + "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", + "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", + "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", +}; +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/tcp_input.c b/cpukit/libnetworking/netinet/tcp_input.c new file mode 100644 index 0000000000..3ab1223d4e --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_input.c @@ -0,0 +1,2149 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#ifndef TUBA_INCLUDE +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/syslog.h> + +#include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +static struct tcpiphdr tcp_saveti; +#endif + +static int tcprexmtthresh = 3; +tcp_seq tcp_iss; +tcp_cc tcp_ccgen; + +struct tcpstat tcpstat; +SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, + CTLFLAG_RD, &tcpstat , tcpstat, ""); + +static int log_in_vain = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW, + &log_in_vain, 0, ""); + +u_long tcp_now; +struct inpcbhead tcb; +struct inpcbinfo tcbinfo; + +static void tcp_dooptions __P((struct tcpcb *, + u_char *, int, struct tcpiphdr *, struct tcpopt *)); +static void tcp_pulloutofband __P((struct socket *, + struct tcpiphdr *, struct mbuf *)); +static int tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *)); +static void tcp_xmit_timer __P((struct tcpcb *, int)); + +#endif /* TUBA_INCLUDE */ + +/* + * Insert segment ti into reassembly queue of tcp with + * control block tp. Return TH_FIN if reassembly now includes + * a segment with FIN. The macro form does the common case inline + * (segment is the next to be received on an established connection, + * and the queue is empty), avoiding linkage into and removal + * from the queue and repetition of various conversions. + * Set DELACK for segments received in order, but ack immediately + * when segments are out of order (so fast retransmit can work). + */ +#ifdef TCP_ACK_HACK +#define TCP_REASS(tp, ti, m, so, flags) { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (struct tcpiphdr *)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + if (ti->ti_flags & TH_PUSH) \ + tp->t_flags |= TF_ACKNOW; \ + else \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + sbappend(&(so)->so_rcv, (m)); \ + sorwakeup(so); \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#else +#define TCP_REASS(tp, ti, m, so, flags) { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (struct tcpiphdr *)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + sbappend(&(so)->so_rcv, (m)); \ + sorwakeup(so); \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#endif +#ifndef TUBA_INCLUDE + +static int +tcp_reass(tp, ti, m) + register struct tcpcb *tp; + register struct tcpiphdr *ti; + struct mbuf *m; +{ + register struct tcpiphdr *q; + struct socket *so = tp->t_inpcb->inp_socket; + int flags; + + /* + * Call with ti==0 after become established to + * force pre-ESTABLISHED data up to user socket. + */ + if (ti == 0) + goto present; + + /* + * Find a segment which begins after this one does. + */ + for (q = tp->seg_next; q != (struct tcpiphdr *)tp; + q = (struct tcpiphdr *)q->ti_next) + if (SEQ_GT(q->ti_seq, ti->ti_seq)) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + register int i; + q = (struct tcpiphdr *)q->ti_prev; + /* conversion to int (in i) handles seq wraparound */ + i = q->ti_seq + q->ti_len - ti->ti_seq; + if (i > 0) { + if (i >= ti->ti_len) { + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += ti->ti_len; + m_freem(m); + /* + * Try to present any queued data + * at the left window edge to the user. + * This is needed after the 3-WHS + * completes. + */ + goto present; /* ??? */ + } + m_adj(m, i); + ti->ti_len -= i; + ti->ti_seq += i; + } + q = (struct tcpiphdr *)(q->ti_next); + } + tcpstat.tcps_rcvoopack++; + tcpstat.tcps_rcvoobyte += ti->ti_len; + REASS_MBUF(ti) = m; /* XXX */ + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct tcpiphdr *)tp) { + register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; + if (i < q->ti_len) { + q->ti_seq += i; + q->ti_len -= i; + m_adj(REASS_MBUF(q), i); + break; + } + q = (struct tcpiphdr *)q->ti_next; + m = REASS_MBUF((struct tcpiphdr *)q->ti_prev); + remque(q->ti_prev); + m_freem(m); + } + + /* + * Stick new segment in its place. + */ + insque(ti, q->ti_prev); + +present: + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = tp->seg_next; + if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + return (0); + do { + tp->rcv_nxt += ti->ti_len; + flags = ti->ti_flags & TH_FIN; + remque(ti); + m = REASS_MBUF(ti); + ti = (struct tcpiphdr *)ti->ti_next; + if (so->so_state & SS_CANTRCVMORE) + m_freem(m); + else + sbappend(&so->so_rcv, m); + } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); + sorwakeup(so); + return (flags); +} + +/* + * TCP input routine, follows pages 65-76 of the + * protocol specification dated September, 1981 very closely. + */ +void +tcp_input(m, iphlen) + register struct mbuf *m; + int iphlen; +{ + register struct tcpiphdr *ti; + register struct inpcb *inp; + u_char *optp = NULL; + int optlen = 0; + int len, tlen, off; + register struct tcpcb *tp = 0; + register int tiflags; + struct socket *so = 0; + int todrop, acked, ourfinisacked, needoutput = 0; + struct in_addr laddr; + int dropsocket = 0; + int iss = 0; + u_long tiwin; + struct tcpopt to; /* options in this segment */ + struct rmxp_tao *taop; /* pointer to our TAO cache entry */ + struct rmxp_tao tao_noncached; /* in case there's no cached entry */ +#ifdef TCPDEBUG + short ostate = 0; +#endif + + bzero((char *)&to, sizeof(to)); + + tcpstat.tcps_rcvtotal++; + /* + * Get IP and TCP header together in first mbuf. + * Note: IP leaves IP header in first mbuf. + */ + ti = mtod(m, struct tcpiphdr *); + if (iphlen > sizeof (struct ip)) + ip_stripoptions(m, (struct mbuf *)0); + if (m->m_len < sizeof (struct tcpiphdr)) { + if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { + tcpstat.tcps_rcvshort++; + return; + } + ti = mtod(m, struct tcpiphdr *); + } + + /* + * Checksum extended TCP header and data. + */ + tlen = ((struct ip *)ti)->ip_len; + len = sizeof (struct ip) + tlen; + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_len = (u_short)tlen; + HTONS(ti->ti_len); + ti->ti_sum = in_cksum(m, len); + if (ti->ti_sum) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } +#endif /* TUBA_INCLUDE */ + + /* + * Check that TCP offset makes sense, + * pull out TCP options and adjust length. XXX + */ + off = ti->ti_off << 2; + if (off < sizeof (struct tcphdr) || off > tlen) { + tcpstat.tcps_rcvbadoff++; + goto drop; + } + tlen -= off; + ti->ti_len = tlen; + if (off > sizeof (struct tcphdr)) { + if (m->m_len < sizeof(struct ip) + off) { + if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { + tcpstat.tcps_rcvshort++; + return; + } + ti = mtod(m, struct tcpiphdr *); + } + optlen = off - sizeof (struct tcphdr); + optp = mtod(m, u_char *) + sizeof (struct tcpiphdr); + } + tiflags = ti->ti_flags; + + /* + * Convert TCP protocol specific fields to host format. + */ + NTOHL(ti->ti_seq); + NTOHL(ti->ti_ack); + NTOHS(ti->ti_win); + NTOHS(ti->ti_urp); + + /* + * Drop TCP, IP headers and TCP options. + */ + m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + + /* + * Locate pcb for segment. + */ +findpcb: + inp = in_pcblookuphash(&tcbinfo, ti->ti_src, ti->ti_sport, + ti->ti_dst, ti->ti_dport, 1); + + /* + * If the state is CLOSED (i.e., TCB does not exist) then + * all data in the incoming segment is discarded. + * If the TCB exists but is in CLOSED state, it is embryonic, + * but should either do a listen or a connect soon. + */ + if (inp == NULL) { + if (log_in_vain && tiflags & TH_SYN) { + char buf[4*sizeof "123"]; + + strcpy(buf, inet_ntoa(ti->ti_dst)); + log(LOG_INFO, "Connection attempt to TCP %s:%d" + " from %s:%d\n", + buf, ntohs(ti->ti_dport), + inet_ntoa(ti->ti_src), ntohs(ti->ti_sport)); + } + goto dropwithreset; + } + tp = intotcpcb(inp); + if (tp == 0) + goto dropwithreset; + if (tp->t_state == TCPS_CLOSED) + goto drop; + + /* Unscale the window into a 32-bit value. */ + if ((tiflags & TH_SYN) == 0) + tiwin = ti->ti_win << tp->snd_scale; + else + tiwin = ti->ti_win; + + so = inp->inp_socket; + if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) { + ostate = tp->t_state; + tcp_saveti = *ti; + } +#endif + if (so->so_options & SO_ACCEPTCONN) { + register struct tcpcb *tp0 = tp; + struct socket *so2; + if ((tiflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) { + /* + * Note: dropwithreset makes sure we don't + * send a RST in response to a RST. + */ + if (tiflags & TH_ACK) { + tcpstat.tcps_badsyn++; + goto dropwithreset; + } + goto drop; + } + so2 = sonewconn(so, 0); + if (so2 == 0) { + tcpstat.tcps_listendrop++; + so2 = sodropablereq(so); + if (so2) { + tcp_drop(sototcpcb(so2), ETIMEDOUT); + so2 = sonewconn(so, 0); + } + if (!so2) + goto drop; + } + so = so2; + /* + * This is ugly, but .... + * + * Mark socket as temporary until we're + * committed to keeping it. The code at + * ``drop'' and ``dropwithreset'' check the + * flag dropsocket to see if the temporary + * socket created here should be discarded. + * We mark the socket as discardable until + * we're committed to it below in TCPS_LISTEN. + */ + dropsocket++; + inp = (struct inpcb *)so->so_pcb; + inp->inp_laddr = ti->ti_dst; + inp->inp_lport = ti->ti_dport; + in_pcbrehash(inp); +#if BSD>=43 + inp->inp_options = ip_srcroute(); +#endif + tp = intotcpcb(inp); + tp->t_state = TCPS_LISTEN; + tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT); + + /* Compute proper scaling value from buffer space */ + while (tp->request_r_scale < TCP_MAX_WINSHIFT && + TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) + tp->request_r_scale++; + } + } + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + if (TCPS_HAVEESTABLISHED(tp->t_state)) + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + + /* + * Process options if not in LISTEN state, + * else do it below (after getting remote address). + */ + if (tp->t_state != TCPS_LISTEN) + tcp_dooptions(tp, optp, optlen, ti, &to); + + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * Make sure that the hidden state-flags are also off. + * Since we check for TCPS_ESTABLISHED above, it can only + * be TH_NEEDSYN. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && + ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) && + ((to.to_flag & TOF_TS) == 0 || + TSTMP_GEQ(to.to_tsval, tp->ts_recent)) && + /* + * Using the CC option is compulsory if once started: + * the segment is OK if no T/TCP was negotiated or + * if the segment has a CC option equal to CCrecv + */ + ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) != (TF_REQ_CC|TF_RCVD_CC) || + (to.to_flag & TOF_CC) != 0 && to.to_cc == tp->cc_recv) && + ti->ti_seq == tp->rcv_nxt && + tiwin && tiwin == tp->snd_wnd && + tp->snd_nxt == tp->snd_max) { + + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + * NOTE that the test is modified according to the latest + * proposal of the tcplw@cray.com list (Braden 1993/04/26). + */ + if ((to.to_flag & TOF_TS) != 0 && + SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) { + tp->ts_recent_age = tcp_now; + tp->ts_recent = to.to_tsval; + } + + if (ti->ti_len == 0) { + if (SEQ_GT(ti->ti_ack, tp->snd_una) && + SEQ_LEQ(ti->ti_ack, tp->snd_max) && + tp->snd_cwnd >= tp->snd_wnd && + tp->t_dupacks < tcprexmtthresh) { + /* + * this is a pure ack for outstanding data. + */ + ++tcpstat.tcps_predack; + if ((to.to_flag & TOF_TS) != 0) + tcp_xmit_timer(tp, + tcp_now - to.to_tsecr + 1); + else if (tp->t_rtt && + SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtt); + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + sbdrop(&so->so_snd, acked); + tp->snd_una = ti->ti_ack; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ + if (tp->snd_una == tp->snd_max) + tp->t_timer[TCPT_REXMT] = 0; + else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + if (so->so_snd.sb_flags & SB_NOTIFY) + sowwakeup(so); + if (so->so_snd.sb_cc) + (void) tcp_output(tp); + return; + } + } else if (ti->ti_ack == tp->snd_una && + tp->seg_next == (struct tcpiphdr *)tp && + ti->ti_len <= sbspace(&so->so_rcv)) { + /* + * this is a pure, in-sequence data packet + * with nothing on the reassembly queue and + * we have enough buffer space to take it. + */ + ++tcpstat.tcps_preddat; + tp->rcv_nxt += ti->ti_len; + tcpstat.tcps_rcvpack++; + tcpstat.tcps_rcvbyte += ti->ti_len; + /* + * Add data to socket buffer. + */ + sbappend(&so->so_rcv, m); + sorwakeup(so); +#ifdef TCP_ACK_HACK + /* + * If this is a short packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + */ + if (tiflags & TH_PUSH) { + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); + } else { + tp->t_flags |= TF_DELACK; + } +#else + tp->t_flags |= TF_DELACK; +#endif + return; + } + } + + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + { int win; + + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = imax(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + } + + switch (tp->t_state) { + + /* + * If the state is LISTEN then ignore segment if it contains an RST. + * If the segment contains an ACK then it is bad and send a RST. + * If it does not contain a SYN then it is not interesting; drop it. + * If it is from this socket, drop it, it must be forged. + * Don't bother responding if the destination was a broadcast. + * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial + * tp->iss, and send a segment: + * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> + * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. + * Fill in remote peer address fields if not previously specified. + * Enter SYN_RECEIVED state, and process any other fields of this + * segment in this state. + */ + case TCPS_LISTEN: { + struct mbuf *am; + register struct sockaddr_in *sin; + + if (tiflags & TH_RST) + goto drop; + if (tiflags & TH_ACK) + goto dropwithreset; + if ((tiflags & TH_SYN) == 0) + goto drop; + if ((ti->ti_dport == ti->ti_sport) && + (ti->ti_dst.s_addr == ti->ti_src.s_addr)) + goto drop; + /* + * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN + * in_broadcast() should never return true on a received + * packet with M_BCAST not set. + */ + if (m->m_flags & (M_BCAST|M_MCAST) || + IN_MULTICAST(ntohl(ti->ti_dst.s_addr))) + goto drop; + am = m_get(M_DONTWAIT, MT_SONAME); /* XXX */ + if (am == NULL) + goto drop; + am->m_len = sizeof (struct sockaddr_in); + sin = mtod(am, struct sockaddr_in *); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = ti->ti_src; + sin->sin_port = ti->ti_sport; + bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero)); + laddr = inp->inp_laddr; + if (inp->inp_laddr.s_addr == INADDR_ANY) + inp->inp_laddr = ti->ti_dst; + if (in_pcbconnect(inp, am)) { + inp->inp_laddr = laddr; + (void) m_free(am); + goto drop; + } + (void) m_free(am); + tp->t_template = tcp_template(tp); + if (tp->t_template == 0) { + tp = tcp_drop(tp, ENOBUFS); + dropsocket = 0; /* socket is already gone */ + goto drop; + } + if ((taop = tcp_gettaocache(inp)) == NULL) { + taop = &tao_noncached; + bzero(taop, sizeof(*taop)); + } + tcp_dooptions(tp, optp, optlen, ti, &to); + if (iss) + tp->iss = iss; + else + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/4; + tp->irs = ti->ti_seq; + tcp_sendseqinit(tp); + tcp_rcvseqinit(tp); + /* + * Initialization of the tcpcb for transaction; + * set SND.WND = SEG.WND, + * initialize CCsend and CCrecv. + */ + tp->snd_wnd = tiwin; /* initial send-window */ + tp->cc_send = CC_INC(tcp_ccgen); + tp->cc_recv = to.to_cc; + /* + * Perform TAO test on incoming CC (SEG.CC) option, if any. + * - compare SEG.CC against cached CC from the same host, + * if any. + * - if SEG.CC > chached value, SYN must be new and is accepted + * immediately: save new CC in the cache, mark the socket + * connected, enter ESTABLISHED state, turn on flag to + * send a SYN in the next segment. + * A virtual advertised window is set in rcv_adv to + * initialize SWS prevention. Then enter normal segment + * processing: drop SYN, process data and FIN. + * - otherwise do a normal 3-way handshake. + */ + if ((to.to_flag & TOF_CC) != 0) { + if (taop->tao_cc != 0 && CC_GT(to.to_cc, taop->tao_cc)) { + taop->tao_cc = to.to_cc; + tp->t_state = TCPS_ESTABLISHED; + + /* + * If there is a FIN, or if there is data and the + * connection is local, then delay SYN,ACK(SYN) in + * the hope of piggy-backing it on a response + * segment. Otherwise must send ACK now in case + * the other side is slow starting. + */ + if ((tiflags & TH_FIN) || (ti->ti_len != 0 && + in_localaddr(inp->inp_faddr))) + tp->t_flags |= (TF_DELACK | TF_NEEDSYN); + else + tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); + + /* + * Limit the `virtual advertised window' to TCP_MAXWIN + * here. Even if we requested window scaling, it will + * become effective only later when our SYN is acked. + */ + tp->rcv_adv += min(tp->rcv_wnd, TCP_MAXWIN); + tcpstat.tcps_connects++; + soisconnected(so); + tp->t_timer[TCPT_KEEP] = tcp_keepinit; + dropsocket = 0; /* committed to socket */ + tcpstat.tcps_accepts++; + goto trimthenstep6; + } + /* else do standard 3-way handshake */ + } else { + /* + * No CC option, but maybe CC.NEW: + * invalidate cached value. + */ + taop->tao_cc = 0; + } + /* + * TAO test failed or there was no CC option, + * do a standard 3-way handshake. + */ + tp->t_flags |= TF_ACKNOW; + tp->t_state = TCPS_SYN_RECEIVED; + tp->t_timer[TCPT_KEEP] = tcp_keepinit; + dropsocket = 0; /* committed to socket */ + tcpstat.tcps_accepts++; + goto trimthenstep6; + } + + /* + * If the state is SYN_RECEIVED: + * if seg contains SYN/ACK, send a RST. + * if seg contains an ACK, but not for our SYN/ACK, send a RST. + */ + case TCPS_SYN_RECEIVED: + if (tiflags & TH_ACK) { + if (tiflags & TH_SYN) { + tcpstat.tcps_badsyn++; + goto dropwithreset; + } + if (SEQ_LEQ(ti->ti_ack, tp->snd_una) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + } + break; + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((taop = tcp_gettaocache(inp)) == NULL) { + taop = &tao_noncached; + bzero(taop, sizeof(*taop)); + } + + if ((tiflags & TH_ACK) && + (SEQ_LEQ(ti->ti_ack, tp->iss) || + SEQ_GT(ti->ti_ack, tp->snd_max))) { + /* + * If we have a cached CCsent for the remote host, + * hence we haven't just crashed and restarted, + * do not send a RST. This may be a retransmission + * from the other side after our earlier ACK was lost. + * Our new SYN, when it arrives, will serve as the + * needed ACK. + */ + if (taop->tao_ccsent != 0) + goto drop; + else + goto dropwithreset; + } + if (tiflags & TH_RST) { + if (tiflags & TH_ACK) + tp = tcp_drop(tp, ECONNREFUSED); + goto drop; + } + if ((tiflags & TH_SYN) == 0) + goto drop; + tp->snd_wnd = ti->ti_win; /* initial send window */ + tp->cc_recv = to.to_cc; /* foreign CC */ + + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + if (tiflags & TH_ACK) { + /* + * Our SYN was acked. If segment contains CC.ECHO + * option, check it to make sure this segment really + * matches our SYN. If not, just drop it as old + * duplicate, but send an RST if we're still playing + * by the old rules. If no CC.ECHO option, make sure + * we don't get fooled into using T/TCP. + */ + if (to.to_flag & TOF_CCECHO) { + if (tp->cc_send != to.to_ccecho) + if (taop->tao_ccsent != 0) + goto drop; + else + goto dropwithreset; + } else + tp->t_flags &= ~TF_RCVD_CC; + tcpstat.tcps_connects++; + soisconnected(so); + /* Do window scaling on this connection? */ + if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + (TF_RCVD_SCALE|TF_REQ_SCALE)) { + tp->snd_scale = tp->requested_s_scale; + tp->rcv_scale = tp->request_r_scale; + } + /* Segment is acceptable, update cache if undefined. */ + if (taop->tao_ccsent == 0) + taop->tao_ccsent = to.to_ccecho; + + tp->rcv_adv += tp->rcv_wnd; + tp->snd_una++; /* SYN is acked */ + /* + * If there's data, delay ACK; if there's also a FIN + * ACKNOW will be turned on later. + */ + if (ti->ti_len != 0) + tp->t_flags |= TF_DELACK; + else + tp->t_flags |= TF_ACKNOW; + /* + * Received <SYN,ACK> in SYN_SENT[*] state. + * Transitions: + * SYN_SENT --> ESTABLISHED + * SYN_SENT* --> FIN_WAIT_1 + */ + if (tp->t_flags & TF_NEEDFIN) { + tp->t_state = TCPS_FIN_WAIT_1; + tp->t_flags &= ~TF_NEEDFIN; + tiflags &= ~TH_SYN; + } else { + tp->t_state = TCPS_ESTABLISHED; + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + } + } else { + /* + * Received initial SYN in SYN-SENT[*] state => simul- + * taneous open. If segment contains CC option and there is + * a cached CC, apply TAO test; if it succeeds, connection is + * half-synchronized. Otherwise, do 3-way handshake: + * SYN-SENT -> SYN-RECEIVED + * SYN-SENT* -> SYN-RECEIVED* + * If there was no CC option, clear cached CC value. + */ + tp->t_flags |= TF_ACKNOW; + tp->t_timer[TCPT_REXMT] = 0; + if (to.to_flag & TOF_CC) { + if (taop->tao_cc != 0 && + CC_GT(to.to_cc, taop->tao_cc)) { + /* + * update cache and make transition: + * SYN-SENT -> ESTABLISHED* + * SYN-SENT* -> FIN-WAIT-1* + */ + taop->tao_cc = to.to_cc; + if (tp->t_flags & TF_NEEDFIN) { + tp->t_state = TCPS_FIN_WAIT_1; + tp->t_flags &= ~TF_NEEDFIN; + } else { + tp->t_state = TCPS_ESTABLISHED; + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + } + tp->t_flags |= TF_NEEDSYN; + } else + tp->t_state = TCPS_SYN_RECEIVED; + } else { + /* CC.NEW or no option => invalidate cache */ + taop->tao_cc = 0; + tp->t_state = TCPS_SYN_RECEIVED; + } + } + +trimthenstep6: + /* + * Advance ti->ti_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + ti->ti_seq++; + if (ti->ti_len > tp->rcv_wnd) { + todrop = ti->ti_len - tp->rcv_wnd; + m_adj(m, -todrop); + ti->ti_len = tp->rcv_wnd; + tiflags &= ~TH_FIN; + tcpstat.tcps_rcvpackafterwin++; + tcpstat.tcps_rcvbyteafterwin += todrop; + } + tp->snd_wl1 = ti->ti_seq - 1; + tp->rcv_up = ti->ti_seq; + /* + * Client side of transaction: already sent SYN and data. + * If the remote host used T/TCP to validate the SYN, + * our data will be ACK'd; if so, enter normal data segment + * processing in the middle of step 5, ack processing. + * Otherwise, goto step 6. + */ + if (tiflags & TH_ACK) + goto process_ACK; + goto step6; + /* + * If the state is LAST_ACK or CLOSING or TIME_WAIT: + * if segment contains a SYN and CC [not CC.NEW] option: + * if state == TIME_WAIT and connection duration > MSL, + * drop packet and send RST; + * + * if SEG.CC > CCrecv then is new SYN, and can implicitly + * ack the FIN (and data) in retransmission queue. + * Complete close and delete TCPCB. Then reprocess + * segment, hoping to find new TCPCB in LISTEN state; + * + * else must be old SYN; drop it. + * else do normal processing. + */ + case TCPS_LAST_ACK: + case TCPS_CLOSING: + case TCPS_TIME_WAIT: + if ((tiflags & TH_SYN) && + (to.to_flag & TOF_CC) && tp->cc_recv != 0) { + if (tp->t_state == TCPS_TIME_WAIT && + tp->t_duration > TCPTV_MSL) + goto dropwithreset; + if (CC_GT(to.to_cc, tp->cc_recv)) { + tp = tcp_close(tp); + goto findpcb; + } + else + goto drop; + } + break; /* continue normal processing */ + } + + /* + * States other than LISTEN or SYN_SENT. + * First check timestamp, if present. + * Then check the connection count, if present. + * Then check that at least some bytes of segment are within + * receive window. If segment begins before rcv_nxt, + * drop leading data (and SYN); if nothing left, just ack. + * + * RFC 1323 PAWS: If we have a timestamp reply on this segment + * and it's less than ts_recent, drop it. + */ + if ((to.to_flag & TOF_TS) != 0 && (tiflags & TH_RST) == 0 && + tp->ts_recent && TSTMP_LT(to.to_tsval, tp->ts_recent)) { + + /* Check to see if ts_recent is over 24 days old. */ + if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { + /* + * Invalidate ts_recent. If this segment updates + * ts_recent, the age will be reset later and ts_recent + * will get a valid value. If it does not, setting + * ts_recent to zero will at least satisfy the + * requirement that zero be placed in the timestamp + * echo reply when ts_recent isn't valid. The + * age isn't reset until we get a valid ts_recent + * because we don't want out-of-order segments to be + * dropped when ts_recent is old. + */ + tp->ts_recent = 0; + } else { + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += ti->ti_len; + tcpstat.tcps_pawsdrop++; + goto dropafterack; + } + } + + /* + * T/TCP mechanism + * If T/TCP was negotiated and the segment doesn't have CC, + * or if it's CC is wrong then drop the segment. + * RST segments do not have to comply with this. + */ + if ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) == (TF_REQ_CC|TF_RCVD_CC) && + ((to.to_flag & TOF_CC) == 0 || tp->cc_recv != to.to_cc) && + (tiflags & TH_RST) == 0) + goto dropafterack; + + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { + if (tiflags & TH_SYN) { + tiflags &= ~TH_SYN; + ti->ti_seq++; + if (ti->ti_urp > 1) + ti->ti_urp--; + else + tiflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > ti->ti_len + || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + tiflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = ti->ti_len; + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += todrop; + } else { + tcpstat.tcps_rcvpartduppack++; + tcpstat.tcps_rcvpartdupbyte += todrop; + } + m_adj(m, todrop); + ti->ti_seq += todrop; + ti->ti_len -= todrop; + if (ti->ti_urp > todrop) + ti->ti_urp -= todrop; + else { + tiflags &= ~TH_URG; + ti->ti_urp = 0; + } + } + + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && + tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { + tp = tcp_close(tp); + tcpstat.tcps_rcvafterclose++; + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); + if (todrop > 0) { + tcpstat.tcps_rcvpackafterwin++; + if (todrop >= ti->ti_len) { + tcpstat.tcps_rcvbyteafterwin += ti->ti_len; + /* + * If a new connection request is received + * while in TIME_WAIT, drop the old connection + * and start over if the sequence numbers + * are above the previous ones. + */ + if (tiflags & TH_SYN && + tp->t_state == TCPS_TIME_WAIT && + SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { + iss = tp->rcv_nxt + TCP_ISSINCR; + tp = tcp_close(tp); + goto findpcb; + } + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_rcvwinprobe++; + } else + goto dropafterack; + } else + tcpstat.tcps_rcvbyteafterwin += todrop; + m_adj(m, -todrop); + ti->ti_len -= todrop; + tiflags &= ~(TH_PUSH|TH_FIN); + } + + /* + * If last ACK falls within this segment's sequence numbers, + * record its timestamp. + * NOTE that the test is modified according to the latest + * proposal of the tcplw@cray.com list (Braden 1993/04/26). + */ + if ((to.to_flag & TOF_TS) != 0 && + SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) { + tp->ts_recent_age = tcp_now; + tp->ts_recent = to.to_tsval; + } + + /* + * If the RST bit is set examine the state: + * SYN_RECEIVED STATE: + * If passive open, return to LISTEN state. + * If active open, inform user that connection was refused. + * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: + * Inform user that connection was reset, and close tcb. + * CLOSING, LAST_ACK, TIME_WAIT STATES + * Close the tcb. + */ + if (tiflags&TH_RST) switch (tp->t_state) { + + case TCPS_SYN_RECEIVED: + so->so_error = ECONNREFUSED; + goto close; + + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + so->so_error = ECONNRESET; + close: + tp->t_state = TCPS_CLOSED; + tcpstat.tcps_drops++; + tp = tcp_close(tp); + goto drop; + + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + tp = tcp_close(tp); + goto drop; + } + + /* + * If a SYN is in the window, then this is an + * error and we send an RST and drop the connection. + */ + if (tiflags & TH_SYN) { + tp = tcp_drop(tp, ECONNRESET); + goto dropwithreset; + } + + /* + * If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN + * flag is on (half-synchronized state), then queue data for + * later processing; else drop segment and return. + */ + if ((tiflags & TH_ACK) == 0) { + if (tp->t_state == TCPS_SYN_RECEIVED || + (tp->t_flags & TF_NEEDSYN)) + goto step6; + else + goto drop; + } + + /* + * Ack processing. + */ + switch (tp->t_state) { + + /* + * In SYN_RECEIVED state, the ack ACKs our SYN, so enter + * ESTABLISHED state and continue processing. + * The ACK was checked above. + */ + case TCPS_SYN_RECEIVED: + + tcpstat.tcps_connects++; + soisconnected(so); + /* Do window scaling? */ + if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + (TF_RCVD_SCALE|TF_REQ_SCALE)) { + tp->snd_scale = tp->requested_s_scale; + tp->rcv_scale = tp->request_r_scale; + } + /* + * Upon successful completion of 3-way handshake, + * update cache.CC if it was undefined, pass any queued + * data to the user, and advance state appropriately. + */ + if ((taop = tcp_gettaocache(inp)) != NULL && + taop->tao_cc == 0) + taop->tao_cc = tp->cc_recv; + + /* + * Make transitions: + * SYN-RECEIVED -> ESTABLISHED + * SYN-RECEIVED* -> FIN-WAIT-1 + */ + if (tp->t_flags & TF_NEEDFIN) { + tp->t_state = TCPS_FIN_WAIT_1; + tp->t_flags &= ~TF_NEEDFIN; + } else { + tp->t_state = TCPS_ESTABLISHED; + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + } + /* + * If segment contains data or ACK, will call tcp_reass() + * later; if not, do so now to pass queued data to user. + */ + if (ti->ti_len == 0 && (tiflags & TH_FIN) == 0) + (void) tcp_reass(tp, (struct tcpiphdr *)0, + (struct mbuf *)0); + tp->snd_wl1 = ti->ti_seq - 1; + /* fall into ... */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < ti->ti_ack <= tp->snd_max + * then advance tp->snd_una to ti->ti_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + + if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { + if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { + tcpstat.tcps_rcvdupack++; + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change), the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshhold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * network (they're now cached at the receiver) + * so bump cwnd by the amount in the receiver + * to keep a constant cwnd packets in the + * network. + */ + if (tp->t_timer[TCPT_REXMT] == 0 || + ti->ti_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks == tcprexmtthresh) { + tcp_seq onxt = tp->snd_nxt; + u_int win = + min(tp->snd_wnd, tp->snd_cwnd) / 2 / + tp->t_maxseg; + + if (win < 2) + win = 2; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rtt = 0; + tp->snd_nxt = ti->ti_ack; + tp->snd_cwnd = tp->t_maxseg; + (void) tcp_output(tp); + tp->snd_cwnd = tp->snd_ssthresh + + tp->t_maxseg * tp->t_dupacks; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (tp->t_dupacks > tcprexmtthresh) { + tp->snd_cwnd += tp->t_maxseg; + (void) tcp_output(tp); + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tp->t_dupacks >= tcprexmtthresh && + tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { + tcpstat.tcps_rcvacktoomuch++; + goto dropafterack; + } + /* + * If we reach this point, ACK is not a duplicate, + * i.e., it ACKs something we sent. + */ + if (tp->t_flags & TF_NEEDSYN) { + /* + * T/TCP: Connection was half-synchronized, and our + * SYN has been ACK'd (so connection is now fully + * synchronized). Go to non-starred state, + * increment snd_una for ACK of SYN, and check if + * we can do window scaling. + */ + tp->t_flags &= ~TF_NEEDSYN; + tp->snd_una++; + /* Do window scaling? */ + if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + (TF_RCVD_SCALE|TF_REQ_SCALE)) { + tp->snd_scale = tp->requested_s_scale; + tp->rcv_scale = tp->request_r_scale; + } + } + +process_ACK: + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + + /* + * If we have a timestamp reply, update smoothed + * round trip time. If no timestamp is present but + * transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ + if (to.to_flag & TOF_TS) + tcp_xmit_timer(tp, tcp_now - to.to_tsecr + 1); + else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp,tp->t_rtt); + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (ti->ti_ack == tp->snd_max) { + tp->t_timer[TCPT_REXMT] = 0; + needoutput = 1; + } else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + /* + * If no data (only SYN) was ACK'd, + * skip rest of ACK processing. + */ + if (acked == 0) + goto step6; + + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet). + */ + { + register u_int cw = tp->snd_cwnd; + register u_int incr = tp->t_maxseg; + + if (cw > tp->snd_ssthresh) + incr = incr * incr / cw; + tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale); + } + if (acked > so->so_snd.sb_cc) { + tp->snd_wnd -= so->so_snd.sb_cc; + sbdrop(&so->so_snd, (int)so->so_snd.sb_cc); + ourfinisacked = 1; + } else { + sbdrop(&so->so_snd, acked); + tp->snd_wnd -= acked; + ourfinisacked = 0; + } + if (so->so_snd.sb_flags & SB_NOTIFY) + sowwakeup(so); + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + */ + if (so->so_state & SS_CANTRCVMORE) { + soisdisconnected(so); + tp->t_timer[TCPT_2MSL] = tcp_maxidle; + } + tp->t_state = TCPS_FIN_WAIT_2; + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + /* Shorten TIME_WAIT [RFC-1644, p.28] */ + if (tp->cc_recv != 0 && + tp->t_duration < TCPTV_MSL) + tp->t_timer[TCPT_2MSL] = + tp->t_rxtcur * TCPTV_TWTRUNC; + else + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisdisconnected(so); + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + tp = tcp_close(tp); + goto drop; + } + break; + + /* + * In TIME_WAIT state the only thing that should arrive + * is a retransmission of the remote FIN. Acknowledge + * it and restart the finack timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + goto dropafterack; + } + } + +step6: + /* + * Update window information. + * Don't look at window if no ACK: TAC's send garbage on first SYN. + */ + if ((tiflags & TH_ACK) && + (SEQ_LT(tp->snd_wl1, ti->ti_seq) || + (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || + (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { + /* keep track of pure window updates */ + if (ti->ti_len == 0 && + tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) + tcpstat.tcps_rcvwinupd++; + tp->snd_wnd = tiwin; + tp->snd_wl1 = ti->ti_seq; + tp->snd_wl2 = ti->ti_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } + + /* + * Process segments with URG. + */ + if ((tiflags & TH_URG) && ti->ti_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + if (ti->ti_urp + so->so_rcv.sb_cc > sb_max) { + ti->ti_urp = 0; /* XXX */ + tiflags &= ~TH_URG; /* XXX */ + goto dodata; /* XXX */ + } + /* + * If this segment advances the known urgent pointer, + * then mark the data stream. This should not happen + * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since + * a FIN has been received from the remote side. + * In these states we ignore the URG. + * + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section as the original + * spec states (in one of two places). + */ + if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { + tp->rcv_up = ti->ti_seq + ti->ti_urp; + so->so_oobmark = so->so_rcv.sb_cc + + (tp->rcv_up - tp->rcv_nxt) - 1; + if (so->so_oobmark == 0) + so->so_state |= SS_RCVATMARK; + sohasoutofband(so); + tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); + } + /* + * Remove out of band data so doesn't get presented to user. + * This can happen independent of advancing the URG pointer, + * but if two URG's are pending at once, some out-of-band + * data may creep in... ick. + */ + if (ti->ti_urp <= (u_long)ti->ti_len +#ifdef SO_OOBINLINE + && (so->so_options & SO_OOBINLINE) == 0 +#endif + ) + tcp_pulloutofband(so, ti, m); + } else + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; +dodata: /* XXX */ + + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((ti->ti_len || (tiflags&TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + TCP_REASS(tp, ti, m, so, tiflags); + /* + * Note the amount of data that peer has sent into + * our window, in order to estimate the sender's + * buffer size. + */ + len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); + } else { + m_freem(m); + tiflags &= ~TH_FIN; + } + + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + socantrcvmore(so); + /* + * If connection is half-synchronized + * (ie NEEDSYN flag on) then delay ACK, + * so it may be piggybacked when SYN is sent. + * Otherwise, since we received a FIN then no + * more input can be expected, send ACK now. + */ + if (tp->t_flags & TF_NEEDSYN) + tp->t_flags |= TF_DELACK; + else + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + tp->t_state = TCPS_CLOSE_WAIT; + break; + + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tp->t_state = TCPS_CLOSING; + break; + + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + /* Shorten TIME_WAIT [RFC-1644, p.28] */ + if (tp->cc_recv != 0 && + tp->t_duration < TCPTV_MSL) { + tp->t_timer[TCPT_2MSL] = + tp->t_rxtcur * TCPTV_TWTRUNC; + /* For transaction client, force ACK now. */ + tp->t_flags |= TF_ACKNOW; + } + else + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisdisconnected(so); + break; + + /* + * In TIME_WAIT state restart the 2 MSL time_wait timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; + } + } +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0); +#endif + + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) + (void) tcp_output(tp); + return; + +dropafterack: + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + */ + if (tiflags & TH_RST) + goto drop; +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); +#endif + m_freem(m); + tp->t_flags |= TF_ACKNOW; + (void) tcp_output(tp); + return; + +dropwithreset: + /* + * Generate a RST, dropping incoming segment. + * Make ACK acceptable to originator of segment. + * Don't bother to respond if destination was broadcast/multicast. + */ + if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) || + IN_MULTICAST(ntohl(ti->ti_dst.s_addr))) + goto drop; +#ifdef TCPDEBUG + if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); +#endif + if (tiflags & TH_ACK) + tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); + else { + if (tiflags & TH_SYN) + ti->ti_len++; + tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, + TH_RST|TH_ACK); + } + /* destroy temporarily created socket */ + if (dropsocket) + (void) soabort(so); + return; + +drop: + /* + * Drop space held by incoming segment and return. + */ +#ifdef TCPDEBUG + if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); +#endif + m_freem(m); + /* destroy temporarily created socket */ + if (dropsocket) + (void) soabort(so); + return; +#ifndef TUBA_INCLUDE +} + +static void +tcp_dooptions(tp, cp, cnt, ti, to) + struct tcpcb *tp; + u_char *cp; + int cnt; + struct tcpiphdr *ti; + struct tcpopt *to; +{ + u_short mss = 0; + int opt, optlen; + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else { + optlen = cp[1]; + if (optlen <= 0) + break; + } + switch (opt) { + + default: + continue; + + case TCPOPT_MAXSEG: + if (optlen != TCPOLEN_MAXSEG) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + bcopy((char *) cp + 2, (char *) &mss, sizeof(mss)); + NTOHS(mss); + break; + + case TCPOPT_WINDOW: + if (optlen != TCPOLEN_WINDOW) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + tp->t_flags |= TF_RCVD_SCALE; + tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); + break; + + case TCPOPT_TIMESTAMP: + if (optlen != TCPOLEN_TIMESTAMP) + continue; + to->to_flag |= TOF_TS; + bcopy((char *)cp + 2, + (char *)&to->to_tsval, sizeof(to->to_tsval)); + NTOHL(to->to_tsval); + bcopy((char *)cp + 6, + (char *)&to->to_tsecr, sizeof(to->to_tsecr)); + NTOHL(to->to_tsecr); + + /* + * A timestamp received in a SYN makes + * it ok to send timestamp requests and replies. + */ + if (ti->ti_flags & TH_SYN) { + tp->t_flags |= TF_RCVD_TSTMP; + tp->ts_recent = to->to_tsval; + tp->ts_recent_age = tcp_now; + } + break; + case TCPOPT_CC: + if (optlen != TCPOLEN_CC) + continue; + to->to_flag |= TOF_CC; + bcopy((char *)cp + 2, + (char *)&to->to_cc, sizeof(to->to_cc)); + NTOHL(to->to_cc); + /* + * A CC or CC.new option received in a SYN makes + * it ok to send CC in subsequent segments. + */ + if (ti->ti_flags & TH_SYN) + tp->t_flags |= TF_RCVD_CC; + break; + case TCPOPT_CCNEW: + if (optlen != TCPOLEN_CC) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + to->to_flag |= TOF_CCNEW; + bcopy((char *)cp + 2, + (char *)&to->to_cc, sizeof(to->to_cc)); + NTOHL(to->to_cc); + /* + * A CC or CC.new option received in a SYN makes + * it ok to send CC in subsequent segments. + */ + tp->t_flags |= TF_RCVD_CC; + break; + case TCPOPT_CCECHO: + if (optlen != TCPOLEN_CC) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + to->to_flag |= TOF_CCECHO; + bcopy((char *)cp + 2, + (char *)&to->to_ccecho, sizeof(to->to_ccecho)); + NTOHL(to->to_ccecho); + break; + } + } + if (ti->ti_flags & TH_SYN) + tcp_mss(tp, mss); /* sets t_maxseg */ +} + +/* + * Pull out of band byte out of a segment so + * it doesn't appear in the user's data queue. + * It is still reflected in the segment length for + * sequencing purposes. + */ +static void +tcp_pulloutofband(so, ti, m) + struct socket *so; + struct tcpiphdr *ti; + register struct mbuf *m; +{ + int cnt = ti->ti_urp - 1; + + while (cnt >= 0) { + if (m->m_len > cnt) { + char *cp = mtod(m, caddr_t) + cnt; + struct tcpcb *tp = sototcpcb(so); + + tp->t_iobc = *cp; + tp->t_oobflags |= TCPOOB_HAVEDATA; + bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); + m->m_len--; + return; + } + cnt -= m->m_len; + m = m->m_next; + if (m == 0) + break; + } + panic("tcp_pulloutofband"); +} + +/* + * Collect new round-trip time estimate + * and update averages and current timeout. + */ +static void +tcp_xmit_timer(tp, rtt) + register struct tcpcb *tp; + short rtt; +{ + register int delta; + + tcpstat.tcps_rttupdated++; + tp->t_rttupdated++; + if (tp->t_srtt != 0) { + /* + * srtt is stored as fixed point with 5 bits after the + * binary point (i.e., scaled by 8). The following magic + * is equivalent to the smoothing algorithm in rfc793 with + * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed + * point). Adjust rtt to origin 0. + */ + delta = ((rtt - 1) << TCP_DELTA_SHIFT) + - (tp->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT)); + + if ((tp->t_srtt += delta) <= 0) + tp->t_srtt = 1; + + /* + * We accumulate a smoothed rtt variance (actually, a + * smoothed mean difference), then set the retransmit + * timer to smoothed rtt + 4 times the smoothed variance. + * rttvar is stored as fixed point with 4 bits after the + * binary point (scaled by 16). The following is + * equivalent to rfc793 smoothing with an alpha of .75 + * (rttvar = rttvar*3/4 + |delta| / 4). This replaces + * rfc793's wired-in beta. + */ + if (delta < 0) + delta = -delta; + delta -= tp->t_rttvar >> (TCP_RTTVAR_SHIFT - TCP_DELTA_SHIFT); + if ((tp->t_rttvar += delta) <= 0) + tp->t_rttvar = 1; + } else { + /* + * No rtt measurement yet - use the unsmoothed rtt. + * Set the variance to half the rtt (so our first + * retransmit happens at 3*rtt). + */ + tp->t_srtt = rtt << TCP_RTT_SHIFT; + tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); + } + tp->t_rtt = 0; + tp->t_rxtshift = 0; + + /* + * the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + */ + TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), + max(tp->t_rttmin, rtt + 2), TCPTV_REXMTMAX); + + /* + * We received an ack for a packet that wasn't retransmitted; + * it is probably safe to discard any error indications we've + * received recently. This isn't quite right, but close enough + * for now (a route might have failed after we sent a segment, + * and the return path might not be symmetrical). + */ + tp->t_softerror = 0; +} + +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * If none, use an mss that can be handled on the outgoing + * interface without forcing IP to fragment; if bigger than + * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES + * to utilize large mbufs. If no route is found, route has no mtu, + * or the destination isn't local, use a default, hopefully conservative + * size (usually 512 or the default IP max size, but no more than the mtu + * of the interface), as we can't discover anything about intervening + * gateways or networks. We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + * + * Also take into account the space needed for options that we + * send regularly. Make maxseg shorter by that amount to assure + * that we can send maxseg amount of data even when the options + * are present. Store the upper limit of the length of options plus + * data in maxopd. + * + * NOTE that this routine is only called when we process an incoming + * segment, for outgoing segments only tcp_mssopt is called. + * + * In case of T/TCP, we call this routine during implicit connection + * setup as well (offer = -1), to initialize maxseg from the cached + * MSS of our peer. + */ +void +tcp_mss(tp, offer) + struct tcpcb *tp; + int offer; +{ + register struct rtentry *rt; + struct ifnet *ifp; + register int rtt, mss; + u_long bufsize; + struct inpcb *inp; + struct socket *so; + struct rmxp_tao *taop; + int origoffer = offer; + + inp = tp->t_inpcb; + if ((rt = tcp_rtlookup(inp)) == NULL) { + tp->t_maxopd = tp->t_maxseg = tcp_mssdflt; + return; + } + ifp = rt->rt_ifp; + so = inp->inp_socket; + + taop = rmx_taop(rt->rt_rmx); + /* + * Offer == -1 means that we didn't receive SYN yet, + * use cached value in that case; + */ + if (offer == -1) + offer = taop->tao_mssopt; + /* + * Offer == 0 means that there was no MSS on the SYN segment, + * in this case we use tcp_mssdflt. + */ + if (offer == 0) + offer = tcp_mssdflt; + else + /* + * Sanity check: make sure that maxopd will be large + * enough to allow some data on segments even is the + * all the option space is used (40bytes). Otherwise + * funny things may happen in tcp_output. + */ + offer = max(offer, 64); + taop->tao_mssopt = offer; + + /* + * While we're here, check if there's an initial rtt + * or rttvar. Convert from the route-table units + * to scaled multiples of the slow timeout timer. + */ + if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { + /* + * XXX the lock bit for RTT indicates that the value + * is also a minimum value; this is subject to time. + */ + if (rt->rt_rmx.rmx_locks & RTV_RTT) + tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ); + tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); + tcpstat.tcps_usedrtt++; + if (rt->rt_rmx.rmx_rttvar) { + tp->t_rttvar = rt->rt_rmx.rmx_rttvar / + (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); + tcpstat.tcps_usedrttvar++; + } else { + /* default variation is +- 1 rtt */ + tp->t_rttvar = + tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE; + } + TCPT_RANGESET(tp->t_rxtcur, + ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, + tp->t_rttmin, TCPTV_REXMTMAX); + } + /* + * if there's an mtu associated with the route, use it + */ + if (rt->rt_rmx.rmx_mtu) + mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); + else + { + mss = ifp->if_mtu - sizeof(struct tcpiphdr); + if (!in_localaddr(inp->inp_faddr)) + mss = min(mss, tcp_mssdflt); + } + mss = min(mss, offer); + /* + * maxopd stores the maximum length of data AND options + * in a segment; maxseg is the amount of data in a normal + * segment. We need to store this value (maxopd) apart + * from maxseg, because now every segment carries options + * and thus we normally have somewhat less data in segments. + */ + tp->t_maxopd = mss; + + /* + * In case of T/TCP, origoffer==-1 indicates, that no segments + * were received yet. In this case we just guess, otherwise + * we do the same as before T/TCP. + */ + if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + (origoffer == -1 || + (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)) + mss -= TCPOLEN_TSTAMP_APPA; + if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && + (origoffer == -1 || + (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC)) + mss -= TCPOLEN_CC_APPA; + +#if (MCLBYTES & (MCLBYTES - 1)) == 0 + if (mss > MCLBYTES) + mss &= ~(MCLBYTES-1); +#else + if (mss > MCLBYTES) + mss = mss / MCLBYTES * MCLBYTES; +#endif + /* + * If there's a pipesize, change the socket buffer + * to that size. Make the socket buffers an integral + * number of mss units; if the mss is larger than + * the socket buffer, decrease the mss. + */ +#ifdef RTV_SPIPE + if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0) +#endif + bufsize = so->so_snd.sb_hiwat; + if (bufsize < mss) + mss = bufsize; + else { + bufsize = roundup(bufsize, mss); + if (bufsize > sb_max) + bufsize = sb_max; + (void)sbreserve(&so->so_snd, bufsize); + } + tp->t_maxseg = mss; + +#ifdef RTV_RPIPE + if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0) +#endif + bufsize = so->so_rcv.sb_hiwat; + if (bufsize > mss) { + bufsize = roundup(bufsize, mss); + if (bufsize > sb_max) + bufsize = sb_max; + (void)sbreserve(&so->so_rcv, bufsize); + } + /* + * Don't force slow-start on local network. + */ + if (!in_localaddr(inp->inp_faddr)) + tp->snd_cwnd = mss; + + if (rt->rt_rmx.rmx_ssthresh) { + /* + * There's some sort of gateway or interface + * buffer limit on the path. Use this to set + * the slow start threshhold, but set the + * threshold to no less than 2*mss. + */ + tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh); + tcpstat.tcps_usedssthresh++; + } +} + +/* + * Determine the MSS option to send on an outgoing SYN. + */ +int +tcp_mssopt(tp) + struct tcpcb *tp; +{ + struct rtentry *rt; + + rt = tcp_rtlookup(tp->t_inpcb); + if (rt == NULL) + return tcp_mssdflt; + + return rt->rt_ifp->if_mtu - sizeof(struct tcpiphdr); +} +#endif /* TUBA_INCLUDE */ diff --git a/cpukit/libnetworking/netinet/tcp_output.c b/cpukit/libnetworking/netinet/tcp_output.c new file mode 100644 index 0000000000..cbb5218dce --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_output.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_output.c 8.4 (Berkeley) 5/24/95 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#define TCPOUTFLAGS +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +#endif + +#ifdef notyet +extern struct mbuf *m_copypack(); +#endif + + +/* + * Tcp output routine: figure out what should be sent and send it. + */ +int +tcp_output(tp) + register struct tcpcb *tp; +{ + register struct socket *so = tp->t_inpcb->inp_socket; + register long len, win; + int off, flags, error; + register struct mbuf *m; + register struct tcpiphdr *ti; + u_char opt[TCP_MAXOLEN]; + unsigned optlen, hdrlen; + int idle, sendalot; + struct rmxp_tao *taop; + struct rmxp_tao tao_noncached; + + /* + * Determine length of data that should be transmitted, + * and flags that will be used. + * If there is some data or critical controls (SYN, RST) + * to send, then transmit; otherwise, investigate further. + */ + idle = (tp->snd_max == tp->snd_una); + if (idle && tp->t_idle >= tp->t_rxtcur) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tp->snd_cwnd = tp->t_maxseg; +again: + sendalot = 0; + off = tp->snd_nxt - tp->snd_una; + win = min(tp->snd_wnd, tp->snd_cwnd); + + flags = tcp_outflags[tp->t_state]; + /* + * Get standard flags, and add SYN or FIN if requested by 'hidden' + * state flags. + */ + if (tp->t_flags & TF_NEEDFIN) + flags |= TH_FIN; + if (tp->t_flags & TF_NEEDSYN) + flags |= TH_SYN; + + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ + if (tp->t_force) { + if (win == 0) { + /* + * If we still have some data to send, then + * clear the FIN bit. Usually this would + * happen below when it realizes that we + * aren't sending all the data. However, + * if we have exactly 1 byte of unset data, + * then it won't clear the FIN bit below, + * and if we are in persist state, we wind + * up sending the packet without recording + * that we sent the FIN bit. + * + * We can't just blindly clear the FIN bit, + * because if we don't have any more data + * to send then the probe will be the FIN + * itself. + */ + if (off < so->so_snd.sb_cc) + flags &= ~TH_FIN; + win = 1; + } else { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + + len = min(so->so_snd.sb_cc, win) - off; + + if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) { + taop = &tao_noncached; + bzero(taop, sizeof(*taop)); + } + + /* + * Lop off SYN bit if it has already been sent. However, if this + * is SYN-SENT state and if segment contains data and if we don't + * know that foreign host supports TAO, suppress sending segment. + */ + if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) { + flags &= ~TH_SYN; + off--, len++; + if (len > 0 && tp->t_state == TCPS_SYN_SENT && + taop->tao_ccsent == 0) + return 0; + } + + /* + * Be careful not to send data and/or FIN on SYN segments + * in cases when no CC option will be sent. + * This measure is needed to prevent interoperability problems + * with not fully conformant TCP implementations. + */ + if ((flags & TH_SYN) && + ((tp->t_flags & TF_NOOPT) || !(tp->t_flags & TF_REQ_CC) || + ((flags & TH_ACK) && !(tp->t_flags & TF_RCVD_CC)))) { + len = 0; + flags &= ~TH_FIN; + } + + if (len < 0) { + /* + * If FIN has been sent but not acked, + * but we haven't been called to retransmit, + * len will be -1. Otherwise, window shrank + * after we sent into it. If window shrank to 0, + * cancel pending retransmit, pull snd_nxt back + * to (closed) window, and set the persist timer + * if it isn't already going. If the window didn't + * close completely, just wait for an ACK. + */ + len = 0; + if (win == 0) { + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rxtshift = 0; + tp->snd_nxt = tp->snd_una; + if (tp->t_timer[TCPT_PERSIST] == 0) + tcp_setpersist(tp); + } + } + if (len > tp->t_maxseg) { + len = tp->t_maxseg; + sendalot = 1; + } + if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) + flags &= ~TH_FIN; + + win = sbspace(&so->so_rcv); + + /* + * Sender silly window avoidance. If connection is idle + * and can send all data, a maximum segment, + * at least a maximum default-size segment do it, + * or are forced, do it; otherwise don't bother. + * If peer's buffer is tiny, then send + * when window is at least half open. + * If retransmitting (possibly after persist timer forced us + * to send into a small window), then must resend. + */ + if (len) { + if (len == tp->t_maxseg) + goto send; + if ((idle || tp->t_flags & TF_NODELAY) && + (tp->t_flags & TF_NOPUSH) == 0 && + len + off >= so->so_snd.sb_cc) + goto send; + if (tp->t_force) + goto send; + if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) + goto send; + if (SEQ_LT(tp->snd_nxt, tp->snd_max)) + goto send; + } + + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input). If the difference is at least two + * max size segments, or at least 50% of the maximum possible + * window, then want to send a window update to peer. + */ + if (win > 0) { + /* + * "adv" is the amount we can increase the window, + * taking into account that we are limited by + * TCP_MAXWIN << tp->rcv_scale. + */ + long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - + (tp->rcv_adv - tp->rcv_nxt); + + if (adv >= (long) (2 * tp->t_maxseg)) + goto send; + if (2 * adv >= (long) so->so_rcv.sb_hiwat) + goto send; + } + + /* + * Send if we owe peer an ACK. + */ + if (tp->t_flags & TF_ACKNOW) + goto send; + if ((flags & TH_RST) || + ((flags & TH_SYN) && (tp->t_flags & TF_NEEDSYN) == 0)) + goto send; + if (SEQ_GT(tp->snd_up, tp->snd_una)) + goto send; + /* + * If our state indicates that FIN should be sent + * and we have not yet done so, or we're retransmitting the FIN, + * then we need to send. + */ + if (flags & TH_FIN && + ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) + goto send; + + /* + * TCP window updates are not reliable, rather a polling protocol + * using ``persist'' packets is used to insure receipt of window + * updates. The three ``states'' for the output side are: + * idle not doing retransmits or persists + * persisting to move a small or zero window + * (re)transmitting and thereby not persisting + * + * tp->t_timer[TCPT_PERSIST] + * is set when we are in persist state. + * tp->t_force + * is set when we are called to send a persist packet. + * tp->t_timer[TCPT_REXMT] + * is set when we are retransmitting + * The output side is idle when both timers are zero. + * + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise force out a byte. + */ + if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_rxtshift = 0; + tcp_setpersist(tp); + } + + /* + * No reason to send a segment, just return. + */ + return (0); + +send: + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set not to do any options. + * NOTE: we assume that the IP/TCP header plus TCP options + * always fit in a single mbuf, leaving room for a maximum + * link header, i.e. + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + */ + optlen = 0; + hdrlen = sizeof (struct tcpiphdr); + if (flags & TH_SYN) { + tp->snd_nxt = tp->iss; + if ((tp->t_flags & TF_NOOPT) == 0) { + u_short mss; + + opt[0] = TCPOPT_MAXSEG; + opt[1] = TCPOLEN_MAXSEG; + mss = htons((u_short) tcp_mssopt(tp)); + (void)memcpy(opt + 2, &mss, sizeof(mss)); + optlen = TCPOLEN_MAXSEG; + + if ((tp->t_flags & TF_REQ_SCALE) && + ((flags & TH_ACK) == 0 || + (tp->t_flags & TF_RCVD_SCALE))) { + *((u_long *) (opt + optlen)) = htonl( + TCPOPT_NOP << 24 | + TCPOPT_WINDOW << 16 | + TCPOLEN_WINDOW << 8 | + tp->request_r_scale); + optlen += 4; + } + } + } + + /* + * Send a timestamp and echo-reply if this is a SYN and our side + * wants to use timestamps (TF_REQ_TSTMP is set) or both our side + * and our peer have sent timestamps in our SYN's. + */ + if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + (flags & TH_RST) == 0 && + ((flags & TH_ACK) == 0 || + (tp->t_flags & TF_RCVD_TSTMP))) { + u_long *lp = (u_long *)(opt + optlen); + + /* Form timestamp option as shown in appendix A of RFC 1323. */ + *lp++ = htonl(TCPOPT_TSTAMP_HDR); + *lp++ = htonl(tcp_now); + *lp = htonl(tp->ts_recent); + optlen += TCPOLEN_TSTAMP_APPA; + } + + /* + * Send `CC-family' options if our side wants to use them (TF_REQ_CC), + * options are allowed (!TF_NOOPT) and it's not a RST. + */ + if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && + (flags & TH_RST) == 0) { + switch (flags & (TH_SYN|TH_ACK)) { + /* + * This is a normal ACK, send CC if we received CC before + * from our peer. + */ + case TH_ACK: + if (!(tp->t_flags & TF_RCVD_CC)) + break; + /*FALLTHROUGH*/ + + /* + * We can only get here in T/TCP's SYN_SENT* state, when + * we're a sending a non-SYN segment without waiting for + * the ACK of our SYN. A check above assures that we only + * do this if our peer understands T/TCP. + */ + case 0: + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_CC; + opt[optlen++] = TCPOLEN_CC; + *(u_int32_t *)&opt[optlen] = htonl(tp->cc_send); + + optlen += 4; + break; + + /* + * This is our initial SYN, check whether we have to use + * CC or CC.new. + */ + case TH_SYN: + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = tp->t_flags & TF_SENDCCNEW ? + TCPOPT_CCNEW : TCPOPT_CC; + opt[optlen++] = TCPOLEN_CC; + *(u_int32_t *)&opt[optlen] = htonl(tp->cc_send); + optlen += 4; + break; + + /* + * This is a SYN,ACK; send CC and CC.echo if we received + * CC from our peer. + */ + case (TH_SYN|TH_ACK): + if (tp->t_flags & TF_RCVD_CC) { + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_CC; + opt[optlen++] = TCPOLEN_CC; + *(u_int32_t *)&opt[optlen] = + htonl(tp->cc_send); + optlen += 4; + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_NOP; + opt[optlen++] = TCPOPT_CCECHO; + opt[optlen++] = TCPOLEN_CC; + *(u_int32_t *)&opt[optlen] = + htonl(tp->cc_recv); + optlen += 4; + } + break; + } + } + + hdrlen += optlen; + + /* + * Adjust data length if insertion of options will + * bump the packet length beyond the t_maxopd length. + * Clear the FIN bit because we cut off the tail of + * the segment. + */ + if (len + optlen > tp->t_maxopd) { + /* + * If there is still more to send, don't close the connection. + */ + flags &= ~TH_FIN; + len = tp->t_maxopd - optlen; + sendalot = 1; + } + +/*#ifdef DIAGNOSTIC*/ + if (max_linkhdr + hdrlen > MHLEN) + panic("tcphdr too big"); +/*#endif*/ + + /* + * Grab a header mbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ + if (len) { + if (tp->t_force && len == 1) + tcpstat.tcps_sndprobe++; + else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { + tcpstat.tcps_sndrexmitpack++; + tcpstat.tcps_sndrexmitbyte += len; + } else { + tcpstat.tcps_sndpack++; + tcpstat.tcps_sndbyte += len; + } +#ifdef notyet + if ((m = m_copypack(so->so_snd.sb_mb, off, + (int)len, max_linkhdr + hdrlen)) == 0) { + error = ENOBUFS; + goto out; + } + /* + * m_copypack left space for our hdr; use it. + */ + m->m_len += hdrlen; + m->m_data -= hdrlen; +#else + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == NULL) { + error = ENOBUFS; + goto out; + } + m->m_data += max_linkhdr; + m->m_len = hdrlen; + if (len <= MHLEN - hdrlen - max_linkhdr) { + m_copydata(so->so_snd.sb_mb, off, (int) len, + mtod(m, caddr_t) + hdrlen); + m->m_len += len; + } else { + m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); + if (m->m_next == 0) { + (void) m_free(m); + error = ENOBUFS; + goto out; + } + } +#endif + /* + * If we're sending everything we've got, set PUSH. + * (This will keep happy those implementations which only + * give data to the user when a buffer fills or + * a PUSH comes in.) + */ + if (off + len == so->so_snd.sb_cc) + flags |= TH_PUSH; + } else { + if (tp->t_flags & TF_ACKNOW) + tcpstat.tcps_sndacks++; + else if (flags & (TH_SYN|TH_FIN|TH_RST)) + tcpstat.tcps_sndctrl++; + else if (SEQ_GT(tp->snd_up, tp->snd_una)) + tcpstat.tcps_sndurg++; + else + tcpstat.tcps_sndwinup++; + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == NULL) { + error = ENOBUFS; + goto out; + } + m->m_data += max_linkhdr; + m->m_len = hdrlen; + } + m->m_pkthdr.rcvif = (struct ifnet *)0; + ti = mtod(m, struct tcpiphdr *); + if (tp->t_template == 0) + panic("tcp_output"); + (void)memcpy(ti, tp->t_template, sizeof (struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + * If resending a FIN, be sure not to use a new sequence number. + */ + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + tp->snd_nxt == tp->snd_max) + tp->snd_nxt--; + /* + * If we are doing retransmissions, then snd_nxt will + * not reflect the first unsent octet. For ACK only + * packets, we do not want the sequence number of the + * retransmitted packet, we want the sequence number + * of the next unsent octet. So, if there is no data + * (and no SYN or FIN), use snd_max instead of snd_nxt + * when filling in ti_seq. But if we are in persist + * state, snd_max might reflect one byte beyond the + * right edge of the window, so use snd_nxt in that + * case, since we know we aren't doing a retransmission. + * (retransmit and persist are mutually exclusive...) + */ + if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) + ti->ti_seq = htonl(tp->snd_nxt); + else + ti->ti_seq = htonl(tp->snd_max); + ti->ti_ack = htonl(tp->rcv_nxt); + if (optlen) { + bcopy(opt, ti + 1, optlen); + ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; + } + ti->ti_flags = flags; + /* + * Calculate receive window. Don't shrink window, + * but avoid silly window syndrome. + */ + if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg) + win = 0; + if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) + win = (long)(tp->rcv_adv - tp->rcv_nxt); + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + ti->ti_win = htons((u_short) (win>>tp->rcv_scale)); + if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { + ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt)); + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_up = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len + optlen) + ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + + optlen + len)); + ti->ti_sum = in_cksum(m, (int)(hdrlen + len)); + + /* + * In transmit state, time the transmission and arrange for + * the retransmit. In persist state, just set snd_max. + */ + if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { + tcp_seq startseq = tp->snd_nxt; + + /* + * Advance snd_nxt over sequence space of this segment. + */ + if (flags & (TH_SYN|TH_FIN)) { + if (flags & TH_SYN) + tp->snd_nxt++; + if (flags & TH_FIN) { + tp->snd_nxt++; + tp->t_flags |= TF_SENTFIN; + } + } + tp->snd_nxt += len; + if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { + tp->snd_max = tp->snd_nxt; + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = startseq; + tcpstat.tcps_segstimed++; + } + } + + /* + * Set retransmit timer if not currently set, + * and not doing an ack or a keep-alive probe. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0 && + tp->snd_nxt != tp->snd_una) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + } else + if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) + tp->snd_max = tp->snd_nxt + len; + +#ifdef TCPDEBUG + /* + * Trace. + */ + if (so->so_options & SO_DEBUG) + tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0); +#endif + + /* + * Fill in IP length and desired time to live and + * send to IP level. There should be a better way + * to handle ttl and tos; we could keep them in + * the template, but need a way to checksum without them. + */ + m->m_pkthdr.len = hdrlen + len; +#ifdef TUBA + if (tp->t_tuba_pcb) + error = tuba_output(m, tp); + else +#endif + { +#if 1 + struct rtentry *rt; +#endif + ((struct ip *)ti)->ip_len = m->m_pkthdr.len; + ((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip_ttl; /* XXX */ + ((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip_tos; /* XXX */ +#if 1 + /* + * See if we should do MTU discovery. We do it only if the following + * are true: + * 1) we have a valid route to the destination + * 2) the MTU is not locked (if it is, then discovery has been + * disabled) + */ + if ((rt = tp->t_inpcb->inp_route.ro_rt) + && rt->rt_flags & RTF_UP + && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { + ((struct ip *)ti)->ip_off |= IP_DF; + } +#endif + error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, + so->so_options & SO_DONTROUTE, 0); + } + if (error) { +out: + if (error == ENOBUFS) { + tcp_quench(tp->t_inpcb, 0); + return (0); + } +#if 1 + if (error == EMSGSIZE) { + /* + * ip_output() will have already fixed the route + * for us. tcp_mtudisc() will, as its last action, + * initiate retransmission, so it is important to + * not do so here. + */ + tcp_mtudisc(tp->t_inpcb, 0); + return 0; + } +#endif + if ((error == EHOSTUNREACH || error == ENETDOWN) + && TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_softerror = error; + return (0); + } + return (error); + } + tcpstat.tcps_sndtotal++; + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertised window. + * Any pending ACK has now been sent. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->last_ack_sent = tp->rcv_nxt; + tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); + if (sendalot) + goto again; + return (0); +} + +void +tcp_setpersist(tp) + register struct tcpcb *tp; +{ + register int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + + if (tp->t_timer[TCPT_REXMT]) + panic("tcp_output REXMT"); + /* + * Start/restart persistance timer. + */ + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], + t * tcp_backoff[tp->t_rxtshift], + TCPTV_PERSMIN, TCPTV_PERSMAX); + if (tp->t_rxtshift < TCP_MAXRXTSHIFT) + tp->t_rxtshift++; +} diff --git a/cpukit/libnetworking/netinet/tcp_seq.h b/cpukit/libnetworking/netinet/tcp_seq.h new file mode 100644 index 0000000000..8cccf199e1 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_seq.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_seq.h 8.3 (Berkeley) 6/21/95 + * $Id$ + */ + +#ifndef _NETINET_TCP_SEQ_H_ +#define _NETINET_TCP_SEQ_H_ +/* + * TCP sequence numbers are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* for modulo comparisons of timestamps */ +#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) +#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * TCP connection counts are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define CC_LT(a,b) ((int)((a)-(b)) < 0) +#define CC_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define CC_GT(a,b) ((int)((a)-(b)) > 0) +#define CC_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* Macro to increment a CC: skip 0 which has a special meaning */ +#define CC_INC(c) (++(c) == 0 ? ++(c) : (c)) + +/* + * Macros to initialize tcp sequence numbers for + * send and receive from initial send and receive + * sequence numbers. + */ +#define tcp_rcvseqinit(tp) \ + (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 + +#define tcp_sendseqinit(tp) \ + (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \ + (tp)->iss + +#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) + /* timestamp wrap-around time */ + +#ifdef KERNEL +extern tcp_cc tcp_ccgen; /* global connection count */ + +/* + * Increment for tcp_iss each second. + * This is designed to increment at the standard 250 KB/s, + * but with a random component averaging 128 KB. + * We also increment tcp_iss by a quarter of this amount + * each time we use the value for a new connection. + * If defined, the tcp_random18() macro should produce a + * number in the range [0-0x3ffff] that is hard to predict. + */ +#ifndef tcp_random18 +#define tcp_random18() ((random() >> 14) & 0x3ffff) +#endif +#define TCP_ISSINCR (122*1024 + tcp_random18()) + +extern tcp_seq tcp_iss; /* tcp initial send seq # */ +#else +#define TCP_ISSINCR (250*1024) /* increment for tcp_iss each second */ +#endif /* KERNEL */ +#endif /* _NETINET_TCP_SEQ_H_ */ diff --git a/cpukit/libnetworking/netinet/tcp_subr.c b/cpukit/libnetworking/netinet/tcp_subr.c new file mode 100644 index 0000000000..e268e32f19 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_subr.c @@ -0,0 +1,632 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <net/route.h> +#include <net/if.h> + +#define _IP_VHL +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +#endif + +int tcp_mssdflt = TCP_MSS; +SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, + CTLFLAG_RW, &tcp_mssdflt , 0, ""); + +static int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; +SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, + CTLFLAG_RW, &tcp_rttdflt , 0, ""); + +static int tcp_do_rfc1323 = 1; +SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, + CTLFLAG_RW, &tcp_do_rfc1323 , 0, ""); + +static int tcp_do_rfc1644 = 1; +SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1644, rfc1644, + CTLFLAG_RW, &tcp_do_rfc1644 , 0, ""); + +static void tcp_cleartaocache(void); +static void tcp_notify __P((struct inpcb *, int)); + +/* + * Target size of TCP PCB hash table. Will be rounded down to a prime + * number. + */ +#ifndef TCBHASHSIZE +#define TCBHASHSIZE 128 +#endif + +/* + * Tcp initialization + */ +void +tcp_init() +{ + + tcp_iss = random(); /* wrong, but better than a constant */ + tcp_ccgen = 1; + tcp_cleartaocache(); + LIST_INIT(&tcb); + tcbinfo.listhead = &tcb; + tcbinfo.hashbase = hashinit(TCBHASHSIZE, M_PCB, &tcbinfo.hashmask); + if (max_protohdr < sizeof(struct tcpiphdr)) + max_protohdr = sizeof(struct tcpiphdr); + if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN) + panic("tcp_init"); +} + +/* + * Create template to be used to send tcp packets on a connection. + * Call after host entry created, allocates an mbuf and fills + * in a skeletal tcp/ip header, minimizing the amount of work + * necessary when the connection is used. + */ +struct tcpiphdr * +tcp_template(tp) + struct tcpcb *tp; +{ + register struct inpcb *inp = tp->t_inpcb; + register struct mbuf *m; + register struct tcpiphdr *n; + + if ((n = tp->t_template) == 0) { + m = m_get(M_DONTWAIT, MT_HEADER); + if (m == NULL) + return (0); + m->m_len = sizeof (struct tcpiphdr); + n = mtod(m, struct tcpiphdr *); + } + n->ti_next = n->ti_prev = 0; + n->ti_x1 = 0; + n->ti_pr = IPPROTO_TCP; + n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); + n->ti_src = inp->inp_laddr; + n->ti_dst = inp->inp_faddr; + n->ti_sport = inp->inp_lport; + n->ti_dport = inp->inp_fport; + n->ti_seq = 0; + n->ti_ack = 0; + n->ti_x2 = 0; + n->ti_off = 5; + n->ti_flags = 0; + n->ti_win = 0; + n->ti_sum = 0; + n->ti_urp = 0; + return (n); +} + +/* + * Send a single message to the TCP at address specified by + * the given TCP/IP header. If m == 0, then we make a copy + * of the tcpiphdr at ti and send directly to the addressed host. + * This is used to force keep alive messages out using the TCP + * template for a connection tp->t_template. If flags are given + * then we send a message back to the TCP which originated the + * segment ti, and discard the mbuf containing it and any other + * attached mbufs. + * + * In any case the ack and sequence number of the transmitted + * segment are as specified by the parameters. + * + * NOTE: If m != NULL, then ti must point to *inside* the mbuf. + */ +void +tcp_respond(tp, ti, m, ack, seq, flags) + struct tcpcb *tp; + register struct tcpiphdr *ti; + register struct mbuf *m; + tcp_seq ack, seq; + int flags; +{ + register int tlen; + int win = 0; + struct route *ro = 0; + struct route sro; + + if (tp) { + win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); + ro = &tp->t_inpcb->inp_route; + } else { + ro = &sro; + bzero(ro, sizeof *ro); + } + if (m == 0) { + m = m_gethdr(M_DONTWAIT, MT_HEADER); + if (m == NULL) + return; +#ifdef TCP_COMPAT_42 + tlen = 1; +#else + tlen = 0; +#endif + m->m_data += max_linkhdr; + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + flags = TH_ACK; + } else { + m_freem(m->m_next); + m->m_next = 0; + m->m_data = (caddr_t)ti; + m->m_len = sizeof (struct tcpiphdr); + tlen = 0; +#define xchg(a,b,type) { type t; t=a; a=b; b=t; } + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); + xchg(ti->ti_dport, ti->ti_sport, u_short); +#undef xchg + } + ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); + tlen += sizeof (struct tcpiphdr); + m->m_len = tlen; + m->m_pkthdr.len = tlen; + m->m_pkthdr.rcvif = (struct ifnet *) 0; + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_seq = htonl(seq); + ti->ti_ack = htonl(ack); + ti->ti_x2 = 0; + ti->ti_off = sizeof (struct tcphdr) >> 2; + ti->ti_flags = flags; + if (tp) + ti->ti_win = htons((u_short) (win >> tp->rcv_scale)); + else + ti->ti_win = htons((u_short)win); + ti->ti_urp = 0; + ti->ti_sum = 0; + ti->ti_sum = in_cksum(m, tlen); + ((struct ip *)ti)->ip_len = tlen; + ((struct ip *)ti)->ip_ttl = ip_defttl; +#ifdef TCPDEBUG + if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_OUTPUT, 0, tp, ti, 0); +#endif + (void) ip_output(m, NULL, ro, 0, NULL); + if (ro == &sro && ro->ro_rt) { + RTFREE(ro->ro_rt); + } +} + +/* + * Create a new TCP control block, making an + * empty reassembly queue and hooking it to the argument + * protocol control block. + */ +struct tcpcb * +tcp_newtcpcb(inp) + struct inpcb *inp; +{ + register struct tcpcb *tp; + + tp = malloc(sizeof(*tp), M_PCB, M_NOWAIT); + if (tp == NULL) + return ((struct tcpcb *)0); + bzero((char *) tp, sizeof(struct tcpcb)); + tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; + tp->t_maxseg = tp->t_maxopd = tcp_mssdflt; + + if (tcp_do_rfc1323) + tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); + if (tcp_do_rfc1644) + tp->t_flags |= TF_REQ_CC; + tp->t_inpcb = inp; + /* + * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no + * rtt estimate. Set rttvar so that srtt + 4 * rttvar gives + * reasonable initial retransmit time. + */ + tp->t_srtt = TCPTV_SRTTBASE; + tp->t_rttvar = ((TCPTV_RTOBASE - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4; + tp->t_rttmin = TCPTV_MIN; + tp->t_rxtcur = TCPTV_RTOBASE; + tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + inp->inp_ip_ttl = ip_defttl; + inp->inp_ppcb = (caddr_t)tp; + return (tp); +} + +/* + * Drop a TCP connection, reporting + * the specified error. If connection is synchronized, + * then send a RST to peer. + */ +struct tcpcb * +tcp_drop(tp, errnum) + register struct tcpcb *tp; + int errnum; +{ + struct socket *so = tp->t_inpcb->inp_socket; + + if (TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_state = TCPS_CLOSED; + (void) tcp_output(tp); + tcpstat.tcps_drops++; + } else + tcpstat.tcps_conndrops++; + if (errnum == ETIMEDOUT && tp->t_softerror) + errnum = tp->t_softerror; + so->so_error = errnum; + return (tcp_close(tp)); +} + +/* + * Close a TCP control block: + * discard all space held by the tcp + * discard internet protocol block + * wake up any sleepers + */ +struct tcpcb * +tcp_close(tp) + register struct tcpcb *tp; +{ + register struct tcpiphdr *t; + struct inpcb *inp = tp->t_inpcb; + struct socket *so = inp->inp_socket; + register struct mbuf *m; + register struct rtentry *rt; + + /* + * If we got enough samples through the srtt filter, + * save the rtt and rttvar in the routing entry. + * 'Enough' is arbitrarily defined as the 16 samples. + * 16 samples is enough for the srtt filter to converge + * to within 5% of the correct value; fewer samples and + * we could save a very bogus rtt. + * + * Don't update the default route's characteristics and don't + * update anything that the user "locked". + */ + if (tp->t_rttupdated >= 16 && + (rt = inp->inp_route.ro_rt) && + ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { + register u_long i = 0; + + if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { + i = tp->t_srtt * + (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); + if (rt->rt_rmx.rmx_rtt && i) + /* + * filter this update to half the old & half + * the new values, converting scale. + * See route.h and tcp_var.h for a + * description of the scaling constants. + */ + rt->rt_rmx.rmx_rtt = + (rt->rt_rmx.rmx_rtt + i) / 2; + else + rt->rt_rmx.rmx_rtt = i; + tcpstat.tcps_cachedrtt++; + } + if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { + i = tp->t_rttvar * + (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); + if (rt->rt_rmx.rmx_rttvar && i) + rt->rt_rmx.rmx_rttvar = + (rt->rt_rmx.rmx_rttvar + i) / 2; + else + rt->rt_rmx.rmx_rttvar = i; + tcpstat.tcps_cachedrttvar++; + } + /* + * update the pipelimit (ssthresh) if it has been updated + * already or if a pipesize was specified & the threshhold + * got below half the pipesize. I.e., wait for bad news + * before we start updating, then update on both good + * and bad news. + */ + if (((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && + ((i = tp->snd_ssthresh) != 0) && rt->rt_rmx.rmx_ssthresh) || + i < (rt->rt_rmx.rmx_sendpipe / 2)) { + /* + * convert the limit from user data bytes to + * packets then to packet data bytes. + */ + i = (i + tp->t_maxseg / 2) / tp->t_maxseg; + if (i < 2) + i = 2; + i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); + if (rt->rt_rmx.rmx_ssthresh) + rt->rt_rmx.rmx_ssthresh = + (rt->rt_rmx.rmx_ssthresh + i) / 2; + else + rt->rt_rmx.rmx_ssthresh = i; + tcpstat.tcps_cachedssthresh++; + } + } + /* free the reassembly queue, if any */ + t = tp->seg_next; + while (t != (struct tcpiphdr *)tp) { + t = (struct tcpiphdr *)t->ti_next; + m = REASS_MBUF((struct tcpiphdr *)t->ti_prev); + remque(t->ti_prev); + m_freem(m); + } + if (tp->t_template) + (void) m_free(dtom(tp->t_template)); + free(tp, M_PCB); + inp->inp_ppcb = 0; + soisdisconnected(so); + in_pcbdetach(inp); + tcpstat.tcps_closed++; + return ((struct tcpcb *)0); +} + +void +tcp_drain() +{ + +} + +/* + * Notify a tcp user of an asynchronous error; + * store error as soft error, but wake up user + * (for now, won't do anything until can select for soft error). + */ +static void +tcp_notify(inp, error) + struct inpcb *inp; + int error; +{ + register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; + register struct socket *so = inp->inp_socket; + + /* + * Ignore some errors if we are hooked up. + * If connection hasn't completed, has retransmitted several times, + * and receives a second error, give up now. This is better + * than waiting a long time to establish a connection that + * can never complete. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (error == EHOSTUNREACH || error == ENETUNREACH || + error == EHOSTDOWN)) { + return; + } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 && + tp->t_softerror) + so->so_error = error; + else + tp->t_softerror = error; + soconnwakeup (so); + sorwakeup(so); + sowwakeup(so); +} + +void +tcp_ctlinput(cmd, sa, vip) + int cmd; + struct sockaddr *sa; + void *vip; +{ + register struct ip *ip = vip; + register struct tcphdr *th; + void (*notify) __P((struct inpcb *, int)) = tcp_notify; + + if (cmd == PRC_QUENCH) + notify = tcp_quench; +#if 1 + else if (cmd == PRC_MSGSIZE) + notify = tcp_mtudisc; +#endif + else if (!PRC_IS_REDIRECT(cmd) && + ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)) + return; + if (ip) { + th = (struct tcphdr *)((caddr_t)ip + + (IP_VHL_HL(ip->ip_vhl) << 2)); + in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, + cmd, notify); + } else + in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); +} + +/* + * When a source quench is received, close congestion window + * to one segment. We will gradually open it again as we proceed. + */ +void +tcp_quench(inp, errnum) + struct inpcb *inp; + int errnum; +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp) + tp->snd_cwnd = tp->t_maxseg; +} + +#if 1 +/* + * When `need fragmentation' ICMP is received, update our idea of the MSS + * based on the new value in the route. Also nudge TCP to send something, + * since we know the packet we just sent was dropped. + * This duplicates some code in the tcp_mss() function in tcp_input.c. + */ +void +tcp_mtudisc(inp, errnum) + struct inpcb *inp; + int errnum; +{ + struct tcpcb *tp = intotcpcb(inp); + struct rtentry *rt; + struct rmxp_tao *taop; + struct socket *so = inp->inp_socket; + int offered; + int mss; + + if (tp) { + rt = tcp_rtlookup(inp); + if (!rt || !rt->rt_rmx.rmx_mtu) { + tp->t_maxopd = tp->t_maxseg = tcp_mssdflt; + return; + } + taop = rmx_taop(rt->rt_rmx); + offered = taop->tao_mssopt; + mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); + if (offered) + mss = min(mss, offered); + /* + * XXX - The above conditional probably violates the TCP + * spec. The problem is that, since we don't know the + * other end's MSS, we are supposed to use a conservative + * default. But, if we do that, then MTU discovery will + * never actually take place, because the conservative + * default is much less than the MTUs typically seen + * on the Internet today. For the moment, we'll sweep + * this under the carpet. + * + * The conservative default might not actually be a problem + * if the only case this occurs is when sending an initial + * SYN with options and data to a host we've never talked + * to before. Then, they will reply with an MSS value which + * will get recorded and the new parameters should get + * recomputed. For Further Study. + */ + if (tp->t_maxopd <= mss) + return; + tp->t_maxopd = mss; + + if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP) + mss -= TCPOLEN_TSTAMP_APPA; + if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && + (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC) + mss -= TCPOLEN_CC_APPA; +#if (MCLBYTES & (MCLBYTES - 1)) == 0 + if (mss > MCLBYTES) + mss &= ~(MCLBYTES-1); +#else + if (mss > MCLBYTES) + mss = mss / MCLBYTES * MCLBYTES; +#endif + if (so->so_snd.sb_hiwat < mss) + mss = so->so_snd.sb_hiwat; + + tp->t_maxseg = mss; + + tcpstat.tcps_mturesent++; + tp->t_rtt = 0; + tp->snd_nxt = tp->snd_una; + tcp_output(tp); + } +} +#endif + +/* + * Look-up the routing entry to the peer of this inpcb. If no route + * is found and it cannot be allocated the return NULL. This routine + * is called by TCP routines that access the rmx structure and by tcp_mss + * to get the interface MTU. + */ +struct rtentry * +tcp_rtlookup(inp) + struct inpcb *inp; +{ + struct route *ro; + struct rtentry *rt; + + ro = &inp->inp_route; + rt = ro->ro_rt; + if (rt == NULL || !(rt->rt_flags & RTF_UP)) { + /* No route yet, so try to acquire one */ + if (inp->inp_faddr.s_addr != INADDR_ANY) { + ro->ro_dst.sa_family = AF_INET; + ro->ro_dst.sa_len = sizeof(ro->ro_dst); + ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = + inp->inp_faddr; + rtalloc(ro); + rt = ro->ro_rt; + } + } + return rt; +} + +/* + * Return a pointer to the cached information about the remote host. + * The cached information is stored in the protocol specific part of + * the route metrics. + */ +struct rmxp_tao * +tcp_gettaocache(inp) + struct inpcb *inp; +{ + struct rtentry *rt = tcp_rtlookup(inp); + + /* Make sure this is a host route and is up. */ + if (rt == NULL || + (rt->rt_flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)) + return NULL; + + return rmx_taop(rt->rt_rmx); +} + +/* + * Clear all the TAO cache entries, called from tcp_init. + * + * XXX + * This routine is just an empty one, because we assume that the routing + * routing tables are initialized at the same time when TCP, so there is + * nothing in the cache left over. + */ +static void +tcp_cleartaocache(void) +{ } diff --git a/cpukit/libnetworking/netinet/tcp_timer.c b/cpukit/libnetworking/netinet/tcp_timer.c new file mode 100644 index 0000000000..04d3d604e2 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_timer.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#ifndef TUBA_INCLUDE +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +#endif + +int tcp_keepinit = TCPTV_KEEP_INIT; +SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, + CTLFLAG_RW, &tcp_keepinit , 0, ""); + +int tcp_keepidle = TCPTV_KEEP_IDLE; +SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, + CTLFLAG_RW, &tcp_keepidle , 0, ""); + +static int tcp_keepintvl = TCPTV_KEEPINTVL; +SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, + CTLFLAG_RW, &tcp_keepintvl , 0, ""); + +static int always_keepalive = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, + CTLFLAG_RW, &always_keepalive , 0, ""); + +static int tcp_keepcnt = TCPTV_KEEPCNT; + /* max idle probes */ +static int tcp_maxpersistidle = TCPTV_KEEP_IDLE; + /* max idle time in persist */ +int tcp_maxidle; +#else /* TUBA_INCLUDE */ + +static int tcp_maxpersistidle; +#endif /* TUBA_INCLUDE */ + +/* + * Fast timeout routine for processing delayed acks + */ +void +tcp_fasttimo() +{ + register struct inpcb *inp; + register struct tcpcb *tp; + int s; + + s = splnet(); + + for (inp = tcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { + if ((tp = (struct tcpcb *)inp->inp_ppcb) && + (tp->t_flags & TF_DELACK)) { + tp->t_flags &= ~TF_DELACK; + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_delack++; + (void) tcp_output(tp); + } + } + splx(s); +} + +/* + * Tcp protocol timeout routine called every 500 ms. + * Updates the timers in all active tcb's and + * causes finite state machine actions if timers expire. + */ +void +tcp_slowtimo() +{ + register struct inpcb *ip, *ipnxt; + register struct tcpcb *tp; + register int i; + int s; +#ifdef TCPDEBUG + int ostate; +#endif + + s = splnet(); + + tcp_maxidle = tcp_keepcnt * tcp_keepintvl; + + ip = tcb.lh_first; + if (ip == NULL) { + splx(s); + return; + } + /* + * Search through tcb's and update active timers. + */ + for (; ip != NULL; ip = ipnxt) { + ipnxt = ip->inp_list.le_next; + tp = intotcpcb(ip); + if (tp == 0 || tp->t_state == TCPS_LISTEN) + continue; + for (i = 0; i < TCPT_NTIMERS; i++) { + if (tp->t_timer[i] && --tp->t_timer[i] == 0) { +#ifdef TCPDEBUG + ostate = tp->t_state; +#endif + tp = tcp_timers(tp, i); + if (tp == NULL) + goto tpgone; +#ifdef TCPDEBUG + if (tp->t_inpcb->inp_socket->so_options + & SO_DEBUG) + tcp_trace(TA_USER, ostate, tp, + (struct tcpiphdr *)0, + PRU_SLOWTIMO); +#endif + } + } + tp->t_idle++; + tp->t_duration++; + if (tp->t_rtt) + tp->t_rtt++; +tpgone: + ; + } + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ +#ifdef TCP_COMPAT_42 + if ((int)tcp_iss < 0) + tcp_iss = TCP_ISSINCR; /* XXX */ +#endif + tcp_now++; /* for timestamps */ + splx(s); +} +#ifndef TUBA_INCLUDE + +/* + * Cancel all timers for TCP tp. + */ +void +tcp_canceltimers(tp) + struct tcpcb *tp; +{ + register int i; + + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; +} + +int tcp_backoff[TCP_MAXRXTSHIFT + 1] = + { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; + +static int tcp_totbackoff = 511; /* sum of tcp_backoff[] */ + +/* + * TCP timer processing. + */ +struct tcpcb * +tcp_timers(tp, timer) + register struct tcpcb *tp; + int timer; +{ + register int rexmt; + + switch (timer) { + + /* + * 2 MSL timeout in shutdown went off. If we're closed but + * still waiting for peer to close and connection has been idle + * too long, or if 2MSL time is up from TIME_WAIT, delete connection + * control block. Otherwise, check again in a bit. + */ + case TCPT_2MSL: + if (tp->t_state != TCPS_TIME_WAIT && + tp->t_idle <= tcp_maxidle) + tp->t_timer[TCPT_2MSL] = tcp_keepintvl; + else + tp = tcp_close(tp); + break; + + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one segment. + */ + case TCPT_REXMT: + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { + tp->t_rxtshift = TCP_MAXRXTSHIFT; + tcpstat.tcps_timeoutdrop++; + tp = tcp_drop(tp, tp->t_softerror ? + tp->t_softerror : ETIMEDOUT); + break; + } + tcpstat.tcps_rexmttimeo++; + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + TCPT_RANGESET(tp->t_rxtcur, rexmt, + tp->t_rttmin, TCPTV_REXMTMAX); + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * If losing, let the lower level know and try for + * a better route. Also, if we backed off this far, + * our srtt estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { + in_losing(tp->t_inpcb); + tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); + tp->t_srtt = 0; + } + tp->snd_nxt = tp->snd_una; + /* + * Force a segment to be sent. + */ + tp->t_flags |= TF_ACKNOW; + /* + * If timing a segment in this window, stop the timer. + */ + tp->t_rtt = 0; + /* + * Close the congestion window down to one segment + * (we'll open it by one segment for each ack we get). + * Since we probably have a window's worth of unacked + * data accumulated, this "slow start" keeps us from + * dumping all that data as back-to-back packets (which + * might overwhelm an intermediate gateway). + * + * There are two phases to the opening: Initially we + * open by one mss on each ack. This makes the window + * size increase exponentially with time. If the + * window is larger than the path can handle, this + * exponential growth results in dropped packet(s) + * almost immediately. To get more time between + * drops but still "push" the network to take advantage + * of improving conditions, we switch from exponential + * to linear window opening at some threshhold size. + * For a threshhold, we use half the current window + * size, truncated to a multiple of the mss. + * + * (the minimum cwnd that will give us exponential + * growth is 2 mss. We don't allow the threshhold + * to go below this.) + */ + { + u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + if (win < 2) + win = 2; + tp->snd_cwnd = tp->t_maxseg; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_dupacks = 0; + } + (void) tcp_output(tp); + break; + + /* + * Persistance timer into zero window. + * Force a byte to be output, if possible. + */ + case TCPT_PERSIST: + tcpstat.tcps_persisttimeo++; + /* + * Hack: if the peer is dead/unreachable, we do not + * time out if the window is closed. After a full + * backoff, drop the connection if the idle time + * (no responses to probes) reaches the maximum + * backoff that we would use if retransmitting. + */ + if (tp->t_rxtshift == TCP_MAXRXTSHIFT) { + u_long maxidle = TCP_REXMTVAL(tp); + if (maxidle < tp->t_rttmin) + maxidle = tp->t_rttmin; + maxidle *= tcp_totbackoff; + if (tp->t_idle >= tcp_maxpersistidle || + tp->t_idle >= maxidle) { + tcpstat.tcps_persistdrop++; + tp = tcp_drop(tp, ETIMEDOUT); + break; + } + } + tcp_setpersist(tp); + tp->t_force = 1; + (void) tcp_output(tp); + tp->t_force = 0; + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case TCPT_KEEP: + tcpstat.tcps_keeptimeo++; + if (tp->t_state < TCPS_ESTABLISHED) + goto dropit; + if ((always_keepalive || + tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && + tp->t_state <= TCPS_CLOSING) { + if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + goto dropit; + /* + * Send a packet designed to force a response + * if the peer is up and reachable: + * either an ACK if the connection is still alive, + * or an RST if the peer has closed the connection + * due to timeout or reboot. + * Using sequence number tp->snd_una-1 + * causes the transmitted zero-length segment + * to lie outside the receive window; + * by the protocol spec, this requires the + * correspondent TCP to respond. + */ + tcpstat.tcps_keepprobe++; +#ifdef TCP_COMPAT_42 + /* + * The keepalive packet must have nonzero length + * to get a 4.2 host to respond. + */ + tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, + tp->rcv_nxt - 1, tp->snd_una - 1, 0); +#else + tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); +#endif + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + } else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + break; + dropit: + tcpstat.tcps_keepdrops++; + tp = tcp_drop(tp, ETIMEDOUT); + break; + } + return (tp); +} +#endif /* TUBA_INCLUDE */ diff --git a/cpukit/libnetworking/netinet/tcp_timer.h b/cpukit/libnetworking/netinet/tcp_timer.h new file mode 100644 index 0000000000..38ffac4ee7 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_timer.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_TCP_TIMER_H_ +#define _NETINET_TCP_TIMER_H_ + +/* + * Definitions of the TCP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define TCPT_NTIMERS 4 + +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_PERSIST 1 /* retransmit persistence */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the TCPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as TCPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The TCPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, + * but not yet established, then we drop the connection. Once the connection + * is established, if the connection is idle for TCPTV_KEEP_IDLE time + * (and keepalives have been enabled on the socket), we begin to probe + * the connection. We force the peer to send us a segment by sending: + * <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK> + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time probing, then we drop the connection. + */ + +/* + * Time constants. + */ +#define TCPTV_MSL ( 30*PR_SLOWHZ) /* max seg lifetime (hah!) */ +#define TCPTV_SRTTBASE 0 /* base roundtrip time; + if 0, no idea yet */ +#define TCPTV_RTOBASE ( 3*PR_SLOWHZ) /* assumed RTO if no info */ +#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ + +#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ +#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ + +#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ + +#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +#define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) /* max allowable REXMT value */ + +#define TCPTV_TWTRUNC 8 /* RTO factor to truncate TW */ + +#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ + +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ + +#ifdef TCPTIMERS +static char *tcptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((u_long)(tv) < (u_long)(tvmin)) \ + (tv) = (tvmin); \ + else if ((u_long)(tv) > (u_long)(tvmax)) \ + (tv) = (tvmax); \ +} + +#ifdef KERNEL +extern int tcp_keepinit; /* time to establish connection */ +extern int tcp_keepidle; /* time before keepalive probes begin */ +extern int tcp_keepintvl; /* time between keepalive probes */ +extern int tcp_maxidle; /* time to drop after starting probes */ +extern int tcp_ttl; /* time to live for TCP segs */ +extern int tcp_backoff[]; +#endif + +#endif diff --git a/cpukit/libnetworking/netinet/tcp_usrreq.c b/cpukit/libnetworking/netinet/tcp_usrreq.c new file mode 100644 index 0000000000..ecd9d95636 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_usrreq.c @@ -0,0 +1,840 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 + * $Id$ + */ + +#include "opt_tcpdebug.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/stat.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +#endif + +/* + * TCP protocol interface to socket abstraction. + */ +extern char *tcpstates[]; + +static int tcp_attach __P((struct socket *)); +static int tcp_connect __P((struct tcpcb *, struct mbuf *)); +static struct tcpcb * + tcp_disconnect __P((struct tcpcb *)); +static struct tcpcb * + tcp_usrclosed __P((struct tcpcb *)); + +#ifdef TCPDEBUG +#define TCPDEBUG0 int ostate +#define TCPDEBUG1() ostate = tp ? tp->t_state : 0 +#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \ + tcp_trace(TA_USER, ostate, tp, 0, req) +#else +#define TCPDEBUG0 +#define TCPDEBUG1() +#define TCPDEBUG2(req) +#endif + +/* + * TCP attaches to socket via pru_attach(), reserving space, + * and an internet control block. + */ +static int +tcp_usr_attach(struct socket *so, int proto) +{ + int s = splnet(); + int error; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp = 0; + TCPDEBUG0; + + TCPDEBUG1(); + if (inp) { + error = EISCONN; + goto out; + } + + error = tcp_attach(so); + if (error) + goto out; + + if ((so->so_options & SO_LINGER) && so->so_linger == 0) + so->so_linger = TCP_LINGERTIME * hz; + tp = sototcpcb(so); +out: + TCPDEBUG2(PRU_ATTACH); + splx(s); + return error; +} + +/* + * pru_detach() detaches the TCP protocol from the socket. + * If the protocol state is non-embryonic, then can't + * do this directly: have to initiate a pru_disconnect(), + * which may finish later; embryonic TCB's can just + * be discarded here. + */ +static int +tcp_usr_detach(struct socket *so) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + TCPDEBUG0; + + if (inp == 0) { + splx(s); + return EINVAL; /* XXX */ + } + tp = intotcpcb(inp); + TCPDEBUG1(); + if (tp->t_state > TCPS_LISTEN) + tp = tcp_disconnect(tp); + else + tp = tcp_close(tp); + + TCPDEBUG2(PRU_DETACH); + splx(s); + return error; +} + +#define COMMON_START() TCPDEBUG0; \ + do { \ + if (inp == 0) { \ + splx(s); \ + return EINVAL; \ + } \ + tp = intotcpcb(inp); \ + TCPDEBUG1(); \ + } while(0) + +#define COMMON_END(req) out: TCPDEBUG2(req); splx(s); return error; goto out + + +/* + * Give the socket an address. + */ +static int +tcp_usr_bind(struct socket *so, struct mbuf *nam) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + struct sockaddr_in *sinp; + + COMMON_START(); + + /* + * Must check for multicast addresses and disallow binding + * to them. + */ + sinp = mtod(nam, struct sockaddr_in *); + if (sinp->sin_family == AF_INET && + IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { + error = EAFNOSUPPORT; + goto out; + } + error = in_pcbbind(inp, nam); + if (error) + goto out; + COMMON_END(PRU_BIND); + +} + +/* + * Prepare to accept connections. + */ +static int +tcp_usr_listen(struct socket *so) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + if (inp->inp_lport == 0) + error = in_pcbbind(inp, NULL); + if (error == 0) + tp->t_state = TCPS_LISTEN; + COMMON_END(PRU_LISTEN); +} + +/* + * Initiate connection to peer. + * Create a template for use in transmissions on this connection. + * Enter SYN_SENT state, and mark socket as connecting. + * Start keep-alive timer, and seed output sequence space. + * Send initial segment on connection. + */ +static int +tcp_usr_connect(struct socket *so, struct mbuf *nam) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + struct sockaddr_in *sinp; + + COMMON_START(); + + /* + * Must disallow TCP ``connections'' to multicast addresses. + */ + sinp = mtod(nam, struct sockaddr_in *); + if (sinp->sin_family == AF_INET + && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { + error = EAFNOSUPPORT; + goto out; + } + + if ((error = tcp_connect(tp, nam)) != 0) + goto out; + error = tcp_output(tp); + COMMON_END(PRU_CONNECT); +} + +/* + * Initiate disconnect from peer. + * If connection never passed embryonic stage, just drop; + * else if don't need to let data drain, then can just drop anyways, + * else have to begin TCP shutdown process: mark socket disconnecting, + * drain unread data, state switch to reflect user close, and + * send segment (e.g. FIN) to peer. Socket will be really disconnected + * when peer sends FIN and acks ours. + * + * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. + */ +static int +tcp_usr_disconnect(struct socket *so) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + tp = tcp_disconnect(tp); + COMMON_END(PRU_DISCONNECT); +} + +/* + * Accept a connection. Essentially all the work is + * done at higher levels; just return the address + * of the peer, storing through addr. + */ +static int +tcp_usr_accept(struct socket *so, struct mbuf *nam) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + in_setpeeraddr(inp, nam); + COMMON_END(PRU_ACCEPT); +} + +/* + * Mark the connection as being incapable of further output. + */ +static int +tcp_usr_shutdown(struct socket *so) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + socantsendmore(so); + tp = tcp_usrclosed(tp); + if (tp) + error = tcp_output(tp); + COMMON_END(PRU_SHUTDOWN); +} + +/* + * After a receive, possibly send window update to peer. + */ +static int +tcp_usr_rcvd(struct socket *so, int flags) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + tcp_output(tp); + COMMON_END(PRU_RCVD); +} + +/* + * Do a send by putting data in output queue and updating urgent + * marker if URG set. Possibly send more data. + */ +static int +tcp_usr_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam, + struct mbuf *control) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + if (control && control->m_len) { + m_freem(control); /* XXX shouldn't caller do this??? */ + if (m) + m_freem(m); + error = EINVAL; + goto out; + } + + if(!(flags & PRUS_OOB)) { + sbappend(&so->so_snd, m); + if (nam && tp->t_state < TCPS_SYN_SENT) { + /* + * Do implied connect if not yet connected, + * initialize window to default value, and + * initialize maxseg/maxopd using peer's cached + * MSS. + */ + error = tcp_connect(tp, nam); + if (error) + goto out; + tp->snd_wnd = TTCP_CLIENT_SND_WND; + tcp_mss(tp, -1); + } + + if (flags & PRUS_EOF) { + /* + * Close the send side of the connection after + * the data is sent. + */ + socantsendmore(so); + tp = tcp_usrclosed(tp); + } + if (tp != NULL) + error = tcp_output(tp); + } else { + if (sbspace(&so->so_snd) < -512) { + m_freem(m); + error = ENOBUFS; + goto out; + } + /* + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section. + * Otherwise, snd_up should be one lower. + */ + sbappend(&so->so_snd, m); + if (nam && tp->t_state < TCPS_SYN_SENT) { + /* + * Do implied connect if not yet connected, + * initialize window to default value, and + * initialize maxseg/maxopd using peer's cached + * MSS. + */ + error = tcp_connect(tp, nam); + if (error) + goto out; + tp->snd_wnd = TTCP_CLIENT_SND_WND; + tcp_mss(tp, -1); + } + tp->snd_up = tp->snd_una + so->so_snd.sb_cc; + tp->t_force = 1; + error = tcp_output(tp); + tp->t_force = 0; + } + COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB : + ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND)); +} + +/* + * Abort the TCP. + */ +static int +tcp_usr_abort(struct socket *so) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + tp = tcp_drop(tp, ECONNABORTED); + COMMON_END(PRU_ABORT); +} + +/* + * Fill in st_bklsize for fstat() operations on a socket. + */ +static int +tcp_usr_sense(struct socket *so, struct stat *sb) +{ + int s = splnet(); + + sb->st_blksize = so->so_snd.sb_hiwat; + splx(s); + return 0; +} + +/* + * Receive out-of-band data. + */ +static int +tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + if ((so->so_oobmark == 0 && + (so->so_state & SS_RCVATMARK) == 0) || + so->so_options & SO_OOBINLINE || + tp->t_oobflags & TCPOOB_HADDATA) { + error = EINVAL; + goto out; + } + if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { + error = EWOULDBLOCK; + goto out; + } + m->m_len = 1; + *mtod(m, caddr_t) = tp->t_iobc; + if ((flags & MSG_PEEK) == 0) + tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); + COMMON_END(PRU_RCVOOB); +} + +static int +tcp_usr_sockaddr(struct socket *so, struct mbuf *nam) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + in_setsockaddr(inp, nam); + COMMON_END(PRU_SOCKADDR); +} + +static int +tcp_usr_peeraddr(struct socket *so, struct mbuf *nam) +{ + int s = splnet(); + int error = 0; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp; + + COMMON_START(); + in_setpeeraddr(inp, nam); + COMMON_END(PRU_PEERADDR); +} + +/* + * XXX - this should just be a call to in_control, but we need to get + * the types worked out. + */ +static int +tcp_usr_control(struct socket *so, int cmd, caddr_t arg, struct ifnet *ifp) +{ + return in_control(so, cmd, arg, ifp); +} + +/* xxx - should be const */ +struct pr_usrreqs tcp_usrreqs = { + tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind, + tcp_usr_connect, pru_connect2_notsupp, tcp_usr_control, tcp_usr_detach, + tcp_usr_disconnect, tcp_usr_listen, tcp_usr_peeraddr, tcp_usr_rcvd, + tcp_usr_rcvoob, tcp_usr_send, tcp_usr_sense, tcp_usr_shutdown, + tcp_usr_sockaddr +}; + +/* + * Common subroutine to open a TCP connection to remote host specified + * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local + * port number if needed. Call in_pcbladdr to do the routing and to choose + * a local host address (interface). If there is an existing incarnation + * of the same connection in TIME-WAIT state and if the remote host was + * sending CC options and if the connection duration was < MSL, then + * truncate the previous TIME-WAIT state and proceed. + * Initialize connection parameters and enter SYN-SENT state. + */ +static int +tcp_connect(tp, nam) + register struct tcpcb *tp; + struct mbuf *nam; +{ + struct inpcb *inp = tp->t_inpcb, *oinp; + struct socket *so = inp->inp_socket; + struct tcpcb *otp; + struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); + struct sockaddr_in *ifaddr; + int error; + struct rmxp_tao *taop; + struct rmxp_tao tao_noncached; + + if (inp->inp_lport == 0) { + error = in_pcbbind(inp, NULL); + if (error) + return error; + } + + /* + * Cannot simply call in_pcbconnect, because there might be an + * earlier incarnation of this same connection still in + * TIME_WAIT state, creating an ADDRINUSE error. + */ + error = in_pcbladdr(inp, nam, &ifaddr); + if (error) + return error; + oinp = in_pcblookuphash(inp->inp_pcbinfo, + sin->sin_addr, sin->sin_port, + inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr + : ifaddr->sin_addr, + inp->inp_lport, 0); + if (oinp) { + if (oinp != inp && (otp = intotcpcb(oinp)) != NULL && + otp->t_state == TCPS_TIME_WAIT && + otp->t_duration < TCPTV_MSL && + (otp->t_flags & TF_RCVD_CC)) + otp = tcp_close(otp); + else + return EADDRINUSE; + } + if (inp->inp_laddr.s_addr == INADDR_ANY) + inp->inp_laddr = ifaddr->sin_addr; + inp->inp_faddr = sin->sin_addr; + inp->inp_fport = sin->sin_port; + in_pcbrehash(inp); + + tp->t_template = tcp_template(tp); + if (tp->t_template == 0) { + in_pcbdisconnect(inp); + return ENOBUFS; + } + + /* Compute window scaling to request. */ + while (tp->request_r_scale < TCP_MAX_WINSHIFT && + (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + tp->request_r_scale++; + + soisconnecting(so); + tcpstat.tcps_connattempt++; + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = tcp_keepinit; + tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + + /* + * Generate a CC value for this connection and + * check whether CC or CCnew should be used. + */ + if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) { + taop = &tao_noncached; + bzero(taop, sizeof(*taop)); + } + + tp->cc_send = CC_INC(tcp_ccgen); + if (taop->tao_ccsent != 0 && + CC_GEQ(tp->cc_send, taop->tao_ccsent)) { + taop->tao_ccsent = tp->cc_send; + } else { + taop->tao_ccsent = 0; + tp->t_flags |= TF_SENDCCNEW; + } + + return 0; +} + +int +tcp_ctloutput(op, so, level, optname, mp) + int op; + struct socket *so; + int level, optname; + struct mbuf **mp; +{ + int error = 0, s; + struct inpcb *inp; + register struct tcpcb *tp; + register struct mbuf *m; + register int i; + + s = splnet(); + inp = sotoinpcb(so); + if (inp == NULL) { + splx(s); + if (op == PRCO_SETOPT && *mp) + (void) m_free(*mp); + return (ECONNRESET); + } + if (level != IPPROTO_TCP) { + error = ip_ctloutput(op, so, level, optname, mp); + splx(s); + return (error); + } + tp = intotcpcb(inp); + + switch (op) { + + case PRCO_SETOPT: + m = *mp; + switch (optname) { + + case TCP_NODELAY: + if (m == NULL || m->m_len < sizeof (int)) + error = EINVAL; + else if (*mtod(m, int *)) + tp->t_flags |= TF_NODELAY; + else + tp->t_flags &= ~TF_NODELAY; + break; + + case TCP_MAXSEG: + if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg) + tp->t_maxseg = i; + else + error = EINVAL; + break; + + case TCP_NOOPT: + if (m == NULL || m->m_len < sizeof (int)) + error = EINVAL; + else if (*mtod(m, int *)) + tp->t_flags |= TF_NOOPT; + else + tp->t_flags &= ~TF_NOOPT; + break; + + case TCP_NOPUSH: + if (m == NULL || m->m_len < sizeof (int)) + error = EINVAL; + else if (*mtod(m, int *)) + tp->t_flags |= TF_NOPUSH; + else + tp->t_flags &= ~TF_NOPUSH; + break; + + default: + error = ENOPROTOOPT; + break; + } + if (m) + (void) m_free(m); + break; + + case PRCO_GETOPT: + *mp = m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof(int); + + switch (optname) { + case TCP_NODELAY: + *mtod(m, int *) = tp->t_flags & TF_NODELAY; + break; + case TCP_MAXSEG: + *mtod(m, int *) = tp->t_maxseg; + break; + case TCP_NOOPT: + *mtod(m, int *) = tp->t_flags & TF_NOOPT; + break; + case TCP_NOPUSH: + *mtod(m, int *) = tp->t_flags & TF_NOPUSH; + break; + default: + error = ENOPROTOOPT; + break; + } + break; + } + splx(s); + return (error); +} + +/* + * tcp_sendspace and tcp_recvspace are the default send and receive window + * sizes, respectively. These are obsolescent (this information should + * be set by the route). + */ +u_long tcp_sendspace = 1024*16; +SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, + CTLFLAG_RW, &tcp_sendspace , 0, ""); +u_long tcp_recvspace = 1024*16; +SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, + CTLFLAG_RW, &tcp_recvspace , 0, ""); + +/* + * Attach TCP protocol to socket, allocating + * internet protocol control block, tcp control block, + * bufer space, and entering LISTEN state if to accept connections. + */ +static int +tcp_attach(so) + struct socket *so; +{ + register struct tcpcb *tp; + struct inpcb *inp; + int error; + + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + error = soreserve(so, tcp_sendspace, tcp_recvspace); + if (error) + return (error); + } + error = in_pcballoc(so, &tcbinfo); + if (error) + return (error); + inp = sotoinpcb(so); + tp = tcp_newtcpcb(inp); + if (tp == 0) { + int nofd = so->so_state & SS_NOFDREF; /* XXX */ + + so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ + in_pcbdetach(inp); + so->so_state |= nofd; + return (ENOBUFS); + } + tp->t_state = TCPS_CLOSED; + return (0); +} + +/* + * Initiate (or continue) disconnect. + * If embryonic state, just send reset (once). + * If in ``let data drain'' option and linger null, just drop. + * Otherwise (hard), mark socket disconnecting and drop + * current input data; switch states based on user close, and + * send segment to peer (with FIN). + */ +static struct tcpcb * +tcp_disconnect(tp) + register struct tcpcb *tp; +{ + struct socket *so = tp->t_inpcb->inp_socket; + + if (tp->t_state < TCPS_ESTABLISHED) + tp = tcp_close(tp); + else if ((so->so_options & SO_LINGER) && so->so_linger == 0) + tp = tcp_drop(tp, 0); + else { + soisdisconnecting(so); + sbflush(&so->so_rcv); + tp = tcp_usrclosed(tp); + if (tp) + (void) tcp_output(tp); + } + return (tp); +} + +/* + * User issued close, and wish to trail through shutdown states: + * if never received SYN, just forget it. If got a SYN from peer, + * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. + * If already got a FIN from peer, then almost done; go to LAST_ACK + * state. In all other cases, have already sent FIN to peer (e.g. + * after PRU_SHUTDOWN), and just have to play tedious game waiting + * for peer to send FIN or not respond to keep-alives, etc. + * We can let the user exit from the close as soon as the FIN is acked. + */ +static struct tcpcb * +tcp_usrclosed(tp) + register struct tcpcb *tp; +{ + + switch (tp->t_state) { + + case TCPS_CLOSED: + case TCPS_LISTEN: + tp->t_state = TCPS_CLOSED; + tp = tcp_close(tp); + break; + + case TCPS_SYN_SENT: + case TCPS_SYN_RECEIVED: + tp->t_flags |= TF_NEEDFIN; + break; + + case TCPS_ESTABLISHED: + tp->t_state = TCPS_FIN_WAIT_1; + break; + + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + break; + } + if (tp && tp->t_state >= TCPS_FIN_WAIT_2) { + soisdisconnected(tp->t_inpcb->inp_socket); + /* To prevent the connection hanging in FIN_WAIT_2 forever. */ + if (tp->t_state == TCPS_FIN_WAIT_2) + tp->t_timer[TCPT_2MSL] = tcp_maxidle; + } + return (tp); +} + diff --git a/cpukit/libnetworking/netinet/tcp_var.h b/cpukit/libnetworking/netinet/tcp_var.h new file mode 100644 index 0000000000..8e63a2cafe --- /dev/null +++ b/cpukit/libnetworking/netinet/tcp_var.h @@ -0,0 +1,374 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1994, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_var.h 8.4 (Berkeley) 5/24/95 + * $Id$ + */ + +#ifndef _NETINET_TCP_VAR_H_ +#define _NETINET_TCP_VAR_H_ +/* + * Kernel variables for tcp. + */ + +/* + * Tcp control block, one per tcp; fields: + */ +struct tcpcb { + struct tcpiphdr *seg_next; /* sequencing queue */ + struct tcpiphdr *seg_prev; + int t_state; /* state of this connection */ + int t_timer[TCPT_NTIMERS]; /* tcp timers */ + int t_rxtshift; /* log(2) of rexmt exp. backoff */ + int t_rxtcur; /* current retransmit value */ + int t_dupacks; /* consecutive dup acks recd */ + u_int t_maxseg; /* maximum segment size */ + u_int t_maxopd; /* mss plus options */ + int t_force; /* 1 if forcing out a byte */ + u_int t_flags; +#define TF_ACKNOW 0x0001 /* ack peer immediately */ +#define TF_DELACK 0x0002 /* ack, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ +#define TF_NEEDSYN 0x0400 /* send SYN (implicit state) */ +#define TF_NEEDFIN 0x0800 /* send FIN (implicit state) */ +#define TF_NOPUSH 0x1000 /* don't push */ +#define TF_REQ_CC 0x2000 /* have/will request CC */ +#define TF_RCVD_CC 0x4000 /* a CC was received in SYN */ +#define TF_SENDCCNEW 0x8000 /* send CCnew instead of CC in SYN */ + + struct tcpiphdr *t_template; /* skeletal packet for transmit */ + struct inpcb *t_inpcb; /* back pointer to internet pcb */ +/* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ +/* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + u_long snd_wnd; /* send window */ +/* receive sequence variables */ + u_long rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ +/* + * Additional variables for this implementation. + */ +/* receive variables */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ +/* congestion control (for slow start, source quench, retransmit after loss) */ + u_long snd_cwnd; /* congestion-controlled window */ + u_long snd_ssthresh; /* snd_cwnd size threshold for + * for slow start exponential to + * linear switch + */ +/* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + u_int t_idle; /* inactivity time */ + int t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + int t_srtt; /* smoothed round-trip time */ + int t_rttvar; /* variance in round-trip time */ + u_int t_rttmin; /* minimum rtt allowed */ + u_long max_sndwnd; /* largest window peer has offered */ + +/* out-of-band data */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 + int t_softerror; /* possible error not yet reported */ + +/* RFC 1323 variables */ + u_char snd_scale; /* window scaling for send window */ + u_char rcv_scale; /* window scaling for recv window */ + u_char request_r_scale; /* pending window scaling */ + u_char requested_s_scale; + u_long ts_recent; /* timestamp echo data */ + u_long ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; +/* RFC 1644 variables */ + tcp_cc cc_send; /* send connection count */ + tcp_cc cc_recv; /* receive connection count */ + u_long t_duration; /* connection duration */ + +/* TUBA stuff */ + caddr_t t_tuba_pcb; /* next level down pcb for TCP over z */ +/* More RTT stuff */ + u_long t_rttupdated; /* number of times rtt sampled */ +}; + +/* + * Structure to hold TCP options that are only used during segment + * processing (in tcp_input), but not held in the tcpcb. + * It's basically used to reduce the number of parameters + * to tcp_dooptions. + */ +struct tcpopt { + u_long to_flag; /* which options are present */ +#define TOF_TS 0x0001 /* timestamp */ +#define TOF_CC 0x0002 /* CC and CCnew are exclusive */ +#define TOF_CCNEW 0x0004 +#define TOF_CCECHO 0x0008 + u_long to_tsval; + u_long to_tsecr; + tcp_cc to_cc; /* holds CC or CCnew */ + tcp_cc to_ccecho; +}; + +/* + * The TAO cache entry which is stored in the protocol family specific + * portion of the route metrics. + */ +struct rmxp_tao { + tcp_cc tao_cc; /* latest CC in valid SYN */ + tcp_cc tao_ccsent; /* latest CC sent to peer */ + u_short tao_mssopt; /* peer's cached MSS */ +#ifdef notyet + u_short tao_flags; /* cache status flags */ +#define TAOF_DONT 0x0001 /* peer doesn't understand rfc1644 */ +#define TAOF_OK 0x0002 /* peer does understand rfc1644 */ +#define TAOF_UNDEF 0 /* we don't know yet */ +#endif /* notyet */ +}; +#define rmx_taop(r) ((struct rmxp_tao *)(r).rmx_filler) + +#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) +#define sototcpcb(so) (intotcpcb(sotoinpcb(so))) + +/* + * The smoothed round-trip time and estimated variance + * are stored as fixed point numbers scaled by the values below. + * For convenience, these scales are also used in smoothing the average + * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). + * With these scales, srtt has 3 bits to the right of the binary point, + * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the + * binary point, and is smoothed with an ALPHA of 0.75. + */ +#define TCP_RTT_SCALE 32 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 5 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 16 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 4 /* shift for rttvar; 2 bits */ +#define TCP_DELTA_SHIFT 2 /* see tcp_input.c */ + +/* + * The initial retransmission should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + * This version of the macro adapted from a paper by Lawrence + * Brakmo and Larry Peterson which outlines a problem caused + * by insufficient precision in the original implementation, + * which results in inappropriately large RTO values for very + * fast networks. + */ +#define TCP_REXMTVAL(tp) \ + ((((tp)->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT)) \ + + (tp)->t_rttvar) >> TCP_DELTA_SHIFT) + +/* XXX + * We want to avoid doing m_pullup on incoming packets but that + * means avoiding dtom on the tcp reassembly code. That in turn means + * keeping an mbuf pointer in the reassembly queue (since we might + * have a cluster). As a quick hack, the source & destination + * port numbers (which are no longer needed once we've located the + * tcpcb) are overlayed with an mbuf pointer. + */ +#define REASS_MBUF(ti) (*(struct mbuf **)&((ti)->ti_t)) + +/* + * TCP statistics. + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcpstat { + u_long tcps_connattempt; /* connections initiated */ + u_long tcps_accepts; /* connections accepted */ + u_long tcps_connects; /* connections established */ + u_long tcps_drops; /* connections dropped */ + u_long tcps_conndrops; /* embryonic connections dropped */ + u_long tcps_closed; /* conn. closed (includes drops) */ + u_long tcps_segstimed; /* segs where we tried to get rtt */ + u_long tcps_rttupdated; /* times we succeeded */ + u_long tcps_delack; /* delayed acks sent */ + u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + u_long tcps_rexmttimeo; /* retransmit timeouts */ + u_long tcps_persisttimeo; /* persist timeouts */ + u_long tcps_keeptimeo; /* keepalive timeouts */ + u_long tcps_keepprobe; /* keepalive probes sent */ + u_long tcps_keepdrops; /* connections dropped in keepalive */ + + u_long tcps_sndtotal; /* total packets sent */ + u_long tcps_sndpack; /* data packets sent */ + u_long tcps_sndbyte; /* data bytes sent */ + u_long tcps_sndrexmitpack; /* data packets retransmitted */ + u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ + u_long tcps_sndacks; /* ack-only packets sent */ + u_long tcps_sndprobe; /* window probes sent */ + u_long tcps_sndurg; /* packets sent with URG only */ + u_long tcps_sndwinup; /* window update-only packets sent */ + u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + u_long tcps_rcvtotal; /* total packets received */ + u_long tcps_rcvpack; /* packets received in sequence */ + u_long tcps_rcvbyte; /* bytes received in sequence */ + u_long tcps_rcvbadsum; /* packets received with ccksum errs */ + u_long tcps_rcvbadoff; /* packets received with bad offset */ + u_long tcps_rcvshort; /* packets received too short */ + u_long tcps_rcvduppack; /* duplicate-only packets received */ + u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ + u_long tcps_rcvpartduppack; /* packets with some duplicate data */ + u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + u_long tcps_rcvoopack; /* out-of-order packets received */ + u_long tcps_rcvoobyte; /* out-of-order bytes received */ + u_long tcps_rcvpackafterwin; /* packets with data after window */ + u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ + u_long tcps_rcvafterclose; /* packets rcvd after "close" */ + u_long tcps_rcvwinprobe; /* rcvd window probe packets */ + u_long tcps_rcvdupack; /* rcvd duplicate acks */ + u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + u_long tcps_rcvackpack; /* rcvd ack packets */ + u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ + u_long tcps_rcvwinupd; /* rcvd window update packets */ + u_long tcps_pawsdrop; /* segments dropped due to PAWS */ + u_long tcps_predack; /* times hdr predict ok for acks */ + u_long tcps_preddat; /* times hdr predict ok for data pkts */ + u_long tcps_pcbcachemiss; + u_long tcps_cachedrtt; /* times cached RTT in route updated */ + u_long tcps_cachedrttvar; /* times cached rttvar updated */ + u_long tcps_cachedssthresh; /* times cached ssthresh updated */ + u_long tcps_usedrtt; /* times RTT initialized from route */ + u_long tcps_usedrttvar; /* times RTTVAR initialized from rt */ + u_long tcps_usedssthresh; /* times ssthresh initialized from rt*/ + u_long tcps_persistdrop; /* timeout in persist state */ + u_long tcps_badsyn; /* bogus SYN, e.g. premature ACK */ + u_long tcps_mturesent; /* resends due to MTU discovery */ + u_long tcps_listendrop; /* listen queue overflows */ +}; + +/* + * Names for TCP sysctl objects + */ +#define TCPCTL_DO_RFC1323 1 /* use RFC-1323 extensions */ +#define TCPCTL_DO_RFC1644 2 /* use RFC-1644 extensions */ +#define TCPCTL_MSSDFLT 3 /* MSS default */ +#define TCPCTL_STATS 4 /* statistics (read-only) */ +#define TCPCTL_RTTDFLT 5 /* default RTT estimate */ +#define TCPCTL_KEEPIDLE 6 /* keepalive idle timer */ +#define TCPCTL_KEEPINTVL 7 /* interval to send keepalives */ +#define TCPCTL_SENDSPACE 8 /* send buffer space */ +#define TCPCTL_RECVSPACE 9 /* receive buffer space */ +#define TCPCTL_KEEPINIT 10 /* receive buffer space */ +#define TCPCTL_MAXID 11 + +#define TCPCTL_NAMES { \ + { 0, 0 }, \ + { "rfc1323", CTLTYPE_INT }, \ + { "rfc1644", CTLTYPE_INT }, \ + { "mssdflt", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ + { "rttdflt", CTLTYPE_INT }, \ + { "keepidle", CTLTYPE_INT }, \ + { "keepintvl", CTLTYPE_INT }, \ + { "sendspace", CTLTYPE_INT }, \ + { "recvspace", CTLTYPE_INT }, \ + { "keepinit", CTLTYPE_INT }, \ +} + +#ifdef KERNEL +extern struct inpcbhead tcb; /* head of queue of active tcpcb's */ +extern struct inpcbinfo tcbinfo; +extern struct tcpstat tcpstat; /* tcp statistics */ +extern int tcp_mssdflt; /* XXX */ +extern u_long tcp_now; /* for RFC 1323 timestamps */ + +void tcp_canceltimers __P((struct tcpcb *)); +struct tcpcb * + tcp_close __P((struct tcpcb *)); +void tcp_ctlinput __P((int, struct sockaddr *, void *)); +int tcp_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); +struct tcpcb * + tcp_drop __P((struct tcpcb *, int)); +void tcp_drain __P((void)); +void tcp_fasttimo __P((void)); +struct rmxp_tao * + tcp_gettaocache __P((struct inpcb *)); +void tcp_init __P((void)); +void tcp_input __P((struct mbuf *, int)); +void tcp_mss __P((struct tcpcb *, int)); +int tcp_mssopt __P((struct tcpcb *)); +void tcp_mtudisc __P((struct inpcb *, int)); +struct tcpcb * + tcp_newtcpcb __P((struct inpcb *)); +int tcp_output __P((struct tcpcb *)); +void tcp_quench __P((struct inpcb *, int)); +void tcp_respond __P((struct tcpcb *, + struct tcpiphdr *, struct mbuf *, u_long, u_long, int)); +struct rtentry * + tcp_rtlookup __P((struct inpcb *)); +void tcp_setpersist __P((struct tcpcb *)); +void tcp_slowtimo __P((void)); +struct tcpiphdr * + tcp_template __P((struct tcpcb *)); +struct tcpcb * + tcp_timers __P((struct tcpcb *, int)); +void tcp_trace __P((int, int, struct tcpcb *, struct tcpiphdr *, int)); + +extern struct pr_usrreqs tcp_usrreqs; +extern u_long tcp_sendspace; +extern u_long tcp_recvspace; + +#endif /* KERNEL */ + +#endif /* _NETINET_TCP_VAR_H_ */ diff --git a/cpukit/libnetworking/netinet/tcpip.h b/cpukit/libnetworking/netinet/tcpip.h new file mode 100644 index 0000000000..b8634bfd15 --- /dev/null +++ b/cpukit/libnetworking/netinet/tcpip.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_TCPIP_H_ +#define _NETINET_TCPIP_H_ + +/* + * Tcp+ip header, after ip options removed. + */ +struct tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ +}; +#ifdef notyet +/* + * Tcp+ip header, after ip options removed but including TCP options. + */ +struct full_tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ + char ti_o[TCP_MAXOLEN]; /* space for tcp options */ +}; +#endif /* notyet */ +#define ti_next ti_i.ih_next +#define ti_prev ti_i.ih_prev +#define ti_x1 ti_i.ih_x1 +#define ti_pr ti_i.ih_pr +#define ti_len ti_i.ih_len +#define ti_src ti_i.ih_src +#define ti_dst ti_i.ih_dst +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +#endif diff --git a/cpukit/libnetworking/netinet/udp.h b/cpukit/libnetworking/netinet/udp.h new file mode 100644 index 0000000000..e73e1f4ddb --- /dev/null +++ b/cpukit/libnetworking/netinet/udp.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)udp.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_UDP_H_ +#define _NETINET_UDP_H_ + +/* + * Udp protocol header. + * Per RFC 768, September, 1981. + */ +struct udphdr { + u_short uh_sport; /* source port */ + u_short uh_dport; /* destination port */ + u_short uh_ulen; /* udp length */ + u_short uh_sum; /* udp checksum */ +}; + +#endif diff --git a/cpukit/libnetworking/netinet/udp_usrreq.c b/cpukit/libnetworking/netinet/udp_usrreq.c new file mode 100644 index 0000000000..5198575c0c --- /dev/null +++ b/cpukit/libnetworking/netinet/udp_usrreq.c @@ -0,0 +1,613 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 + * $Id$ + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/syslog.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +/* + * UDP protocol implementation. + * Per RFC 768, August, 1980. + */ +#ifndef COMPAT_42 +static int udpcksum = 1; +#else +static int udpcksum = 0; /* XXX */ +#endif +SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, + &udpcksum, 0, ""); + +static int log_in_vain = 0; +SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, + &log_in_vain, 0, ""); + +static struct inpcbhead udb; /* from udp_var.h */ +static struct inpcbinfo udbinfo; + +#ifndef UDBHASHSIZE +#define UDBHASHSIZE 64 +#endif + + struct udpstat udpstat; /* from udp_var.h */ +SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD, + &udpstat, udpstat, ""); + +static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; + +static void udp_detach __P((struct inpcb *)); +static int udp_output __P((struct inpcb *, struct mbuf *, struct mbuf *, + struct mbuf *)); +static void udp_notify __P((struct inpcb *, int)); + +void +udp_init() +{ + LIST_INIT(&udb); + udbinfo.listhead = &udb; + udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); +} + +void +udp_input(m, iphlen) + register struct mbuf *m; + int iphlen; +{ + register struct ip *ip; + register struct udphdr *uh; + register struct inpcb *inp; + struct mbuf *opts = 0; + int len; + struct ip save_ip; + + udpstat.udps_ipackets++; + + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if (iphlen > sizeof (struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); + } + + /* + * Get IP and UDP header together in first mbuf. + */ + ip = mtod(m, struct ip *); + if (m->m_len < iphlen + sizeof(struct udphdr)) { + if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { + udpstat.udps_hdrops++; + return; + } + ip = mtod(m, struct ip *); + } + uh = (struct udphdr *)((caddr_t)ip + iphlen); + + /* + * Make mbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((u_short)uh->uh_ulen); + if (ip->ip_len != len) { + if (len > ip->ip_len || len < sizeof(struct udphdr)) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(m, len - ip->ip_len); + /* ip->ip_len = len; */ + } + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum) { + ((struct ipovly *)ip)->ih_next = 0; + ((struct ipovly *)ip)->ih_prev = 0; + ((struct ipovly *)ip)->ih_x1 = 0; + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); + if (uh->uh_sum) { + udpstat.udps_badsum++; + m_freem(m); + return; + } + } + + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || + in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { + struct inpcb *last; + /* + * Deliver a multicast or broadcast datagram to *all* sockets + * for which the local and remote addresses and ports match + * those of the incoming datagram. This allows more than + * one process to receive multi/broadcasts on the same port. + * (This really ought to be done for unicast datagrams as + * well, but that would cause problems with existing + * applications that open both address-specific sockets and + * a wildcard socket listening to the same port -- they would + * end up receiving duplicates of every unicast datagram. + * Those applications open the multiple sockets to overcome an + * inadequacy of the UDP socket interface, but for backwards + * compatibility we avoid the problem here rather than + * fixing the interface. Maybe 4.5BSD will remedy this?) + */ + + /* + * Construct sockaddr format source address. + */ + udp_in.sin_port = uh->uh_sport; + udp_in.sin_addr = ip->ip_src; + m->m_len -= sizeof (struct udpiphdr); + m->m_data += sizeof (struct udpiphdr); + /* + * Locate pcb(s) for datagram. + * (Algorithm copied from raw_intr().) + */ + last = NULL; + for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { + if (inp->inp_lport != uh->uh_dport) + continue; + if (inp->inp_laddr.s_addr != INADDR_ANY) { + if (inp->inp_laddr.s_addr != + ip->ip_dst.s_addr) + continue; + } + if (inp->inp_faddr.s_addr != INADDR_ANY) { + if (inp->inp_faddr.s_addr != + ip->ip_src.s_addr || + inp->inp_fport != uh->uh_sport) + continue; + } + + if (last != NULL) { + struct mbuf *n; + + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + if (last->inp_flags & INP_CONTROLOPTS + || last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, n); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&udp_in, + n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + udpstat.udps_fullsock++; + } else + sorwakeup(last->inp_socket); + opts = 0; + } + } + last = inp; + /* + * Don't look for additional matches if this one does + * not have either the SO_REUSEPORT or SO_REUSEADDR + * socket options set. This heuristic avoids searching + * through all pcbs in the common case of a non-shared + * port. It * assumes that an application will never + * clear these options after setting them. + */ + if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) + break; + } + + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + udpstat.udps_noportbcast++; + goto bad; + } + if (last->inp_flags & INP_CONTROLOPTS + || last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, m); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&udp_in, + m, opts) == 0) { + udpstat.udps_fullsock++; + goto bad; + } + sorwakeup(last->inp_socket); + return; + } + /* + * Locate pcb for datagram. + */ + inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport, + ip->ip_dst, uh->uh_dport, 1); + if (inp == NULL) { + if (log_in_vain) { + char buf[4*sizeof "123"]; + + strcpy(buf, inet_ntoa(ip->ip_dst)); + log(LOG_INFO, "Connection attempt to UDP %s:%d" + " from %s:%d\n", + buf, ntohs(uh->uh_dport), + inet_ntoa(ip->ip_src), ntohs(uh->uh_sport)); + } + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } + *ip = save_ip; + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); + return; + } + + /* + * Construct sockaddr format source address. + * Stuff source address and datagram in user buffer. + */ + udp_in.sin_port = uh->uh_sport; + udp_in.sin_addr = ip->ip_src; + if (inp->inp_flags & INP_CONTROLOPTS + || inp->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(inp, &opts, ip, m); + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_pkthdr.len -= iphlen; + m->m_data += iphlen; + if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, + m, opts) == 0) { + udpstat.udps_fullsock++; + goto bad; + } + sorwakeup(inp->inp_socket); + return; +bad: + m_freem(m); + if (opts) + m_freem(opts); +} + +/* + * Notify a udp user of an asynchronous error; + * just wake up so that he can collect error status. + */ +static void +udp_notify(inp, errnum) + register struct inpcb *inp; + int errnum; +{ + inp->inp_socket->so_error = errnum; + sorwakeup(inp->inp_socket); + sowwakeup(inp->inp_socket); +} + +void +udp_ctlinput(cmd, sa, vip) + int cmd; + struct sockaddr *sa; + void *vip; +{ + register struct ip *ip = vip; + register struct udphdr *uh; + + if (!PRC_IS_REDIRECT(cmd) && + ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) + return; + if (ip) { + uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); + in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, + cmd, udp_notify); + } else + in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); +} + +static int +udp_output(inp, m, addr, control) + register struct inpcb *inp; + register struct mbuf *m; + struct mbuf *addr, *control; +{ + register struct udpiphdr *ui; + register int len = m->m_pkthdr.len; + struct in_addr laddr; + int s = 0, error = 0; + + if (control) + m_freem(control); /* XXX */ + + if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { + error = EMSGSIZE; + goto release; + } + + if (addr) { + laddr = inp->inp_laddr; + if (inp->inp_faddr.s_addr != INADDR_ANY) { + error = EISCONN; + goto release; + } + /* + * Must block input while temporarily connected. + */ + s = splnet(); + error = in_pcbconnect(inp, addr); + if (error) { + splx(s); + goto release; + } + } else { + if (inp->inp_faddr.s_addr == INADDR_ANY) { + error = ENOTCONN; + goto release; + } + } + /* + * Calculate data length and get a mbuf + * for UDP and IP headers. + */ + M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); + if (m == 0) { + error = ENOBUFS; + if (addr) + splx(s); + goto release; + } + + /* + * Fill in mbuf with extended UDP header + * and addresses and length put into network format. + */ + ui = mtod(m, struct udpiphdr *); + ui->ui_next = ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); + ui->ui_src = inp->inp_laddr; + ui->ui_dst = inp->inp_faddr; + ui->ui_sport = inp->inp_lport; + ui->ui_dport = inp->inp_fport; + ui->ui_ulen = ui->ui_len; + + /* + * Stuff checksum and output datagram. + */ + ui->ui_sum = 0; + if (udpcksum) { + if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) + ui->ui_sum = 0xffff; + } + ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; + ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ + ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ + udpstat.udps_opackets++; + error = ip_output(m, inp->inp_options, &inp->inp_route, + inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), + inp->inp_moptions); + + if (addr) { + in_pcbdisconnect(inp); + inp->inp_laddr = laddr; + splx(s); + } + return (error); + +release: + m_freem(m); + return (error); +} + +static u_long udp_sendspace = 9216; /* really max datagram size */ + /* 40 1K datagrams */ +SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, + &udp_sendspace, 0, ""); + +static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); +SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, + &udp_recvspace, 0, ""); + +/*ARGSUSED*/ +int +udp_usrreq(so, req, m, addr, control) + struct socket *so; + int req; + struct mbuf *m, *addr, *control; +{ + struct inpcb *inp = sotoinpcb(so); + int error = 0; + int s; + + if (req == PRU_CONTROL) + return (in_control(so, (u_long)m, (caddr_t)addr, + (struct ifnet *)control)); + if (inp == NULL && req != PRU_ATTACH) { + error = EINVAL; + goto release; + } + /* + * Note: need to block udp_input while changing + * the udp pcb queue and/or pcb addresses. + */ + switch (req) { + + case PRU_ATTACH: + if (inp != NULL) { + error = EINVAL; + break; + } + s = splnet(); + error = in_pcballoc(so, &udbinfo); + splx(s); + if (error) + break; + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + break; + ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl; + break; + + case PRU_DETACH: + udp_detach(inp); + break; + + case PRU_BIND: + s = splnet(); + error = in_pcbbind(inp, addr); + splx(s); + break; + + case PRU_LISTEN: + error = EOPNOTSUPP; + break; + + case PRU_CONNECT: + if (inp->inp_faddr.s_addr != INADDR_ANY) { + error = EISCONN; + break; + } + s = splnet(); + error = in_pcbconnect(inp, addr); + splx(s); + if (error == 0) + soisconnected(so); + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; + break; + + case PRU_ACCEPT: + error = EOPNOTSUPP; + break; + + case PRU_DISCONNECT: + if (inp->inp_faddr.s_addr == INADDR_ANY) { + error = ENOTCONN; + break; + } + s = splnet(); + in_pcbdisconnect(inp); + inp->inp_laddr.s_addr = INADDR_ANY; + splx(s); + so->so_state &= ~SS_ISCONNECTED; /* XXX */ + break; + + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_SEND: + return (udp_output(inp, m, addr, control)); + + case PRU_ABORT: + soisdisconnected(so); + udp_detach(inp); + break; + + case PRU_SOCKADDR: + in_setsockaddr(inp, addr); + break; + + case PRU_PEERADDR: + in_setpeeraddr(inp, addr); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + return (EOPNOTSUPP); /* do not free mbuf's */ + + default: + panic("udp_usrreq"); + } + +release: + if (control) { + printf("udp control data unexpectedly retained\n"); + m_freem(control); + } + if (m) + m_freem(m); + return (error); +} + +static void +udp_detach(inp) + struct inpcb *inp; +{ + int s = splnet(); + + in_pcbdetach(inp); + splx(s); +} diff --git a/cpukit/libnetworking/netinet/udp_var.h b/cpukit/libnetworking/netinet/udp_var.h new file mode 100644 index 0000000000..90785b53de --- /dev/null +++ b/cpukit/libnetworking/netinet/udp_var.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NETINET_UDP_VAR_H_ +#define _NETINET_UDP_VAR_H_ + +/* + * UDP kernel structures and variables. + */ +struct udpiphdr { + struct ipovly ui_i; /* overlaid ip structure */ + struct udphdr ui_u; /* udp header */ +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct udpstat { + /* input statistics: */ + u_long udps_ipackets; /* total input packets */ + u_long udps_hdrops; /* packet shorter than header */ + u_long udps_badsum; /* checksum error */ + u_long udps_badlen; /* data length larger than packet */ + u_long udps_noport; /* no socket on port */ + u_long udps_noportbcast; /* of above, arrived as broadcast */ + u_long udps_fullsock; /* not delivered, input socket full */ + u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ + u_long udpps_pcbhashmiss; /* input packets not for hashed pcb */ + /* output statistics: */ + u_long udps_opackets; /* total output packets */ +}; + +/* + * Names for UDP sysctl objects + */ +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_STATS 2 /* statistics (read-only) */ +#define UDPCTL_MAXDGRAM 3 /* max datagram size */ +#define UDPCTL_RECVSPACE 4 /* default receive buffer space */ +#define UDPCTL_MAXID 5 + +#define UDPCTL_NAMES { \ + { 0, 0 }, \ + { "checksum", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ + { "maxdgram", CTLTYPE_INT }, \ + { "recvspace", CTLTYPE_INT }, \ +} + +#ifdef KERNEL +extern struct inpcbhead udb; +extern struct inpcbinfo udbinfo; +extern struct udpstat udpstat; + +void udp_ctlinput __P((int, struct sockaddr *, void *)); +void udp_init __P((void)); +void udp_input __P((struct mbuf *, int)); +int udp_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +#endif + +#endif diff --git a/cpukit/libnetworking/nfs/bootp_subr.c b/cpukit/libnetworking/nfs/bootp_subr.c new file mode 100644 index 0000000000..f07ce6bd48 --- /dev/null +++ b/cpukit/libnetworking/nfs/bootp_subr.c @@ -0,0 +1,960 @@ +/* $Id$ */ + +/* + * Copyright (c) 1995 Gordon Ross, Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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 the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * based on: + * nfs/krpc_subr.c + * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/sockio.h> +#include <sys/proc.h> +#include <sys/mount.h> +#include <sys/mbuf.h> +#include <sys/reboot.h> +#include <sys/socket.h> +#include <sys/socketvar.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <net/if_types.h> +#include <net/if_dl.h> +#include <netinet/if_ether.h> + +#include <nfs/rpcv2.h> +#include <nfs/nfsproto.h> +#include <nfs/nfs.h> +#include <nfs/nfsdiskless.h> +#include <nfs/krpc.h> +#include <nfs/xdr_subs.h> + + +#define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ + +/* + * What is the longest we will wait before re-sending a request? + * Note this is also the frequency of "RPC timeout" messages. + * The re-send loop count sup linearly to this maximum, so the + * first complaint will happen after (1+2+3+4+5)=15 seconds. + */ +#define MAX_RESEND_DELAY 5 /* seconds */ + +/* Definitions from RFC951 */ +struct bootp_packet { + u_int8_t op; + u_int8_t htype; + u_int8_t hlen; + u_int8_t hops; + u_int32_t xid; + u_int16_t secs; + u_int16_t flags; + struct in_addr ciaddr; + struct in_addr yiaddr; + struct in_addr siaddr; + struct in_addr giaddr; + unsigned char chaddr[16]; + char sname[64]; + char file[128]; + unsigned char vend[256]; +}; + +#define IPPORT_BOOTPC 68 +#define IPPORT_BOOTPS 67 + +extern int nfs_diskless_valid; +extern struct nfsv3_diskless nfsv3_diskless; + +/* mountd RPC */ +static int md_mount __P((struct sockaddr_in *mdsin, char *path, + u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp)); +static int md_lookup_swap __P((struct sockaddr_in *mdsin,char *path, + u_char *fhp, int *fhsizep, + struct nfs_args *args, + struct proc *procp)); +static int setfs __P((struct sockaddr_in *addr, char *path, char *p)); +static int getdec __P((char **ptr)); +static char *substr __P((char *a,char *b)); +static void mountopts __P((struct nfs_args *args, char *p)); +static int xdr_opaque_decode __P((struct mbuf **ptr,u_char *buf, + int len)); +static int xdr_int_decode __P((struct mbuf **ptr,int *iptr)); +static void printip __P((char *prefix,struct in_addr addr)); + +#ifdef BOOTP_DEBUG +void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma); +void bootpboot_p_ma(struct sockaddr *ma); +void bootpboot_p_rtentry(struct rtentry *rt); +void bootpboot_p_tree(struct radix_node *rn); +void bootpboot_p_rtlist(void); +void bootpboot_p_iflist(void); +#endif + +int bootpc_call(struct bootp_packet *call, + struct bootp_packet *reply, + struct proc *procp); + +int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, + struct proc *procp); + +int +bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, + struct sockaddr_in *myaddr, + struct sockaddr_in *netmask, + struct sockaddr_in *gw, + struct proc *procp); + +void bootpc_init(void); + +#ifdef BOOTP_DEBUG +void bootpboot_p_sa(sa,ma) + struct sockaddr *sa; + struct sockaddr *ma; +{ + if (!sa) { + printf("(sockaddr *) <null>"); + return; + } + switch (sa->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + printf("inet %x",ntohl(sin->sin_addr.s_addr)); + if (ma) { + struct sockaddr_in *sin = (struct sockaddr_in *) ma; + printf(" mask %x",ntohl(sin->sin_addr.s_addr)); + } + } + break; + case AF_LINK: + { + struct sockaddr_dl *sli = (struct sockaddr_dl *) sa; + int i; + printf("link %.*s ",sli->sdl_nlen,sli->sdl_data); + for (i=0;i<sli->sdl_alen;i++) { + if (i>0) + printf(":"); + printf("%x",(unsigned char) sli->sdl_data[i+sli->sdl_nlen]); + } + } + break; + default: + printf("af%d",sa->sa_family); + } +} + +void bootpboot_p_ma(ma) + struct sockaddr *ma; +{ + if (!ma) { + printf("<null>"); + return; + } + printf("%x",*(int*)ma); +} + +void bootpboot_p_rtentry(rt) + struct rtentry *rt; +{ + bootpboot_p_sa(rt_key(rt),rt_mask(rt)); + printf(" "); + bootpboot_p_ma(rt->rt_genmask); + printf(" "); + bootpboot_p_sa(rt->rt_gateway,NULL); + printf(" "); + printf("flags %x",(unsigned short) rt->rt_flags); + printf(" %d",rt->rt_rmx.rmx_expire); + printf(" %s%d\n",rt->rt_ifp->if_name,rt->rt_ifp->if_unit); +} +void bootpboot_p_tree(rn) + struct radix_node *rn; +{ + while (rn) { + if (rn->rn_b < 0) { + if (rn->rn_flags & RNF_ROOT) { + } else { + bootpboot_p_rtentry((struct rtentry *) rn); + } + rn = rn->rn_dupedkey; + } else { + bootpboot_p_tree(rn->rn_l); + bootpboot_p_tree(rn->rn_r); + return; + } + + } +} + +void bootpboot_p_rtlist(void) +{ + printf("Routing table:\n"); + bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop); +} + +void bootpboot_p_iflist(void) +{ + struct ifnet *ifp; + struct ifaddr *ifa; + printf("Interface list:\n"); + for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link)) + { + for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa; + ifa=TAILQ_NEXT(ifa,ifa_link)) + if (ifa->ifa_addr->sa_family == AF_INET ) { + printf("%s%d flags %x, addr %x, bcast %x, net %x\n", + ifp->if_name,ifp->if_unit, + (unsigned short) ifp->if_flags, + ntohl(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr.s_addr), + ntohl(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr) + ); + } + } +} +#endif + +int +bootpc_call(call,reply,procp) + struct bootp_packet *call; + struct bootp_packet *reply; /* output */ + struct proc *procp; +{ + struct socket *so; + struct sockaddr_in *sin,sa; + struct mbuf *m, *nam; + struct uio auio; + struct iovec aio; + int error, rcvflg, timo, secs, len; + u_int tport; + + /* Free at end if not null. */ + nam = NULL; + + /* + * Create socket and set its recieve timeout. + */ + if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp))) + goto out; + + m = m_get(M_WAIT, MT_SOOPTS); + if (m == NULL) { + error = ENOBUFS; + goto out; + } else { + struct timeval *tv; + tv = mtod(m, struct timeval *); + m->m_len = sizeof(*tv); + tv->tv_sec = 1; + tv->tv_usec = 0; + if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) + goto out; + } + + /* + * Enable broadcast. + */ + { + int *on; + m = m_get(M_WAIT, MT_SOOPTS); + if (m == NULL) { + error = ENOBUFS; + goto out; + } + on = mtod(m, int *); + m->m_len = sizeof(*on); + *on = 1; + if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m))) + goto out; + } + + /* + * Bind the local endpoint to a bootp client port. + */ + m = m_getclr(M_WAIT, MT_SONAME); + sin = mtod(m, struct sockaddr_in *); + sin->sin_len = m->m_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = htons(IPPORT_BOOTPC); + error = sobind(so, m); + m_freem(m); + if (error) { + printf("bind failed\n"); + goto out; + } + + /* + * Setup socket address for the server. + */ + nam = m_get(M_WAIT, MT_SONAME); + if (nam == NULL) { + error = ENOBUFS; + goto out; + } + sin = mtod(nam, struct sockaddr_in *); + sin-> sin_len = sizeof(*sin); + sin-> sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_BROADCAST; + sin->sin_port = htons(IPPORT_BOOTPS); + + nam->m_len = sizeof(*sin); + + /* + * Send it, repeatedly, until a reply is received, + * but delay each re-send by an increasing amount. + * If the delay hits the maximum, start complaining. + */ + timo = 0; + for (;;) { + /* Send BOOTP request (or re-send). */ + + aio.iov_base = (caddr_t) call; + aio.iov_len = sizeof(*call); + + auio.uio_iov = &aio; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_offset = 0; + auio.uio_resid = sizeof(*call); + auio.uio_procp = procp; + + error = sosend(so, nam, &auio, NULL, NULL, 0); + if (error) { + printf("bootpc_call: sosend: %d\n", error); + goto out; + } + + /* Determine new timeout. */ + if (timo < MAX_RESEND_DELAY) + timo++; + else + printf("BOOTP timeout for server 0x%x\n", + (int)ntohl(sin->sin_addr.s_addr)); + + /* + * Wait for up to timo seconds for a reply. + * The socket receive timeout was set to 1 second. + */ + secs = timo; + while (secs > 0) { + aio.iov_base = (caddr_t) reply; + aio.iov_len = sizeof(*reply); + + auio.uio_iov = &aio; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_offset = 0; + auio.uio_resid = sizeof(*reply); + auio.uio_procp = procp; + + rcvflg = 0; + error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg); + if (error == EWOULDBLOCK) { + secs--; + call->secs=htons(ntohs(call->secs)+1); + continue; + } + if (error) + goto out; + len = sizeof(*reply) - auio.uio_resid; + + /* Do we have the required number of bytes ? */ + if (len < BOOTP_MIN_LEN) + continue; + + /* Is it the right reply? */ + if (reply->op != 2) + continue; + + if (reply->xid != call->xid) + continue; + + if (reply->hlen != call->hlen) + continue; + + if (bcmp(reply->chaddr,call->chaddr,call->hlen)) + continue; + + goto gotreply; /* break two levels */ + + } /* while secs */ + } /* forever send/receive */ + + error = ETIMEDOUT; + goto out; + + gotreply: + out: + if (nam) m_freem(nam); + soclose(so); + return error; +} + +int +bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, + struct proc *procp) +{ + struct sockaddr_in *sin; + int error; + struct sockaddr_in dst; + struct sockaddr_in gw; + struct sockaddr_in mask; + + /* + * Bring up the interface. + * + * Get the old interface flags and or IFF_UP into them; if + * IFF_UP set blindly, interface selection can be clobbered. + */ + error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); + if (error) + panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error); + ireq->ifr_flags |= IFF_UP; + error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); + if (error) + panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error); + + /* + * Do enough of ifconfig(8) so that the chosen interface + * can talk to the servers. (just set the address) + */ + + /* addr is 0.0.0.0 */ + + sin = (struct sockaddr_in *)&ireq->ifr_addr; + bzero((caddr_t)sin, sizeof(*sin)); + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); + if (error) + panic("bootpc_fakeup_interface: set if addr, error=%d", error); + + /* netmask is 0.0.0.0 */ + + sin = (struct sockaddr_in *)&ireq->ifr_addr; + bzero((caddr_t)sin, sizeof(*sin)); + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); + if (error) + panic("bootpc_fakeup_interface: set if net addr, error=%d", error); + + /* Broadcast is 255.255.255.255 */ + + sin = (struct sockaddr_in *)&ireq->ifr_addr; + bzero((caddr_t)sin, sizeof(*sin)); + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_BROADCAST; + error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); + if (error) + panic("bootpc_fakeup_interface: set if broadcast addr, error=%d", error); + + /* Add default route to 0.0.0.0 so we can send data */ + + bzero((caddr_t) &dst, sizeof(dst)); + dst.sin_len=sizeof(dst); + dst.sin_family=AF_INET; + dst.sin_addr.s_addr = htonl(0); + + bzero((caddr_t) &gw, sizeof(gw)); + gw.sin_len=sizeof(gw); + gw.sin_family=AF_INET; + gw.sin_addr.s_addr = htonl(0x0); + + bzero((caddr_t) &mask, sizeof(mask)); + mask.sin_len=sizeof(mask); + mask.sin_family=AF_INET; + mask.sin_addr.s_addr = htonl(0); + + error = rtrequest(RTM_ADD, + (struct sockaddr *) &dst, + (struct sockaddr *) &gw, + (struct sockaddr *) &mask, + RTF_UP | RTF_STATIC + , NULL); + if (error) + printf("bootpc_fakeup_interface: add default route, error=%d\n", error); + return error; +} + +int +bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, + struct sockaddr_in *myaddr, + struct sockaddr_in *netmask, + struct sockaddr_in *gw, + struct proc *procp) +{ + int error; + struct sockaddr_in oldgw; + struct sockaddr_in olddst; + struct sockaddr_in oldmask; + struct sockaddr_in *sin; + + /* Remove old default route to 0.0.0.0 */ + + bzero((caddr_t) &olddst, sizeof(olddst)); + olddst.sin_len=sizeof(olddst); + olddst.sin_family=AF_INET; + olddst.sin_addr.s_addr = INADDR_ANY; + + bzero((caddr_t) &oldgw, sizeof(oldgw)); + oldgw.sin_len=sizeof(oldgw); + oldgw.sin_family=AF_INET; + oldgw.sin_addr.s_addr = INADDR_ANY; + + bzero((caddr_t) &oldmask, sizeof(oldmask)); + oldmask.sin_len=sizeof(oldmask); + oldmask.sin_family=AF_INET; + oldmask.sin_addr.s_addr = INADDR_ANY; + + error = rtrequest(RTM_DELETE, + (struct sockaddr *) &olddst, + (struct sockaddr *) &oldgw, + (struct sockaddr *) &oldmask, + (RTF_UP | RTF_STATIC), NULL); + if (error) { + printf("nfs_boot: del default route, error=%d\n", error); + return error; + } + + /* + * Do enough of ifconfig(8) so that the chosen interface + * can talk to the servers. (just set the address) + */ + bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask)); + error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); + if (error) + panic("nfs_boot: set if netmask, error=%d", error); + + /* Broadcast is with host part of IP address all 1's */ + + sin = (struct sockaddr_in *)&ireq->ifr_addr; + bzero((caddr_t)sin, sizeof(*sin)); + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; + error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); + if (error) + panic("bootpc_call: set if broadcast addr, error=%d", error); + + bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); + error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); + if (error) + panic("nfs_boot: set if addr, error=%d", error); + + /* Add new default route */ + + error = rtrequest(RTM_ADD, + (struct sockaddr *) &olddst, + (struct sockaddr *) gw, + (struct sockaddr *) &oldmask, + (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); + if (error) { + printf("nfs_boot: add net route, error=%d\n", error); + return error; + } + + return 0; +} + +static int setfs(addr, path, p) + struct sockaddr_in *addr; + char *path; + char *p; +{ + unsigned ip = 0; + int val; + + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + ip = val << 24; + if (*p != '.') return(0); + p++; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + ip |= (val << 16); + if (*p != '.') return(0); + p++; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + ip |= (val << 8); + if (*p != '.') return(0); + p++; + if (((val = getdec(&p)) < 0) || (val > 255)) return(0); + ip |= val; + if (*p != ':') return(0); + p++; + + addr->sin_addr.s_addr = htonl(ip); + addr->sin_len = sizeof(struct sockaddr_in); + addr->sin_family = AF_INET; + + strncpy(path,p,MNAMELEN-1); + return(1); +} + +static int getdec(ptr) + char **ptr; +{ + char *p = *ptr; + int ret=0; + if ((*p < '0') || (*p > '9')) return(-1); + while ((*p >= '0') && (*p <= '9')) { + ret = ret*10 + (*p - '0'); + p++; + } + *ptr = p; + return(ret); +} + +static char *substr(a,b) + char *a,*b; +{ + char *loc1; + char *loc2; + + while (*a != '\0') { + loc1 = a; + loc2 = b; + while (*loc1 == *loc2++) { + if (*loc1 == '\0') return (0); + loc1++; + if (*loc2 == '\0') return (loc1); + } + a++; + } + return (0); +} + +static void printip(char *prefix,struct in_addr addr) +{ + unsigned int ip; + + ip = ntohl(addr.s_addr); + + printf("%s is %d.%d.%d.%d\n",prefix, + ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 ); +} + +void +bootpc_init(void) +{ + struct bootp_packet call; + struct bootp_packet reply; + static u_int32_t xid = ~0xFF; + + struct ifreq ireq; + struct ifnet *ifp; + struct socket *so; + int error; + int code,ncode,len; + int i,j; + char *p; + unsigned int ip; + + struct sockaddr_in myaddr; + struct sockaddr_in netmask; + struct sockaddr_in gw; + int gotgw=0; + int gotnetmask=0; + int gotrootpath=0; + int gotswappath=0; + char lookup_path[24]; + +#define EALEN 6 + unsigned char ea[EALEN]; + struct ifaddr *ifa; + struct sockaddr_dl *sdl = NULL; + char *delim; + struct proc *procp = NULL; + + /* + * If already filled in, don't touch it here + */ + if (nfs_diskless_valid) + return; + + /* + * Bump time if 0. + if (!time.tv_sec) + time.tv_sec++; + */ + + /* + * Find a network interface. + */ + for (ifp = ifnet; ifp != 0; ifp = ifp->if_next) + if ((ifp->if_flags & + (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) + break; + if (ifp == NULL) + panic("bootpc_init: no suitable interface"); + bzero(&ireq,sizeof(ireq)); + sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit); + printf("bootpc_init: using network interface '%s'\n", + ireq.ifr_name); + + if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) + panic("nfs_boot: socreate, error=%d", error); + + bootpc_fakeup_interface(&ireq,so,procp); + + printf("Bootpc testing starting\n"); + + /* Get HW address */ + + for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_LINK && + (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) && + sdl->sdl_type == IFT_ETHER) + break; + + if (!sdl) + panic("bootpc: Unable to find HW address"); + if (sdl->sdl_alen != EALEN ) + panic("bootpc: HW address len is %d, expected value is %d", + sdl->sdl_alen,EALEN); + + printf("bootpc hw address is "); + delim=""; + for (j=0;j<sdl->sdl_alen;j++) { + printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]); + delim=":"; + } + printf("\n"); + +#if 0 + bootpboot_p_iflist(); + bootpboot_p_rtlist(); +#endif + + bzero((caddr_t) &call, sizeof(call)); + + /* bootpc part */ + call.op = 1; /* BOOTREQUEST */ + call.htype= 1; /* 10mb ethernet */ + call.hlen=sdl->sdl_alen; /* Hardware address length */ + call.hops=0; + xid++; + call.xid = txdr_unsigned(xid); + bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen); + + call.vend[0]=99; + call.vend[1]=130; + call.vend[2]=83; + call.vend[3]=99; + call.vend[4]=255; + + call.secs = 0; + call.flags = htons(0x8000); /* We need an broadcast answer */ + + error = bootpc_call(&call,&reply,procp); + + if (error) + panic("BOOTP call failed -- error %d", error); + + bzero(&myaddr,sizeof(myaddr)); + bzero(&netmask,sizeof(netmask)); + bzero(&gw,sizeof(gw)); + + myaddr.sin_len = sizeof(myaddr); + myaddr.sin_family = AF_INET; + + netmask.sin_len = sizeof(netmask); + netmask.sin_family = AF_INET; + + gw.sin_len = sizeof(gw); + gw.sin_family= AF_INET; + + rtems_bsdnet_bootp_server_address = reply.siaddr; + rtems_bsdnet_log_host_address = reply.siaddr; + + myaddr.sin_addr = reply.yiaddr; + + ip = ntohl(myaddr.sin_addr.s_addr); + sprintf(lookup_path,"swap.%d.%d.%d.%d", + ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 ); + + printip("My ip address",myaddr.sin_addr); + + printip("Server ip address",reply.siaddr); + + gw.sin_addr = reply.giaddr; + printip("Gateway ip address",reply.giaddr); + + if (reply.sname[0]) + printf("Server name is %s\n",reply.sname); + if (reply.file[0]) + printf("boot file is %s\n",reply.file); + rtems_bsdnet_bootp_boot_file_name = strdup (reply.file); + if (reply.vend[0]==99 && reply.vend[1]==130 && + reply.vend[2]==83 && reply.vend[3]==99) { + j=4; + ncode = reply.vend[j]; + while (j<sizeof(reply.vend)) { + code = reply.vend[j] = ncode; + if (code==255) + break; + if (code==0) { + j++; + continue; + } + len = reply.vend[j+1]; + j+=2; + if (len+j>=sizeof(reply.vend)) { + printf("Truncated field"); + break; + } + ncode = reply.vend[j+len]; + reply.vend[j+len]='\0'; + p = &reply.vend[j]; + switch (code) { + case 1: + if (len!=4) + panic("bootpc: subnet mask len is %d",len); + bcopy(&reply.vend[j],&netmask.sin_addr,4); + gotnetmask=1; + printip("Subnet mask",netmask.sin_addr); + break; + case 6: + /* Domain Name servers */ + if (len % 4) + panic("bootpc: DNS Len is %d",len); + { + int dlen = 0; + while ((dlen < len) && + (rtems_bsdnet_nameserver_count < sizeof rtems_bsdnet_config.name_server / + sizeof rtems_bsdnet_config.name_server[0])) { + bcopy(&reply.vend[j+dlen], + &rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count], + 4); + printip("Domain Name Server", + rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count]); + rtems_bsdnet_nameserver_count++; + dlen += 4; + } + } + break; + case 16: /* Swap server IP address. unused */ + case 2: + /* Time offset */ + break; + case 3: + /* Routers */ + if (len % 4) + panic("bootpc: Router Len is %d",len); + if (len > 0) { + bcopy(&reply.vend[j],&gw.sin_addr,4); + printip("Router",gw.sin_addr); + gotgw=1; + } + break; + case 7: + /* Log servers */ + if (len % 4) + panic("bootpc: Log server len is %d",len); + if (len > 0) { + bcopy(&reply.vend[j],&rtems_bsdnet_log_host_address,4); + printip("Log server",rtems_bsdnet_log_host_address); + } + break; + case 12: + if (len>=MAXHOSTNAMELEN) + panic("bootpc: hostname >=%d bytes",MAXHOSTNAMELEN); + if (sethostname (&reply.vend[j], len) < 0) + panic("Can't set host name"); + printf("Hostname is %.*s\n",len,&reply.vend[j]); + break; + case 15: + /* Domain name */ + rtems_bsdnet_domain_name = strdup (&reply.vend[j]); + if (rtems_bsdnet_domain_name) + printf("Domain name is %s\n", rtems_bsdnet_domain_name); + break; + default: + printf("Ignoring field type %d\n",code); + } + j+=len; + } + } + + if (!gotnetmask) { + if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr))) + netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr))) + netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); + else + netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); + } + if (!gotgw) { + /* Use proxyarp */ + gw.sin_addr.s_addr = myaddr.sin_addr.s_addr; + } + +#if 0 + bootpboot_p_iflist(); + bootpboot_p_rtlist(); +#endif + error = bootpc_adjust_interface(&ireq,so, + &myaddr,&netmask,&gw,procp); + + soclose(so); + +#if 0 + bootpboot_p_iflist(); + bootpboot_p_rtlist(); +#endif + + +#if 0 + myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; +#endif + +#if 0 + bootpboot_p_iflist(); + bootpboot_p_rtlist(); +#endif + return; +} diff --git a/cpukit/libnetworking/nfs/krpc.h b/cpukit/libnetworking/nfs/krpc.h new file mode 100644 index 0000000000..8a21392657 --- /dev/null +++ b/cpukit/libnetworking/nfs/krpc.h @@ -0,0 +1,26 @@ +/* $NetBSD: krpc.h,v 1.4 1995/12/19 23:07:11 cgd Exp $ */ +/* $Id$ */ + +#include <sys/cdefs.h> + +int krpc_call __P((struct sockaddr_in *sin, + u_int prog, u_int vers, u_int func, + struct mbuf **data, struct mbuf **from, struct proc *procp)); + +int krpc_portmap __P((struct sockaddr_in *sin, + u_int prog, u_int vers, u_int16_t *portp, struct proc *procp)); + +struct mbuf *xdr_string_encode __P((char *str, int len)); + +/* + * RPC definitions for the portmapper + */ +#define PMAPPORT 111 +#define PMAPPROG 100000 +#define PMAPVERS 2 +#define PMAPPROC_NULL 0 +#define PMAPPROC_SET 1 +#define PMAPPROC_UNSET 2 +#define PMAPPROC_GETPORT 3 +#define PMAPPROC_DUMP 4 +#define PMAPPROC_CALLIT 5 diff --git a/cpukit/libnetworking/nfs/nfs.h b/cpukit/libnetworking/nfs/nfs.h new file mode 100644 index 0000000000..68f206e213 --- /dev/null +++ b/cpukit/libnetworking/nfs/nfs.h @@ -0,0 +1,620 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NFS_NFS_H_ +#define _NFS_NFS_H_ + +#include <nfs/rpcv2.h> + +/* + * Tunable constants for nfs + */ + +#define NFS_MAXIOVEC 34 +#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ +#define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ +#define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */ +#define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */ +#define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */ +#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/ +#define NFS_MAXREXMIT 100 /* Stop counting after this many */ +#define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */ +#define NFS_RETRANS 10 /* Num of retrans for soft mounts */ +#define NFS_MAXGRPS 16 /* Max. size of groups list */ +#ifndef NFS_MINATTRTIMO +#define NFS_MINATTRTIMO 5 /* Attribute cache timeout in sec */ +#endif +#ifndef NFS_MAXATTRTIMO +#define NFS_MAXATTRTIMO 60 +#endif +#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */ +#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */ +#define NFS_READDIRSIZE 8192 /* Def. readdir size */ +#define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ +#define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ +#define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ +#ifndef NFS_GATHERDELAY +#define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ +#endif +#define NFS_DIRBLKSIZ 4096 /* Must be a multiple of DIRBLKSIZ */ + +/* + * Oddballs + */ +#define NMOD(a) ((a) % nfs_asyncdaemons) +#define NFS_CMPFH(n, f, s) \ + ((n)->n_fhsize == (s) && !bcmp((caddr_t)(n)->n_fhp, (caddr_t)(f), (s))) +#define NFS_ISV3(v) (VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV3) +#define NFS_SRVMAXDATA(n) \ + (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \ + NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA) + +/* + * XXX + * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but + * until then... + * Same goes for sys/malloc.h, which needs M_NFSDIROFF, + * M_NFSRVDESC and M_NFSBIGFH added. + * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an + * exclusive create. + * The B_INVAFTERWRITE flag should be set to whatever is required by the + * buffer cache code to say "Invalidate the block after it is written back". + */ +#ifndef B_NEEDCOMMIT +#define B_NEEDCOMMIT B_APPENDWRITE +#endif +#ifndef M_NFSRVDESC +#define M_NFSRVDESC M_TEMP +#endif +#ifndef M_NFSDIROFF +#define M_NFSDIROFF M_TEMP +#endif +#ifndef M_NFSBIGFH +#define M_NFSBIGFH M_TEMP +#endif +#ifndef VA_EXCLUSIVE +#define VA_EXCLUSIVE 0 +#endif +#ifdef __FreeBSD__ +#define B_INVAFTERWRITE B_NOCACHE +#else +#define B_INVAFTERWRITE B_INVAL +#endif + +/* + * These ifdefs try to handle the differences between the various 4.4BSD-Lite + * based vfs interfaces. + * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to + * differentiate between NetBSD-1.0 and NetBSD-current, so.. + * I also don't know about BSDi's 2.0 release. + */ +#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#define HAS_VOPLEASE 1 +#endif +#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#define HAS_VOPREVOKE 1 +#endif + +/* + * The IO_METASYNC flag should be implemented for local file systems. + * (Until then, it is nothin at all.) + */ +#ifndef IO_METASYNC +#define IO_METASYNC 0 +#endif + +/* + * Set the attribute timeout based on how recently the file has been modified. + */ +#define NFS_ATTRTIMEO(np) \ + ((((np)->n_flag & NMODIFIED) || \ + (time.tv_sec - (np)->n_mtime) / 10 < NFS_MINATTRTIMO) ? NFS_MINATTRTIMO : \ + ((time.tv_sec - (np)->n_mtime) / 10 > NFS_MAXATTRTIMO ? NFS_MAXATTRTIMO : \ + (time.tv_sec - (np)->n_mtime) / 10)) + +/* + * Expected allocation sizes for major data structures. If the actual size + * of the structure exceeds these sizes, then malloc() will be allocating + * almost twice the memory required. This is used in nfs_init() to warn + * the sysadmin that the size of a structure should be reduced. + * (These sizes are always a power of 2. If the kernel malloc() changes + * to one that does not allocate space in powers of 2 size, then this all + * becomes bunk!) + */ +#define NFS_NODEALLOC 256 +#define NFS_MNTALLOC 512 +#define NFS_SVCALLOC 256 +#define NFS_UIDALLOC 128 + +/* + * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs + * should ever try and use it. + */ +struct nfsd_args { + int sock; /* Socket to serve */ + caddr_t name; /* Client address for connection based sockets */ + int namelen; /* Length of name */ +}; + +struct nfsd_srvargs { + struct nfsd *nsd_nfsd; /* Pointer to in kernel nfsd struct */ + uid_t nsd_uid; /* Effective uid mapped to cred */ + u_long nsd_haddr; /* Ip address of client */ + struct ucred nsd_cr; /* Cred. uid maps to */ + int nsd_authlen; /* Length of auth string (ret) */ + u_char *nsd_authstr; /* Auth string (ret) */ + int nsd_verflen; /* and the verfier */ + u_char *nsd_verfstr; + struct timeval nsd_timestamp; /* timestamp from verifier */ + u_long nsd_ttl; /* credential ttl (sec) */ + NFSKERBKEY_T nsd_key; /* Session key */ +}; + +struct nfsd_cargs { + char *ncd_dirp; /* Mount dir path */ + uid_t ncd_authuid; /* Effective uid */ + int ncd_authtype; /* Type of authenticator */ + int ncd_authlen; /* Length of authenticator string */ + u_char *ncd_authstr; /* Authenticator string */ + int ncd_verflen; /* and the verifier */ + u_char *ncd_verfstr; + NFSKERBKEY_T ncd_key; /* Session key */ +}; + +/* + * Stats structure + */ +struct nfsstats { + int attrcache_hits; + int attrcache_misses; + int lookupcache_hits; + int lookupcache_misses; + int direofcache_hits; + int direofcache_misses; + int biocache_reads; + int read_bios; + int read_physios; + int biocache_writes; + int write_bios; + int write_physios; + int biocache_readlinks; + int readlink_bios; + int biocache_readdirs; + int readdir_bios; + int rpccnt[NFS_NPROCS]; + int rpcretries; + int srvrpccnt[NFS_NPROCS]; + int srvrpc_errs; + int srv_errs; + int rpcrequests; + int rpctimeouts; + int rpcunexpected; + int rpcinvalid; + int srvcache_inproghits; + int srvcache_idemdonehits; + int srvcache_nonidemdonehits; + int srvcache_misses; + int srvnqnfs_leases; + int srvnqnfs_maxleases; + int srvnqnfs_getleases; + int srvvop_writes; +}; + +/* + * Flags for nfssvc() system call. + */ +#define NFSSVC_BIOD 0x002 +#define NFSSVC_NFSD 0x004 +#define NFSSVC_ADDSOCK 0x008 +#define NFSSVC_AUTHIN 0x010 +#define NFSSVC_GOTAUTH 0x040 +#define NFSSVC_AUTHINFAIL 0x080 +#define NFSSVC_MNTD 0x100 + +/* + * fs.nfs sysctl(3) identifiers + */ +#define NFS_NFSSTATS 1 /* struct: struct nfsstats */ +#define NFS_NFSPRIVPORT 2 /* int: prohibit nfs to resvports */ + +#define FS_NFS_NAMES { \ + { 0, 0 }, \ + { "nfsstats", CTLTYPE_STRUCT }, \ + { "nfsprivport", CTLTYPE_INT }, \ +} + +/* + * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts. + * What should be in this set is open to debate, but I believe that since + * I/O system calls on ufs are never interrupted by signals the set should + * be minimal. My reasoning is that many current programs that use signals + * such as SIGALRM will not expect file I/O system calls to be interrupted + * by them and break. + */ +#if defined(KERNEL) || defined(_KERNEL) + +struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ + +#define NFSINT_SIGMASK (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \ + sigmask(SIGHUP)|sigmask(SIGQUIT)) + +/* + * Socket errors ignored for connectionless sockets?? + * For now, ignore them all + */ +#define NFSIGNORE_SOERROR(s, e) \ + ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK && \ + ((s) & PR_CONNREQUIRED) == 0) + +/* + * Nfs outstanding request list element + */ +struct nfsreq { + TAILQ_ENTRY(nfsreq) r_chain; + struct mbuf *r_mreq; + struct mbuf *r_mrep; + struct mbuf *r_md; + caddr_t r_dpos; + struct nfsmount *r_nmp; + struct vnode *r_vp; + u_long r_xid; + int r_flags; /* flags on request, see below */ + int r_retry; /* max retransmission count */ + int r_rexmit; /* current retrans count */ + int r_timer; /* tick counter on reply */ + int r_procnum; /* NFS procedure number */ + int r_rtt; /* RTT for rpc */ + struct proc *r_procp; /* Proc that did I/O system call */ +}; + +/* + * Queue head for nfsreq's + */ +extern TAILQ_HEAD(nfs_reqq, nfsreq) nfs_reqq; + +/* Flag values for r_flags */ +#define R_TIMING 0x01 /* timing request (in mntp) */ +#define R_SENT 0x02 /* request has been sent */ +#define R_SOFTTERM 0x04 /* soft mnt, too many retries */ +#define R_INTR 0x08 /* intr mnt, signal pending */ +#define R_SOCKERR 0x10 /* Fatal error on socket */ +#define R_TPRINTFMSG 0x20 /* Did a tprintf msg. */ +#define R_MUSTRESEND 0x40 /* Must resend request */ +#define R_GETONEREP 0x80 /* Probe for one reply only */ + +/* + * A list of nfssvc_sock structures is maintained with all the sockets + * that require service by the nfsd. + * The nfsuid structs hang off of the nfssvc_sock structs in both lru + * and uid hash lists. + */ +#ifndef NFS_UIDHASHSIZ +#define NFS_UIDHASHSIZ 29 /* Tune the size of nfssvc_sock with this */ +#endif +#define NUIDHASH(sock, uid) \ + (&(sock)->ns_uidhashtbl[(uid) % NFS_UIDHASHSIZ]) +#ifndef NFS_WDELAYHASHSIZ +#define NFS_WDELAYHASHSIZ 16 /* and with this */ +#endif +#define NWDELAYHASH(sock, f) \ + (&(sock)->ns_wdelayhashtbl[(*((u_long *)(f))) % NFS_WDELAYHASHSIZ]) +#ifndef NFS_MUIDHASHSIZ +#define NFS_MUIDHASHSIZ 63 /* Tune the size of nfsmount with this */ +#endif +#define NMUIDHASH(nmp, uid) \ + (&(nmp)->nm_uidhashtbl[(uid) % NFS_MUIDHASHSIZ]) +#define NFSNOHASH(fhsum) \ + (&nfsnodehashtbl[(fhsum) & nfsnodehash]) + +/* + * Network address hash list element + */ +union nethostaddr { + u_long had_inetaddr; + struct mbuf *had_nam; +}; + +struct nfsuid { + TAILQ_ENTRY(nfsuid) nu_lru; /* LRU chain */ + LIST_ENTRY(nfsuid) nu_hash; /* Hash list */ + int nu_flag; /* Flags */ + union nethostaddr nu_haddr; /* Host addr. for dgram sockets */ + struct ucred nu_cr; /* Cred uid mapped to */ + int nu_expire; /* Expiry time (sec) */ + struct timeval nu_timestamp; /* Kerb. timestamp */ + u_long nu_nickname; /* Nickname on server */ + NFSKERBKEY_T nu_key; /* and session key */ +}; + +#define nu_inetaddr nu_haddr.had_inetaddr +#define nu_nam nu_haddr.had_nam +/* Bits for nu_flag */ +#define NU_INETADDR 0x1 +#define NU_NAM 0x2 +#define NU_NETFAM(u) (((u)->nu_flag & NU_INETADDR) ? AF_INET : AF_ISO) + +struct nfssvc_sock { + TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */ + TAILQ_HEAD(, nfsuid) ns_uidlruhead; + struct file *ns_fp; + struct socket *ns_so; + struct mbuf *ns_nam; + struct mbuf *ns_raw; + struct mbuf *ns_rawend; + struct mbuf *ns_rec; + struct mbuf *ns_recend; + struct mbuf *ns_frag; + int ns_flag; + int ns_solock; + int ns_cc; + int ns_reclen; + int ns_numuids; + u_long ns_sref; + LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */ + LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ]; + LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ]; +}; + +/* Bits for "ns_flag" */ +#define SLP_VALID 0x01 +#define SLP_DOREC 0x02 +#define SLP_NEEDQ 0x04 +#define SLP_DISCONN 0x08 +#define SLP_GETSTREAM 0x10 +#define SLP_LASTFRAG 0x20 +#define SLP_ALLFLAGS 0xff + +extern TAILQ_HEAD(nfssvc_sockhead, nfssvc_sock) nfssvc_sockhead; +extern int nfssvc_sockhead_flag; +#define SLP_INIT 0x01 +#define SLP_WANTINIT 0x02 + +/* + * One of these structures is allocated for each nfsd. + */ +struct nfsd { + TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */ + int nfsd_flag; /* NFSD_ flags */ + struct nfssvc_sock *nfsd_slp; /* Current socket */ + int nfsd_authlen; /* Authenticator len */ + u_char nfsd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */ + int nfsd_verflen; /* and the Verifier */ + u_char nfsd_verfstr[RPCVERF_MAXSIZ]; + struct proc *nfsd_procp; /* Proc ptr */ + struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */ +}; + +/* Bits for "nfsd_flag" */ +#define NFSD_WAITING 0x01 +#define NFSD_REQINPROG 0x02 +#define NFSD_NEEDAUTH 0x04 +#define NFSD_AUTHFAIL 0x08 + +/* + * This structure is used by the server for describing each request. + * Some fields are used only when write request gathering is performed. + */ +struct nfsrv_descript { + u_quad_t nd_time; /* Write deadline (usec) */ + off_t nd_off; /* Start byte offset */ + off_t nd_eoff; /* and end byte offset */ + LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */ + LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */ + LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */ + struct mbuf *nd_mrep; /* Request mbuf list */ + struct mbuf *nd_md; /* Current dissect mbuf */ + struct mbuf *nd_mreq; /* Reply mbuf list */ + struct mbuf *nd_nam; /* and socket addr */ + struct mbuf *nd_nam2; /* return socket addr */ + caddr_t nd_dpos; /* Current dissect pos */ + int nd_procnum; /* RPC # */ + int nd_stable; /* storage type */ + int nd_flag; /* nd_flag */ + int nd_len; /* Length of this write */ + int nd_repstat; /* Reply status */ + u_long nd_retxid; /* Reply xid */ + u_long nd_duration; /* Lease duration */ + struct timeval nd_starttime; /* Time RPC initiated */ + fhandle_t nd_fh; /* File handle */ + struct ucred nd_cr; /* Credentials */ +}; + +/* Bits for "nd_flag" */ +#define ND_READ LEASE_READ +#define ND_WRITE LEASE_WRITE +#define ND_CHECK 0x04 +#define ND_LEASE (ND_READ | ND_WRITE | ND_CHECK) +#define ND_NFSV3 0x08 +#define ND_NQNFS 0x10 +#define ND_KERBNICK 0x20 +#define ND_KERBFULL 0x40 +#define ND_KERBAUTH (ND_KERBNICK | ND_KERBFULL) + +extern TAILQ_HEAD(nfsd_head, nfsd) nfsd_head; +extern int nfsd_head_flag; +#define NFSD_CHECKSLP 0x01 + +/* + * These macros compare nfsrv_descript structures. + */ +#define NFSW_CONTIG(o, n) \ + ((o)->nd_eoff >= (n)->nd_off && \ + !bcmp((caddr_t)&(o)->nd_fh, (caddr_t)&(n)->nd_fh, NFSX_V3FH)) + +#define NFSW_SAMECRED(o, n) \ + (((o)->nd_flag & ND_KERBAUTH) == ((n)->nd_flag & ND_KERBAUTH) && \ + !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ + sizeof (struct ucred))) + +int nfs_reply __P((struct nfsreq *)); +int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); +int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); +int nfs_rephead __P((int,struct nfsrv_descript *,struct nfssvc_sock *,int,int,u_quad_t *,struct mbuf **,struct mbuf **,caddr_t *)); +int nfs_sndlock __P((int *,struct nfsreq *)); +void nfs_sndunlock __P((int *flagp)); +int nfs_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *)); +int nfs_vinvalbuf __P((struct vnode *,int,struct ucred *,struct proc *,int)); +int nfs_readrpc __P((struct vnode *,struct uio *,struct ucred *)); +int nfs_writerpc __P((struct vnode *,struct uio *,struct ucred *,int *,int *)); +int nfs_readdirrpc __P((register struct vnode *,struct uio *,struct ucred *)); +int nfs_asyncio __P((struct buf *,struct ucred *)); +int nfs_doio __P((struct buf *,struct ucred *,struct proc *)); +int nfs_readlinkrpc __P((struct vnode *,struct uio *,struct ucred *)); +int nfs_sigintr __P((struct nfsmount *,struct nfsreq *r,struct proc *)); +int nfs_readdirplusrpc __P((struct vnode *,register struct uio *,struct ucred *)); +int nfsm_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *)); +void nfsm_srvfattr __P((struct nfsrv_descript *,struct vattr *,struct nfs_fattr *)); +void nfsm_srvwcc __P((struct nfsrv_descript *,int,struct vattr *,int,struct vattr *,struct mbuf **,char **)); +void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct mbuf **,char **)); +int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); +int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); +int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +void nfsm_adj __P((struct mbuf *,int,int)); +int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); +void nfsrv_initcache __P((void)); +int nfs_getauth __P((struct nfsmount *,struct nfsreq *,struct ucred *,char **,int *,char *,int *,NFSKERBKEY_T)); +int nfs_getnickauth __P((struct nfsmount *,struct ucred *,char **,int *,char *,int)); +int nfs_savenickauth __P((struct nfsmount *,struct ucred *,int,NFSKERBKEY_T,struct mbuf **,char **,struct mbuf *)); +int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); +void nfs_nhinit __P((void)); +void nfs_timer __P((void*)); +u_long nfs_hash __P((nfsfh_t *,int)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); +int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); +void nfsrv_cleancache __P((void)); +int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); +int nfs_init __P((void)); +void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +int nfs_connect __P((struct nfsmount *,struct nfsreq *)); +void nfs_disconnect __P((struct nfsmount *nmp)); +int nfs_getattrcache __P((struct vnode *,struct vattr *)); +int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); +int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *, int getpages)); +int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); +void nfsrv_init __P((int)); +void nfs_clearcommit __P((struct mount *)); +int nfsrv_errmap __P((struct nfsrv_descript *, int)); +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrvw_sort __P((gid_t [],int)); +void nfsrv_setcred __P((struct ucred *,struct ucred *)); +int nfs_writebp __P((struct buf *,int)); +int nfsrv_object_create __P(( struct vnode * )); +void nfsrv_wakenfsd __P((struct nfssvc_sock *slp)); +int nfsrv_writegather __P((struct nfsrv_descript **, struct nfssvc_sock *, + struct proc *, struct mbuf **)); +int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *, + struct proc *p)); + +int nfsrv3_access __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_commit __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, + struct ucred *,struct nfssvc_sock *,struct mbuf *, + int *,int)); +int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_link __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_lookup __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_mkdir __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_mknod __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_noop __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_null __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_pathconf __P((struct nfsrv_descript *nfsd, + struct nfssvc_sock *slp, struct proc *procp, + struct mbuf **mrq)); +int nfsrv_read __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_readdir __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_readdirplus __P((struct nfsrv_descript *nfsd, + struct nfssvc_sock *slp, struct proc *procp, + struct mbuf **mrq)); +int nfsrv_readlink __P((struct nfsrv_descript *nfsd, + struct nfssvc_sock *slp, struct proc *procp, + struct mbuf **mrq)); +int nfsrv_remove __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_rename __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_rmdir __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_setattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_statfs __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); +int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, + struct proc *procp, struct mbuf **mrq)); + +#ifdef NFS_DEBUG + +extern int nfs_debug; +#define NFS_DEBUG_ASYNCIO 1 /* asynchronous i/o */ +#define NFS_DEBUG_WG 2 /* server write gathering */ +#define NFS_DEBUG_RC 4 /* server request caching */ + +#define NFS_DPF(cat, args) \ + do { \ + if (nfs_debug & NFS_DEBUG_##cat) printf args; \ + } while (0) + +#else + +#define NFS_DPF(cat, args) + +#endif + +#endif /* KERNEL */ + +#endif diff --git a/cpukit/libnetworking/nfs/nfsdiskless.h b/cpukit/libnetworking/nfs/nfsdiskless.h new file mode 100644 index 0000000000..0ed5c8f6f7 --- /dev/null +++ b/cpukit/libnetworking/nfs/nfsdiskless.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NFS_NFSDISKLESS_H_ +#define _NFS_NFSDISKLESS_H_ + +/* + * Structure that must be initialized for a diskless nfs client. + * This structure is used by nfs_mountroot() to set up the root and swap + * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net + * interface can communicate with the server. + * The primary bootstrap is expected to fill in the appropriate fields before + * starting the kernel. Whether or not the swap area is nfs mounted is determined + * by the value in swdevt[0]. (equal to NODEV --> swap over nfs) + * Currently only works for AF_INET protocols. + * NB: All fields are stored in net byte order to avoid hassles with + * client/server byte ordering differences. + */ + +/* + * I have defined a new structure that can handle an NFS Version 3 file handle + * but the kernel still expects the old Version 2 one to be provided. The + * changes required in nfs_vfsops.c for using the new are documented there in + * comments. (I felt that breaking network booting code by changing this + * structure would not be prudent at this time, since almost all servers are + * still Version 2 anyhow.) + */ +struct nfsv3_diskless { + struct ifaliasreq myif; /* Default interface */ + struct sockaddr_in mygateway; /* Default gateway */ + struct nfs_args swap_args; /* Mount args for swap file */ + int swap_fhsize; /* Size of file handle */ + u_char swap_fh[NFSX_V3FHMAX]; /* Swap file's file handle */ + struct sockaddr_in swap_saddr; /* Address of swap server */ + char swap_hostnam[MNAMELEN]; /* Host name for mount pt */ + int swap_nblks; /* Size of server swap file */ + struct ucred swap_ucred; /* Swap credentials */ + struct nfs_args root_args; /* Mount args for root fs */ + int root_fhsize; /* Size of root file handle */ + u_char root_fh[NFSX_V3FHMAX]; /* File handle of root dir */ + struct sockaddr_in root_saddr; /* Address of root server */ + char root_hostnam[MNAMELEN]; /* Host name for mount pt */ + long root_time; /* Timestamp of root fs */ + char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */ +}; + +struct nfs_diskless { + struct ifaliasreq myif; /* Default interface */ + struct sockaddr_in mygateway; /* Default gateway */ + struct nfs_args swap_args; /* Mount args for swap file */ + u_char swap_fh[NFSX_V2FH]; /* Swap file's file handle */ + struct sockaddr_in swap_saddr; /* Address of swap server */ + char swap_hostnam[MNAMELEN]; /* Host name for mount pt */ + int swap_nblks; /* Size of server swap file */ + struct ucred swap_ucred; /* Swap credentials */ + struct nfs_args root_args; /* Mount args for root fs */ + u_char root_fh[NFSX_V2FH]; /* File handle of root dir */ + struct sockaddr_in root_saddr; /* Address of root server */ + char root_hostnam[MNAMELEN]; /* Host name for mount pt */ + long root_time; /* Timestamp of root fs */ + char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */ +}; + +#endif diff --git a/cpukit/libnetworking/nfs/nfsproto.h b/cpukit/libnetworking/nfs/nfsproto.h new file mode 100644 index 0000000000..6ce7c5b960 --- /dev/null +++ b/cpukit/libnetworking/nfs/nfsproto.h @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)nfsproto.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NFS_NFSPROTO_H_ +#define _NFS_NFSPROTO_H_ + +/* + * nfs definitions as per the Version 2 and 3 specs + */ + +/* + * Constants as defined in the Sun NFS Version 2 and 3 specs. + * "NFS: Network File System Protocol Specification" RFC1094 + * and in the "NFS: Network File System Version 3 Protocol + * Specification" + */ + +#define NFS_PORT 2049 +#define NFS_PROG 100003 +#define NFS_VER2 2 +#define NFS_VER3 3 +#define NFS_V2MAXDATA 8192 +#define NFS_MAXDGRAMDATA 16384 +#define NFS_MAXDATA 32768 +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_MAXPKTHDR 404 +#define NFS_MAXPACKET (NFS_MAXPKTHDR + NFS_MAXDATA) +#define NFS_MINPACKET 20 +#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ + +/* Stat numbers for rpc returns (version 2 and 3) */ +#define NFS_OK 0 +#define NFSERR_PERM 1 +#define NFSERR_NOENT 2 +#define NFSERR_IO 5 +#define NFSERR_NXIO 6 +#define NFSERR_ACCES 13 +#define NFSERR_EXIST 17 +#define NFSERR_XDEV 18 /* Version 3 only */ +#define NFSERR_NODEV 19 +#define NFSERR_NOTDIR 20 +#define NFSERR_ISDIR 21 +#define NFSERR_INVAL 22 /* Version 3 only */ +#define NFSERR_FBIG 27 +#define NFSERR_NOSPC 28 +#define NFSERR_ROFS 30 +#define NFSERR_MLINK 31 /* Version 3 only */ +#define NFSERR_NAMETOL 63 +#define NFSERR_NOTEMPTY 66 +#define NFSERR_DQUOT 69 +#define NFSERR_STALE 70 +#define NFSERR_REMOTE 71 /* Version 3 only */ +#define NFSERR_WFLUSH 99 /* Version 2 only */ +#define NFSERR_BADHANDLE 10001 /* The rest Version 3 only */ +#define NFSERR_NOT_SYNC 10002 +#define NFSERR_BAD_COOKIE 10003 +#define NFSERR_NOTSUPP 10004 +#define NFSERR_TOOSMALL 10005 +#define NFSERR_SERVERFAULT 10006 +#define NFSERR_BADTYPE 10007 +#define NFSERR_JUKEBOX 10008 +#define NFSERR_TRYLATER NFSERR_JUKEBOX +#define NFSERR_STALEWRITEVERF 30001 /* Fake return for nfs_commit() */ + +#define NFSERR_RETVOID 0x20000000 /* Return void, not error */ +#define NFSERR_AUTHERR 0x40000000 /* Mark an authentication error */ +#define NFSERR_RETERR 0x80000000 /* Mark an error return for V3 */ + +/* Sizes in bytes of various nfs rpc components */ +#define NFSX_UNSIGNED 4 + +/* specific to NFS Version 2 */ +#define NFSX_V2FH 32 +#define NFSX_V2FATTR 68 +#define NFSX_V2SATTR 32 +#define NFSX_V2COOKIE 4 +#define NFSX_V2STATFS 20 + +/* specific to NFS Version 3 */ +#define NFSX_V3FH (sizeof (fhandle_t)) /* size this server uses */ +#define NFSX_V3FHMAX 64 /* max. allowed by protocol */ +#define NFSX_V3FATTR 84 +#define NFSX_V3SATTR 60 /* max. all fields filled in */ +#define NFSX_V3SRVSATTR (sizeof (struct nfsv3_sattr)) +#define NFSX_V3POSTOPATTR (NFSX_V3FATTR + NFSX_UNSIGNED) +#define NFSX_V3WCCDATA (NFSX_V3POSTOPATTR + 8 * NFSX_UNSIGNED) +#define NFSX_V3COOKIEVERF 8 +#define NFSX_V3WRITEVERF 8 +#define NFSX_V3CREATEVERF 8 +#define NFSX_V3STATFS 52 +#define NFSX_V3FSINFO 48 +#define NFSX_V3PATHCONF 24 + +/* variants for both versions */ +#define NFSX_FH(v3) ((v3) ? (NFSX_V3FHMAX + NFSX_UNSIGNED) : \ + NFSX_V2FH) +#define NFSX_SRVFH(v3) ((v3) ? NFSX_V3FH : NFSX_V2FH) +#define NFSX_FATTR(v3) ((v3) ? NFSX_V3FATTR : NFSX_V2FATTR) +#define NFSX_PREOPATTR(v3) ((v3) ? (7 * NFSX_UNSIGNED) : 0) +#define NFSX_POSTOPATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : 0) +#define NFSX_POSTOPORFATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : \ + NFSX_V2FATTR) +#define NFSX_WCCDATA(v3) ((v3) ? NFSX_V3WCCDATA : 0) +#define NFSX_WCCORFATTR(v3) ((v3) ? NFSX_V3WCCDATA : NFSX_V2FATTR) +#define NFSX_SATTR(v3) ((v3) ? NFSX_V3SATTR : NFSX_V2SATTR) +#define NFSX_COOKIEVERF(v3) ((v3) ? NFSX_V3COOKIEVERF : 0) +#define NFSX_WRITEVERF(v3) ((v3) ? NFSX_V3WRITEVERF : 0) +#define NFSX_READDIR(v3) ((v3) ? (5 * NFSX_UNSIGNED) : \ + (2 * NFSX_UNSIGNED)) +#define NFSX_STATFS(v3) ((v3) ? NFSX_V3STATFS : NFSX_V2STATFS) + +/* nfs rpc procedure numbers (before version mapping) */ +#define NFSPROC_NULL 0 +#define NFSPROC_GETATTR 1 +#define NFSPROC_SETATTR 2 +#define NFSPROC_LOOKUP 3 +#define NFSPROC_ACCESS 4 +#define NFSPROC_READLINK 5 +#define NFSPROC_READ 6 +#define NFSPROC_WRITE 7 +#define NFSPROC_CREATE 8 +#define NFSPROC_MKDIR 9 +#define NFSPROC_SYMLINK 10 +#define NFSPROC_MKNOD 11 +#define NFSPROC_REMOVE 12 +#define NFSPROC_RMDIR 13 +#define NFSPROC_RENAME 14 +#define NFSPROC_LINK 15 +#define NFSPROC_READDIR 16 +#define NFSPROC_READDIRPLUS 17 +#define NFSPROC_FSSTAT 18 +#define NFSPROC_FSINFO 19 +#define NFSPROC_PATHCONF 20 +#define NFSPROC_COMMIT 21 + +/* And leasing (nqnfs) procedure numbers (must be last) */ +#define NQNFSPROC_GETLEASE 22 +#define NQNFSPROC_VACATED 23 +#define NQNFSPROC_EVICTED 24 + +#define NFSPROC_NOOP 25 +#define NFS_NPROCS 26 + +/* Actual Version 2 procedure numbers */ +#define NFSV2PROC_NULL 0 +#define NFSV2PROC_GETATTR 1 +#define NFSV2PROC_SETATTR 2 +#define NFSV2PROC_NOOP 3 +#define NFSV2PROC_ROOT NFSV2PROC_NOOP /* Obsolete */ +#define NFSV2PROC_LOOKUP 4 +#define NFSV2PROC_READLINK 5 +#define NFSV2PROC_READ 6 +#define NFSV2PROC_WRITECACHE NFSV2PROC_NOOP /* Obsolete */ +#define NFSV2PROC_WRITE 8 +#define NFSV2PROC_CREATE 9 +#define NFSV2PROC_REMOVE 10 +#define NFSV2PROC_RENAME 11 +#define NFSV2PROC_LINK 12 +#define NFSV2PROC_SYMLINK 13 +#define NFSV2PROC_MKDIR 14 +#define NFSV2PROC_RMDIR 15 +#define NFSV2PROC_READDIR 16 +#define NFSV2PROC_STATFS 17 + +/* + * Constants used by the Version 3 protocol for various RPCs + */ +#define NFSV3SATTRTIME_DONTCHANGE 0 +#define NFSV3SATTRTIME_TOSERVER 1 +#define NFSV3SATTRTIME_TOCLIENT 2 + +#define NFSV3ACCESS_READ 0x01 +#define NFSV3ACCESS_LOOKUP 0x02 +#define NFSV3ACCESS_MODIFY 0x04 +#define NFSV3ACCESS_EXTEND 0x08 +#define NFSV3ACCESS_DELETE 0x10 +#define NFSV3ACCESS_EXECUTE 0x20 + +#define NFSV3WRITE_UNSTABLE 0 +#define NFSV3WRITE_DATASYNC 1 +#define NFSV3WRITE_FILESYNC 2 + +#define NFSV3CREATE_UNCHECKED 0 +#define NFSV3CREATE_GUARDED 1 +#define NFSV3CREATE_EXCLUSIVE 2 + +#define NFSV3FSINFO_LINK 0x01 +#define NFSV3FSINFO_SYMLINK 0x02 +#define NFSV3FSINFO_HOMOGENEOUS 0x08 +#define NFSV3FSINFO_CANSETTIME 0x10 + +/* Conversion macros */ +#define vtonfsv2_mode(t,m) \ + txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \ + MAKEIMODE((t), (m))) +#define vtonfsv3_mode(m) txdr_unsigned((m) & 07777) +#define nfstov_mode(a) (fxdr_unsigned(u_short, (a))&07777) +#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((long)(a))]) +#define vtonfsv3_type(a) txdr_unsigned(nfsv3_type[((long)(a))]) +#define nfsv2tov_type(a) nv2tov_type[fxdr_unsigned(u_long,(a))&0x7] +#define nfsv3tov_type(a) nv3tov_type[fxdr_unsigned(u_long,(a))&0x7] + +/* File types */ +typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, + NFSOCK=6, NFFIFO=7 } nfstype; + +/* Structs for common parts of the rpc's */ +/* + * File Handle (32 bytes for version 2), variable up to 64 for version 3. + * File Handles of up to NFS_SMALLFH in size are stored directly in the + * nfs node, whereas larger ones are malloc'd. (This never happens when + * NFS_SMALLFH is set to 64.) + * NFS_SMALLFH should be in the range of 32 to 64 and be divisible by 4. + */ +#ifndef NFS_SMALLFH +#define NFS_SMALLFH 64 +#endif +union nfsfh { + fhandle_t fh_generic; + u_char fh_bytes[NFS_SMALLFH]; +}; +typedef union nfsfh nfsfh_t; + +struct nfsv2_time { + u_long nfsv2_sec; + u_long nfsv2_usec; +}; +typedef struct nfsv2_time nfstime2; + +struct nfsv3_time { + u_long nfsv3_sec; + u_long nfsv3_nsec; +}; +typedef struct nfsv3_time nfstime3; + +/* + * Quads are defined as arrays of 2 longs to ensure dense packing for the + * protocol and to facilitate xdr conversion. + */ +struct nfs_uquad { + u_long nfsuquad[2]; +}; +typedef struct nfs_uquad nfsuint64; + +/* + * Used to convert between two u_longs and a u_quad_t. + */ +union nfs_quadconvert { + u_long lval[2]; + u_quad_t qval; +}; +typedef union nfs_quadconvert nfsquad_t; + +/* + * NFS Version 3 special file number. + */ +struct nfsv3_spec { + u_long specdata1; + u_long specdata2; +}; +typedef struct nfsv3_spec nfsv3spec; + +/* + * File attributes and setable attributes. These structures cover both + * NFS version 2 and the version 3 protocol. Note that the union is only + * used so that one pointer can refer to both variants. These structures + * go out on the wire and must be densely packed, so no quad data types + * are used. (all fields are longs or u_longs or structures of same) + * NB: You can't do sizeof(struct nfs_fattr), you must use the + * NFSX_FATTR(v3) macro. + */ +struct nfs_fattr { + u_long fa_type; + u_long fa_mode; + u_long fa_nlink; + u_long fa_uid; + u_long fa_gid; + union { + struct { + u_long nfsv2fa_size; + u_long nfsv2fa_blocksize; + u_long nfsv2fa_rdev; + u_long nfsv2fa_blocks; + u_long nfsv2fa_fsid; + u_long nfsv2fa_fileid; + nfstime2 nfsv2fa_atime; + nfstime2 nfsv2fa_mtime; + nfstime2 nfsv2fa_ctime; + } fa_nfsv2; + struct { + nfsuint64 nfsv3fa_size; + nfsuint64 nfsv3fa_used; + nfsv3spec nfsv3fa_rdev; + nfsuint64 nfsv3fa_fsid; + nfsuint64 nfsv3fa_fileid; + nfstime3 nfsv3fa_atime; + nfstime3 nfsv3fa_mtime; + nfstime3 nfsv3fa_ctime; + } fa_nfsv3; + } fa_un; +}; + +/* and some ugly defines for accessing union components */ +#define fa2_size fa_un.fa_nfsv2.nfsv2fa_size +#define fa2_blocksize fa_un.fa_nfsv2.nfsv2fa_blocksize +#define fa2_rdev fa_un.fa_nfsv2.nfsv2fa_rdev +#define fa2_blocks fa_un.fa_nfsv2.nfsv2fa_blocks +#define fa2_fsid fa_un.fa_nfsv2.nfsv2fa_fsid +#define fa2_fileid fa_un.fa_nfsv2.nfsv2fa_fileid +#define fa2_atime fa_un.fa_nfsv2.nfsv2fa_atime +#define fa2_mtime fa_un.fa_nfsv2.nfsv2fa_mtime +#define fa2_ctime fa_un.fa_nfsv2.nfsv2fa_ctime +#define fa3_size fa_un.fa_nfsv3.nfsv3fa_size +#define fa3_used fa_un.fa_nfsv3.nfsv3fa_used +#define fa3_rdev fa_un.fa_nfsv3.nfsv3fa_rdev +#define fa3_fsid fa_un.fa_nfsv3.nfsv3fa_fsid +#define fa3_fileid fa_un.fa_nfsv3.nfsv3fa_fileid +#define fa3_atime fa_un.fa_nfsv3.nfsv3fa_atime +#define fa3_mtime fa_un.fa_nfsv3.nfsv3fa_mtime +#define fa3_ctime fa_un.fa_nfsv3.nfsv3fa_ctime + +struct nfsv2_sattr { + u_long sa_mode; + u_long sa_uid; + u_long sa_gid; + u_long sa_size; + nfstime2 sa_atime; + nfstime2 sa_mtime; +}; + +/* + * NFS Version 3 sattr structure for the new node creation case. + */ +struct nfsv3_sattr { + u_long sa_modetrue; + u_long sa_mode; + u_long sa_uidtrue; + u_long sa_uid; + u_long sa_gidtrue; + u_long sa_gid; + u_long sa_sizefalse; + u_long sa_atimetype; + nfstime3 sa_atime; + u_long sa_mtimetype; + nfstime3 sa_mtime; +}; + +struct nfs_statfs { + union { + struct { + u_long nfsv2sf_tsize; + u_long nfsv2sf_bsize; + u_long nfsv2sf_blocks; + u_long nfsv2sf_bfree; + u_long nfsv2sf_bavail; + } sf_nfsv2; + struct { + nfsuint64 nfsv3sf_tbytes; + nfsuint64 nfsv3sf_fbytes; + nfsuint64 nfsv3sf_abytes; + nfsuint64 nfsv3sf_tfiles; + nfsuint64 nfsv3sf_ffiles; + nfsuint64 nfsv3sf_afiles; + u_long nfsv3sf_invarsec; + } sf_nfsv3; + } sf_un; +}; + +#define sf_tsize sf_un.sf_nfsv2.nfsv2sf_tsize +#define sf_bsize sf_un.sf_nfsv2.nfsv2sf_bsize +#define sf_blocks sf_un.sf_nfsv2.nfsv2sf_blocks +#define sf_bfree sf_un.sf_nfsv2.nfsv2sf_bfree +#define sf_bavail sf_un.sf_nfsv2.nfsv2sf_bavail +#define sf_tbytes sf_un.sf_nfsv3.nfsv3sf_tbytes +#define sf_fbytes sf_un.sf_nfsv3.nfsv3sf_fbytes +#define sf_abytes sf_un.sf_nfsv3.nfsv3sf_abytes +#define sf_tfiles sf_un.sf_nfsv3.nfsv3sf_tfiles +#define sf_ffiles sf_un.sf_nfsv3.nfsv3sf_ffiles +#define sf_afiles sf_un.sf_nfsv3.nfsv3sf_afiles +#define sf_invarsec sf_un.sf_nfsv3.nfsv3sf_invarsec + +struct nfsv3_fsinfo { + u_long fs_rtmax; + u_long fs_rtpref; + u_long fs_rtmult; + u_long fs_wtmax; + u_long fs_wtpref; + u_long fs_wtmult; + u_long fs_dtpref; + nfsuint64 fs_maxfilesize; + nfstime3 fs_timedelta; + u_long fs_properties; +}; + +struct nfsv3_pathconf { + u_long pc_linkmax; + u_long pc_namemax; + u_long pc_notrunc; + u_long pc_chownrestricted; + u_long pc_caseinsensitive; + u_long pc_casepreserving; +}; + +#endif diff --git a/cpukit/libnetworking/nfs/rpcv2.h b/cpukit/libnetworking/nfs/rpcv2.h new file mode 100644 index 0000000000..5fd6e7febf --- /dev/null +++ b/cpukit/libnetworking/nfs/rpcv2.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NFS_RPCV2_H_ +#define _NFS_RPCV2_H_ + +/* + * Definitions for Sun RPC Version 2, from + * "RPC: Remote Procedure Call Protocol Specification" RFC1057 + */ + +/* Version # */ +#define RPC_VER2 2 + +/* Authentication */ +#define RPCAUTH_NULL 0 +#define RPCAUTH_UNIX 1 +#define RPCAUTH_SHORT 2 +#define RPCAUTH_KERB4 4 +#define RPCAUTH_NQNFS 300000 +#define RPCAUTH_MAXSIZ 400 +#define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */ +#define RPCAUTH_UNIXGIDS 16 + +/* + * Constants associated with authentication flavours. + */ +#define RPCAKN_FULLNAME 0 +#define RPCAKN_NICKNAME 1 + +/* Rpc Constants */ +#define RPC_CALL 0 +#define RPC_REPLY 1 +#define RPC_MSGACCEPTED 0 +#define RPC_MSGDENIED 1 +#define RPC_PROGUNAVAIL 1 +#define RPC_PROGMISMATCH 2 +#define RPC_PROCUNAVAIL 3 +#define RPC_GARBAGE 4 /* I like this one */ +#define RPC_MISMATCH 0 +#define RPC_AUTHERR 1 + +/* Authentication failures */ +#define AUTH_BADCRED 1 +#define AUTH_REJECTCRED 2 +#define AUTH_BADVERF 3 +#define AUTH_REJECTVERF 4 +#define AUTH_TOOWEAK 5 /* Give em wheaties */ + +/* Sizes of rpc header parts */ +#define RPC_SIZ 24 +#define RPC_REPLYSIZ 28 + +/* RPC Prog definitions */ +#define RPCPROG_MNT 100005 +#define RPCMNT_VER1 1 +#define RPCMNT_VER3 3 +#define RPCMNT_MOUNT 1 +#define RPCMNT_DUMP 2 +#define RPCMNT_UMOUNT 3 +#define RPCMNT_UMNTALL 4 +#define RPCMNT_EXPORT 5 +#define RPCMNT_NAMELEN 255 +#define RPCMNT_PATHLEN 1024 +#define RPCPROG_NFS 100003 + +/* + * Structures used for RPCAUTH_KERB4. + */ +struct nfsrpc_fullverf { + u_long t1; + u_long t2; + u_long w2; +}; + +struct nfsrpc_fullblock { + u_long t1; + u_long t2; + u_long w1; + u_long w2; +}; + +struct nfsrpc_nickverf { + u_long kind; + struct nfsrpc_fullverf verf; +}; + +/* + * and their sizes in bytes.. If sizeof (struct nfsrpc_xx) != these + * constants, well then things will break in mount_nfs and nfsd. + */ +#define RPCX_FULLVERF 12 +#define RPCX_FULLBLOCK 16 +#define RPCX_NICKVERF 16 + +#ifdef NFSKERB +XXX +#else +typedef u_char NFSKERBKEY_T[2]; +typedef u_char NFSKERBKEYSCHED_T[2]; +#endif +#define NFS_KERBSRV "rcmd" /* Kerberos Service for NFS */ +#define NFS_KERBTTL (30 * 60) /* Credential ttl (sec) */ +#define NFS_KERBCLOCKSKEW (5 * 60) /* Clock skew (sec) */ +#define NFS_KERBW1(t) (*((u_long *)(&((t).dat[((t).length + 3) & ~0x3])))) +#endif diff --git a/cpukit/libnetworking/nfs/xdr_subs.h b/cpukit/libnetworking/nfs/xdr_subs.h new file mode 100644 index 0000000000..874730378f --- /dev/null +++ b/cpukit/libnetworking/nfs/xdr_subs.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)xdr_subs.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NFS_XDR_SUBS_H_ +#define _NFS_XDR_SUBS_H_ + +/* + * Macros used for conversion to/from xdr representation by nfs... + * These use the MACHINE DEPENDENT routines ntohl, htonl + * As defined by "XDR: External Data Representation Standard" RFC1014 + * + * To simplify the implementation, we use ntohl/htonl even on big-endian + * machines, and count on them being `#define'd away. Some of these + * might be slightly more efficient as quad_t copies on a big-endian, + * but we cannot count on their alignment anyway. + */ + +#define fxdr_unsigned(t, v) ((t)ntohl((long)(v))) +#define txdr_unsigned(v) (htonl((long)(v))) + +#define fxdr_nfsv2time(f, t) { \ + (t)->tv_sec = ntohl(((struct nfsv2_time *)(f))->nfsv2_sec); \ + if (((struct nfsv2_time *)(f))->nfsv2_usec != 0xffffffff) \ + (t)->tv_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfsv2_usec); \ + else \ + (t)->tv_nsec = 0; \ +} +#define txdr_nfsv2time(f, t) { \ + ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->tv_sec); \ + if ((f)->tv_nsec != -1) \ + ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->tv_nsec / 1000); \ + else \ + ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \ +} + +#define fxdr_nfsv3time(f, t) { \ + (t)->tv_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \ + (t)->tv_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \ +} +#define txdr_nfsv3time(f, t) { \ + ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->tv_sec); \ + ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->tv_nsec); \ +} + +#define fxdr_hyper(f, t) { \ + ((long *)(t))[_QUAD_HIGHWORD] = ntohl(((long *)(f))[0]); \ + ((long *)(t))[_QUAD_LOWWORD] = ntohl(((long *)(f))[1]); \ +} +#define txdr_hyper(f, t) { \ + ((long *)(t))[0] = htonl(((long *)(f))[_QUAD_HIGHWORD]); \ + ((long *)(t))[1] = htonl(((long *)(f))[_QUAD_LOWWORD]); \ +} + +#endif diff --git a/cpukit/libnetworking/opt_ipfw.h b/cpukit/libnetworking/opt_ipfw.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/cpukit/libnetworking/opt_ipfw.h diff --git a/cpukit/libnetworking/opt_mrouting.h b/cpukit/libnetworking/opt_mrouting.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/cpukit/libnetworking/opt_mrouting.h diff --git a/cpukit/libnetworking/opt_tcpdebug.h b/cpukit/libnetworking/opt_tcpdebug.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/cpukit/libnetworking/opt_tcpdebug.h diff --git a/cpukit/libnetworking/poll.h b/cpukit/libnetworking/poll.h new file mode 100644 index 0000000000..74dfca76c1 --- /dev/null +++ b/cpukit/libnetworking/poll.h @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 1997 Peter Wemm <peter@freebsd.org> + * 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 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 AUTHOR 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. + * + * $Id$ + */ + +#ifndef _SYS_POLL_H_ +#define _SYS_POLL_H_ + +/* + * This file is intended to be compatable with the traditional poll.h. + */ + +/* + * This structure is passed as an array to poll(2). + */ +struct pollfd { + int fd; /* which file descriptor to poll */ + short events; /* events we are interested in */ + short revents; /* events found on return */ +}; + +/* + * Requestable events. If poll(2) finds any of these set, they are + * copied to revents on return. + * XXX Note that FreeBSD doesn't make much distinction between POLLPRI + * and POLLRDBAND since none of the file types have distinct priority + * bands - and only some have an urgent "mode". + * XXX Note POLLIN isn't really supported in true SVSV terms. Under SYSV + * POLLIN includes all of normal, band and urgent data. Most poll handlers + * on FreeBSD only treat it as "normal" data. + */ +#define POLLIN 0x0001 /* any readable data available */ +#define POLLPRI 0x0002 /* OOB/Urgent readable data */ +#define POLLOUT 0x0004 /* file descriptor is writeable */ +#define POLLRDNORM 0x0040 /* non-OOB/URG data available */ +#define POLLWRNORM POLLOUT /* no write type differentiation */ +#define POLLRDBAND 0x0080 /* OOB/Urgent readable data */ +#define POLLWRBAND 0x0100 /* OOB/Urgent data can be written */ + +/* + * FreeBSD extensions: polling on a regular file might return one + * of these events (currently only supported on UFS). + */ +#define POLLEXTEND 0x0200 /* file may have been extended */ +#define POLLATTRIB 0x0400 /* file attributes may have changed */ +#define POLLNLINK 0x0800 /* (un)link/rename may have happened */ +#define POLLWRITE 0x1000 /* file's contents may have changed */ + +/* + * These events are set if they occur regardless of whether they were + * requested. + */ +#define POLLERR 0x0008 /* some poll error occurred */ +#define POLLHUP 0x0010 /* file descriptor was "hung up" */ +#define POLLNVAL 0x0020 /* requested events "invalid" */ + +#define POLLSTANDARD (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|\ + POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) + +/* + * Request that poll() wait forever. + * XXX in SYSV, this is defined in stropts.h, which is not included + * by poll.h. + */ +#define INFTIM (-1) + +#ifndef KERNEL + +#include <sys/cdefs.h> + +__BEGIN_DECLS +/* + * XXX logically, poll() should be declared in <poll.h>, but SVR4 at + * least has it here in <sys/poll.h>. + * XXX poll() has "unsigned long" nfds on SVR4, not unsigned as on the + * other BSDs. + */ +int poll __P((struct pollfd *_pfd, unsigned _nfds, int _timeout)); +__END_DECLS + +#endif /* !KERNEL */ + +#endif /* !_SYS_POLL_H_ */ diff --git a/cpukit/libnetworking/resolv.h b/cpukit/libnetworking/resolv.h new file mode 100644 index 0000000000..614f204706 --- /dev/null +++ b/cpukit/libnetworking/resolv.h @@ -0,0 +1,306 @@ +/*- + * Copyright (c) 1983, 1987, 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * From Id: resolv.h,v 8.12 1998/04/28 19:36:46 halley Exp $ + * $Id$ + */ + +#ifndef _RESOLV_H_ +#define _RESOLV_H_ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/cdefs.h> +#include <stdio.h> + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__RES > 19931104)". Do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __RES 19960801 + +/* + * This used to be defined in res_query.c, now it's in herror.c. It was + * never extern'd by any *.h file before it was placed here. herror.c is + * part of libresolv.a even though it might make more sense in libnetdb.a + * or even libnet.a. + */ + +extern int h_errno; + +/* + * Resolver configuration file. + * Normally not present, but may contain the address of the + * inital name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +/* + * Global defines and variables for resolver stub. + */ +#define MAXNS 3 /* max # name servers we'll track */ +#define MAXDFLSRCH 3 /* # default domain levels to try */ +#define MAXDNSRCH 6 /* max # domains in search path */ +#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ + +#define RES_TIMEOUT 5 /* min. seconds between retries */ +#define MAXRESOLVSORT 10 /* number of net to sort on */ +#define RES_MAXNDOTS 15 /* should reflect bit field size */ + +struct __res_state { + int retrans; /* retransmition time interval */ + int retry; /* number of times to retransmit */ + u_long options; /* option flags - see below. */ + int nscount; /* number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /* address of name server */ +#define nsaddr nsaddr_list[0] /* for backward compatibility */ + u_short id; /* current message id */ + char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ + char defdname[256]; /* default domain (deprecated) */ + u_long pfcode; /* RES_PRF_ flags - see below. */ + unsigned ndots:4; /* threshold for initial abs. query */ + unsigned nsort:4; /* number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + u_int32_t mask; + } sort_list[MAXRESOLVSORT]; + char pad[72]; /* on an i386 this means 512b total */ +}; + +/* + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /* address initialized */ +#define RES_DEBUG 0x00000002 /* print debug messages */ +#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /* use virtual circuit */ +#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /* ignore truncation errors */ +#define RES_RECURSE 0x00000040 /* recursion desired */ +#define RES_DEFNAMES 0x00000080 /* use default domain name */ +#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /* search up local domain tree */ +#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ +#define RES_NOTLDQUERY 0x00004000 /* Don't query TLD names */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) + +/* + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +/* 0x00008000 */ + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook)__P((struct sockaddr_in * const *ns, + const u_char **query, + int *querylen, + u_char *ans, + int anssiz, + int *resplen)); + +typedef res_sendhookact (*res_send_rhook)__P((const struct sockaddr_in *ns, + const u_char *query, + int querylen, + u_char *ans, + int anssiz, + int *resplen)); + +struct res_sym { + int number; /* Identifying number, like T_MX */ + char * name; /* Its symbolic name, like "MX" */ + char * humanname; /* Its fun name, like "mail exchanger" */ +}; + +extern struct __res_state _res; +extern const struct res_sym __p_class_syms[]; +extern const struct res_sym __p_type_syms[]; + +/* Private routines shared between libc/net, named, nslookup and others. */ +#define res_hnok __res_hnok +#define res_ownok __res_ownok +#define res_mailok __res_mailok +#define res_dnok __res_dnok +#define sym_ston __sym_ston +#define sym_ntos __sym_ntos +#define sym_ntop __sym_ntop +#define b64_ntop __b64_ntop +#define b64_pton __b64_pton +#define loc_ntoa __loc_ntoa +#define loc_aton __loc_aton +#define fp_resstat __fp_resstat +#define p_query __p_query +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define fp_query __fp_query +#define fp_nquery __fp_nquery +#define hostalias __hostalias +#define putlong __putlong +#define putshort __putshort +#define p_class __p_class +#define p_time __p_time +#define p_type __p_type +#define p_query __p_query +#define p_cdnname __p_cdnname +#define p_section __p_section +#define p_cdname __p_cdname +#define p_fqnname __p_fqnname +#define p_fqname __p_fqname +#define p_option __p_option +#define p_secstodate __p_secstodate +#define dn_count_labels __dn_count_labels +#define dn_comp __dn_comp +#define dn_expand __dn_expand +#define res_init __res_init +#define res_randomid __res_randomid +#define res_query __res_query +#define res_search __res_search +#define res_querydomain __res_querydomain +#define res_mkquery __res_mkquery +#define res_send __res_send +#define res_isourserver __res_isourserver +#define res_nameinquery __res_nameinquery +#define res_queriesmatch __res_queriesmatch +#define res_close __res_close +#define res_mkupdate __res_mkupdate +#define res_mkupdrec __res_mkupdrec +#define res_freeupdrec __res_freeupdrec + +__BEGIN_DECLS +int res_hnok __P((const char *)); +int res_ownok __P((const char *)); +int res_mailok __P((const char *)); +int res_dnok __P((const char *)); +int sym_ston __P((const struct res_sym *, const char *, int *)); +const char * sym_ntos __P((const struct res_sym *, int, int *)); +const char * sym_ntop __P((const struct res_sym *, int, int *)); +int b64_ntop __P((u_char const *, size_t, char *, size_t)); +int b64_pton __P((char const *, u_char *, size_t)); +int loc_aton __P((const char *, u_char *)); +const char * loc_ntoa __P((const u_char *, char *)); +int dn_skipname __P((const u_char *, const u_char *)); +void fp_resstat __P((struct __res_state *, FILE *)); +void fp_query __P((const u_char *, FILE *)); +void fp_nquery __P((const u_char *, int, FILE *)); +const char * hostalias __P((const char *)); +void putlong __P((u_int32_t, u_char *)); +void putshort __P((u_int16_t, u_char *)); +const char * p_class __P((int)); +const char * p_time __P((u_int32_t)); +const char * p_type __P((int)); +void p_query __P((const u_char *)); +const u_char * p_cdnname __P((const u_char *, const u_char *, int, FILE *)); +const u_char * p_cdname __P((const u_char *, const u_char *, FILE *)); +const u_char * p_fqnname __P((const u_char *, const u_char *, + int, char *, int)); +const u_char * p_fqname __P((const u_char *, const u_char *, FILE *)); +const char * p_option __P((u_long)); +char * p_secstodate __P((u_long)); +int dn_count_labels __P((const char *)); +int dn_comp __P((const char *, u_char *, int, + u_char **, u_char **)); +int dn_expand __P((const u_char *, const u_char *, const u_char *, + char *, int)); +int res_init __P((void)); +u_int res_randomid __P((void)); +int res_query __P((const char *, int, int, u_char *, int)); +int res_search __P((const char *, int, int, u_char *, int)); +int res_querydomain __P((const char *, const char *, int, int, + u_char *, int)); +int res_mkquery __P((int, const char *, int, int, const u_char *, + int, const u_char *, u_char *, int)); +int res_send __P((const u_char *, int, u_char *, int)); +int res_isourserver __P((const struct sockaddr_in *)); +int res_nameinquery __P((const char *, int, int, + const u_char *, const u_char *)); +int res_queriesmatch __P((const u_char *, const u_char *, + const u_char *, const u_char *)); +void res_close __P((void)); +const char * p_section __P((int, int)); +/* XXX The following depend on the ns_updrec typedef in arpa/nameser.h */ +#ifdef _ARPA_NAMESER_H_ +int res_update __P((ns_updrec *)); +int res_mkupdate __P((ns_updrec *, u_char *, int)); +ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long)); +void res_freeupdrec __P((ns_updrec *)); +#endif +__END_DECLS + +#endif /* !_RESOLV_H_ */ diff --git a/cpukit/libnetworking/rtems/issetugid.c b/cpukit/libnetworking/rtems/issetugid.c new file mode 100644 index 0000000000..1ae81c9f2e --- /dev/null +++ b/cpukit/libnetworking/rtems/issetugid.c @@ -0,0 +1,8 @@ +/* + * Dummy version of BSD routine + */ +int +issetugid (void) +{ + return 0; +} diff --git a/cpukit/libnetworking/rtems/rtems_bootp.c b/cpukit/libnetworking/rtems/rtems_bootp.c new file mode 100644 index 0000000000..c3bb8d7ad4 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_bootp.c @@ -0,0 +1,15 @@ +#include <rtems.h> +#include <rtems/error.h> +#include <sys/types.h> +#include <rtems/rtems_bsdnet.h> + +/* + * Perform a BOOTP request + */ +void +rtems_bsdnet_do_bootp (void) +{ + rtems_bsdnet_semaphore_obtain (); + bootpc_init (); + rtems_bsdnet_semaphore_release (); +} diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet.h b/cpukit/libnetworking/rtems/rtems_bsdnet.h new file mode 100644 index 0000000000..9ae48d8cfe --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_bsdnet.h @@ -0,0 +1,99 @@ +#ifndef _RTEMS_BSDNET_ +#define _RTEMS_BSDNET_ + +#include <rtems.h> + +/* + * Values that may be obtained by BOOTP + */ +extern struct in_addr rtems_bsdnet_bootp_server_address; +extern char *rtems_bsdnet_bootp_boot_file_name; + +/* + * Manipulate routing tables + */ +struct sockaddr; +struct rtentry; +int rtems_bsdnet_rtrequest ( + int req, + struct sockaddr *dst, + struct sockaddr *gateway, + struct sockaddr *netmask, + int flags, + struct rtentry **net_nrt); + +/* + * Diagnostics + */ +void rtems_bsdnet_show_inet_routes (void); +void rtems_bsdnet_show_mbuf_stats (void); +void rtems_bsdnet_show_if_stats (void); +void rtems_bsdnet_show_ip_stats (void); +void rtems_bsdnet_show_icmp_stats (void); +void rtems_bsdnet_show_udp_stats (void); +void rtems_bsdnet_show_tcp_stats (void); + +/* + * Network configuration + */ +struct rtems_bsdnet_ifconfig { + /* + * These two entries must be supplied for each interface. + */ + char *name; + int (*attach)(struct rtems_bsdnet_ifconfig *conf); + + /* + * Link to next interface + */ + struct rtems_bsdnet_ifconfig *next; + + /* + * The following entries may be obtained + * from BOOTP or explicitily supplied. + */ + char *ip_address; + char *ip_netmask; + void *hardware_address; + + /* + * The driver assigns defaults values to the following + * entries if they are not explicitly supplied. + */ + int ignore_broadcast; + int mtu; + int rbuf_count; + int xbuf_count; +}; + +struct rtems_bsdnet_config { + /* + * This entry points to the head of the ifconfig chain. + */ + struct rtems_bsdnet_ifconfig *ifconfig; + + /* + * This entry should be rtems_bsdnet_do_bootp if BOOTP + * is being used to configure the network, and NULL + * if BOOTP is not being used. + */ + void (*bootp)(void); + + /* + * The remaining items can be initialized to 0, in + * which case the default value will be used. + */ + rtems_task_priority network_task_priority; /* 100 */ + unsigned long mbuf_bytecount; /* 64 kbytes */ + unsigned long mbuf_cluster_bytecount; /* 128 kbytes */ + char *hostname; /* BOOTP */ + char *domainname; /* BOOTP */ + char *gateway; /* BOOTP */ + char *log_host; /* BOOTP */ + char *name_server[3]; /* BOOTP */ +}; +extern struct rtems_bsdnet_config rtems_bsdnet_config; +int rtems_bsdnet_initialize_network (void); +void rtems_bsdnet_do_bootp (void); + +#endif /* _RTEMS_BSDNET_ */ diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h new file mode 100644 index 0000000000..f27eb74491 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h @@ -0,0 +1,156 @@ +/* + * Declarations to fit FreeBSD to RTEMS. + * This include file should *never* be exposed to the application programmer. + */ + +#ifndef _RTEMS_BSDNET_INTERNAL_H_ +#define _RTEMS_BSDNET_INTERNAL_H_ + +typedef unsigned int vm_offset_t; +typedef long long vm_ooffset_t; +typedef unsigned int vm_pindex_t; +typedef unsigned int vm_size_t; + +#define _BSD_OFF_T_ rtems_signed32 +#define _BSD_PID_T_ rtems_id +#define _BSD_VA_LIST_ char * + +#include <sys/time.h> +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; +struct mdproc { + int md_flags; + int *md_regs; +}; + +#define USHRT_MAX 65535 + +/* + * Other RTEMS/BSD glue + */ +struct socket; +extern void soconnsleep (struct socket *so); +extern void soconnwakeup (struct socket *so); +#define splnet() 0 +#define splimp() 0 +#define splx(s) + +#define ovbcopy(f,t,n) bcopy(f,t,n) +#define copyout(f,t,n) (memcpy(t,f,n),0) +#define copyin(f,t,n) (memcpy(t,f,n),0) + +#define random() rtems_bsdnet_random() +#define panic rtems_panic +#define suser(a,b) 0 + +void microtime (struct timeval *tv); +#define hz rtems_bsdnet_ticks_per_second +#define tick rtems_bsdnet_microseconds_per_tick + +#define SHRT_MAX 65535 + +#define log rtems_bsdnet_log + +/* + * Since we can't have two sys/types.h files, we'll hack around + * and copy the contents of the BSD sys/types.h to here.... + */ +#include <sys/cdefs.h> + +typedef u_int64_t u_quad_t; /* quads */ +typedef int64_t quad_t; +typedef quad_t * qaddr_t; + +typedef void __sighandler_t __P((int)); +typedef __sighandler_t *sig_t; /* type of pointer to a signal function */ +#define NSIG 32 +struct sigaltstack { + char *ss_sp; /* signal stack base */ + int ss_size; /* signal stack length */ + int ss_flags; /* SS_DISABLE and/or SS_ONSTACK */ +}; + +#ifdef KERNEL +typedef int boolean_t; +typedef struct vm_page *vm_page_t; +#endif + +#ifndef _POSIX_SOURCE +/* + * minor() gives a cookie instead of an index since we don't want to + * change the meanings of bits 0-15 or waste time and space shifting + * bits 16-31 for devices that don't use them. + */ +#define major(x) ((int)(((u_int)(x) >> 8)&0xff)) /* major number */ +#define minor(x) ((int)((x)&0xffff00ff)) /* minor number */ +#define makedev(x,y) ((dev_t)(((x) << 8) | (y))) /* create dev_t */ +#endif + +#include <machine/endian.h> + +typedef quad_t rlim_t; /* resource limit */ +typedef u_int32_t fixpt_t; /* fixed point number */ + +/* + * Forward structure declarations for function prototypes. We include the + * common structures that cross subsystem boundaries here; others are mostly + * used in the same place that the structure is defined. + */ +struct proc; +struct pgrp; +struct ucred; +struct rusage; +struct file; +struct buf; +struct tty; +struct uio; + +/* + * Redo kernel memory allocation + */ +#define malloc rtems_bsdnet_malloc +#define free rtems_bsdnet_free + +#define M_NOWAIT 0x0001 +void *rtems_bsdnet_malloc (unsigned long size, int type, int flags); +void rtems_bsdnet_free (void *addr, int type); + +void rtems_bsdnet_semaphore_obtain (void); +void rtems_bsdnet_semaphore_release (void); +void rtems_bsdnet_schednetisr (int n); + +unsigned long rtems_bsdnet_seconds_since_boot (void); +unsigned long rtems_bsdnet_random (void); + +rtems_id rtems_bsdnet_newproc ( + char *name, + int stacksize, + void (*entry)(void *), + void *arg +); + +rtems_status_code rtems_bsdnet_event_receive ( + rtems_event_set event_in, + rtems_option option_set, + rtems_interval ticks, + rtems_event_set *event_out +); + +/* + * Network configuration + */ +extern int rtems_bsdnet_ticks_per_second; +extern int rtems_bsdnet_microseconds_per_tick; +extern struct in_addr rtems_bsdnet_log_host_address; +extern char *rtems_bsdnet_domain_name; +extern struct in_addr rtems_bsdnet_nameserver[]; +extern int rtems_bsdnet_nameserver_count; + +/* + * Internal IOCTL command + */ +#define SIO_RTEMS_SHOW_STATS _IO('i', 250) + +#endif /* _RTEMS_BSDNET_INTERNAL_H_ */ diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c new file mode 100644 index 0000000000..339d99052b --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -0,0 +1,898 @@ +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/domain.h> +#include <sys/mbuf.h> +#include <sys/socketvar.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/callout.h> +#include <sys/proc.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <vm/vm.h> +#include <arpa/inet.h> + +#include <net/netisr.h> +#include <net/route.h> + +/* + * Events used by networking routines. + * Everything will break if the application + * tries to use these events or if the `sleep' + * events are equal to any of the NETISR * events. + */ +#define SBWAIT_EVENT RTEMS_EVENT_24 +#define SOSLEEP_EVENT RTEMS_EVENT_25 +#define NETISR_IP_EVENT (1 << NETISR_IP) +#define NETISR_ARP_EVENT (1 << NETISR_ARP) +#define NETISR_EVENTS (NETISR_IP_EVENT|NETISR_ARP_EVENT) + + +/* + * Memory allocation + */ +static int nmbuf = (64 * 1024) / MSIZE; + int nmbclusters = (128 * 1024) / MCLBYTES; + +/* + * Socket buffering parameters + */ +unsigned long sb_efficiency = 8; + +/* + * Network task synchronization + */ +static rtems_id networkSemaphore; +static rtems_id networkDaemonTid; +static rtems_unsigned32 networkDaemonPriority; +static void networkDaemon (void *task_argument); + +/* + * Network timing + */ +int rtems_bsdnet_ticks_per_second; +int rtems_bsdnet_microseconds_per_tick; + +/* + * Callout processing + */ +static rtems_interval ticksWhenCalloutsLastChecked; +static struct callout *callfree, calltodo; + +/* + * FreeBSD variables + */ +int nfs_diskless_valid; + +/* + * BOOTP values + */ +struct in_addr rtems_bsdnet_log_host_address; +struct in_addr rtems_bsdnet_bootp_server_address; +char *rtems_bsdnet_bootp_boot_file_name; +char *rtems_bsdnet_domain_name; +struct in_addr rtems_bsdnet_nameserver[sizeof rtems_bsdnet_config.name_server / + sizeof rtems_bsdnet_config.name_server[0]]; +int rtems_bsdnet_nameserver_count; + +extern rtems_libio_handler_t rtems_bsdnet_io_handler; + +/* + * Perform FreeBSD memory allocation. + * FIXME: This should be modified to keep memory allocation statistics. + */ +#undef malloc +#undef free +extern void *malloc (size_t); +extern void free (void *); +void * +rtems_bsdnet_malloc (unsigned long size, int type, int flags) +{ + void *p; + + for (;;) { + p = malloc (size); + if (p) + return p; + if (flags & M_NOWAIT) + return p; + /* + * FIXME: This should be redone as: + * static volatile int rtems_bsdnet_need_memory; + * + * rtems_bsdnet_need_memory = 1; + * message_queue_receive + * + * Then in rtems_bsdnet_freee: + * free (....); + * if (rtems_bsdnet_need_memory) + * rtems_bsdnet_need_memory = 0; + * message_queue_broadcast + */ + rtems_task_wake_after (rtems_bsdnet_ticks_per_second); + } +} + +/* + * Free FreeBSD memory + * FIXME: This should be modified to keep memory allocation statistics. + */ +void +rtems_bsdnet_free (void *addr, int type) +{ + free (addr); +} + +/* + * Do the initializations required by the BSD code + * FIXME: Maybe we should use a different memory allocation scheme that + * would let us share space between mbufs and mbuf clusters. + * For now, we'll just take the easy way out! + */ +static void +bsd_init () +{ + /* + * Set up mbuf data strutures + * Cluster allocation *must* come first -- see comment on kmem_malloc(). + */ + m_clalloc (nmbclusters, M_DONTWAIT); + mclrefcnt = malloc (nmbclusters); + if (mclrefcnt == NULL) + rtems_panic ("No memory for mbuf cluster reference counts."); + memset (mclrefcnt, '\0', nmbclusters); + m_mballoc (nmbuf, M_DONTWAIT); + mbstat.m_mtypes[MT_FREE] = nmbuf; + + + /* + * Set up domains + */ + { + extern struct domain routedomain; + extern struct domain inetdomain; + + routedomain.dom_next = domains; + domains = &routedomain; + inetdomain.dom_next = domains; + domains = &inetdomain; + domaininit (NULL); + } + + /* + * Set up interfaces + */ + ifinit (NULL); +} + +/* + * Initialize and start network operations + */ +static void +rtems_bsdnet_initialize (void) +{ + rtems_status_code sc; + + /* + * Set the priority of all network tasks + */ + if (rtems_bsdnet_config.network_task_priority == 0) + networkDaemonPriority = 100; + else + networkDaemonPriority = rtems_bsdnet_config.network_task_priority; + + /* + * Set the memory allocation limits + */ + if (rtems_bsdnet_config.mbuf_bytecount) + nmbuf = rtems_bsdnet_config.mbuf_bytecount / MSIZE; + if (rtems_bsdnet_config.mbuf_cluster_bytecount) + nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES; + + /* + * Create the task-synchronization semaphore + */ + sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'), + 0, + RTEMS_FIFO | + RTEMS_BINARY_SEMAPHORE | + RTEMS_NO_INHERIT_PRIORITY | + RTEMS_NO_PRIORITY_CEILING | + RTEMS_LOCAL, + 0, + &networkSemaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't create network seamphore: `%s'\n", rtems_status_text (sc)); + + /* + * Compute clock tick conversion factors + */ + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtems_bsdnet_ticks_per_second); + if (rtems_bsdnet_ticks_per_second <= 0) + rtems_bsdnet_ticks_per_second = 1; + rtems_bsdnet_microseconds_per_tick = 1000000 / rtems_bsdnet_ticks_per_second; + + /* + * Ensure that `seconds' is greater than 0 + */ + rtems_task_wake_after (rtems_bsdnet_ticks_per_second); + + /* + * Set up BSD-style sockets + */ + bsd_init (); + + /* + * Start network daemon + */ + networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL); + + /* + * Register as an external I/O handler + */ + rtems_register_libio_handler (RTEMS_FILE_DESCRIPTOR_TYPE_SOCKET, + &rtems_bsdnet_io_handler); + + /* + * Let other network tasks begin + */ + rtems_bsdnet_semaphore_release (); +} + +rtems_id TaskWithSemaphore; +/* + * Obtain network mutex + */ +void +rtems_bsdnet_semaphore_obtain (void) +{ + rtems_status_code sc; + + sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); +rtems_task_ident (RTEMS_SELF, 0, &TaskWithSemaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't obtain network semaphore: `%s'\n", rtems_status_text (sc)); +} + +/* + * Release network mutex + */ +void +rtems_bsdnet_semaphore_release (void) +{ + rtems_status_code sc; + +TaskWithSemaphore = 0; + sc = rtems_semaphore_release (networkSemaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't release network semaphore: `%s'\n", rtems_status_text (sc)); + } + +/* + * Wait for something to happen to a socket buffer + */ +int +sbwait(sb) + struct sockbuf *sb; +{ + rtems_event_set events; + rtems_id tid; + rtems_status_code sc; + + /* + * Soak up any pending events. + * The sleep/wakeup synchronization in the FreeBSD + * kernel has no memory. + */ + rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Set this task as the target of the wakeup operation. + */ + if (sb->sb_sel.si_pid) + rtems_panic ("Another task is already sleeping on that socket buffer"); + rtems_task_ident (RTEMS_SELF, 0, &tid); + sb->sb_sel.si_pid = tid; + + /* + * Mark the socket buffer as waiting. + */ + sb->sb_flags |= SB_WAIT; + + /* + * Release the network semaphore. + */ + rtems_bsdnet_semaphore_release (); + + /* + * Wait for the wakeup event. + */ + sc = rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events); + + /* + * Reobtain the network semaphore. + */ + rtems_bsdnet_semaphore_obtain (); + + /* + * Relinquish ownership of the socket buffer + */ + sb->sb_flags &= ~SB_WAIT; + sb->sb_sel.si_pid = 0; + + /* + * Return the status of the wait. + */ + switch (sc) { + case RTEMS_SUCCESSFUL: return 0; + case RTEMS_TIMEOUT: return EWOULDBLOCK; + default: return ENXIO; + } +} + + +/* + * Wake up the task waiting on a socket buffer. + */ +void +sowakeup(so, sb) + register struct socket *so; + register struct sockbuf *sb; +{ + if (sb->sb_flags & SB_WAIT) { + sb->sb_flags &= ~SB_WAIT; + rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT); + } +} + +/* + * For now, a socket can be used by only one task at a time. + */ +int +sb_lock(sb) + register struct sockbuf *sb; +{ + rtems_panic ("Socket buffer is already in use."); + return 0; +} +void +wakeup (void *p) +{ + rtems_panic ("Wakeup called"); +} + +/* + * Wait for a connection/disconnection event. + */ +void +soconnsleep (struct socket *so) +{ + rtems_event_set events; + rtems_id tid; + + /* + * Soak up any pending events. + * The sleep/wakeup synchronization in the FreeBSD + * kernel has no memory. + */ + rtems_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Set this task as the target of the wakeup operation. + */ + if (so->so_pgid) + rtems_panic ("Another task is already sleeping on that socket"); + rtems_task_ident (RTEMS_SELF, 0, &tid); + so->so_pgid = tid; + + /* + * Wait for the wakeup event. + */ + rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Relinquish ownership of the socket. + */ + so->so_pgid = 0; +} + +/* + * Wake up a task waiting for a connection/disconnection to complete. + */ +void +soconnwakeup (struct socket *so) +{ + if (so->so_pgid) + rtems_event_send (so->so_pgid, SOSLEEP_EVENT); +} + +/* + * Send an event to the network daemon. + * This corresponds to sending a software interrupt in the BSD kernel. + */ +void +rtems_bsdnet_schednetisr (int n) +{ + rtems_event_send (networkDaemonTid, 1 << n); +} + +/* + * The network daemon + * This provides a context to run BSD software interrupts + */ +static void +networkDaemon (void *task_argument) +{ + rtems_event_set events; + rtems_interval now; + int ticksPassed; + unsigned32 timeout; + struct callout *c; + + for (;;) { + c = calltodo.c_next; + if (c) + timeout = c->c_time; + else + timeout = RTEMS_NO_TIMEOUT; + rtems_bsdnet_event_receive (NETISR_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + timeout, + &events); + if (events & NETISR_IP_EVENT) + ipintr (); + if (events & NETISR_ARP_EVENT) + arpintr (); + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + ticksPassed = now - ticksWhenCalloutsLastChecked; + if (ticksPassed != 0) { + ticksWhenCalloutsLastChecked = now; + + c = calltodo.c_next; + if (c) { + c->c_time -= ticksPassed; + while ((c = calltodo.c_next) != NULL && c->c_time <= 0) { + void *arg; + void (*func) (void *); + + func = c->c_func; + arg = c->c_arg; + calltodo.c_next = c->c_next; + c->c_next = callfree; + callfree = c; + (*func)(arg); + } + } + } + } +} + +/* + * Structure passed to task-start stub + */ +struct newtask { + void (*entry)(void *); + void *arg; +}; + +/* + * Task-start stub + */ +static void +taskEntry (rtems_task_argument arg) +{ + struct newtask t; + + /* + * Pick up task information and free + * the memory allocated to pass the + * information to this task. + */ + t = *(struct newtask *)arg; + free ((struct newtask *)arg); + + /* + * Enter the competition for the network semaphore + */ + rtems_bsdnet_semaphore_obtain (); + + /* + * Enter the task + */ + (*t.entry)(t.arg); + rtems_panic ("Network task returned!\n"); +} + +/* + * Start a network task + */ +rtems_id +rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg) +{ + struct newtask *t; + char nm[4]; + rtems_id tid; + rtems_status_code sc; + + strncpy (nm, name, 4); + sc = rtems_task_create (rtems_build_name(nm[0], nm[1], nm[2], nm[3]), + networkDaemonPriority, + stacksize, + RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), + RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL, + &tid); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't create network daemon `%s': `%s'\n", name, rtems_status_text (sc)); + + /* + * Set up task arguments + */ + t = malloc (sizeof *t); + t->entry = entry; + t->arg = arg; + + /* + * Start the task + */ + sc = rtems_task_start (tid, taskEntry, (rtems_task_argument)t); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't start network daemon `%s': `%s'\n", name, rtems_status_text (sc)); + + /* + * Let our caller know the i.d. of the new task + */ + return tid; +} + +rtems_status_code rtems_bsdnet_event_receive ( + rtems_event_set event_in, + rtems_option option_set, + rtems_interval ticks, + rtems_event_set *event_out) +{ + rtems_status_code sc; + + rtems_bsdnet_semaphore_release (); + sc = rtems_event_receive (event_in, option_set, ticks, event_out); + rtems_bsdnet_semaphore_obtain (); + return sc; +} + +/* + * Return time since startup + */ +void +microtime (struct timeval *t) +{ + rtems_interval now; + + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + t->tv_sec = now / rtems_bsdnet_ticks_per_second; + t->tv_usec = (now % rtems_bsdnet_ticks_per_second) * rtems_bsdnet_microseconds_per_tick; +} + +unsigned long +rtems_bsdnet_seconds_since_boot (void) +{ + rtems_interval now; + + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + return now / rtems_bsdnet_ticks_per_second; +} + +/* + * Fake random number generator + */ +unsigned long +rtems_bsdnet_random (void) +{ + rtems_interval now; + + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + return (now * 99991); +} + +/* + * Callout list processing + */ +void +timeout(void (*ftn)(void *), void *arg, int ticks) +{ + register struct callout *new, *p, *t; + + if (ticks <= 0) + ticks = 1; + + /* Fill in the next free callout structure. */ + if (callfree == NULL) { + callfree = malloc (sizeof *callfree); + if (callfree == NULL) + rtems_panic ("No memory for timeout table entry"); + callfree->c_next = NULL; + } + + new = callfree; + callfree = new->c_next; + new->c_arg = arg; + new->c_func = ftn; + + /* + * The time for each event is stored as a difference from the time + * of the previous event on the queue. Walk the queue, correcting + * the ticks argument for queue entries passed. Correct the ticks + * value for the queue entry immediately after the insertion point + * as well. Watch out for negative c_time values; these represent + * overdue events. + */ + for (p = &calltodo; + (t = p->c_next) != NULL && ticks > t->c_time; p = t) + if (t->c_time > 0) + ticks -= t->c_time; + new->c_time = ticks; + if (t != NULL) + t->c_time -= ticks; + + /* Insert the new entry into the queue. */ + p->c_next = new; + new->c_next = t; +} + +/* + * Ticks till specified time + * FIXME: This version worries only about seconds, but that's good + * enough for the way the network code uses this routine. + */ +int +hzto(struct timeval *tv) +{ + long diff = tv->tv_sec - rtems_bsdnet_seconds_since_boot(); + + if (diff <= 0) + return 1; + return diff * rtems_bsdnet_ticks_per_second; +} + +/* + * Kernel debugging + */ +int rtems_bsdnet_log_priority; +void +rtems_bsdnet_log (int priority, const char *fmt, ...) +{ + va_list args; + + if (priority & rtems_bsdnet_log_priority) { + va_start (args, fmt); + vprintf (fmt, args); + va_end (args); + } +} + +/* + * Hack alert: kmem_malloc `knows' that its + * first invocation is to get mbuf clusters! + */ +int mb_map_full; +vm_map_t mb_map; +vm_offset_t +kmem_malloc (vm_map_t *map, vm_size_t size, boolean_t waitflag) +{ + void *p; + + /* + * Can't get memory if we're already running. + */ + if (networkDaemonTid) { + if (waitflag == M_WAITOK) + rtems_panic ("Someone is asking for more memory"); + return 0; + } + +#define ROUNDSIZE 2048 + p = malloc (size+ROUNDSIZE); + p = (void *)((unsigned long)p & ~(ROUNDSIZE-1)); + if ((p == NULL) && (waitflag == M_WAITOK)) + rtems_panic ("Can't get initial network memory!"); + if (mbutl == NULL) + mbutl = p; + return (vm_offset_t)p; +} + +/* + * IP header checksum routine for processors which don't have an inline version + */ +u_int +in_cksum_hdr (const void *ip) +{ + rtems_unsigned32 sum; + const rtems_unsigned16 *sp; + int i; + + sum = 0; + sp = (rtems_unsigned16 *)ip; + for (i = 0 ; i < 10 ; i++) + sum += *sp++; + while (sum > 0xFFFF) + sum = (sum & 0xffff) + (sum >> 16); + return ~sum & 0xFFFF; +} + +/* + * Manipulate routing tables + */ +int rtems_bsdnet_rtrequest ( + int req, + struct sockaddr *dst, + struct sockaddr *gateway, + struct sockaddr *netmask, + int flags, + struct rtentry **net_nrt) +{ + int error; + + rtems_bsdnet_semaphore_obtain (); + error = rtrequest (req, dst, gateway, netmask, flags, net_nrt); + rtems_bsdnet_semaphore_release (); + if (error) { + errno = error; + return -1; + } + return 0; +} + +static void +rtems_bsdnet_setup (void) +{ + struct rtems_bsdnet_ifconfig *ifp; + int s; + struct ifreq ifreq; + struct sockaddr_in address; + struct sockaddr_in netmask; + struct sockaddr_in broadcast; + struct sockaddr_in gateway; + int i; + + /* + * Set local parameters + */ + if (rtems_bsdnet_config.hostname) + sethostname (rtems_bsdnet_config.hostname, + strlen (rtems_bsdnet_config.hostname)); + if (rtems_bsdnet_config.domainname) + rtems_bsdnet_domain_name = + strdup (rtems_bsdnet_config.domainname); + if (rtems_bsdnet_config.log_host) + rtems_bsdnet_log_host_address.s_addr = + inet_addr (rtems_bsdnet_config.log_host); + for (i = 0 ; i < sizeof rtems_bsdnet_config.name_server / + sizeof rtems_bsdnet_config.name_server[0] ; i++) { + if (!rtems_bsdnet_config.name_server[i]) + break; + rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count++].s_addr + = inet_addr (rtems_bsdnet_config.name_server[i]); + } + + /* + * Configure interfaces + */ + s = socket (AF_INET, SOCK_DGRAM, 0); + if (s < 0) + rtems_panic ("Can't create initial socket: %s", strerror (errno)); + for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) { + if (ifp->ip_address == NULL) + continue; + + /* + * Get the interface flags + */ + strcpy (ifreq.ifr_name, ifp->name); + if (ioctl (s, SIOCGIFFLAGS, &ifreq) < 0) + rtems_panic ("Can't get %s flags: %s", ifp->name, strerror (errno)); + + /* + * Bring interface up + */ + ifreq.ifr_flags |= IFF_UP; + if (ioctl (s, SIOCSIFFLAGS, &ifreq) < 0) + rtems_panic ("Can't bring %s up: %s", ifp->name, strerror (errno)); + + /* + * Set interface netmask + */ + memset (&netmask, '\0', sizeof netmask); + netmask.sin_len = sizeof netmask; + netmask.sin_family = AF_INET; + netmask.sin_addr.s_addr = inet_addr (ifp->ip_netmask); + memcpy (&ifreq.ifr_addr, &netmask, sizeof netmask); + if (ioctl (s, SIOCSIFNETMASK, &ifreq) < 0) + rtems_panic ("Can't set %s netmask: %s", ifp->name, strerror (errno)); + + /* + * Set interface address + */ + memset (&address, '\0', sizeof address); + address.sin_len = sizeof address; + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr (ifp->ip_address); + memcpy (&ifreq.ifr_addr, &address, sizeof address); + if (ioctl (s, SIOCSIFADDR, &ifreq) < 0) + rtems_panic ("Can't set %s address: %s", ifp->name, strerror (errno)); + + /* + * Set interface broadcast address + */ + memset (&broadcast, '\0', sizeof broadcast); + broadcast.sin_len = sizeof broadcast; + broadcast.sin_family = AF_INET; + broadcast.sin_addr.s_addr = address.sin_addr.s_addr | ~netmask.sin_addr.s_addr; + memcpy (&ifreq.ifr_broadaddr, &broadcast, sizeof broadcast); + if (ioctl (s, SIOCSIFBRDADDR, &ifreq) < 0) + rtems_panic ("Can't set %s broadcast address: %s", ifp->name, strerror (errno)); + } + + /* + * We're done with the dummy socket + */ + close (s); + + /* + * Set default route + */ + if (rtems_bsdnet_config.gateway) { + address.sin_addr.s_addr = INADDR_ANY; + netmask.sin_addr.s_addr = INADDR_ANY; + memset (&gateway, '\0', sizeof gateway); + gateway.sin_len = sizeof gateway; + gateway.sin_family = AF_INET; + gateway.sin_addr.s_addr = inet_addr (rtems_bsdnet_config.gateway); + if (rtems_bsdnet_rtrequest ( + RTM_ADD, + (struct sockaddr *)&address, + (struct sockaddr *)&gateway, + (struct sockaddr *)&netmask, + (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0) + rtems_panic ("Can't set default route: %s", strerror (errno)); + } +} + +/* + * Initialize the network + */ +int +rtems_bsdnet_initialize_network (void) +{ + struct rtems_bsdnet_ifconfig *ifp; + + /* + * Start network tasks. + * Initialize BSD network data structures. + */ + rtems_bsdnet_initialize (); + + /* + * Attach interfaces + */ + for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) { + rtems_bsdnet_semaphore_obtain (); + (ifp->attach)(ifp); + rtems_bsdnet_semaphore_release (); + } + + /* + * Bring up the network + */ + rtems_bsdnet_setup (); + if (rtems_bsdnet_config.bootp) + (*rtems_bsdnet_config.bootp)(); + return 0; +} diff --git a/cpukit/libnetworking/rtems/rtems_showicmpstat.c b/cpukit/libnetworking/rtems/rtems_showicmpstat.c new file mode 100644 index 0000000000..0432c3a9a9 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showicmpstat.c @@ -0,0 +1,56 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp_var.h> + +/* + * Display ICMP statistics + * Don't lock the rest of the network tasks out while printing. + * It's no big deal if the values change while being printed. + */ +static void +showicmpstat (const char *name, unsigned long n) +{ + if (n) + printf ("%35s%12lu\n", name, n); +} + +void +rtems_bsdnet_show_icmp_stats (void) +{ + int i; + char cbuf[20]; + + printf ("************ ICMP Statistics ************\n"); + showicmpstat ("Calls to icmp_error()", icmpstat.icps_error); + showicmpstat ("Errors not sent -- old was icmp", icmpstat.icps_oldicmp); + for (i = 0 ; i <= ICMP_MAXTYPE ; i++) { + if (icmpstat.icps_outhist[i]) { + sprintf (cbuf, "Type %d sent", i); + showicmpstat (cbuf, icmpstat.icps_outhist[i]); + } + } + showicmpstat ("icmp_code out of range", icmpstat.icps_badcode); + showicmpstat ("packet < ICMP_MINLEN", icmpstat.icps_tooshort); + showicmpstat ("bad checksum", icmpstat.icps_checksum); + showicmpstat ("calculated bound mismatch", icmpstat.icps_badlen); + showicmpstat ("number of responses", icmpstat.icps_reflect); + showicmpstat ("b/mcast echo requests dropped", icmpstat.icps_bmcastecho); + showicmpstat ("b/mcast tstamp requests dropped", icmpstat.icps_bmcasttstamp); + for (i = 0 ; i <= ICMP_MAXTYPE ; i++) { + if (icmpstat.icps_inhist[i]) { + sprintf (cbuf, "Type %d received", i); + showicmpstat (cbuf, icmpstat.icps_inhist[i]); + } + } + + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_showifstat.c b/cpukit/libnetworking/rtems/rtems_showifstat.c new file mode 100644 index 0000000000..b9a264fb34 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showifstat.c @@ -0,0 +1,106 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> + +/* + * Display an address + */ +static int +showaddress (char *name, struct sockaddr *a) +{ + struct sockaddr_in *sa; + + if (!a || (a->sa_family != AF_INET)) + return 0; + printf ("%s:", name); + sa = (struct sockaddr_in *)a; + printf ("%-16s", inet_ntoa (sa->sin_addr)); + return 1; +} + +/* + * Display interface statistics + */ +void +rtems_bsdnet_show_if_stats (void) +{ + struct ifnet *ifp; + struct ifaddr *ifa; + unsigned int bit, flags; + int printed; + + printf ("************ INTERFACE STATISTICS ************\n"); + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + printf ("***** %s%d *****\n", ifp->if_name, ifp->if_unit); + for (ifa = ifp->if_addrlist ; ifa ; ifa = ifa->ifa_next) { + printed = showaddress ("Address", ifa->ifa_addr); + if (ifp->if_flags & IFF_BROADCAST) + printed |= showaddress ("Broadcast Address", ifa->ifa_broadaddr); + if (ifp->if_flags & IFF_POINTOPOINT) + printed |= showaddress ("Destination Address", ifa->ifa_dstaddr); + printed |= showaddress ("Net mask", ifa->ifa_netmask); + if (printed) + printf ("\n"); + } + + printf ("Flags:"); + for (bit = 1, flags = ifp->if_flags ; flags ; bit <<= 1) { + char *cp; + switch (flags & bit) { + default: cp = NULL; break; + case IFF_UP: cp = "Up"; break; + case IFF_BROADCAST: cp = "Broadcast"; break; + case IFF_DEBUG: cp = "Debug"; break; + case IFF_LOOPBACK: cp = "Loopback"; break; + case IFF_POINTOPOINT: cp = "Point-to-point"; break; + case IFF_RUNNING: cp = "Running"; break; + case IFF_NOARP: cp = "No-ARP"; break; + case IFF_PROMISC: cp = "Promiscuous"; break; + case IFF_ALLMULTI: cp = "All-multicast"; break; + case IFF_OACTIVE: cp = "Active"; break; + case IFF_SIMPLEX: cp = "Simplex"; break; + case IFF_LINK0: cp = "Link0"; break; + case IFF_LINK1: cp = "Link1"; break; + case IFF_LINK2: cp = "Link2"; break; + case IFF_MULTICAST: cp = "Multicast"; break; + } + if (cp) { + flags &= ~bit; + printf (" %s", cp); + } + } + printf ("\n"); + + printf ("Send queue limit:%-4d length:%-4d Dropped:%-8d\n", + ifp->if_snd.ifq_maxlen, + ifp->if_snd.ifq_len, + ifp->if_snd.ifq_drops); + + /* + * FIXME: Could print if_data statistics here, + * but right now the drivers maintain their + * own statistics. + */ + + /* + * Grab the network semaphore. + * In most cases this is not necessary, but it's + * easier to always call the driver ioctl function + * while holding the semaphore than to try + * and explain why some ioctl commands are invoked + * while holding the semaphore and others are + * invoked while not holding the semaphore. + */ + rtems_bsdnet_semaphore_obtain (); + (*ifp->if_ioctl)(ifp, SIO_RTEMS_SHOW_STATS, NULL); + rtems_bsdnet_semaphore_release (); + } + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_showipstat.c b/cpukit/libnetworking/rtems/rtems_showipstat.c new file mode 100644 index 0000000000..053c07c8e7 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showipstat.c @@ -0,0 +1,55 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +/* + * Display IP statistics + * Don't lock the rest of the network tasks out while printing. + * It's no big deal if the values change while being printed. + */ +static void +showipstat (const char *name, unsigned long n) +{ + if (n) + printf ("%35s%12lu\n", name, n); +} + +void +rtems_bsdnet_show_ip_stats (void) +{ + printf ("************ IP Statistics ************\n"); + showipstat ("total packets received", ipstat.ips_total); + showipstat ("checksum bad", ipstat.ips_badsum); + showipstat ("packet too short", ipstat.ips_tooshort); + showipstat ("not enough data", ipstat.ips_toosmall); + showipstat ("ip header length < data size", ipstat.ips_badhlen); + showipstat ("ip length < ip header length", ipstat.ips_badlen); + showipstat ("fragments received", ipstat.ips_fragments); + showipstat ("frags dropped (dups, out of space)", ipstat.ips_fragdropped); + showipstat ("fragments timed out", ipstat.ips_fragtimeout); + showipstat ("packets forwarded", ipstat.ips_forward); + showipstat ("packets rcvd for unreachable dest", ipstat.ips_cantforward); + showipstat ("packets forwarded on same net", ipstat.ips_redirectsent); + showipstat ("unknown or unsupported protocol", ipstat.ips_noproto); + showipstat ("datagrams delivered to upper level", ipstat.ips_delivered); + showipstat ("total ip packets generated here", ipstat.ips_localout); + showipstat ("lost packets due to nobufs, etc.", ipstat.ips_odropped); + showipstat ("total packets reassembled ok", ipstat.ips_reassembled); + showipstat ("datagrams successfully fragmented", ipstat.ips_fragmented); + showipstat ("output fragments created", ipstat.ips_ofragments); + showipstat ("don't fragment flag was set, etc.", ipstat.ips_cantfrag); + showipstat ("error in option processing", ipstat.ips_badoptions); + showipstat ("packets discarded due to no route", ipstat.ips_noroute); + showipstat ("ip version != 4", ipstat.ips_badvers); + showipstat ("total raw ip packets generated", ipstat.ips_rawout); + showipstat ("ip length > max ip packet size", ipstat.ips_toolong); + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_showmbuf.c b/cpukit/libnetworking/rtems/rtems_showmbuf.c new file mode 100644 index 0000000000..41c7f4c6a1 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showmbuf.c @@ -0,0 +1,61 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> + +/* + * Display MBUF statistics + * Don't lock the rest of the network tasks out while printing. + * It's no big deal if the values change while being printed. + */ +void +rtems_bsdnet_show_mbuf_stats (void) +{ + int i; + int printed = 0; + char *cp; + + printf ("************ MBUF STATISTICS ************\n"); + printf ("mbufs:%4lu clusters:%4lu free:%4lu\n", + mbstat.m_mbufs, mbstat.m_clusters, mbstat.m_clfree); + printf ("drops:%4lu waits:%4lu drains:%4lu\n", + mbstat.m_drops, mbstat.m_wait, mbstat.m_drain); + for (i = 0 ; i < 20 ; i++) { + switch (i) { + case MT_FREE: cp = "free"; break; + case MT_DATA: cp = "data"; break; + case MT_HEADER: cp = "header"; break; + case MT_SOCKET: cp = "socket"; break; + case MT_PCB: cp = "pcb"; break; + case MT_RTABLE: cp = "rtable"; break; + case MT_HTABLE: cp = "htable"; break; + case MT_ATABLE: cp = "atable"; break; + case MT_SONAME: cp = "soname"; break; + case MT_SOOPTS: cp = "soopts"; break; + case MT_FTABLE: cp = "ftable"; break; + case MT_RIGHTS: cp = "rights"; break; + case MT_IFADDR: cp = "ifaddr"; break; + case MT_CONTROL: cp = "control"; break; + case MT_OOBDATA: cp = "oobdata"; break; + default: cp = NULL; break; + } + if ((cp != NULL) || (mbstat.m_mtypes[i] != 0)) { + char cbuf[16]; + if (cp == NULL) { + sprintf (cbuf, "Type %d", i); + cp = cbuf; + } + printf ("%10s:%-8u", cp, mbstat.m_mtypes[i]); + if (++printed == 4) { + printf ("\n"); + printed = 0; + } + } + } + if (printed) + printf ("\n"); + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_showroute.c b/cpukit/libnetworking/rtems/rtems_showroute.c new file mode 100644 index 0000000000..8695680d5e --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showroute.c @@ -0,0 +1,159 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> + +/* + * We'll use the application versions of malloc and free. + */ +#undef malloc +#undef free +/* + * Information per route + */ +struct rinfo { + struct in_addr dst; + struct in_addr gw_mask; + unsigned long pksent; + unsigned long expire; + int flags; + char ifname[16]; + short ifunit; + short refcnt; +}; + +/* + * Information per display + */ +struct dinfo { + int capacity; + int count; + struct rinfo *routes; +}; + +/* + * Package everything up before printing it. + * We don't want to block all network operations till + * the printing completes! + */ +static int +show_inet_route (rn, vw) + struct radix_node *rn; + void *vw; +{ + struct rtentry *rt = (struct rtentry *)rn; + struct ifnet *ifp; + struct dinfo *dp = (struct dinfo *)vw; + struct rinfo *r; + + /* + * Get a pointer to a new route info structure + */ + if (dp->count >= dp->capacity) { + r = realloc (dp->routes, (sizeof *r) * (dp->capacity + 20)); + if (r == 0) + return ENOMEM; + dp->capacity += 20; + dp->routes = r; + } + r = dp->routes + dp->count++; + + /* + * Fill in the route info structure + */ + r->dst = ((struct sockaddr_in *)rt_key(rt))->sin_addr; + if (rt->rt_flags & RTF_GATEWAY) + r->gw_mask = ((struct sockaddr_in *)rt->rt_gateway)->sin_addr; + else if (!(rt->rt_flags & RTF_HOST)) + r->gw_mask = ((struct sockaddr_in *)rt_mask(rt))->sin_addr; + r->flags = rt->rt_flags; + r->refcnt = rt->rt_refcnt; + r->pksent = rt->rt_rmx.rmx_pksent; + r->expire = rt->rt_rmx.rmx_expire; + ifp = rt->rt_ifp; + strncpy (r->ifname, ifp->if_name, sizeof r->ifname); + r->ifunit = ifp->if_unit; + return 0; +} + +/* + * Reentrant version of inet_ntoa + */ +char * +inet_ntoa_r (struct in_addr ina, char *buf) +{ + unsigned char *ucp = (unsigned char *)&ina; + + sprintf (buf, "%d.%d.%d.%d", + ucp[0] & 0xff, + ucp[1] & 0xff, + ucp[2] & 0xff, + ucp[3] & 0xff); + return buf; +} + +void +rtems_bsdnet_show_inet_routes (void) +{ + struct radix_node_head *rnh; + struct dinfo d; + struct rinfo *r; + int i, error; + + rnh = rt_tables[AF_INET]; + if (!rnh) + return; + d.count = d.capacity = 0; + d.routes = NULL; + rtems_bsdnet_semaphore_obtain (); + error = rnh->rnh_walktree(rnh, show_inet_route, &d); + rtems_bsdnet_semaphore_release (); + if (error) { + printf ("Can't get route info: %s\n", strerror (error)); + return; + } + if (d.count == 0) { + printf ("No routes!\n"); + return; + } + printf ("Destination Gateway/Mask Flags Refs Use Expire Interface\n"); + for (i = 0, r = d.routes ; i < d.count ; i++, r++) { + char buf[30]; + char *cp, *fc, flagbuf[10]; + unsigned long flagbit; + + if (r->dst.s_addr == INADDR_ANY) + cp = "default"; + else + cp = inet_ntoa_r (r->dst, buf); + printf ("%-16s", cp); + if (!(r->flags & RTF_HOST)) + cp = inet_ntoa_r (r->gw_mask, buf); + else + cp = ""; + printf ("%-16s", cp); + fc = "UGHRDM XLS"; + for (flagbit = 0x1, cp = flagbuf ; *fc ; flagbit <<= 1, fc++) { + if ((r->flags & flagbit) && (*fc != ' ')) + *cp++ = *fc; + } + *cp = '\0'; + printf ("%-10s%3d%9ld%7ld %.*s%d\n", flagbuf, + r->refcnt, r->pksent, + r->expire, + (int)sizeof r->ifname, r->ifname, + r->ifunit); + } + free (d.routes); +} diff --git a/cpukit/libnetworking/rtems/rtems_showtcpstat.c b/cpukit/libnetworking/rtems/rtems_showtcpstat.c new file mode 100644 index 0000000000..f293289df8 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showtcpstat.c @@ -0,0 +1,98 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_var.h> + +/* + * Display TCP statistics + * Don't lock the rest of the network tasks out while printing. + * It's no big deal if the values change while being printed. + */ +static void +showtcpstat (const char *name, unsigned long n) +{ + if (n) + printf ("%35s%12lu\n", name, n); +} + +void +rtems_bsdnet_show_tcp_stats (void) +{ + printf ("************ TCP Statistics ************\n"); + showtcpstat ("connections initiated", tcpstat.tcps_connattempt); + showtcpstat ("connections accepted", tcpstat.tcps_accepts); + showtcpstat ("connections established", tcpstat.tcps_connects); + showtcpstat ("connections dropped", tcpstat.tcps_drops); + showtcpstat ("embryonic connections dropped", tcpstat.tcps_conndrops); + showtcpstat ("conn. closed (includes drops)", tcpstat.tcps_closed); + showtcpstat ("segs where we tried to get rtt", tcpstat.tcps_segstimed); + showtcpstat ("times we succeeded", tcpstat.tcps_rttupdated); + showtcpstat ("delayed acks sent", tcpstat.tcps_delack); + showtcpstat ("conn. dropped in rxmt timeout", tcpstat.tcps_timeoutdrop); + showtcpstat ("retransmit timeouts", tcpstat.tcps_rexmttimeo); + showtcpstat ("persist timeouts", tcpstat.tcps_persisttimeo); + showtcpstat ("keepalive timeouts", tcpstat.tcps_keeptimeo); + showtcpstat ("keepalive probes sent", tcpstat.tcps_keepprobe); + showtcpstat ("connections dropped in keepalive", tcpstat.tcps_keepdrops); + + showtcpstat ("total packets sent", tcpstat.tcps_sndtotal); + showtcpstat ("data packets sent", tcpstat.tcps_sndpack); + showtcpstat ("data bytes sent", tcpstat.tcps_sndbyte); + showtcpstat ("data packets retransmitted", tcpstat.tcps_sndrexmitpack); + showtcpstat ("data bytes retransmitted", tcpstat.tcps_sndrexmitbyte); + showtcpstat ("ack-only packets sent", tcpstat.tcps_sndacks); + showtcpstat ("window probes sent", tcpstat.tcps_sndprobe); + showtcpstat ("packets sent with URG only", tcpstat.tcps_sndurg); + showtcpstat ("window update-only packets sent", tcpstat.tcps_sndwinup); + showtcpstat ("control (SYN|FIN|RST) packets sent", tcpstat.tcps_sndctrl); + + showtcpstat ("total packets received", tcpstat.tcps_rcvtotal); + showtcpstat ("packets received in sequence", tcpstat.tcps_rcvpack); + showtcpstat ("bytes received in sequence", tcpstat.tcps_rcvbyte); + showtcpstat ("packets received with ccksum errs", tcpstat.tcps_rcvbadsum); + showtcpstat ("packets received with bad offset", tcpstat.tcps_rcvbadoff); + showtcpstat ("packets received too short", tcpstat.tcps_rcvshort); + showtcpstat ("duplicate-only packets received", tcpstat.tcps_rcvduppack); + showtcpstat ("duplicate-only bytes received", tcpstat.tcps_rcvdupbyte); + showtcpstat ("packets with some duplicate data", tcpstat.tcps_rcvpartduppack); + showtcpstat ("dup. bytes in part-dup. packets", tcpstat.tcps_rcvpartdupbyte); + showtcpstat ("out-of-order packets received", tcpstat.tcps_rcvoopack); + showtcpstat ("out-of-order bytes received", tcpstat.tcps_rcvoobyte); + showtcpstat ("packets with data after window", tcpstat.tcps_rcvpackafterwin); + showtcpstat ("bytes rcvd after window", tcpstat.tcps_rcvbyteafterwin); + showtcpstat ("packets rcvd after \"close\"", tcpstat.tcps_rcvafterclose); + showtcpstat ("rcvd window probe packets", tcpstat.tcps_rcvwinprobe); + showtcpstat ("rcvd duplicate acks", tcpstat.tcps_rcvdupack); + showtcpstat ("rcvd acks for unsent data", tcpstat.tcps_rcvacktoomuch); + showtcpstat ("rcvd ack packets", tcpstat.tcps_rcvackpack); + showtcpstat ("bytes acked by rcvd acks", tcpstat.tcps_rcvackbyte); + showtcpstat ("rcvd window update packets", tcpstat.tcps_rcvwinupd); + showtcpstat ("segments dropped due to PAWS", tcpstat.tcps_pawsdrop); + showtcpstat ("times hdr predict ok for acks", tcpstat.tcps_predack); + showtcpstat ("times hdr predict ok for data pkts", tcpstat.tcps_preddat); + showtcpstat ("pcb cache misses", tcpstat.tcps_pcbcachemiss); + showtcpstat ("times cached RTT in route updated", tcpstat.tcps_cachedrtt); + showtcpstat ("times cached rttvar updated", tcpstat.tcps_cachedrttvar); + showtcpstat ("times cached ssthresh updated", tcpstat.tcps_cachedssthresh); + showtcpstat ("times RTT initialized from route", tcpstat.tcps_usedrtt); + showtcpstat ("times RTTVAR initialized from rt", tcpstat.tcps_usedrttvar); + showtcpstat ("times ssthresh initialized from rt", tcpstat.tcps_usedssthresh); + showtcpstat ("timeout in persist state", tcpstat.tcps_persistdrop); + showtcpstat ("bogus SYN, e.g. premature ACK", tcpstat.tcps_badsyn); + showtcpstat ("resends due to MTU discovery", tcpstat.tcps_mturesent); + showtcpstat ("listen queue overflows", tcpstat.tcps_listendrop); + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_showudpstat.c b/cpukit/libnetworking/rtems/rtems_showudpstat.c new file mode 100644 index 0000000000..a8d8dc2668 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showudpstat.c @@ -0,0 +1,44 @@ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +/* + * Display UDP statistics + * Don't lock the rest of the network tasks out while printing. + * It's no big deal if the values change while being printed. + */ +static void +showudpstat (const char *name, unsigned long n) +{ + if (n) + printf ("%35s%12lu\n", name, n); +} + +void +rtems_bsdnet_show_udp_stats (void) +{ + printf ("************ UDP Statistics ************\n"); + showudpstat ("total input packets", udpstat.udps_ipackets); + showudpstat ("packet shorter than header", udpstat.udps_hdrops); + showudpstat ("checksum error", udpstat.udps_badsum); + showudpstat ("data length larger than packet", udpstat.udps_badlen); + showudpstat ("no socket on port", udpstat.udps_noport); + showudpstat ("of above, arrived as broadcast", udpstat.udps_noportbcast); + showudpstat ("not delivered, input socket full", udpstat.udps_fullsock); + showudpstat ("input packets missing pcb cache", udpstat.udpps_pcbcachemiss); + showudpstat ("input packets not for hashed pcb", udpstat.udpps_pcbhashmiss); + showudpstat ("total output packets", udpstat.udps_opackets); + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_syscall.c b/cpukit/libnetworking/rtems/rtems_syscall.c new file mode 100644 index 0000000000..42361d22cd --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_syscall.c @@ -0,0 +1,743 @@ +#include <string.h> +#include <stdarg.h> +#include <stdio.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> + +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/proc.h> +#include <sys/filio.h> + +#include <net/if.h> +#include <net/route.h> + +/* + ********************************************************************* + * Map RTEMS file descriptor to BSD socket * + ********************************************************************* + */ +struct fdsock { + int indexFreeNext; + struct socket *sock; +}; +static struct fdsock *fdsock; +static int fdsockCount; +static int indexFreeHead = -1; + +/* + * Convert an RTEMS file descriptor to a BSD socket pointer. + */ +static struct socket * +fdToSocket (int fd) +{ + int i; + struct socket *s; + + if ((fd < 0) + || (rtems_file_descriptor_type(fd) != RTEMS_FILE_DESCRIPTOR_TYPE_SOCKET) + || ((i = rtems_file_descriptor_base(fd)) >= fdsockCount) + || ((s = fdsock[i].sock) == NULL)) { + errno = EBADF; + return NULL; + } + return s; +} + +/* + * Enlarge the size of the file-descritor/socket pointer map. + */ +static int +enlargeFdMap (void) +{ + struct fdsock *nfdsock; + int i; + + nfdsock = realloc (fdsock, sizeof *fdsock * (fdsockCount + 20)); + if (nfdsock == NULL) { + errno = ENFILE; + return 0; + } + fdsock = nfdsock; + for (i = fdsockCount, fdsockCount += 20 ; i < fdsockCount ; i++) { + fdsock[i].sock = NULL; + fdsock[i].indexFreeNext = indexFreeHead; + indexFreeHead = i; + } + return 1; +} + +/* + * Create a file descriptor for a new socket + */ +static int +makeFd (struct socket *s) +{ + int i; + + if ((indexFreeHead < 0) && !enlargeFdMap ()) + return -1; + i = indexFreeHead; + indexFreeHead = fdsock[i].indexFreeNext; + fdsock[i].sock = s; + return rtems_make_file_descriptor(i,RTEMS_FILE_DESCRIPTOR_TYPE_SOCKET); +} + +/* + * Package system call argument into mbuf. + */ +static int +sockargstombuf (struct mbuf **mp, const void *buf, int buflen, int type) +{ + struct mbuf *m; + + if ((u_int)buflen > MLEN) + return (EINVAL); + m = m_get(M_WAIT, type); + if (m == NULL) + return (ENOBUFS); + m->m_len = buflen; + memcpy (mtod(m, caddr_t), buf, buflen); + *mp = m; + if (type == MT_SONAME) { + struct sockaddr *sa; + sa = mtod(m, struct sockaddr *); + sa->sa_len = buflen; + } + return 0; +} + +/* + ********************************************************************* + * BSD-style entry points * + ********************************************************************* + */ +int +socket (int domain, int type, int protocol) +{ + int fd = -1; + int error; + struct socket *so; + + rtems_bsdnet_semaphore_obtain (); + error = socreate(domain, &so, type, protocol, NULL); + if (error == 0) { + fd = makeFd (so); + if (fd < 0) + soclose (so); + } + else { + errno = error; + fd = -1; + } + rtems_bsdnet_semaphore_release (); + return fd; +} + +int +bind (int s, struct sockaddr *name, int namelen) +{ + int error; + int ret = -1; + struct socket *so; + struct mbuf *nam; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) != NULL) { + error = sockargstombuf (&nam, name, namelen, MT_SONAME); + if (error == 0) { + error = sobind (so, nam); + if (error == 0) + ret = 0; + else + errno = error; + m_freem (nam); + } + else { + errno = error; + } + } + rtems_bsdnet_semaphore_release (); + return ret; +} + +int +connect (int s, struct sockaddr *name, int namelen) +{ + int error; + int ret = -1; + struct socket *so; + struct mbuf *nam; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + errno = EALREADY; + rtems_bsdnet_semaphore_release (); + return -1; + } + error = sockargstombuf (&nam, name, namelen, MT_SONAME); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + error = soconnect (so, nam); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + m_freem(nam); + errno = EINPROGRESS; + rtems_bsdnet_semaphore_release (); + return -1; + } + while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { + soconnsleep (so); + } + if (error == 0) { + error = so->so_error; + so->so_error = 0; + } + so->so_state &= ~SS_ISCONNECTING; + m_freem (nam); + if (error == 0) + ret = 0; + rtems_bsdnet_semaphore_release (); + return ret; +} + +int +listen (int s, int backlog) +{ + int error; + int ret = -1; + struct socket *so; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) != NULL) { + error = solisten (so, backlog); + if (error == 0) + ret = 0; + else + errno = error; + } + rtems_bsdnet_semaphore_release (); + return ret; +} + +int +accept (int s, struct sockaddr *name, int *namelen) +{ + int fd; + struct socket *head, *so; + struct mbuf *nam; + + rtems_bsdnet_semaphore_obtain (); + if ((head = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + if ((head->so_options & SO_ACCEPTCONN) == 0) { + errno = EINVAL; + rtems_bsdnet_semaphore_release (); + return -1; + } + if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) { + errno = EWOULDBLOCK; + rtems_bsdnet_semaphore_release (); + return -1; + } + while (head->so_comp.tqh_first == NULL && head->so_error == 0) { + if (head->so_state & SS_CANTRCVMORE) { + head->so_error = ECONNABORTED; + break; + } + soconnsleep (head); + } + if (head->so_error) { + errno = head->so_error; + head->so_error = 0; + rtems_bsdnet_semaphore_release (); + return -1; + } + + so = head->so_comp.tqh_first; + TAILQ_REMOVE(&head->so_comp, so, so_list); + head->so_qlen--; + + fd = makeFd (so); + if (fd < 0) { + TAILQ_INSERT_HEAD(&head->so_comp, so, so_list); + head->so_qlen++; + soconnwakeup (head); + rtems_bsdnet_semaphore_release (); + return -1; + } + so->so_state &= ~SS_COMP; + so->so_head = NULL; + + nam = m_get(M_WAIT, MT_SONAME); + (void) soaccept(so, nam); + if (name) { + /* check length before it is destroyed */ + if (*namelen > nam->m_len) + *namelen = nam->m_len; + memcpy (name, mtod(nam, caddr_t), *namelen); + } + m_freem(nam); + rtems_bsdnet_semaphore_release (); + return (fd); + +} + +/* + * All `transmit' operations end up calling this routine. + */ +ssize_t +sendmsg (int s, const struct msghdr *mp, int flags) +{ + int ret = -1; + int error; + struct uio auio; + struct iovec *iov; + struct socket *so; + struct mbuf *to, *control; + int i; + int len; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_offset = 0; + auio.uio_resid = 0; + iov = mp->msg_iov; + for (i = 0; i < mp->msg_iovlen; i++, iov++) { + if ((auio.uio_resid += iov->iov_len) < 0) { + errno = EINVAL; + rtems_bsdnet_semaphore_release (); + return -1; + } + } + if (mp->msg_name) { + error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + } + else { + to = NULL; + } + if (mp->msg_control) { + if (mp->msg_controllen < sizeof (struct cmsghdr)) { + errno = EINVAL; + if (to) + m_freem(to); + rtems_bsdnet_semaphore_release (); + return -1; + } + sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL); + } + else { + control = NULL; + } + len = auio.uio_resid; + error = sosend (so, to, &auio, (struct mbuf *)0, control, flags); + if (error) { + if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) + error = 0; + } + if (error) + errno = error; + else + ret = len - auio.uio_resid; + if (to) + m_freem(to); + rtems_bsdnet_semaphore_release (); + return (ret); +} + +/* + * Send a message to a host + */ +ssize_t +sendto (int s, const void *buf, size_t buflen, int flags, const struct sockaddr *to, int tolen) +{ + struct msghdr msg; + struct iovec iov; + + iov.iov_base = (void *)buf; + iov.iov_len = buflen; + msg.msg_name = (caddr_t)to; + msg.msg_namelen = tolen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + return sendmsg (s, &msg, flags); +} + +/* + * Send a message to a connected host + */ +ssize_t +send (int s, const void *buf, size_t buflen, int flags) +{ + return sendto (s, buf, buflen, flags, NULL, 0); +} + +/* + * All `receive' operations end up calling this routine. + */ +ssize_t +recvmsg (int s, struct msghdr *mp, int flags) +{ + int ret = -1; + int error; + struct uio auio; + struct iovec *iov; + struct socket *so; + struct mbuf *from = NULL, *control = NULL; + int i; + int len; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_READ; + auio.uio_offset = 0; + auio.uio_resid = 0; + iov = mp->msg_iov; + for (i = 0; i < mp->msg_iovlen; i++, iov++) { + if ((auio.uio_resid += iov->iov_len) < 0) { + errno = EINVAL; + rtems_bsdnet_semaphore_release (); + return -1; + } + } + len = auio.uio_resid; + mp->msg_flags = flags; + error = soreceive (so, &from, &auio, (struct mbuf **)NULL, + mp->msg_control ? &control : (struct mbuf **)NULL, + &mp->msg_flags); + if (error) { + if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) + error = 0; + } + if (error) { + errno = error; + } + else { + ret = len - auio.uio_resid; + if (mp->msg_name) { + len = mp->msg_namelen; + if ((len <= 0) || (from == NULL)) { + len = 0; + } + else { + if (len > from->m_len) + len = from->m_len; + memcpy (mp->msg_name, mtod(from, caddr_t), len); + } + mp->msg_namelen = len; + } + if (mp->msg_control) { + struct mbuf *m; + caddr_t ctlbuf; + + len = mp->msg_controllen; + m = control; + mp->msg_controllen = 0; + ctlbuf = (caddr_t) mp->msg_control; + + while (m && (len > 0)) { + unsigned int tocopy; + + if (len >= m->m_len) + tocopy = m->m_len; + else { + mp->msg_flags |= MSG_CTRUNC; + tocopy = len; + } + memcpy(ctlbuf, mtod(m, caddr_t), tocopy); + ctlbuf += tocopy; + len -= tocopy; + m = m->m_next; + } + mp->msg_controllen = ctlbuf - mp->msg_control; + } + } + if (from) + m_freem (from); + if (control) + m_freem (control); + rtems_bsdnet_semaphore_release (); + return (ret); +} + +/* + * Receive a message from a host + */ +ssize_t +recvfrom (int s, void *buf, size_t buflen, int flags, const struct sockaddr *from, int *fromlen) +{ + struct msghdr msg; + struct iovec iov; + int ret; + + iov.iov_base = buf; + iov.iov_len = buflen; + msg.msg_name = (caddr_t)from; + msg.msg_namelen = *fromlen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + ret = recvmsg (s, &msg, flags); + if ((from != NULL) && (fromlen != NULL) && (ret >= 0)) + *fromlen = msg.msg_namelen; + return ret; +} + +/* + * Receive a message from a connected host + */ +ssize_t +recv (int s, void *buf, size_t buflen, int flags) +{ + return recvfrom (s, buf, buflen, flags, NULL, NULL); +} + +int +setsockopt (int s, int level, int name, const void *val, int len) +{ + struct socket *so; + struct mbuf *m = NULL; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + if (len > MLEN) { + errno = EINVAL; + rtems_bsdnet_semaphore_release (); + return -1; + } + if (val) { + error = sockargstombuf (&m, val, len, MT_SOOPTS); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + } + error = sosetopt(so, level, name, m); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + rtems_bsdnet_semaphore_release (); + return 0; +} + +int +getsockopt (int s, int level, int name, void *aval, int *avalsize) +{ + struct socket *so; + struct mbuf *m = NULL, *m0; + char *val = aval; + int i, op, valsize; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + if (val) + valsize = *avalsize; + else + valsize = 0; + if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) { + op = 0; + while (m && op < valsize) { + i = valsize - op; + if (i > m->m_len) + i = m->m_len; + memcpy (val, mtod(m, caddr_t), i); + op += i; + val += i; + m0 = m; + MFREE (m0, m); + } + *avalsize = op; + } + if (m != NULL) + (void) m_free(m); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + rtems_bsdnet_semaphore_release (); + return 0; +} + +int +getpeername (int s, struct sockaddr *name, int *namelen) +{ + struct socket *so; + struct mbuf *m; + int len = *namelen; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + m = m_getclr(M_WAIT, MT_SONAME); + if (m == NULL) { + errno = ENOBUFS; + rtems_bsdnet_semaphore_release (); + return -1; + } + error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m); + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + if (len > m->m_len) { + len = m->m_len; + *namelen = len; + } + memcpy (name, mtod(m, caddr_t), len); + m_freem (m); + rtems_bsdnet_semaphore_release (); + return 0; +} + +/* + ************************************************************************ + * RTEMS EXTERNAL I/O HANDLER ROUTINES * + ************************************************************************ + */ +static int +rtems_bsdnet_close (int fd) +{ + struct socket *so; + int error; + int i; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (fd)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + error = soclose (so); + i = rtems_file_descriptor_base(fd); + fdsock[i].indexFreeNext = indexFreeHead;; + indexFreeHead = i; + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + rtems_bsdnet_semaphore_release (); + return 0; +} + +static int +rtems_bsdnet_read (int fd, void *buffer, unsigned32 count) +{ + return recv (fd, buffer, count, 0); +} + +static int +rtems_bsdnet_write (int fd, const void *buffer, unsigned32 count) +{ + return send (fd, buffer, count, 0); +} + +static int +so_ioctl (struct socket *so, unsigned32 command, void *buffer) +{ + switch (command) { + case FIONBIO: + if (*(int *)buffer) + so->so_state |= SS_NBIO; + else + so->so_state &= ~SS_NBIO; + return 0; + + case FIONREAD: + *(int *)buffer = so->so_rcv.sb_cc; + return 0; + } + + if (IOCGROUP(command) == 'i') + return ifioctl (so, command, buffer, NULL); + if (IOCGROUP(command) == 'r') + return rtioctl (command, buffer, NULL); + return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0); +} + +static int +rtems_bsdnet_ioctl (int fd, unsigned32 command, void *buffer) +{ + struct socket *so; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (fd)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + error = so_ioctl (so, command, buffer); + rtems_bsdnet_semaphore_release (); + if (error) { + errno = error; + return -1; + } + return 0; +} + +rtems_libio_handler_t rtems_bsdnet_io_handler = { + NULL, /* open */ + rtems_bsdnet_close, /* close */ + rtems_bsdnet_read, /* read */ + rtems_bsdnet_write, /* write */ + rtems_bsdnet_ioctl, /* ioctl */ + NULL, /* lseek */ +}; + diff --git a/cpukit/libnetworking/rtems/sghostname.c b/cpukit/libnetworking/rtems/sghostname.c new file mode 100644 index 0000000000..ec9753649b --- /dev/null +++ b/cpukit/libnetworking/rtems/sghostname.c @@ -0,0 +1,47 @@ +/* + * RTEMS versions of hostname functions + * FIXME: Not thread-safe + */ + +#include <string.h> +#include <errno.h> +#include <rtems/rtems_bsdnet.h> +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/kernel.h> + +static char *rtems_hostname; + +int +gethostname (char *name, int namelen) +{ + char *cp = rtems_hostname; + + if (cp == NULL) + cp = ""; + strncpy (name, cp, namelen); + return 0; +} + +int +sethostname (char *name, int namelen) +{ + char *old, *new; + + if (namelen >= MAXHOSTNAMELEN) { + errno = EINVAL; + return -1; + } + new = malloc (namelen + 1, M_HTABLE, M_NOWAIT); + if (new == NULL) { + errno = ENOMEM; + return -1; + } + strncpy (new, name, namelen); + new[namelen] = '\0'; + old = rtems_hostname; + rtems_hostname = new; + if (old) + free (old, M_HTABLE); + return 0; +} diff --git a/cpukit/libnetworking/rtems/tftp.h b/cpukit/libnetworking/rtems/tftp.h new file mode 100644 index 0000000000..d09782e22b --- /dev/null +++ b/cpukit/libnetworking/rtems/tftp.h @@ -0,0 +1,85 @@ +/* + * $Id$ + */ + +/* + * Trivial File Transfer Protocol (TFTP) + * + * Transfer file to/from remote host + * + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + */ + +/* + * Usage: + * + * To open `/bootfiles/image' on `hostname' for reading: + * fd = open ("/TFTP/hostname/bootfiles/image", O_RDONLY); + * + * The `hostname' must be four dot-separated decimal values. + * + * To open a file on the host which supplied the BOOTP + * information just leave the `hostname' part empty: + * fd = open ("/TFTP//bootfiles/image", O_RDONLY); + * + */ + +#ifndef _TFTP_DRIVER_h +#define _TFTP_DRIVER_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Driver entry points + */ +#define TFTP_DRIVER_TABLE_ENTRY \ + { rtems_tftp_initialize, rtems_tftp_open, rtems_tftp_close, \ + rtems_tftp_read, rtems_tftp_write, rtems_tftp_control } + +rtems_device_driver rtems_tftp_initialize( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_open( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_close( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_read( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_write( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_control( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libnetworking/sys/buf.h b/cpukit/libnetworking/sys/buf.h new file mode 100644 index 0000000000..6cca571141 --- /dev/null +++ b/cpukit/libnetworking/sys/buf.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)buf.h 8.9 (Berkeley) 3/30/95 + * $Id$ + */ + +#ifndef _SYS_BUF_H_ +#define _SYS_BUF_H_ + +#include <sys/queue.h> + +#define NOLIST ((struct buf *)0x87654321) + +struct buf; + +struct iodone_chain { + long ic_prev_flags; + void (*ic_prev_iodone) __P((struct buf *)); + void *ic_prev_iodone_chain; + struct { + long ia_long; + void *ia_ptr; + } ic_args[5]; +}; + +typedef TAILQ_HEAD(buf_queue_head, buf) buf_queue_head, *buf_queue_head_t; + +/* + * The buffer header describes an I/O operation in the kernel. + */ +struct buf { + LIST_ENTRY(buf) b_hash; /* Hash chain. */ + LIST_ENTRY(buf) b_vnbufs; /* Buffer's associated vnode. */ + TAILQ_ENTRY(buf) b_freelist; /* Free list position if not active. */ + TAILQ_ENTRY(buf) b_act; /* Device driver queue when active. *new* */ + struct proc *b_proc; /* Associated proc; NULL if kernel. */ + long b_flags; /* B_* flags. */ + unsigned short b_qindex; /* buffer queue index */ + unsigned char b_usecount; /* buffer use count */ + int b_error; /* Errno value. */ + long b_bufsize; /* Allocated buffer size. */ + long b_bcount; /* Valid bytes in buffer. */ + long b_resid; /* Remaining I/O. */ + dev_t b_dev; /* Device associated with buffer. */ + struct { + caddr_t b_addr; /* Memory, superblocks, indirect etc. */ + } b_un; + caddr_t b_kvabase; /* base kva for buffer */ + int b_kvasize; /* size of kva for buffer */ + void *b_saveaddr; /* Original b_addr for physio. */ + daddr_t b_lblkno; /* Logical block number. */ + daddr_t b_blkno; /* Underlying physical block number. */ + /* Function to call upon completion. */ + void (*b_iodone) __P((struct buf *)); + /* For nested b_iodone's. */ + struct iodone_chain *b_iodone_chain; + struct vnode *b_vp; /* Device vnode. */ + int b_dirtyoff; /* Offset in buffer of dirty region. */ + int b_dirtyend; /* Offset of end of dirty region. */ + struct ucred *b_rcred; /* Read credentials reference. */ + struct ucred *b_wcred; /* Write credentials reference. */ + int b_validoff; /* Offset in buffer of valid region. */ + int b_validend; /* Offset of end of valid region. */ + daddr_t b_pblkno; /* physical block number */ + caddr_t b_savekva; /* saved kva for transfer while bouncing */ + void *b_driver1; /* for private use by the driver */ + void *b_driver2; /* for private use by the driver */ + void *b_spc; + union cluster_info { + TAILQ_HEAD(cluster_list_head, buf) cluster_head; + TAILQ_ENTRY(buf) cluster_entry; + } b_cluster; + struct vm_page *b_pages[btoc(MAXPHYS)]; + int b_npages; +}; + +/* Device driver compatibility definitions. */ +#define b_data b_un.b_addr /* b_un.b_addr is not changeable. */ + +/* + * These flags are kept in b_flags. + */ +#define B_AGE 0x00000001 /* Move to age queue when I/O done. */ +#define B_NEEDCOMMIT 0x00000002 /* Append-write in progress. */ +#define B_ASYNC 0x00000004 /* Start I/O, do not wait. */ +#define B_BAD 0x00000008 /* Bad block revectoring in progress. */ +#define B_BUSY 0x00000010 /* I/O in progress. */ +#define B_CACHE 0x00000020 /* Bread found us in the cache. */ +#define B_CALL 0x00000040 /* Call b_iodone from biodone. */ +#define B_DELWRI 0x00000080 /* Delay I/O until buffer reused. */ +#define B_DIRTY 0x00000100 /* Dirty page to be pushed out async. */ +#define B_DONE 0x00000200 /* I/O completed. */ +#define B_EINTR 0x00000400 /* I/O was interrupted */ +#define B_ERROR 0x00000800 /* I/O error occurred. */ +#define B_GATHERED 0x00001000 /* LFS: already in a segment. */ +#define B_INVAL 0x00002000 /* Does not contain valid info. */ +#define B_LOCKED 0x00004000 /* Locked in core (not reusable). */ +#define B_NOCACHE 0x00008000 /* Do not cache block after use. */ +#define B_MALLOC 0x00010000 /* malloced b_data */ +#define B_CLUSTEROK 0x00020000 /* Pagein op, so swap() can count it. */ +#define B_PHYS 0x00040000 /* I/O to user memory. */ +#define B_RAW 0x00080000 /* Set by physio for raw transfers. */ +#define B_READ 0x00100000 /* Read buffer. */ +#define B_TAPE 0x00200000 /* Magnetic tape I/O. */ +#define B_RELBUF 0x00400000 /* Release VMIO buffer. */ +#define B_WANTED 0x00800000 /* Process wants this buffer. */ +#define B_WRITE 0x00000000 /* Write buffer (pseudo flag). */ +#define B_WRITEINPROG 0x01000000 /* Write in progress. */ +#define B_XXX 0x02000000 /* Debugging flag. */ +#define B_PAGING 0x04000000 /* volatile paging I/O -- bypass VMIO */ +#define B_ORDERED 0x08000000 /* Must guarantee I/O ordering */ +#define B_VMIO 0x20000000 /* VMIO flag */ +#define B_CLUSTER 0x40000000 /* pagein op, so swap() can count it */ +#define B_BOUNCE 0x80000000 /* bounce buffer flag */ + +/* + * number of buffer hash entries + */ +#define BUFHSZ 512 + +/* + * buffer hash table calculation, originally by David Greenman + */ +#define BUFHASH(vnp, bn) \ + (&bufhashtbl[(((unsigned long)(vnp) >> 7)+(int)(bn)) % BUFHSZ]) + +/* + * Definitions for the buffer free lists. + */ +#define BUFFER_QUEUES 6 /* number of free buffer queues */ + +extern LIST_HEAD(bufhashhdr, buf) bufhashtbl[BUFHSZ], invalhash; +extern TAILQ_HEAD(bqueues, buf) bufqueues[BUFFER_QUEUES]; + +#define QUEUE_NONE 0 /* on no queue */ +#define QUEUE_LOCKED 1 /* locked buffers */ +#define QUEUE_LRU 2 /* useful buffers */ +#define QUEUE_VMIO 3 /* VMIO buffers */ +#define QUEUE_AGE 4 /* not-useful buffers */ +#define QUEUE_EMPTY 5 /* empty buffer headers*/ + +/* + * Zero out the buffer's data area. + */ +#define clrbuf(bp) { \ + bzero((bp)->b_data, (u_int)(bp)->b_bcount); \ + (bp)->b_resid = 0; \ +} + +/* Flags to low-level allocation routines. */ +#define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */ +#define B_SYNC 0x02 /* Do all allocations synchronously. */ + +#ifdef KERNEL +extern int nbuf; /* The number of buffer headers */ +extern struct buf *buf; /* The buffer headers. */ +extern char *buffers; /* The buffer contents. */ +extern int bufpages; /* Number of memory pages in the buffer pool. */ +extern struct buf *swbuf; /* Swap I/O buffer headers. */ +extern int nswbuf; /* Number of swap I/O buffer headers. */ +extern TAILQ_HEAD(swqueue, buf) bswlist; + +void bufinit __P((void)); +void bremfree __P((struct buf *)); +int bread __P((struct vnode *, daddr_t, int, + struct ucred *, struct buf **)); +int breadn __P((struct vnode *, daddr_t, int, daddr_t *, int *, int, + struct ucred *, struct buf **)); +int bwrite __P((struct buf *)); +void bdwrite __P((struct buf *)); +void bawrite __P((struct buf *)); +int bowrite __P((struct buf *)); +void brelse __P((struct buf *)); +void bqrelse __P((struct buf *)); +int vfs_bio_awrite __P((struct buf *)); +struct buf * getpbuf __P((void)); +struct buf *incore __P((struct vnode *, daddr_t)); +struct buf *gbincore __P((struct vnode *, daddr_t)); +int inmem __P((struct vnode *, daddr_t)); +struct buf *getblk __P((struct vnode *, daddr_t, int, int, int)); +struct buf *geteblk __P((int)); +int allocbuf __P((struct buf *, int)); +int biowait __P((struct buf *)); +void biodone __P((struct buf *)); + +void cluster_callback __P((struct buf *)); +int cluster_read __P((struct vnode *, u_quad_t, daddr_t, long, + struct ucred *, struct buf **)); +int cluster_wbuild __P((struct vnode *, long, daddr_t, int)); +void cluster_write __P((struct buf *, u_quad_t)); +int physio __P((void (*)(struct buf *), struct buf *, dev_t, + int, u_int (*)(struct buf *), struct uio *)); +u_int minphys __P((struct buf *)); +void vfs_bio_clrbuf __P((struct buf *)); +void vfs_busy_pages __P((struct buf *, int clear_modify)); +void vfs_unbusy_pages(struct buf *); +void vwakeup __P((struct buf *)); +void vmapbuf __P((struct buf *)); +void vunmapbuf __P((struct buf *)); +void relpbuf __P((struct buf *)); +void brelvp __P((struct buf *)); +void bgetvp __P((struct vnode *, struct buf *)); +void pbgetvp __P((struct vnode *, struct buf *)); +void pbrelvp __P((struct buf *)); +void reassignbuf __P((struct buf *, struct vnode *)); +struct buf *trypbuf __P((void)); +void vm_bounce_alloc __P((struct buf *)); +void vm_bounce_free __P((struct buf *)); +vm_offset_t vm_bounce_kva_alloc __P((int)); +void vm_bounce_kva_alloc_free __P((vm_offset_t, int)); +#endif /* KERNEL */ + +#endif /* !_SYS_BUF_H_ */ diff --git a/cpukit/libnetworking/sys/callout.h b/cpukit/libnetworking/sys/callout.h new file mode 100644 index 0000000000..5fec98f28b --- /dev/null +++ b/cpukit/libnetworking/sys/callout.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)callout.h 8.2 (Berkeley) 1/21/94 + * $Id$ + */ + +#ifndef _SYS_CALLOUT_H_ +#define _SYS_CALLOUT_H_ + +struct callout { + struct callout *c_next; /* next callout in queue */ + void *c_arg; /* function argument */ + void (*c_func) __P((void *)); /* function to call */ + int c_time; /* ticks to the event */ +}; + +#ifdef KERNEL +extern struct callout *callfree, *callout, calltodo; +extern int ncallout; +#endif + +#endif diff --git a/cpukit/libnetworking/sys/conf.h b/cpukit/libnetworking/sys/conf.h new file mode 100644 index 0000000000..92d99d9d07 --- /dev/null +++ b/cpukit/libnetworking/sys/conf.h @@ -0,0 +1,228 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)conf.h 8.5 (Berkeley) 1/9/95 + * $Id$ + */ + +#ifndef _SYS_CONF_H_ +#define _SYS_CONF_H_ + +/* + * Definitions of device driver entry switches + */ + +struct buf; +struct proc; +struct tty; +struct uio; +struct vnode; + +typedef int d_open_t __P((dev_t dev, int oflags, int devtype, struct proc *p)); +typedef int d_close_t __P((dev_t dev, int fflag, int devtype, struct proc *p)); +typedef void d_strategy_t __P((struct buf *bp)); +typedef int d_ioctl_t __P((dev_t dev, int cmd, caddr_t data, + int fflag, struct proc *p)); +typedef int d_dump_t __P((dev_t dev)); +typedef int d_psize_t __P((dev_t dev)); + +typedef int d_read_t __P((dev_t dev, struct uio *uio, int ioflag)); +typedef int d_write_t __P((dev_t dev, struct uio *uio, int ioflag)); +typedef void d_stop_t __P((struct tty *tp, int rw)); +typedef int d_reset_t __P((dev_t dev)); +typedef struct tty *d_devtotty_t __P((dev_t dev)); +typedef int d_select_t __P((dev_t dev, int which, struct proc *p)); +typedef int d_mmap_t __P((dev_t dev, int offset, int nprot)); + +typedef int l_open_t __P((dev_t dev, struct tty *tp)); +typedef int l_close_t __P((struct tty *tp, int flag)); +typedef int l_read_t __P((struct tty *tp, struct uio *uio, int flag)); +typedef int l_write_t __P((struct tty *tp, struct uio *uio, int flag)); +typedef int l_ioctl_t __P((struct tty *tp, int cmd, caddr_t data, + int flag, struct proc *p)); +typedef int l_rint_t __P((int c, struct tty *tp)); +typedef int l_start_t __P((struct tty *tp)); +typedef int l_modem_t __P((struct tty *tp, int flag)); + +/* + * Block device switch table + */ +struct bdevsw { + d_open_t *d_open; + d_close_t *d_close; + d_strategy_t *d_strategy; + d_ioctl_t *d_ioctl; + d_dump_t *d_dump; + d_psize_t *d_psize; + int d_flags; + char *d_name; /* name of the driver e.g. audio */ + struct cdevsw *d_cdev; /* cross pointer to the cdev */ + int d_maj; /* the major number we were assigned */ +}; + +#ifdef KERNEL +extern struct bdevsw *bdevsw[]; +#endif + +/* + * Character device switch table + */ +struct cdevsw { + d_open_t *d_open; + d_close_t *d_close; + d_read_t *d_read; + d_write_t *d_write; + d_ioctl_t *d_ioctl; + d_stop_t *d_stop; + d_reset_t *d_reset; /* XXX not used */ + d_devtotty_t *d_devtotty; + d_select_t *d_select; + d_mmap_t *d_mmap; + d_strategy_t *d_strategy; + char *d_name; /* see above */ + struct bdevsw *d_bdev; + int d_maj; +}; + +#ifdef KERNEL +extern struct cdevsw *cdevsw[]; +#endif + +/* + * Line discipline switch table + */ +struct linesw { + l_open_t *l_open; + l_close_t *l_close; + l_read_t *l_read; + l_write_t *l_write; + l_ioctl_t *l_ioctl; + l_rint_t *l_rint; + l_start_t *l_start; + l_modem_t *l_modem; +}; + +#ifdef KERNEL +extern struct linesw linesw[]; +extern int nlinesw; + +int ldisc_register __P((int , struct linesw *)); +void ldisc_deregister __P((int)); +#define LDISC_LOAD -1 /* Loadable line discipline */ +#endif + +/* + * Swap device table + */ +struct swdevt { + dev_t sw_dev; + int sw_flags; + int sw_nblks; + struct vnode *sw_vp; +}; +#define SW_FREED 0x01 +#define SW_SEQUENTIAL 0x02 +#define sw_freed sw_flags /* XXX compat */ + +#ifdef KERNEL +d_open_t noopen; +d_close_t noclose; +d_read_t noread; +d_write_t nowrite; +d_ioctl_t noioctl; +d_stop_t nostop; +d_reset_t noreset; +d_devtotty_t nodevtotty; +d_select_t noselect; +d_mmap_t nommap; + +/* Bogus defines for compatibility. */ +#define noioc noioctl +#define nostrat nostrategy +#define zerosize nopsize +/* + * XXX d_strategy seems to be unused for cdevs that aren't associated with + * bdevs and called without checking for it being non-NULL for bdevs. + */ +#define nostrategy ((d_strategy_t *)NULL) + +d_dump_t nodump; + +/* + * nopsize is little used, so not worth having dummy functions for. + */ +#define nopsize ((d_psize_t *)NULL) + +d_open_t nullopen; +d_close_t nullclose; +#define nullstop nostop /* one void return is as good as another */ +#define nullreset noreset /* one unused function is as good as another */ + +d_open_t nxopen; +d_close_t nxclose; +d_read_t nxread; +d_write_t nxwrite; +d_ioctl_t nxioctl; +#define nxstop nostop /* one void return is as good as another */ +#define nxreset noreset /* one unused function is as good as another */ +#define nxdevtotty nodevtotty /* one NULL return is as good as another */ +d_select_t nxselect; +#define nxmmap nommap /* one -1 return is as good as another */ +#define nxstrategy nostrategy /* one NULL value is as good as another */ +d_dump_t nxdump; +#define nxpsize nopsize /* one NULL value is as good as another */ + +d_read_t rawread; +d_write_t rawwrite; + +l_read_t l_noread; +l_write_t l_nowrite; + +int bdevsw_add __P((dev_t *descrip,struct bdevsw *new,struct bdevsw **old)); +int cdevsw_add __P((dev_t *descrip,struct cdevsw *new,struct cdevsw **old)); +void cdevsw_make __P((struct bdevsw *from)); +void bdevsw_add_generic __P((int bdev, int cdev, struct bdevsw *bdevsw)); +dev_t chrtoblk __P((dev_t dev)); +int isdisk __P((dev_t dev, int type)); +int iskmemdev __P((dev_t dev)); +int iszerodev __P((dev_t dev)); +void setconf __P((void)); +#endif /* KERNEL */ + +#include <machine/conf.h> + +#endif /* !_SYS_CONF_H_ */ diff --git a/cpukit/libnetworking/sys/domain.h b/cpukit/libnetworking/sys/domain.h new file mode 100644 index 0000000000..2ec8a5fb05 --- /dev/null +++ b/cpukit/libnetworking/sys/domain.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)domain.h 8.1 (Berkeley) 6/2/93 + * $Id$ + */ + +#ifndef _SYS_DOMAIN_H_ +#define _SYS_DOMAIN_H_ + +/* + * Structure per communications domain. + */ + +/* + * Forward structure declarations for function prototypes [sic]. + */ +struct mbuf; + +struct domain { + int dom_family; /* AF_xxx */ + char *dom_name; + void (*dom_init) /* initialize domain data structures */ + __P((void)); + int (*dom_externalize) /* externalize access rights */ + __P((struct mbuf *)); + void (*dom_dispose) /* dispose of internalized rights */ + __P((struct mbuf *)); + struct protosw *dom_protosw, *dom_protoswNPROTOSW; + struct domain *dom_next; + int (*dom_rtattach) /* initialize routing table */ + __P((void **, int)); + int dom_rtoffset; /* an arg to rtattach, in bits */ + int dom_maxrtkey; /* for routing layer */ +}; + +#ifdef KERNEL +extern struct domain *domains; +extern struct domain localdomain; + +#define DOMAIN_SET(name) \ + DATA_SET(domain_set, name ## domain); + +#endif + +#endif diff --git a/cpukit/libnetworking/sys/kernel.h b/cpukit/libnetworking/sys/kernel.h new file mode 100644 index 0000000000..35bce70bd6 --- /dev/null +++ b/cpukit/libnetworking/sys/kernel.h @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 1995 Terrence R. Lambert + * All rights reserved. + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)kernel.h 8.3 (Berkeley) 1/21/94 + * $Id$ + */ + +#ifndef _SYS_KERNEL_H_ +#define _SYS_KERNEL_H_ + +/* Global variables for the kernel. */ + +/* 1.1 */ +extern long hostid; +extern char hostname[MAXHOSTNAMELEN]; +extern int hostnamelen; +extern char domainname[MAXHOSTNAMELEN]; +extern int domainnamelen; +extern char kernelname[MAXPATHLEN]; + +/* 1.2 */ +extern volatile struct timeval mono_time; +extern struct timeval boottime; +extern struct timeval runtime; +/* extern volatile struct timeval time; */ +extern struct timezone tz; /* XXX */ + +extern int tick; /* usec per tick (1000000 / hz) */ +extern int hz; /* system clock's frequency */ +extern int psratio; /* ratio: prof / stat */ +extern int stathz; /* statistics clock's frequency */ +extern int profhz; /* profiling clock's frequency */ +extern int ticks; +extern int lbolt; /* once a second sleep address */ +extern int tickdelta; +extern long timedelta; + +/* + * The following macros are used to declare global sets of objects, which + * are collected by the linker into a `struct linker_set' as defined below. + * + * NB: the constants defined below must match those defined in + * ld/ld.h. Since their calculation requires arithmetic, we + * can't name them symbolically (e.g., 23 is N_SETT | N_EXT). + */ +#define MAKE_SET(set, sym, type) +#define TEXT_SET(set, sym) MAKE_SET(set, sym, 23) +#define DATA_SET(set, sym) MAKE_SET(set, sym, 25) +#define BSS_SET(set, sym) MAKE_SET(set, sym, 27) +#define ABS_SET(set, sym) MAKE_SET(set, sym, 21) + + +/* + * Enumerated types for known system startup interfaces. + * + * Startup occurs in ascending numeric order; the list entries are + * sorted prior to attempting startup to guarantee order. Items + * of the same level are arbitrated for order based on the 'order' + * element. + * + * These numbers are arbitrary and are chosen ONLY for ordering; the + * enumeration values are explicit rather than implicit to provide + * for binary compatibility with inserted elements. + * + * The SI_SUB_RUN_SCHEDULER value must have the highest lexical value. + * + * The SI_SUB_CONSOLE and SI_SUB_SWAP values represent values used by + * the BSD 4.4Lite but not by FreeBSD; they are maintained in dependent + * order to support porting. + * + * The SI_SUB_PROTO_BEGIN and SI_SUB_PROTO_END bracket a range of + * initializations to take place at splimp(). This is a historical + * wart that should be removed -- probably running everything at + * splimp() until the first init that doesn't want it is the correct + * fix. They are currently present to ensure historical behavior. + */ +enum sysinit_sub_id { + SI_SUB_DUMMY = 0x00000000, /* not executed; for linker*/ + SI_SUB_CONSOLE = 0x08000000, /* console*/ + SI_SUB_COPYRIGHT = 0x08000001, /* first use of console*/ + SI_SUB_VM = 0x10000000, /* virtual memory system init*/ + SI_SUB_KMEM = 0x18000000, /* kernel memory*/ + SI_SUB_CPU = 0x20000000, /* CPU resource(s)*/ + SI_SUB_DEVFS = 0x22000000, /* get DEVFS ready */ + SI_SUB_DRIVERS = 0x23000000, /* Let Drivers initialize */ + SI_SUB_CONFIGURE = 0x24000000, /* Configure devices */ + SI_SUB_INTRINSIC = 0x28000000, /* proc 0*/ + SI_SUB_RUN_QUEUE = 0x30000000, /* the run queue*/ + SI_SUB_VM_CONF = 0x38000000, /* config VM, set limits*/ + SI_SUB_VFS = 0x40000000, /* virtual file system*/ + SI_SUB_CLOCKS = 0x48000000, /* real time and stat clocks*/ + SI_SUB_MBUF = 0x50000000, /* mbufs*/ + SI_SUB_CLIST = 0x58000000, /* clists*/ + SI_SUB_SYSV_SHM = 0x64000000, /* System V shared memory*/ + SI_SUB_SYSV_SEM = 0x68000000, /* System V semaphores*/ + SI_SUB_SYSV_MSG = 0x6C000000, /* System V message queues*/ + SI_SUB_PSEUDO = 0x70000000, /* pseudo devices*/ + SI_SUB_PROTO_BEGIN = 0x80000000, /* XXX: set splimp (kludge)*/ + SI_SUB_PROTO_IF = 0x84000000, /* interfaces*/ + SI_SUB_PROTO_DOMAIN = 0x88000000, /* domains (address families?)*/ + SI_SUB_PROTO_END = 0x8fffffff, /* XXX: set splx (kludge)*/ + SI_SUB_KPROF = 0x90000000, /* kernel profiling*/ + SI_SUB_KICK_SCHEDULER = 0xa0000000, /* start the timeout events*/ + SI_SUB_ROOT = 0xb0000000, /* root mount*/ + SI_SUB_ROOT_FDTAB = 0xb8000000, /* root vnode in fd table...*/ + SI_SUB_SWAP = 0xc0000000, /* swap*/ + SI_SUB_INTRINSIC_POST = 0xd0000000, /* proc 0 cleanup*/ + SI_SUB_KTHREAD_INIT = 0xe0000000, /* init process*/ + SI_SUB_KTHREAD_PAGE = 0xe4000000, /* pageout daemon*/ + SI_SUB_KTHREAD_VM = 0xe8000000, /* vm daemon*/ + SI_SUB_KTHREAD_UPDATE = 0xec000000, /* update daemon*/ + SI_SUB_RUN_SCHEDULER = 0xffffffff /* scheduler: no return*/ +}; + + +/* + * Some enumerated orders; "ANY" sorts last. + */ +enum sysinit_elem_order { + SI_ORDER_FIRST = 0x00000000, /* first*/ + SI_ORDER_SECOND = 0x00000001, /* second*/ + SI_ORDER_THIRD = 0x00000002, /* third*/ + SI_ORDER_MIDDLE = 0x10000000, /* somewhere in the middle */ + SI_ORDER_ANY = 0xffffffff /* last*/ +}; + + +/* + * System initialization call types; currently two are supported... one + * to do a simple function call and one to cause a process to be started + * by the kernel on the callers behalf. + */ +typedef enum sysinit_elem_type { + SI_TYPE_DEFAULT = 0x00000000, /* No special processing*/ + SI_TYPE_KTHREAD = 0x00000001 /* start kernel thread*/ +} si_elem_t; + + +/* + * A system initialization call instance + * + * The subsystem + */ +struct sysinit { + unsigned int subsystem; /* subsystem identifier*/ + unsigned int order; /* init order within subsystem*/ + void (*func) __P((void *)); /* init function*/ + void *udata; /* multiplexer/argument */ + si_elem_t type; /* sysinit_elem_type*/ +}; + + +/* + * Default: no special processing + */ +#define SYSINIT(uniquifier, subsystem, order, func, ident) + +/* + * Call 'fork()' before calling '(*func)(ident)'; + * for making a kernel 'thread' (or builtin process.) + */ +#define SYSINIT_KT(uniquifier, subsystem, order, func, ident) + + +/* + * A kernel process descriptor; used to start "internal" daemons + * + * Note: global_procpp may be NULL for no global save area + */ +struct kproc_desc { + char *arg0; /* arg 0 (for 'ps' listing)*/ + void (*func) __P((void)); /* "main" for kernel process*/ + struct proc **global_procpp; /* ptr to proc ptr save area*/ +}; + +void kproc_start __P((void *udata)); + +#ifdef PSEUDO_LKM +#include <sys/conf.h> +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +#define PSEUDO_SET(init, name) \ + extern struct linker_set MODVNOPS; \ + MOD_MISC(name); \ + static int \ + name ## _load(struct lkm_table *lkmtp, int cmd) \ + { init((void *)NULL /* XXX unused (?) */); return 0; } \ + static int \ + name ## _unload(struct lkm_table *lkmtp, int cmd) \ + { return EINVAL; } \ + int \ + name ## _mod(struct lkm_table *lkmtp, int cmd, int ver) { \ + DISPATCH(lkmtp, cmd, ver, name ## _load, name ## _unload, \ + lkm_nullcmd); } +#else /* PSEUDO_LKM */ + +/* + * Compatibility. To be deprecated after LKM is updated. + */ +#define PSEUDO_SET(sym, name) SYSINIT(ps, SI_SUB_PSEUDO, SI_ORDER_ANY, sym, 0) + +#endif /* PSEUDO_LKM */ + +struct linker_set { + int ls_length; + const void *ls_items[1]; /* really ls_length of them, + * trailing NULL */ +}; + +extern struct linker_set execsw_set; + +#endif /* !_SYS_KERNEL_H_*/ diff --git a/cpukit/libnetworking/sys/libkern.h b/cpukit/libnetworking/sys/libkern.h new file mode 100644 index 0000000000..bdc060346a --- /dev/null +++ b/cpukit/libnetworking/sys/libkern.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)libkern.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _SYS_LIBKERN_H_ +#define _SYS_LIBKERN_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +/* BCD conversions. */ +extern u_char const bcd2bin_data[]; +extern u_char const bin2bcd_data[]; +extern char const hex2ascii_data[]; + +#define bcd2bin(bcd) (bcd2bin_data[bcd]) +#define bin2bcd(bin) (bin2bcd_data[bin]) +#define hex2ascii(hex) (hex2ascii_data[hex]) + +static __inline int imax(int a, int b) { return (a > b ? a : b); } +static __inline int imin(int a, int b) { return (a < b ? a : b); } +static __inline long lmax(long a, long b) { return (a > b ? a : b); } +static __inline long lmin(long a, long b) { return (a < b ? a : b); } +static __inline u_int max(u_int a, u_int b) { return (a > b ? a : b); } +static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); } +static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); } +static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); } +static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); } +static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); } + +/* Prototypes for non-quad routines. */ +int bcmp __P((const void *, const void *, size_t)); +#ifndef HAVE_INLINE_FFS +int ffs __P((int)); +#endif +#ifndef HAVE_INLINE_FLS +int fls __P((int)); +#endif +int locc __P((int, char *, u_int)); +void qsort __P((void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *))); +u_long random __P((void)); +char *index __P((const char *, int)); +char *rindex __P((const char *, int)); +int scanc __P((u_int, const u_char *, const u_char *, int)); +int skpc __P((int, int, char *)); +void srandom __P((u_long)); +char *strcat __P((char *, const char *)); +int strcmp __P((const char *, const char *)); +char *strcpy __P((char *, const char *)); +size_t strlen __P((const char *)); +int strncmp __P((const char *, const char *, size_t)); +char *strncpy __P((char *, const char *, size_t)); + +#endif /* !_SYS_LIBKERN_H_ */ diff --git a/cpukit/libnetworking/sys/malloc.h b/cpukit/libnetworking/sys/malloc.h new file mode 100644 index 0000000000..ec85c1814d --- /dev/null +++ b/cpukit/libnetworking/sys/malloc.h @@ -0,0 +1,355 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)malloc.h 8.5 (Berkeley) 5/3/95 + * $Id$ + */ + +#ifndef _SYS_MALLOC_H_ +#define _SYS_MALLOC_H_ + +#include <rtems/rtems_bsdnet_internal.h> /* Ensure we get RTEMS malloc hooks */ +#define KMEMSTATS + +/* + * flags to malloc + */ +#define M_WAITOK 0x0000 +#define M_NOWAIT 0x0001 +#define M_KERNEL 0x0002 + +/* + * Types of memory to be allocated + */ +#define M_FREE 0 /* should be on free list */ +#define M_MBUF 1 /* mbuf */ +#define M_DEVBUF 2 /* device driver memory */ +#define M_SOCKET 3 /* socket structure */ +#define M_PCB 4 /* protocol control block */ +#define M_RTABLE 5 /* routing tables */ +#define M_HTABLE 6 /* IMP host tables */ +#define M_FTABLE 7 /* fragment reassembly header */ +#define M_ZOMBIE 8 /* zombie proc status */ +#define M_IFADDR 9 /* interface address */ +#define M_SOOPTS 10 /* socket options */ +#define M_SONAME 11 /* socket name */ +#define M_NAMEI 12 /* namei path name buffer */ +#define M_GPROF 13 /* kernel profiling buffer */ +#define M_IOCTLOPS 14 /* ioctl data buffer */ +#define M_MAPMEM 15 /* mapped memory descriptors */ +#define M_CRED 16 /* credentials */ +#define M_PGRP 17 /* process group header */ +#define M_SESSION 18 /* session header */ +#define M_IOV 19 /* large iov's */ +#define M_MOUNT 20 /* vfs mount struct */ +#define M_FHANDLE 21 /* network file handle */ +#define M_NFSREQ 22 /* NFS request header */ +#define M_NFSMNT 23 /* NFS mount structure */ +#define M_NFSNODE 24 /* NFS vnode private part */ +#define M_VNODE 25 /* Dynamically allocated vnodes */ +#define M_CACHE 26 /* Dynamically allocated cache entries */ +#define M_DQUOT 27 /* UFS quota entries */ +#define M_UFSMNT 28 /* UFS mount structure */ +#define M_SHM 29 /* SVID compatible shared memory segments */ +#define M_VMMAP 30 /* VM map structures */ +#define M_VMMAPENT 31 /* VM map entry structures */ +#define M_VMOBJ 32 /* VM object structure */ +#define M_VMOBJHASH 33 /* VM object hash structure */ +#define M_VMPMAP 34 /* VM pmap */ +#define M_VMPVENT 35 /* VM phys-virt mapping entry */ +#define M_VMPAGER 36 /* XXX: VM pager struct */ +#define M_VMPGDATA 37 /* XXX: VM pager private data */ +#define M_FILE 38 /* Open file structure */ +#define M_FILEDESC 39 /* Open file descriptor table */ +#define M_LOCKF 40 /* Byte-range locking structures */ +#define M_PROC 41 /* Proc structures */ +#define M_SUBPROC 42 /* Proc sub-structures */ +#define M_SEGMENT 43 /* Segment for LFS */ +#define M_LFSNODE 44 /* LFS vnode private part */ +#define M_FFSNODE 45 /* FFS vnode private part */ +#define M_MFSNODE 46 /* MFS vnode private part */ +#define M_NQLEASE 47 /* Nqnfs lease */ +#define M_NQMHOST 48 /* Nqnfs host address table */ +#define M_NETADDR 49 /* Export host address structure */ +#define M_NFSSVC 50 /* Nfs server structure */ +#define M_NFSUID 51 /* Nfs uid mapping structure */ +#define M_NFSD 52 /* Nfs server daemon structure */ +#define M_IPMOPTS 53 /* internet multicast options */ +#define M_IPMADDR 54 /* internet multicast address */ +#define M_IFMADDR 55 /* link-level multicast address */ +#define M_MRTABLE 56 /* multicast routing tables */ +#define M_ISOFSMNT 57 /* ISOFS mount structure */ +#define M_ISOFSNODE 58 /* ISOFS vnode private part */ +#define M_NFSRVDESC 59 /* NFS server socket descriptor */ +#define M_NFSDIROFF 60 /* NFS directory offset data */ +#define M_NFSBIGFH 61 /* NFS version 3 file handle */ +#define M_MSDOSFSMNT 67 /* MSDOSFS mount structure */ +#define M_MSDOSFSNODE 68 /* MSDOSFS vnode private part */ +#define M_MSDOSFSFAT 69 /* MSDOSFS file allocation table */ +#define M_DEVFSMNT 70 /* DEVFS mount structure */ +#define M_DEVFSBACK 71 /* DEVFS Back node */ +#define M_DEVFSFRONT 72 /* DEVFS Front node */ +#define M_DEVFSNODE 73 /* DEVFS node */ +#define M_TEMP 74 /* misc temporary data buffers */ +#define M_TTYS 75 /* tty data structures */ +#define M_GZIP 76 /* Gzip trees */ +#define M_IPFW 77 /* IpFw/IpAcct chain's */ +#define M_DEVL 78 /* isa_device lists in userconfig() */ +#define M_PKTCLASS 79 /* structures used in packet classifier */ +#define M_SYSCTL 80 /* sysctl internal magic */ +#define M_SECA 81 /* security associations, key management */ +#define M_BIOBUF 82 /* BIO buffer */ +#define M_KTRACE 83 /* KTRACE */ +#define M_SELECT 84 /* select() buffer */ +#define M_CFS 85 /* Coda */ +#define M_LAST 86 /* Must be last type + 1 */ + +#define INITKMEMNAMES { \ + "free", /* 0 M_FREE */ \ + "mbuf", /* 1 M_MBUF */ \ + "devbuf", /* 2 M_DEVBUF */ \ + "socket", /* 3 M_SOCKET */ \ + "pcb", /* 4 M_PCB */ \ + "routetbl", /* 5 M_RTABLE */ \ + "hosttbl", /* 6 M_HTABLE */ \ + "fragtbl", /* 7 M_FTABLE */ \ + "zombie", /* 8 M_ZOMBIE */ \ + "ifaddr", /* 9 M_IFADDR */ \ + "soopts", /* 10 M_SOOPTS */ \ + "soname", /* 11 M_SONAME */ \ + "namei", /* 12 M_NAMEI */ \ + "gprof", /* 13 M_GPROF */ \ + "ioctlops", /* 14 M_IOCTLOPS */ \ + "mapmem", /* 15 M_MAPMEM */ \ + "cred", /* 16 M_CRED */ \ + "pgrp", /* 17 M_PGRP */ \ + "session", /* 18 M_SESSION */ \ + "iov", /* 19 M_IOV */ \ + "mount", /* 20 M_MOUNT */ \ + "fhandle", /* 21 M_FHANDLE */ \ + "NFS req", /* 22 M_NFSREQ */ \ + "NFS mount", /* 23 M_NFSMNT */ \ + "NFS node", /* 24 M_NFSNODE */ \ + "vnodes", /* 25 M_VNODE */ \ + "namecache", /* 26 M_CACHE */ \ + "UFS quota", /* 27 M_DQUOT */ \ + "UFS mount", /* 28 M_UFSMNT */ \ + "shm", /* 29 M_SHM */ \ + "VM map", /* 30 M_VMMAP */ \ + "VM mapent", /* 31 M_VMMAPENT */ \ + "VM object", /* 32 M_VMOBJ */ \ + "VM objhash", /* 33 M_VMOBJHASH */ \ + "VM pmap", /* 34 M_VMPMAP */ \ + "VM pvmap", /* 35 M_VMPVENT */ \ + "VM pager", /* 36 M_VMPAGER */ \ + "VM pgdata", /* 37 M_VMPGDATA */ \ + "file", /* 38 M_FILE */ \ + "file desc", /* 39 M_FILEDESC */ \ + "lockf", /* 40 M_LOCKF */ \ + "proc", /* 41 M_PROC */ \ + "subproc", /* 42 M_SUBPROC */ \ + "LFS segment", /* 43 M_SEGMENT */ \ + "LFS node", /* 44 M_LFSNODE */ \ + "FFS node", /* 45 M_FFSNODE */ \ + "MFS node", /* 46 M_MFSNODE */ \ + "NQNFS Lease", /* 47 M_NQLEASE */ \ + "NQNFS Host", /* 48 M_NQMHOST */ \ + "Export Host", /* 49 M_NETADDR */ \ + "NFS srvsock", /* 50 M_NFSSVC */ \ + "NFS uid", /* 51 M_NFSUID */ \ + "NFS daemon", /* 52 M_NFSD */ \ + "ip_moptions", /* 53 M_IPMOPTS */ \ + "in_multi", /* 54 M_IPMADDR */ \ + "ether_multi", /* 55 M_IFMADDR */ \ + "mrt", /* 56 M_MRTABLE */ \ + "ISOFS mount", /* 57 M_ISOFSMNT */ \ + "ISOFS node", /* 58 M_ISOFSNODE */ \ + "NFSV3 srvdesc",/* 59 M_NFSRVDESC */ \ + "NFSV3 diroff", /* 60 M_NFSDIROFF */ \ + "NFSV3 bigfh", /* 61 M_NFSBIGFH */ \ + NULL, \ + NULL, NULL, NULL, NULL, \ + "MSDOSFS mount",/* 67 M_MSDOSFSMNT */ \ + "MSDOSFS node", /* 68 M_MSDOSFSNODE */ \ + "MSDOSFS FAT", /* 69 M_MSDOSFSFAR */ \ + "DEVFS mount", /* 70 M_DEVFSMNT */ \ + "DEVFS back", /* 71 M_DEVFSBACK */ \ + "DEVFS front", /* 72 M_DEVFSFRONT */ \ + "DEVFS node", /* 73 M_DEVFSNODE */ \ + "temp", /* 74 M_TEMP */ \ + "ttys", /* 75 M_TTYS */ \ + "Gzip trees", /* 76 M_GZIP */ \ + "IpFw/IpAcct", /* 77 M_IPFW */ \ + "isa_devlist", /* 78 M_DEVL */ \ + "PktClass", /* 79 M_PKTCLASS */ \ + "sysctl", /* 80 M_SYSCTL */ \ + "key mgmt", /* 81 M_SECA */ \ + "BIO buffer", /* 82 M_BIOBUF */ \ + "KTRACE", /* 83 M_KTRACE */ \ + "select", /* 84 M_SELECT */ \ + "Coda", /* 85 M_CFS */ \ +} + +struct kmemstats { + long ks_inuse; /* # of packets of this type currently in use */ + long ks_calls; /* total packets of this type ever allocated */ + long ks_memuse; /* total memory held in bytes */ + u_short ks_limblocks; /* number of times blocked for hitting limit */ + u_short ks_mapblocks; /* number of times blocked for kernel map */ + long ks_maxused; /* maximum number ever used */ + long ks_limit; /* most that are allowed to exist */ + long ks_size; /* sizes of this thing that are allocated */ + long ks_spare; +}; + +/* + * Array of descriptors that describe the contents of each page + */ +struct kmemusage { + short ku_indx; /* bucket index */ + union { + u_short freecnt;/* for small allocations, free pieces in page */ + u_short pagecnt;/* for large allocations, pages alloced */ + } ku_un; +}; +#define ku_freecnt ku_un.freecnt +#define ku_pagecnt ku_un.pagecnt + +/* + * Set of buckets for each size of memory block that is retained + */ +struct kmembuckets { + caddr_t kb_next; /* list of free blocks */ + caddr_t kb_last; /* last free block */ + long kb_calls; /* total calls to allocate this size */ + long kb_total; /* total number of blocks allocated */ + long kb_totalfree; /* # of free elements in this bucket */ + long kb_elmpercl; /* # of elements in this sized allocation */ + long kb_highwat; /* high water mark */ + long kb_couldfree; /* over high water mark and could free */ +}; + +#ifdef KERNEL +#define MINALLOCSIZE (1 << MINBUCKET) +#define BUCKETINDX(size) \ + ((size) <= (MINALLOCSIZE * 128) \ + ? (size) <= (MINALLOCSIZE * 8) \ + ? (size) <= (MINALLOCSIZE * 2) \ + ? (size) <= (MINALLOCSIZE * 1) \ + ? (MINBUCKET + 0) \ + : (MINBUCKET + 1) \ + : (size) <= (MINALLOCSIZE * 4) \ + ? (MINBUCKET + 2) \ + : (MINBUCKET + 3) \ + : (size) <= (MINALLOCSIZE* 32) \ + ? (size) <= (MINALLOCSIZE * 16) \ + ? (MINBUCKET + 4) \ + : (MINBUCKET + 5) \ + : (size) <= (MINALLOCSIZE * 64) \ + ? (MINBUCKET + 6) \ + : (MINBUCKET + 7) \ + : (size) <= (MINALLOCSIZE * 2048) \ + ? (size) <= (MINALLOCSIZE * 512) \ + ? (size) <= (MINALLOCSIZE * 256) \ + ? (MINBUCKET + 8) \ + : (MINBUCKET + 9) \ + : (size) <= (MINALLOCSIZE * 1024) \ + ? (MINBUCKET + 10) \ + : (MINBUCKET + 11) \ + : (size) <= (MINALLOCSIZE * 8192) \ + ? (size) <= (MINALLOCSIZE * 4096) \ + ? (MINBUCKET + 12) \ + : (MINBUCKET + 13) \ + : (size) <= (MINALLOCSIZE * 16384) \ + ? (MINBUCKET + 14) \ + : (MINBUCKET + 15)) + +/* + * Turn virtual addresses into kmem map indices + */ +#define kmemxtob(alloc) (kmembase + (alloc) * PAGE_SIZE) +#define btokmemx(addr) (((caddr_t)(addr) - kmembase) / PAGE_SIZE) +#define btokup(addr) (&kmemusage[(caddr_t)(addr) - kmembase >> PAGE_SHIFT]) + +/* + * Macro versions for the usual cases of malloc/free + */ +#if defined(KMEMSTATS) || defined(DIAGNOSTIC) +#define MALLOC(space, cast, size, type, flags) \ + (space) = (cast)malloc((u_long)(size), type, flags) +#define FREE(addr, type) free((addr), type) + +#else /* do not collect statistics */ +#define MALLOC(space, cast, size, type, flags) { \ + register struct kmembuckets *kbp = &bucket[BUCKETINDX(size)]; \ + long s = splimp(); \ + if (kbp->kb_next == NULL) { \ + (space) = (cast)malloc((u_long)(size), type, flags); \ + } else { \ + (space) = (cast)kbp->kb_next; \ + kbp->kb_next = *(caddr_t *)(space); \ + } \ + splx(s); \ +} + +#define FREE(addr, type) { \ + register struct kmembuckets *kbp; \ + register struct kmemusage *kup = btokup(addr); \ + long s = splimp(); \ + if (1 << kup->ku_indx > MAXALLOCSAVE) { \ + free((addr), type); \ + } else { \ + kbp = &bucket[kup->ku_indx]; \ + if (kbp->kb_next == NULL) \ + kbp->kb_next = (caddr_t)(addr); \ + else \ + *(caddr_t *)(kbp->kb_last) = (caddr_t)(addr); \ + *(caddr_t *)(addr) = NULL; \ + kbp->kb_last = (caddr_t)(addr); \ + } \ + splx(s); \ +} +#endif /* do not collect statistics */ + +extern struct kmemstats kmemstats[]; +extern struct kmemusage *kmemusage; +extern char *kmembase; +extern struct kmembuckets bucket[]; + +void *contigmalloc __P((unsigned long size, int type, int flags, + unsigned long low, unsigned long high, + unsigned long alignment, unsigned long boundary)); +void free __P((void *addr, int type)); +void *malloc __P((unsigned long size, int type, int flags)); +#endif /* KERNEL */ + +#endif /* !_SYS_MALLOC_H_ */ diff --git a/cpukit/libnetworking/sys/mbuf.h b/cpukit/libnetworking/sys/mbuf.h new file mode 100644 index 0000000000..b380b3fca3 --- /dev/null +++ b/cpukit/libnetworking/sys/mbuf.h @@ -0,0 +1,439 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)mbuf.h 8.5 (Berkeley) 2/19/95 + * $Id$ + */ + +#ifndef _SYS_MBUF_H_ +#define _SYS_MBUF_H_ + +#ifndef M_WAITOK +#include <sys/malloc.h> +#endif + +/* + * Mbufs are of a single size, MSIZE (machine/machparam.h), which + * includes overhead. An mbuf may add a single "mbuf cluster" of size + * MCLBYTES (also in machine/machparam.h), which has no additional overhead + * and is used instead of the internal data area; this is done when + * at least MINCLSIZE of data must be stored. + */ + +#define MLEN (MSIZE - sizeof(struct m_hdr)) /* normal data len */ +#define MHLEN (MLEN - sizeof(struct pkthdr)) /* data len w/pkthdr */ + +#define MINCLSIZE (MHLEN + MLEN) /* smallest amount to put in cluster */ +#define M_MAXCOMPRESS (MHLEN / 2) /* max amount to copy for compression */ + +/* + * Macros for type conversion + * mtod(m,t) - convert mbuf pointer to data pointer of correct type + * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) + * mtocl(x) - convert pointer within cluster to cluster index # + * cltom(x) - convert cluster # to ptr to beginning of cluster + */ +#define mtod(m,t) ((t)((m)->m_data)) +#define dtom(x) ((struct mbuf *)((long)(x) & ~(MSIZE-1))) +#define mtocl(x) (((u_long)(x) - (u_long)mbutl) >> MCLSHIFT) +#define cltom(x) ((caddr_t)((u_long)mbutl + ((u_long)(x) << MCLSHIFT))) + +/* header at beginning of each mbuf: */ +struct m_hdr { + struct mbuf *mh_next; /* next buffer in chain */ + struct mbuf *mh_nextpkt; /* next chain in queue/record */ + caddr_t mh_data; /* location of data */ + int mh_len; /* amount of data in this mbuf */ + short mh_type; /* type of data in this mbuf */ + short mh_flags; /* flags; see below */ +}; + +/* record/packet header in first mbuf of chain; valid if M_PKTHDR set */ +struct pkthdr { + struct ifnet *rcvif; /* rcv interface */ + int len; /* total packet length */ +}; + +/* description of external storage mapped into mbuf, valid if M_EXT set */ +struct m_ext { + caddr_t ext_buf; /* start of buffer */ + void (*ext_free) /* free routine if not the usual */ + __P((caddr_t, u_int)); + u_int ext_size; /* size of buffer, for ext_free */ + void (*ext_ref) /* add a reference to the ext object */ + __P((caddr_t, u_int)); +}; + +struct mbuf { + struct m_hdr m_hdr; + union { + struct { + struct pkthdr MH_pkthdr; /* M_PKTHDR set */ + union { + struct m_ext MH_ext; /* M_EXT set */ + char MH_databuf[MHLEN]; + } MH_dat; + } MH; + char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */ + } M_dat; +}; +#define m_next m_hdr.mh_next +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_type m_hdr.mh_type +#define m_flags m_hdr.mh_flags +#define m_nextpkt m_hdr.mh_nextpkt +#define m_act m_nextpkt +#define m_pkthdr M_dat.MH.MH_pkthdr +#define m_ext M_dat.MH.MH_dat.MH_ext +#define m_pktdat M_dat.MH.MH_dat.MH_databuf +#define m_dat M_dat.M_databuf + +/* mbuf flags */ +#define M_EXT 0x0001 /* has associated external storage */ +#define M_PKTHDR 0x0002 /* start of record */ +#define M_EOR 0x0004 /* end of record */ +#define M_PROTO1 0x0008 /* protocol-specific */ + +/* mbuf pkthdr flags, also in m_flags */ +#define M_BCAST 0x0100 /* send/received as link-level broadcast */ +#define M_MCAST 0x0200 /* send/received as link-level multicast */ + +/* flags copied when copying m_pkthdr */ +#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_PROTO1|M_BCAST|M_MCAST) + +/* mbuf types */ +#define MT_FREE 0 /* should be on free list */ +#define MT_DATA 1 /* dynamic (data) allocation */ +#define MT_HEADER 2 /* packet header */ +#define MT_SOCKET 3 /* socket structure */ +#define MT_PCB 4 /* protocol control block */ +#define MT_RTABLE 5 /* routing tables */ +#define MT_HTABLE 6 /* IMP host tables */ +#define MT_ATABLE 7 /* address resolution tables */ +#define MT_SONAME 8 /* socket name */ +#define MT_SOOPTS 10 /* socket options */ +#define MT_FTABLE 11 /* fragment reassembly header */ +#define MT_RIGHTS 12 /* access rights */ +#define MT_IFADDR 13 /* interface address */ +#define MT_CONTROL 14 /* extra-data protocol message */ +#define MT_OOBDATA 15 /* expedited data */ + +/* flags to m_get/MGET */ +#define M_DONTWAIT M_NOWAIT +#define M_WAIT M_WAITOK + +/* Freelists: + * + * Normal mbuf clusters are normally treated as character arrays + * after allocation, but use the first word of the buffer as a free list + * pointer while on the free list. + */ +union mcluster { + union mcluster *mcl_next; + char mcl_buf[MCLBYTES]; +}; + +/* + * mbuf utility macros: + * + * MBUFLOCK(code) + * prevents a section of code from from being interrupted by network + * drivers. + */ +#define MBUFLOCK(code) \ + { int ms = splimp(); \ + { code } \ + splx(ms); \ + } + +/* + * mbuf allocation/deallocation macros: + * + * MGET(struct mbuf *m, int how, int type) + * allocates an mbuf and initializes it to contain internal data. + * + * MGETHDR(struct mbuf *m, int how, int type) + * allocates an mbuf and initializes it to contain a packet header + * and internal data. + */ +#define MGET(m, how, type) { \ + int _ms = splimp(); \ + if (mmbfree == 0) \ + (void)m_mballoc(1, (how)); \ + if (((m) = mmbfree) != 0) { \ + mmbfree = (m)->m_next; \ + mbstat.m_mtypes[MT_FREE]--; \ + (m)->m_type = (type); \ + mbstat.m_mtypes[type]++; \ + (m)->m_next = (struct mbuf *)NULL; \ + (m)->m_nextpkt = (struct mbuf *)NULL; \ + (m)->m_data = (m)->m_dat; \ + (m)->m_flags = 0; \ + splx(_ms); \ + } else { \ + splx(_ms); \ + (m) = m_retry((how), (type)); \ + } \ +} + +#define MGETHDR(m, how, type) { \ + int _ms = splimp(); \ + if (mmbfree == 0) \ + (void)m_mballoc(1, (how)); \ + if (((m) = mmbfree) != 0) { \ + mmbfree = (m)->m_next; \ + mbstat.m_mtypes[MT_FREE]--; \ + (m)->m_type = (type); \ + mbstat.m_mtypes[type]++; \ + (m)->m_next = (struct mbuf *)NULL; \ + (m)->m_nextpkt = (struct mbuf *)NULL; \ + (m)->m_data = (m)->m_pktdat; \ + (m)->m_flags = M_PKTHDR; \ + splx(_ms); \ + } else { \ + splx(_ms); \ + (m) = m_retryhdr((how), (type)); \ + } \ +} + +/* + * Mbuf cluster macros. + * MCLALLOC(caddr_t p, int how) allocates an mbuf cluster. + * MCLGET adds such clusters to a normal mbuf; + * the flag M_EXT is set upon success. + * MCLFREE releases a reference to a cluster allocated by MCLALLOC, + * freeing the cluster if the reference count has reached 0. + */ +#define MCLALLOC(p, how) \ + MBUFLOCK( \ + if (mclfree == 0) \ + (void)m_clalloc(1, (how)); \ + if (((p) = (caddr_t)mclfree) != 0) { \ + ++mclrefcnt[mtocl(p)]; \ + mbstat.m_clfree--; \ + mclfree = ((union mcluster *)(p))->mcl_next; \ + } \ + ) + +#define MCLGET(m, how) \ + { MCLALLOC((m)->m_ext.ext_buf, (how)); \ + if ((m)->m_ext.ext_buf != NULL) { \ + (m)->m_data = (m)->m_ext.ext_buf; \ + (m)->m_flags |= M_EXT; \ + (m)->m_ext.ext_free = NULL; \ + (m)->m_ext.ext_ref = NULL; \ + (m)->m_ext.ext_size = MCLBYTES; \ + } \ + } + +#define MCLFREE(p) \ + MBUFLOCK ( \ + if (--mclrefcnt[mtocl(p)] == 0) { \ + ((union mcluster *)(p))->mcl_next = mclfree; \ + mclfree = (union mcluster *)(p); \ + mbstat.m_clfree++; \ + } \ + ) + +/* + * MFREE(struct mbuf *m, struct mbuf *n) + * Free a single mbuf and associated external storage. + * Place the successor, if any, in n. + */ +#define MFREE(m, n) \ + MBUFLOCK( \ + mbstat.m_mtypes[(m)->m_type]--; \ + if ((m)->m_flags & M_EXT) { \ + if ((m)->m_ext.ext_free) \ + (*((m)->m_ext.ext_free))((m)->m_ext.ext_buf, \ + (m)->m_ext.ext_size); \ + else { \ + char *p = (m)->m_ext.ext_buf; \ + if (--mclrefcnt[mtocl(p)] == 0) { \ + ((union mcluster *)(p))->mcl_next = mclfree; \ + mclfree = (union mcluster *)(p); \ + mbstat.m_clfree++; \ + } \ + } \ + } \ + (n) = (m)->m_next; \ + (m)->m_type = MT_FREE; \ + mbstat.m_mtypes[MT_FREE]++; \ + (m)->m_next = mmbfree; \ + mmbfree = (m); \ + ) + +/* + * Copy mbuf pkthdr from from to to. + * from must have M_PKTHDR set, and to must be empty. + */ +#define M_COPY_PKTHDR(to, from) { \ + (to)->m_pkthdr = (from)->m_pkthdr; \ + (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ + (to)->m_data = (to)->m_pktdat; \ +} + +/* + * Set the m_data pointer of a newly-allocated mbuf (m_get/MGET) to place + * an object of the specified size at the end of the mbuf, longword aligned. + */ +#define M_ALIGN(m, len) \ + { (m)->m_data += (MLEN - (len)) &~ (sizeof(long) - 1); } +/* + * As above, for mbufs allocated with m_gethdr/MGETHDR + * or initialized by M_COPY_PKTHDR. + */ +#define MH_ALIGN(m, len) \ + { (m)->m_data += (MHLEN - (len)) &~ (sizeof(long) - 1); } + +/* + * Compute the amount of space available + * before the current start of data in an mbuf. + */ +#define M_LEADINGSPACE(m) \ + ((m)->m_flags & M_EXT ? /* (m)->m_data - (m)->m_ext.ext_buf */ 0 : \ + (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \ + (m)->m_data - (m)->m_dat) + +/* + * Compute the amount of space available + * after the end of data in an mbuf. + */ +#define M_TRAILINGSPACE(m) \ + ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size - \ + ((m)->m_data + (m)->m_len) : \ + &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len)) + +/* + * Arrange to prepend space of size plen to mbuf m. + * If a new mbuf must be allocated, how specifies whether to wait. + * If how is M_DONTWAIT and allocation fails, the original mbuf chain + * is freed and m is set to NULL. + */ +#define M_PREPEND(m, plen, how) { \ + if (M_LEADINGSPACE(m) >= (plen)) { \ + (m)->m_data -= (plen); \ + (m)->m_len += (plen); \ + } else \ + (m) = m_prepend((m), (plen), (how)); \ + if ((m) && (m)->m_flags & M_PKTHDR) \ + (m)->m_pkthdr.len += (plen); \ +} + +/* change mbuf to new type */ +#define MCHTYPE(m, t) { \ + MBUFLOCK(mbstat.m_mtypes[(m)->m_type]--; mbstat.m_mtypes[t]++;) \ + (m)->m_type = t;\ +} + +/* length to m_copy to copy all */ +#define M_COPYALL 1000000000 + +/* compatibility with 4.3 */ +#define m_copy(m, o, l) m_copym((m), (o), (l), M_DONTWAIT) + +/* + * Mbuf statistics. + */ +struct mbstat { + u_long m_mbufs; /* mbufs obtained from page pool */ + u_long m_clusters; /* clusters obtained from page pool */ + u_long m_spare; /* spare field */ + u_long m_clfree; /* free clusters */ + u_long m_drops; /* times failed to find space */ + u_long m_wait; /* times waited for space */ + u_long m_drain; /* times drained protocols for space */ + u_short m_mtypes[256]; /* type specific mbuf allocations */ +}; + +#ifdef KERNEL +extern struct mbuf *mbutl; /* virtual address of mclusters */ +extern char *mclrefcnt; /* cluster reference counts */ +extern struct mbstat mbstat; +extern int nmbclusters; +extern int nmbufs; +extern struct mbuf *mmbfree; +extern union mcluster *mclfree; +extern int max_linkhdr; /* largest link-level header */ +extern int max_protohdr; /* largest protocol header */ +extern int max_hdr; /* largest link+protocol header */ +extern int max_datalen; /* MHLEN - max_hdr */ +extern int mbtypes[]; /* XXX */ + +struct mbuf *m_copym __P((struct mbuf *, int, int, int)); +struct mbuf *m_copypacket __P((struct mbuf *, int)); +struct mbuf *m_devget __P((char *, int, int, struct ifnet *, + void (*copy)(char *, caddr_t, u_int))); +struct mbuf *m_free __P((struct mbuf *)); +struct mbuf *m_get __P((int, int)); +struct mbuf *m_getclr __P((int, int)); +struct mbuf *m_gethdr __P((int, int)); +struct mbuf *m_prepend __P((struct mbuf *,int,int)); +struct mbuf *m_pullup __P((struct mbuf *, int)); +struct mbuf *m_retry __P((int, int)); +struct mbuf *m_retryhdr __P((int, int)); +struct mbuf *m_split __P((struct mbuf *,int,int)); +void m_adj __P((struct mbuf *, int)); +void m_cat __P((struct mbuf *,struct mbuf *)); +int m_mballoc __P((int, int)); +int m_clalloc __P((int, int)); +void m_copyback __P((struct mbuf *, int, int, caddr_t)); +void m_copydata __P((struct mbuf *,int,int,caddr_t)); +void m_freem __P((struct mbuf *)); + +#ifdef MBTYPES +int mbtypes[] = { /* XXX */ + M_FREE, /* MT_FREE 0 should be on free list */ + M_MBUF, /* MT_DATA 1 dynamic (data) allocation */ + M_MBUF, /* MT_HEADER 2 packet header */ + M_SOCKET, /* MT_SOCKET 3 socket structure */ + M_PCB, /* MT_PCB 4 protocol control block */ + M_RTABLE, /* MT_RTABLE 5 routing tables */ + M_HTABLE, /* MT_HTABLE 6 IMP host tables */ + 0, /* MT_ATABLE 7 address resolution tables */ + M_MBUF, /* MT_SONAME 8 socket name */ + 0, /* 9 */ + M_SOOPTS, /* MT_SOOPTS 10 socket options */ + M_FTABLE, /* MT_FTABLE 11 fragment reassembly header */ + M_MBUF, /* MT_RIGHTS 12 access rights */ + M_IFADDR, /* MT_IFADDR 13 interface address */ + M_MBUF, /* MT_CONTROL 14 extra-data protocol message */ + M_MBUF, /* MT_OOBDATA 15 expedited data */ +#ifdef DATAKIT + 25, 26, 27, 28, 29, 30, 31, 32 /* datakit ugliness */ +#endif +}; +#endif +#endif + +#endif /* !_SYS_MBUF_H_ */ diff --git a/cpukit/libnetworking/sys/mount.h b/cpukit/libnetworking/sys/mount.h new file mode 100644 index 0000000000..a6254e302d --- /dev/null +++ b/cpukit/libnetworking/sys/mount.h @@ -0,0 +1,531 @@ +/* + * Copyright (c) 1989, 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)mount.h 8.13 (Berkeley) 3/27/94 + * $Id$ + */ + +#ifndef _SYS_MOUNT_H_ +#define _SYS_MOUNT_H_ + +#ifndef KERNEL +#include <sys/ucred.h> +#endif +#include <sys/queue.h> + +typedef struct fsid { long val[2]; } fsid_t; /* file system id type */ + +/* + * File identifier. + * These are unique per filesystem on a single machine. + */ +#define MAXFIDSZ 16 + +struct fid { + u_short fid_len; /* length of data in bytes */ + u_short fid_reserved; /* force longword alignment */ + char fid_data[MAXFIDSZ]; /* data (variable length) */ +}; + +/* + * file system statistics + */ + +#define MNAMELEN 90 /* length of buffer for returned name */ + +struct statfs { + long f_spare2; /* placeholder */ + long f_bsize; /* fundamental file system block size */ + long f_iosize; /* optimal transfer block size */ + long f_blocks; /* total data blocks in file system */ + long f_bfree; /* free blocks in fs */ + long f_bavail; /* free blocks avail to non-superuser */ + long f_files; /* total file nodes in file system */ + long f_ffree; /* free file nodes in fs */ + fsid_t f_fsid; /* file system id */ + uid_t f_owner; /* user that mounted the filesystem */ + int f_type; /* type of filesystem (see below) */ + int f_flags; /* copy of mount flags */ + long f_spare[6]; /* spare for later */ + char f_mntonname[MNAMELEN]; /* directory on which mounted */ + char f_mntfromname[MNAMELEN];/* mounted filesystem */ +}; + +/* + * File system types. + */ +#define MOUNT_NONE 0 +#define MOUNT_UFS 1 /* Fast Filesystem */ +#define MOUNT_NFS 2 /* Sun-compatible Network Filesystem */ +#define MOUNT_MFS 3 /* Memory-based Filesystem */ +#define MOUNT_MSDOS 4 /* MS/DOS Filesystem */ +#define MOUNT_LFS 5 /* Log-based Filesystem */ +#define MOUNT_LOFS 6 /* Loopback Filesystem */ +#define MOUNT_FDESC 7 /* File Descriptor Filesystem */ +#define MOUNT_PORTAL 8 /* Portal Filesystem */ +#define MOUNT_NULL 9 /* Minimal Filesystem Layer */ +#define MOUNT_UMAP 10 /* User/Group Identifier Remapping Filesystem */ +#define MOUNT_KERNFS 11 /* Kernel Information Filesystem */ +#define MOUNT_PROCFS 12 /* /proc Filesystem */ +#define MOUNT_AFS 13 /* Andrew Filesystem */ +#define MOUNT_CD9660 14 /* ISO9660 (aka CDROM) Filesystem */ +#define MOUNT_UNION 15 /* Union (translucent) Filesystem */ +#define MOUNT_DEVFS 16 /* existing device Filesystem */ +#define MOUNT_EXT2FS 17 /* Linux EXT2FS */ +#define MOUNT_TFS 18 /* Netcon Novell filesystem */ +#define MOUNT_CFS 19 /* Coda filesystem */ +#define MOUNT_MAXTYPE 19 + +#define INITMOUNTNAMES { \ + "none", /* 0 MOUNT_NONE */ \ + "ufs", /* 1 MOUNT_UFS */ \ + "nfs", /* 2 MOUNT_NFS */ \ + "mfs", /* 3 MOUNT_MFS */ \ + "msdos", /* 4 MOUNT_MSDOS */ \ + "lfs", /* 5 MOUNT_LFS */ \ + "lofs", /* 6 MOUNT_LOFS */ \ + "fdesc", /* 7 MOUNT_FDESC */ \ + "portal", /* 8 MOUNT_PORTAL */ \ + "null", /* 9 MOUNT_NULL */ \ + "umap", /* 10 MOUNT_UMAP */ \ + "kernfs", /* 11 MOUNT_KERNFS */ \ + "procfs", /* 12 MOUNT_PROCFS */ \ + "afs", /* 13 MOUNT_AFS */ \ + "cd9660", /* 14 MOUNT_CD9660 */ \ + "union", /* 15 MOUNT_UNION */ \ + "devfs", /* 16 MOUNT_DEVFS */ \ + "ext2fs", /* 17 MOUNT_EXT2FS */ \ + "tfs", /* 18 MOUNT_TFS */ \ + "cfs", /* 19 MOUNT_CFS */ \ + 0, /* 20 MOUNT_SPARE */ \ +} + +/* + * Structure per mounted file system. Each mounted file system has an + * array of operations and an instance record. The file systems are + * put on a doubly linked list. + */ +LIST_HEAD(vnodelst, vnode); + +struct mount { + CIRCLEQ_ENTRY(mount) mnt_list; /* mount list */ + struct vfsops *mnt_op; /* operations on fs */ + struct vfsconf *mnt_vfc; /* configuration info */ + struct vnode *mnt_vnodecovered; /* vnode we mounted on */ + struct vnodelst mnt_vnodelist; /* list of vnodes this mount */ + int mnt_flag; /* flags */ + int mnt_maxsymlinklen; /* max size of short symlink */ + struct statfs mnt_stat; /* cache of filesystem stats */ + qaddr_t mnt_data; /* private data */ +/* struct vfsconf *mnt_vfc; */ /* configuration info */ + time_t mnt_time; /* last time written*/ +}; + +/* + * Mount flags. + * + * Unmount uses MNT_FORCE flag. + */ +#define MNT_RDONLY 0x00000001 /* read only filesystem */ +#define MNT_SYNCHRONOUS 0x00000002 /* file system written synchronously */ +#define MNT_NOEXEC 0x00000004 /* can't exec from filesystem */ +#define MNT_NOSUID 0x00000008 /* don't honor setuid bits on fs */ +#define MNT_NODEV 0x00000010 /* don't interpret special files */ +#define MNT_UNION 0x00000020 /* union with underlying filesystem */ +#define MNT_ASYNC 0x00000040 /* file system written asynchronously */ +#define MNT_NOATIME 0x10000000 /* Disable update of file access times */ + +/* + * exported mount flags. + */ +#define MNT_EXRDONLY 0x00000080 /* exported read only */ +#define MNT_EXPORTED 0x00000100 /* file system is exported */ +#define MNT_DEFEXPORTED 0x00000200 /* exported to the world */ +#define MNT_EXPORTANON 0x00000400 /* use anon uid mapping for everyone */ +#define MNT_EXKERB 0x00000800 /* exported with Kerberos uid mapping */ + +/* + * Flags set by internal operations. + */ +#define MNT_LOCAL 0x00001000 /* filesystem is stored locally */ +#define MNT_QUOTA 0x00002000 /* quotas are enabled on filesystem */ +#define MNT_ROOTFS 0x00004000 /* identifies the root filesystem */ +#define MNT_USER 0x00008000 /* mounted by a user */ + +/* + * Mask of flags that are visible to statfs() + */ +#define MNT_VISFLAGMASK (MNT_RDONLY|MNT_SYNCHRONOUS|MNT_NOEXEC|MNT_NOSUID| \ + MNT_NODEV|MNT_UNION|MNT_ASYNC|MNT_EXRDONLY|MNT_EXPORTED| \ + MNT_DEFEXPORTED|MNT_EXPORTANON|MNT_EXKERB|MNT_LOCAL| \ + MNT_QUOTA|MNT_ROOTFS|MNT_USER|MNT_NOATIME) + +/* + * filesystem control flags. + * + * MNT_MLOCK lock the mount entry so that name lookup cannot proceed + * past the mount point. This keeps the subtree stable during mounts + * and unmounts. + */ +#define MNT_UPDATE 0x00010000 /* not a real mount, just an update */ +#define MNT_DELEXPORT 0x00020000 /* delete export host lists */ +#define MNT_RELOAD 0x00040000 /* reload filesystem data */ +#define MNT_FORCE 0x00080000 /* force unmount or readonly change */ +#define MNT_MLOCK 0x00100000 /* lock so that subtree is stable */ +#define MNT_MWAIT 0x00200000 /* someone is waiting for lock */ +#define MNT_MPBUSY 0x00400000 /* scan of mount point in progress */ +#define MNT_MPWANT 0x00800000 /* waiting for mount point */ +#define MNT_UNMOUNT 0x01000000 /* unmount in progress */ +#define MNT_WANTRDWR 0x02000000 /* want upgrade to read/write */ + +/* + * used to get configured filesystems information + */ +#define VFS_MAXNAMELEN 32 +struct vfsconf { + void *vfc_vfsops; + char vfc_name[VFS_MAXNAMELEN]; + int vfc_index; + int vfc_refcount; + int vfc_flags; +}; + +/* + * NB: these flags refer to IMPLEMENTATION properties, not properties of + * any actual mounts; i.e., it does not make sense to change the flags. + */ +#define VFCF_STATIC 0x00000001 /* statically compiled into kernel */ +#define VFCF_NETWORK 0x00000002 /* may get data over the network */ +#define VFCF_READONLY 0x00000004 /* writes are not implemented */ +#define VFCF_SYNTHETIC 0x00000008 /* data does not represent real files */ +#define VFCF_LOOPBACK 0x00000010 /* aliases some other mounted FS */ +#define VFCF_UNICODE 0x00000020 /* stores file names as Unicode*/ + +/* + * Operations supported on mounted file system. + */ +#ifdef KERNEL + +extern int doforce; /* Flag to permit forcible unmounting. */ +extern struct vfsconf void_vfsconf; +extern struct vfsconf *vfsconf[]; + +#ifdef __STDC__ +struct nameidata; +struct mbuf; +#endif + +struct vfsops { + int (*vfs_mount) __P((struct mount *mp, char *path, caddr_t data, + struct nameidata *ndp, struct proc *p)); + int (*vfs_start) __P((struct mount *mp, int flags, + struct proc *p)); + int (*vfs_unmount) __P((struct mount *mp, int mntflags, + struct proc *p)); + int (*vfs_root) __P((struct mount *mp, struct vnode **vpp)); + int (*vfs_quotactl) __P((struct mount *mp, int cmds, uid_t uid, + caddr_t arg, struct proc *p)); + int (*vfs_statfs) __P((struct mount *mp, struct statfs *sbp, + struct proc *p)); + int (*vfs_sync) __P((struct mount *mp, int waitfor, + struct ucred *cred, struct proc *p)); + int (*vfs_vget) __P((struct mount *mp, ino_t ino, + struct vnode **vpp)); + int (*vfs_fhtovp) __P((struct mount *mp, struct fid *fhp, + struct mbuf *nam, struct vnode **vpp, + int *exflagsp, struct ucred **credanonp)); + int (*vfs_vptofh) __P((struct vnode *vp, struct fid *fhp)); + int (*vfs_init) __P((void)); +}; + +#define VFS_MOUNT(MP, PATH, DATA, NDP, P) \ + (*(MP)->mnt_op->vfs_mount)(MP, PATH, DATA, NDP, P) +#define VFS_START(MP, FLAGS, P) (*(MP)->mnt_op->vfs_start)(MP, FLAGS, P) +#define VFS_UNMOUNT(MP, FORCE, P) (*(MP)->mnt_op->vfs_unmount)(MP, FORCE, P) +#define VFS_ROOT(MP, VPP) (*(MP)->mnt_op->vfs_root)(MP, VPP) +#define VFS_QUOTACTL(MP,C,U,A,P) (*(MP)->mnt_op->vfs_quotactl)(MP, C, U, A, P) +#define VFS_STATFS(MP, SBP, P) (*(MP)->mnt_op->vfs_statfs)(MP, SBP, P) +#define VFS_SYNC(MP, WAIT, C, P) (*(MP)->mnt_op->vfs_sync)(MP, WAIT, C, P) +#define VFS_VGET(MP, INO, VPP) (*(MP)->mnt_op->vfs_vget)(MP, INO, VPP) +#define VFS_FHTOVP(MP, FIDP, NAM, VPP, EXFLG, CRED) \ + (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, NAM, VPP, EXFLG, CRED) +#define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP) + +#ifdef VFS_LKM +#include <sys/conf.h> +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +#define VFS_SET(vfsops, fsname, index, flags) \ + static struct vfsconf _fs_vfsconf = { \ + &vfsops, \ + #fsname, \ + index, \ + 0, \ + flags \ + }; \ + extern struct linker_set MODVNOPS; \ + MOD_VFS(#fsname,index,&MODVNOPS,&_fs_vfsconf); \ + int \ + fsname ## _mod(struct lkm_table *lkmtp, int cmd, int ver) { \ + DISPATCH(lkmtp, cmd, ver, lkm_nullcmd, lkm_nullcmd, lkm_nullcmd); } +#else + +#define VFS_SET(vfsops, fsname, index, flags) \ + static struct vfsconf _fs_vfsconf = { \ + &vfsops, \ + #fsname, \ + index, \ + 0, \ + flags | VFCF_STATIC \ + }; \ + DATA_SET(vfs_set,_fs_vfsconf) +#endif /* VFS_LKM */ + +#endif /* KERNEL */ + +/* + * Flags for various system call interfaces. + * + * waitfor flags to vfs_sync() and getfsstat() + */ +#define MNT_WAIT 1 +#define MNT_NOWAIT 2 + +/* + * Generic file handle + */ +struct fhandle { + fsid_t fh_fsid; /* File system id of mount point */ + struct fid fh_fid; /* File sys specific id */ +}; +typedef struct fhandle fhandle_t; + +#ifdef KERNEL +#include <net/radix.h> +#include <sys/socket.h> /* XXX for AF_MAX */ + +/* + * Network address lookup element + */ +struct netcred { + struct radix_node netc_rnodes[2]; + int netc_exflags; + struct ucred netc_anon; +}; + +/* + * Network export information + */ +struct netexport { + struct netcred ne_defexported; /* Default export */ + struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */ +}; +#endif /* KERNEL */ + +/* + * Export arguments for local filesystem mount calls. + */ +struct export_args { + int ex_flags; /* export related flags */ + uid_t ex_root; /* mapping for root uid */ + struct ucred ex_anon; /* mapping for anonymous user */ + struct sockaddr *ex_addr; /* net address to which exported */ + int ex_addrlen; /* and the net address length */ + struct sockaddr *ex_mask; /* mask of valid bits in saddr */ + int ex_masklen; /* and the smask length */ +}; + +/* + * Arguments to mount UFS-based filesystems + */ +struct ufs_args { + char *fspec; /* block special device to mount */ + struct export_args export; /* network export information */ +}; + +#ifdef MFS +/* + * Arguments to mount MFS + */ +struct mfs_args { + char *fspec; /* name to export for statfs */ + struct export_args export; /* if exported MFSes are supported */ + caddr_t base; /* base of file system in memory */ + u_long size; /* size of file system */ +}; +#endif /* MFS */ + +#ifdef MSDOSFS +/* + * Arguments to mount MSDOS filesystems. + */ +struct msdosfs_args { + char *fspec; /* blocks special holding the fs to mount */ + struct export_args export; /* network export information */ + uid_t uid; /* uid that owns msdosfs files */ + gid_t gid; /* gid that owns msdosfs files */ + mode_t mask; /* mask to be applied for msdosfs perms */ +}; +#endif + +#ifdef CD9660 +/* + * Arguments to mount ISO 9660 filesystems. + */ +struct iso_args { + char *fspec; /* block special device to mount */ + struct export_args export; /* network export info */ + int flags; /* mounting flags, see below */ + int ssector; /* starting sector */ + +}; +#define ISOFSMNT_NORRIP 0x00000001 /* disable Rock Ridge Ext.*/ +#define ISOFSMNT_GENS 0x00000002 /* enable generation numbers */ +#define ISOFSMNT_EXTATT 0x00000004 /* enable extended attributes */ +#endif /* CD9660 */ + +#ifdef NFS +/* + * Arguments to mount NFS + */ +struct nfs_args { + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retrys */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ +#endif /* NFS */ + +#ifdef KERNEL +extern int (*mountroot) __P((void *)); +extern struct vfsops *mountrootvfsops; + +/* + * exported vnode operations + */ +int dounmount __P((struct mount *, int, struct proc *)); +struct mount *getvfs __P((fsid_t *)); /* return vfs given fsid */ +void getnewfsid __P((struct mount *, int)); +int vflush __P((struct mount *, struct vnode *, int)); +int vfs_export /* process mount export info */ + __P((struct mount *, struct netexport *, struct export_args *)); +struct netcred *vfs_export_lookup /* lookup host in fs export list */ + __P((struct mount *, struct netexport *, struct mbuf *)); +int vfs_lock __P((struct mount *)); /* lock a vfs */ +int vfs_mountedon __P((struct vnode *)); /* is a vfs mounted on vp */ +int vfs_mountroot __P((void *)); /* XXX goes away? */ +void vfs_msync __P((struct mount *, int)); +void vfs_unlock __P((struct mount *)); /* unlock a vfs */ +void vfs_unmountall __P((void)); +int vfs_busy __P((struct mount *)); /* mark a vfs busy */ +void vfs_unbusy __P((struct mount *)); /* mark a vfs not busy */ +extern CIRCLEQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */ +extern struct vfsops *vfssw[]; /* filesystem type table */ + +#else /* KERNEL */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int fstatfs __P((int, struct statfs *)); +int getfh __P((const char *, fhandle_t *)); +int getfsstat __P((struct statfs *, long, int)); +int getmntinfo __P((struct statfs **, int)); +int mount __P((int, const char *, int, void *)); +int statfs __P((const char *, struct statfs *)); +int unmount __P((const char *, int)); + +/* C library stuff */ +struct vfsconf *getvfsbyname __P((const char *)); +struct vfsconf *getvfsbytype __P((int)); +struct vfsconf *getvfsent __P((void)); +void setvfsent __P((int)); +void endvfsent __P((void)); +int vfsisloadable __P((const char *)); +int vfsload __P((const char *)); +__END_DECLS + +#endif /* KERNEL */ + +#endif /* !_SYS_MOUNT_H_ */ diff --git a/cpukit/libnetworking/sys/param.h b/cpukit/libnetworking/sys/param.h new file mode 100644 index 0000000000..31551c7e06 --- /dev/null +++ b/cpukit/libnetworking/sys/param.h @@ -0,0 +1,227 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)param.h 8.3 (Berkeley) 4/4/95 + * $Id$ + */ + +#ifndef _SYS_PARAM_H_ +#define _SYS_PARAM_H_ + +#define BSD 199506 /* System version (year & month). */ +#define BSD4_3 1 +#define BSD4_4 1 + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef LOCORE +#include <sys/types.h> +#endif + +/* + * Machine-independent constants (some used in following include files). + * Redefined constants are from POSIX 1003.1 limits file. + * + * MAXCOMLEN should be >= sizeof(ac_comm) (see <acct.h>) + * MAXLOGNAME should be >= UT_NAMESIZE (see <utmp.h>) + */ +#include <sys/syslimits.h> + +#define MAXCOMLEN 16 /* max command name remembered */ +#define MAXINTERP 32 /* max interpreter file name length */ +#define MAXLOGNAME 12 /* max login name length */ +#define MAXUPRC CHILD_MAX /* max simultaneous processes */ +#define NCARGS ARG_MAX /* max bytes for an exec function */ +#define NGROUPS NGROUPS_MAX /* max number groups */ +#define NOFILE OPEN_MAX /* max open files per process */ +#define NOGROUP 65535 /* marker for empty group set member */ +#define MAXHOSTNAMELEN 256 /* max hostname size */ + +/* More types and definitions used throughout the kernel. */ +#ifdef KERNEL +#include <sys/cdefs.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/ucred.h> +#include <sys/uio.h> +#include <sys/rtprio.h> + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#endif + +/* Signals. */ +#include <sys/signal.h> + +/* Machine type dependent parameters. */ +#include <machine/param.h> +#include <machine/limits.h> + +/* + * Priorities. Note that with 32 run queues, differences less than 4 are + * insignificant. + */ +#define PSWP 0 +#define PVM 4 +#define PINOD 8 +#define PRIBIO 16 +#define PVFS 20 +#define PZERO 22 /* No longer magic, shouldn't be here. XXX */ +#define PSOCK 24 +#define PWAIT 32 +#define PLOCK 36 +#define PPAUSE 40 +#define PUSER 50 +#define MAXPRI 127 /* Priorities range from 0 through MAXPRI. */ + +#define PRIMASK 0x0ff +#define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */ + +#define NZERO 0 /* default "nice" */ + +#define NBPW sizeof(int) /* number of bytes per word (integer) */ + +#define CMASK 022 /* default file mask: S_IWGRP|S_IWOTH */ +#define NODEV (dev_t)(-1) /* non-existent device */ + +/* + * Clustering of hardware pages on machines with ridiculously small + * page sizes is done here. The paging subsystem deals with units of + * CLSIZE pte's describing PAGE_SIZE (from machine/machparam.h) pages each. + */ +#if 0 +#define CLBYTES (CLSIZE*PAGE_SIZE) +#endif + +#define CBLOCK 128 /* Clist block size, must be a power of 2. */ +#define CBQSIZE (CBLOCK/NBBY) /* Quote bytes/cblock - can do better. */ + /* Data chars/clist. */ +#define CBSIZE (CBLOCK - sizeof(struct cblock *) - CBQSIZE) +#define CROUND (CBLOCK - 1) /* Clist rounding. */ + +/* + * File system parameters and macros. + * + * The file system is made out of blocks of at most MAXBSIZE units, with + * smaller units (fragments) only in the last direct block. MAXBSIZE + * primarily determines the size of buffers in the buffer pool. It may be + * made larger without any effect on existing file systems; however making + * it smaller make make some file systems unmountable. Also, MAXBSIZE + * must be less than MAXPHYS!!! DFLTBSIZE is the average amount of + * memory allocated by vfs_bio per nbuf. BKVASIZE is the average amount + * of kernel virtual space allocated per nbuf. BKVASIZE should be >= + * DFLTBSIZE. If it is significantly bigger than DFLTBSIZE, then + * kva fragmentation causes fewer performance problems. + */ +#define MAXBSIZE 65536 +#define BKVASIZE 8192 +#define DFLTBSIZE 4096 +#define MAXFRAG 8 + +/* + * MAXPATHLEN defines the longest permissible path length after expanding + * symbolic links. It is used to allocate a temporary buffer from the buffer + * pool in which to do the name expansion, hence should be a power of two, + * and must be less than or equal to MAXBSIZE. MAXSYMLINKS defines the + * maximum number of symbolic links that may be expanded in a path name. + * It should be set high enough to allow all legitimate uses, but halt + * infinite loops reasonably quickly. + */ +#define MAXPATHLEN PATH_MAX +#define MAXSYMLINKS 32 + +/* Bit map related macros. */ +#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) +#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) +#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) + +/* Macros for counting and rounding. */ +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif +#define rounddown(x, y) (((x)/(y))*(y)) +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ +#define powerof2(x) ((((x)-1)&(x))==0) + +/* Macros for min/max. */ +#ifndef KERNEL +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +/* + * Constants for setting the parameters of the kernel memory allocator. + * + * 2 ** MINBUCKET is the smallest unit of memory that will be + * allocated. It must be at least large enough to hold a pointer. + * + * Units of memory less or equal to MAXALLOCSAVE will permanently + * allocate physical memory; requests for these size pieces of + * memory are quite fast. Allocations greater than MAXALLOCSAVE must + * always allocate and free physical memory; requests for these + * size allocations should be done infrequently as they will be slow. + * + * Constraints: PAGE_SIZE <= MAXALLOCSAVE <= 2 ** (MINBUCKET + 14), and + * MAXALLOCSIZE must be a power of two. + */ +#define MINBUCKET 4 /* 4 => min allocation of 16 bytes */ +#define MAXALLOCSAVE (2 * PAGE_SIZE) + +/* + * Scale factor for scaled integers used to count %cpu time and load avgs. + * + * The number of CPU `tick's that map to a unique `%age' can be expressed + * by the formula (1 / (2 ^ (FSHIFT - 11))). The maximum load average that + * can be calculated (assuming 32 bits) can be closely approximated using + * the formula (2 ^ (2 * (16 - FSHIFT))) for (FSHIFT < 15). + * + * For the scheduler to maintain a 1:1 mapping of CPU `tick' to `%age', + * FSHIFT must be at least 11; this gives us a maximum load avg of ~1024. + */ +#define FSHIFT 11 /* bits to right of fixed binary point */ +#define FSCALE (1<<FSHIFT) + +#endif /* _SYS_PARAM_H_ */ diff --git a/cpukit/libnetworking/sys/proc.h b/cpukit/libnetworking/sys/proc.h new file mode 100644 index 0000000000..8b8b7dc1b9 --- /dev/null +++ b/cpukit/libnetworking/sys/proc.h @@ -0,0 +1,6 @@ +/* + * Dummy structure + */ +struct proc { + int this_should_never_be_referenced; +}; diff --git a/cpukit/libnetworking/sys/protosw.h b/cpukit/libnetworking/sys/protosw.h new file mode 100644 index 0000000000..a7aa52feea --- /dev/null +++ b/cpukit/libnetworking/sys/protosw.h @@ -0,0 +1,300 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)protosw.h 8.1 (Berkeley) 6/2/93 + * $Id$ + */ + +#ifndef _SYS_PROTOSW_H_ +#define _SYS_PROTOSW_H_ + +struct ifnet; +struct mbuf; +struct sockaddr; +struct socket; +struct sockproto; +struct stat; + +/* + * Protocol switch table. + * + * Each protocol has a handle initializing one of these structures, + * which is used for protocol-protocol and system-protocol communication. + * + * A protocol is called through the pr_init entry before any other. + * Thereafter it is called every 200ms through the pr_fasttimo entry and + * every 500ms through the pr_slowtimo for timer based actions. + * The system will call the pr_drain entry if it is low on space and + * this should throw away any non-critical data. + * + * Protocols pass data between themselves as chains of mbufs using + * the pr_input and pr_output hooks. Pr_input passes data up (towards + * UNIX) and pr_output passes it down (towards the imps); control + * information passes up and down on pr_ctlinput and pr_ctloutput. + * The protocol is responsible for the space occupied by any the + * arguments to these entries and must dispose it. + * + * The userreq routine interfaces protocols to the system and is + * described below. + */ +struct protosw { + short pr_type; /* socket type used for */ + struct domain *pr_domain; /* domain protocol a member of */ + short pr_protocol; /* protocol number */ + short pr_flags; /* see below */ +/* protocol-protocol hooks */ + void (*pr_input) __P((struct mbuf *, int len)); + /* input to protocol (from below) */ + int (*pr_output) __P((struct mbuf *m, struct socket *so)); + /* output to protocol (from above) */ + void (*pr_ctlinput)__P((int, struct sockaddr *, void *)); + /* control input (from below) */ + int (*pr_ctloutput)__P((int, struct socket *, int, int, + struct mbuf **)); + /* control output (from above) */ +/* user-protocol hook */ + int (*pr_ousrreq) __P((struct socket *, int, struct mbuf *, + struct mbuf *, struct mbuf *)); + /* user request: see list below */ +/* utility hooks */ + void (*pr_init) __P((void)); /* initialization hook */ + void (*pr_fasttimo) __P((void)); + /* fast timeout (200ms) */ + void (*pr_slowtimo) __P((void)); + /* slow timeout (500ms) */ + void (*pr_drain) __P((void)); + /* flush any excess space possible */ + struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */ +}; + +#define PR_SLOWHZ 2 /* 2 slow timeouts per second */ +#define PR_FASTHZ 5 /* 5 fast timeouts per second */ + +/* + * Values for pr_flags. + * PR_ADDR requires PR_ATOMIC; + * PR_ADDR and PR_CONNREQUIRED are mutually exclusive. + * PR_IMPLOPCL means that the protocol allows sendto without prior connect, + * and the protocol understands the MSG_EOF flag. The first property is + * is only relevant if PR_CONNREQUIRED is set (otherwise sendto is allowed + * anyhow). + */ +#define PR_ATOMIC 0x01 /* exchange atomic messages only */ +#define PR_ADDR 0x02 /* addresses given with messages */ +#define PR_CONNREQUIRED 0x04 /* connection required by protocol */ +#define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */ +#define PR_RIGHTS 0x10 /* passes capabilities */ +#define PR_IMPLOPCL 0x20 /* implied open/close */ + +/* + * The arguments to usrreq are: + * (*protosw[].pr_usrreq)(up, req, m, nam, opt); + * where up is a (struct socket *), req is one of these requests, + * m is a optional mbuf chain containing a message, + * nam is an optional mbuf chain containing an address, + * and opt is a pointer to a socketopt structure or nil. + * The protocol is responsible for disposal of the mbuf chain m, + * the caller is responsible for any space held by nam and opt. + * A non-zero return from usrreq gives an + * UNIX error number which should be passed to higher level software. + */ +#define PRU_ATTACH 0 /* attach protocol to up */ +#define PRU_DETACH 1 /* detach protocol from up */ +#define PRU_BIND 2 /* bind socket to address */ +#define PRU_LISTEN 3 /* listen for connection */ +#define PRU_CONNECT 4 /* establish connection to peer */ +#define PRU_ACCEPT 5 /* accept connection from peer */ +#define PRU_DISCONNECT 6 /* disconnect from peer */ +#define PRU_SHUTDOWN 7 /* won't send any more data */ +#define PRU_RCVD 8 /* have taken data; more room now */ +#define PRU_SEND 9 /* send this data */ +#define PRU_ABORT 10 /* abort (fast DISCONNECT, DETATCH) */ +#define PRU_CONTROL 11 /* control operations on protocol */ +#define PRU_SENSE 12 /* return status into m */ +#define PRU_RCVOOB 13 /* retrieve out of band data */ +#define PRU_SENDOOB 14 /* send out of band data */ +#define PRU_SOCKADDR 15 /* fetch socket's address */ +#define PRU_PEERADDR 16 /* fetch peer's address */ +#define PRU_CONNECT2 17 /* connect two sockets */ +/* begin for protocols internal use */ +#define PRU_FASTTIMO 18 /* 200ms timeout */ +#define PRU_SLOWTIMO 19 /* 500ms timeout */ +#define PRU_PROTORCV 20 /* receive from below */ +#define PRU_PROTOSEND 21 /* send to below */ +/* end for protocol's internal use */ +#define PRU_SEND_EOF 22 /* send and close */ +#define PRU_NREQ 22 + +#ifdef PRUREQUESTS +char *prurequests[] = { + "ATTACH", "DETACH", "BIND", "LISTEN", + "CONNECT", "ACCEPT", "DISCONNECT", "SHUTDOWN", + "RCVD", "SEND", "ABORT", "CONTROL", + "SENSE", "RCVOOB", "SENDOOB", "SOCKADDR", + "PEERADDR", "CONNECT2", "FASTTIMO", "SLOWTIMO", + "PROTORCV", "PROTOSEND", + "SEND_EOF", +}; +#endif + +#ifdef KERNEL /* users shouldn't see this decl */ +struct stat; +struct ifnet; + +/* + * If the ordering here looks odd, that's because it's alphabetical. + */ +struct pr_usrreqs { + int (*pru_abort) __P((struct socket *so)); + int (*pru_accept) __P((struct socket *so, struct mbuf *nam)); + int (*pru_attach) __P((struct socket *so, int proto)); + int (*pru_bind) __P((struct socket *so, struct mbuf *nam)); + int (*pru_connect) __P((struct socket *so, struct mbuf *nam)); + int (*pru_connect2) __P((struct socket *so1, struct socket *so2)); + int (*pru_control) __P((struct socket *so, int cmd, caddr_t data, + struct ifnet *ifp)); + int (*pru_detach) __P((struct socket *so)); + int (*pru_disconnect) __P((struct socket *so)); + int (*pru_listen) __P((struct socket *so)); + int (*pru_peeraddr) __P((struct socket *so, struct mbuf *nam)); + int (*pru_rcvd) __P((struct socket *so, int flags)); + int (*pru_rcvoob) __P((struct socket *so, struct mbuf *m, + int flags)); + /* + * The `m' parameter here is almost certainly going to become a + * `struct uio' at some point in the future. Similar changes + * will probably happen for the receive entry points. + */ + int (*pru_send) __P((struct socket *so, int flags, struct mbuf *m, + struct mbuf *addr, struct mbuf *control)); +#define PRUS_OOB 0x1 +#define PRUS_EOF 0x2 + int (*pru_sense) __P((struct socket *so, struct stat *sb)); + int (*pru_shutdown) __P((struct socket *so)); + int (*pru_sockaddr) __P((struct socket *so, struct mbuf *nam)); +}; + +int pru_accept_notsupp __P((struct socket *so, struct mbuf *nam)); +int pru_connect2_notsupp __P((struct socket *so1, struct socket *so2)); +int pru_control_notsupp __P((struct socket *so, int cmd, caddr_t data, + struct ifnet *ifp)); +int pru_listen_notsupp __P((struct socket *so)); +int pru_rcvd_notsupp __P((struct socket *so, int flags)); +int pru_rcvoob_notsupp __P((struct socket *so, struct mbuf *m, int flags)); +int pru_sense_null __P((struct socket *so, struct stat *sb)); + +#define PRU_OLDSTYLE + +#ifdef PRU_OLDSTYLE +/* + * Protocols which don't yet implement pr_usrreqs can point it to this + * structure, which will call the old pr_usrreq() entry point with the + * appropriate arguments. + */ +extern struct pr_usrreqs pru_oldstyle; +#endif /* PRU_OLDSTYLE */ + +#endif /* KERNEL */ + +/* + * The arguments to the ctlinput routine are + * (*protosw[].pr_ctlinput)(cmd, sa, arg); + * where cmd is one of the commands below, sa is a pointer to a sockaddr, + * and arg is a `void *' argument used within a protocol family. + */ +#define PRC_IFDOWN 0 /* interface transition */ +#define PRC_ROUTEDEAD 1 /* select new route if possible ??? */ +#define PRC_QUENCH2 3 /* DEC congestion bit says slow down */ +#define PRC_QUENCH 4 /* some one said to slow down */ +#define PRC_MSGSIZE 5 /* message size forced drop */ +#define PRC_HOSTDEAD 6 /* host appears to be down */ +#define PRC_HOSTUNREACH 7 /* deprecated (use PRC_UNREACH_HOST) */ +#define PRC_UNREACH_NET 8 /* no route to network */ +#define PRC_UNREACH_HOST 9 /* no route to host */ +#define PRC_UNREACH_PROTOCOL 10 /* dst says bad protocol */ +#define PRC_UNREACH_PORT 11 /* bad port # */ +/* was PRC_UNREACH_NEEDFRAG 12 (use PRC_MSGSIZE) */ +#define PRC_UNREACH_SRCFAIL 13 /* source route failed */ +#define PRC_REDIRECT_NET 14 /* net routing redirect */ +#define PRC_REDIRECT_HOST 15 /* host routing redirect */ +#define PRC_REDIRECT_TOSNET 16 /* redirect for type of service & net */ +#define PRC_REDIRECT_TOSHOST 17 /* redirect for tos & host */ +#define PRC_TIMXCEED_INTRANS 18 /* packet lifetime expired in transit */ +#define PRC_TIMXCEED_REASS 19 /* lifetime expired on reass q */ +#define PRC_PARAMPROB 20 /* header incorrect */ + +#define PRC_NCMDS 21 + +#define PRC_IS_REDIRECT(cmd) \ + ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST) + +#ifdef PRCREQUESTS +char *prcrequests[] = { + "IFDOWN", "ROUTEDEAD", "#2", "DEC-BIT-QUENCH2", + "QUENCH", "MSGSIZE", "HOSTDEAD", "#7", + "NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH", + "#12", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT", + "TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS", + "PARAMPROB" +}; +#endif + +/* + * The arguments to ctloutput are: + * (*protosw[].pr_ctloutput)(req, so, level, optname, optval); + * req is one of the actions listed below, so is a (struct socket *), + * level is an indication of which protocol layer the option is intended. + * optname is a protocol dependent socket option request, + * optval is a pointer to a mbuf-chain pointer, for value-return results. + * The protocol is responsible for disposal of the mbuf chain *optval + * if supplied, + * the caller is responsible for any space held by *optval, when returned. + * A non-zero return from usrreq gives an + * UNIX error number which should be passed to higher level software. + */ +#define PRCO_GETOPT 0 +#define PRCO_SETOPT 1 + +#define PRCO_NCMDS 2 + +#ifdef PRCOREQUESTS +char *prcorequests[] = { + "GETOPT", "SETOPT", +}; +#endif + +#ifdef KERNEL +struct protosw *pffindproto __P((int family, int protocol, int type)); +struct protosw *pffindtype __P((int family, int type)); +#endif + +#endif diff --git a/cpukit/libnetworking/sys/queue.h b/cpukit/libnetworking/sys/queue.h new file mode 100644 index 0000000000..e8aa08cf5d --- /dev/null +++ b/cpukit/libnetworking/sys/queue.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $Id$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * slingly-linked tail queues, lists, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may only be traversed in the forward direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + (head)->slh_first = NULL; \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} + +#define SLIST_INSERT_HEAD(head, elm, field) { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} + +#define SLIST_REMOVE_HEAD(head, field) { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} + +#define SLIST_REMOVE(head, elm, type, field) { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while( curelm->field.sle_next != (elm) ) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} + +/* + * Singly-linked Tail queue definitions. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} + +#define STAILQ_INSERT_HEAD(head, elm, field) { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} + +#define STAILQ_INSERT_TAIL(head, elm, field) { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) { \ + if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (tqelm)->field.stqe_next = (elm); \ +} + +#define STAILQ_REMOVE_HEAD(head, field) { \ + if (((head)->stqh_first = \ + (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} + +#define STAILQ_REMOVE(head, elm, type, field) { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD(head, field); \ + } \ + else { \ + struct type *curelm = (head)->stqh_first; \ + while( curelm->field.stqe_next != (elm) ) \ + curelm = curelm->field.stqe_next; \ + if((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) { \ + (head)->lh_first = NULL; \ +} + +#define LIST_INSERT_AFTER(listelm, elm, field) { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} + +#define LIST_INSERT_BEFORE(listelm, elm, field) { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} + +#define LIST_INSERT_HEAD(head, elm, field) { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} + +#define LIST_REMOVE(elm, field) { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_LAST(head) ((head)->tqh_last) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, field) ((elm)->field.tqe_prev) + +#define TAILQ_INIT(head) { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} + +#define TAILQ_INSERT_HEAD(head, elm, field) { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} + +#define TAILQ_INSERT_TAIL(head, elm, field) { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} + +#define TAILQ_REMOVE(head, elm, field) { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} + +#define CIRCLEQ_REMOVE(head, elm, field) { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} + +#ifdef KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __GNUC__ + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = a, *head = b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__GNUC__ */ + +void insque __P((void *a, void *b)); +void remque __P((void *a)); + +#endif /* __GNUC__ */ + +#endif /* KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/cpukit/libnetworking/sys/reboot.h b/cpukit/libnetworking/sys/reboot.h new file mode 100644 index 0000000000..48a7f0f782 --- /dev/null +++ b/cpukit/libnetworking/sys/reboot.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993, 1994 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)reboot.h 8.3 (Berkeley) 12/13/94 + * $Id$ + */ + +#ifndef _SYS_REBOOT_H_ +#define _SYS_REBOOT_H_ + +/* + * Arguments to reboot system call. These are passed to + * the boot program and on to init. + */ +#define RB_AUTOBOOT 0 /* flags for system auto-booting itself */ + +#define RB_ASKNAME 0x001 /* ask for file name to reboot from */ +#define RB_SINGLE 0x002 /* reboot to single user only */ +#define RB_NOSYNC 0x004 /* dont sync before reboot */ +#define RB_HALT 0x008 /* don't reboot, just halt */ +#define RB_INITNAME 0x010 /* name given for /etc/init (unused) */ +#define RB_DFLTROOT 0x020 /* use compiled-in rootdev */ +#define RB_KDB 0x040 /* give control to kernel debugger */ +#define RB_RDONLY 0x080 /* mount root fs read-only */ +#define RB_DUMP 0x100 /* dump kernel memory before reboot */ +#define RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ +#define RB_CONFIG 0x400 /* invoke user configuration routing */ +#define RB_VERBOSE 0x800 /* print all potentially useful info */ +#define RB_SERIAL 0x1000 /* user serial port as console */ +#define RB_CDROM 0x2000 /* use cdrom as root */ +#define RB_POWEROFF 0x4000 /* if you can, turn the power off */ +#define RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ +#define RB_MUTE 0x10000 /* Come up with the console muted */ +#define RB_SELFTEST 0x20000 /* don't boot to normal operation, do selftest */ + +#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ + +/* + * Constants for converting boot-style device number to type, + * adaptor (uba, mba, etc), unit number and partition number. + * Type (== major device number) is in the low byte + * for backward compatibility. Except for that of the "magic + * number", each mask applies to the shifted value. + * Format: + * (4) (4) (4) (4) (8) (8) + * -------------------------------- + * |MA | AD| CT| UN| PART | TYPE | + * -------------------------------- + */ +#define B_ADAPTORSHIFT 24 +#define B_ADAPTORMASK 0x0f +#define B_ADAPTOR(val) (((val) >> B_ADAPTORSHIFT) & B_ADAPTORMASK) +#define B_CONTROLLERSHIFT 20 +#define B_CONTROLLERMASK 0xf +#define B_CONTROLLER(val) (((val)>>B_CONTROLLERSHIFT) & B_CONTROLLERMASK) +#define B_SLICESHIFT 20 +#define B_SLICEMASK 0xff +#define B_SLICE(val) (((val)>>B_SLICESHIFT) & B_SLICEMASK) +#define B_UNITSHIFT 16 +#define B_UNITMASK 0xf +#define B_UNIT(val) (((val) >> B_UNITSHIFT) & B_UNITMASK) +#define B_PARTITIONSHIFT 8 +#define B_PARTITIONMASK 0xff +#define B_PARTITION(val) (((val) >> B_PARTITIONSHIFT) & B_PARTITIONMASK) +#define B_TYPESHIFT 0 +#define B_TYPEMASK 0xff +#define B_TYPE(val) (((val) >> B_TYPESHIFT) & B_TYPEMASK) + +#define B_MAGICMASK 0xf0000000 +#define B_DEVMAGIC 0xa0000000 + +#define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \ + (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \ + ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \ + ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC) + +#endif diff --git a/cpukit/libnetworking/sys/resourcevar.h b/cpukit/libnetworking/sys/resourcevar.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/cpukit/libnetworking/sys/resourcevar.h diff --git a/cpukit/libnetworking/sys/rtprio.h b/cpukit/libnetworking/sys/rtprio.h new file mode 100644 index 0000000000..dd9521e7c8 --- /dev/null +++ b/cpukit/libnetworking/sys/rtprio.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1994, Henrik Vestergaard Draboel + * 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 (name). + * 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 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 AUTHOR 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. + * + * $Id$ + */ + +#ifndef _SYS_RTPRIO_H_ +#define _SYS_RTPRIO_H_ + +/* + * Process realtime-priority specifications to rtprio. + */ + +/* priority types */ +#define RTP_PRIO_REALTIME 0 +#define RTP_PRIO_NORMAL 1 +#define RTP_PRIO_IDLE 2 + +/* priority range */ +#define RTP_PRIO_MIN 0 /* Highest priority */ +#define RTP_PRIO_MAX 31 /* Lowest priority */ + +/* + * rtprio() syscall functions + */ +#define RTP_LOOKUP 0 +#define RTP_SET 1 + +#ifndef LOCORE +struct rtprio { + u_short type; + u_short prio; +}; +#endif + +#ifndef KERNEL +#include <sys/cdefs.h> + +__BEGIN_DECLS +int rtprio __P((int, pid_t, struct rtprio *)); +__END_DECLS +#endif /* !KERNEL */ +#endif /* !_SYS_RTPRIO_H_ */ diff --git a/cpukit/libnetworking/sys/select.h b/cpukit/libnetworking/sys/select.h new file mode 100644 index 0000000000..e69971e3b6 --- /dev/null +++ b/cpukit/libnetworking/sys/select.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)select.h 8.2 (Berkeley) 1/4/94 + * $Id$ + */ + +#ifndef _SYS_SELECT_H_ +#define _SYS_SELECT_H_ + +/* + * Used to maintain information about processes that wish to be + * notified when I/O becomes possible. + */ +struct selinfo { + pid_t si_pid; /* process to be notified */ + short si_flags; /* see below */ +}; +#define SI_COLL 0x0001 /* collision occurred */ + +#ifdef KERNEL +struct proc; + +void selrecord __P((struct proc *selector, struct selinfo *)); +void selwakeup __P((struct selinfo *)); +#endif + +#endif /* !_SYS_SELECT_H_ */ diff --git a/cpukit/libnetworking/sys/signalvar.h b/cpukit/libnetworking/sys/signalvar.h new file mode 100644 index 0000000000..8900458fdb --- /dev/null +++ b/cpukit/libnetworking/sys/signalvar.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)signalvar.h 8.6 (Berkeley) 2/19/95 + * $Id$ + */ + +#ifndef _SYS_SIGNALVAR_H_ /* tmp for user.h */ +#define _SYS_SIGNALVAR_H_ + +/* + * Kernel signal definitions and data structures, + * not exported to user programs. + */ + +/* + * Process signal actions and state, needed only within the process + * (not necessarily resident). + */ +struct sigacts { + sig_t ps_sigact[NSIG]; /* disposition of signals */ + sigset_t ps_catchmask[NSIG]; /* signals to be blocked */ + sigset_t ps_sigonstack; /* signals to take on sigstack */ + sigset_t ps_sigintr; /* signals that interrupt syscalls */ + sigset_t ps_sigreset; /* signals that reset when caught */ + sigset_t ps_signodefer; /* signals not masked while handled */ + sigset_t ps_oldmask; /* saved mask from before sigpause */ + int ps_flags; /* signal flags, below */ + struct sigaltstack ps_sigstk; /* sp & on stack state variable */ + int ps_sig; /* for core dump/debugger XXX */ + u_long ps_code; /* for core dump/debugger XXX */ + sigset_t ps_usertramp; /* SunOS compat; libc sigtramp XXX */ +}; + +/* signal flags */ +#define SAS_OLDMASK 0x01 /* need to restore mask before pause */ +#define SAS_ALTSTACK 0x02 /* have alternate signal stack */ + +/* additional signal action values, used only temporarily/internally */ +#define SIG_CATCH ((__sighandler_t *)2) +#define SIG_HOLD ((__sighandler_t *)3) + +/* + * get signal action for process and signal; currently only for current process + */ +#define SIGACTION(p, sig) (p->p_sigacts->ps_sigact[(sig)]) + +/* + * Determine signal that should be delivered to process p, the current + * process, 0 if none. If there is a pending stop signal with default + * action, the process stops in issignal(). + */ +#define CURSIG(p) \ + (((p)->p_siglist == 0 || \ + (((p)->p_flag & P_TRACED) == 0 && \ + ((p)->p_siglist & ~(p)->p_sigmask) == 0)) ? \ + 0 : issignal(p)) + +/* + * Clear a pending signal from a process. + */ +#define CLRSIG(p, sig) { (p)->p_siglist &= ~sigmask(sig); } + +/* + * Signal properties and actions. + * The array below categorizes the signals and their default actions + * according to the following properties: + */ +#define SA_KILL 0x01 /* terminates process by default */ +#define SA_CORE 0x02 /* ditto and coredumps */ +#define SA_STOP 0x04 /* suspend process */ +#define SA_TTYSTOP 0x08 /* ditto, from tty */ +#define SA_IGNORE 0x10 /* ignore by default */ +#define SA_CONT 0x20 /* continue if suspended */ +#define SA_CANTMASK 0x40 /* non-maskable, catchable */ + +#ifdef SIGPROP +static int sigprop[NSIG + 1] = { + 0, /* unused */ + SA_KILL, /* SIGHUP */ + SA_KILL, /* SIGINT */ + SA_KILL|SA_CORE, /* SIGQUIT */ + SA_KILL|SA_CORE, /* SIGILL */ + SA_KILL|SA_CORE, /* SIGTRAP */ + SA_KILL|SA_CORE, /* SIGABRT */ + SA_KILL|SA_CORE, /* SIGEMT */ + SA_KILL|SA_CORE, /* SIGFPE */ + SA_KILL, /* SIGKILL */ + SA_KILL|SA_CORE, /* SIGBUS */ + SA_KILL|SA_CORE, /* SIGSEGV */ + SA_KILL|SA_CORE, /* SIGSYS */ + SA_KILL, /* SIGPIPE */ + SA_KILL, /* SIGALRM */ + SA_KILL, /* SIGTERM */ + SA_IGNORE, /* SIGURG */ + SA_STOP, /* SIGSTOP */ + SA_STOP|SA_TTYSTOP, /* SIGTSTP */ + SA_IGNORE|SA_CONT, /* SIGCONT */ + SA_IGNORE, /* SIGCHLD */ + SA_STOP|SA_TTYSTOP, /* SIGTTIN */ + SA_STOP|SA_TTYSTOP, /* SIGTTOU */ + SA_IGNORE, /* SIGIO */ + SA_KILL, /* SIGXCPU */ + SA_KILL, /* SIGXFSZ */ + SA_KILL, /* SIGVTALRM */ + SA_KILL, /* SIGPROF */ + SA_IGNORE, /* SIGWINCH */ + SA_IGNORE, /* SIGINFO */ + SA_KILL, /* SIGUSR1 */ + SA_KILL, /* SIGUSR2 */ +}; + +#define contsigmask (sigmask(SIGCONT)) +#define stopsigmask (sigmask(SIGSTOP) | sigmask(SIGTSTP) | \ + sigmask(SIGTTIN) | sigmask(SIGTTOU)) + +#endif /* SIGPROP */ + +#define sigcantmask (sigmask(SIGKILL) | sigmask(SIGSTOP)) + +#ifdef KERNEL +/* + * Machine-independent functions: + */ +void execsigs __P((struct proc *p)); +void gsignal __P((int pgid, int sig)); +int issignal __P((struct proc *p)); +void killproc __P((struct proc *p, char *why)); +void pgsignal __P((struct pgrp *pgrp, int sig, int checkctty)); +void postsig __P((int sig)); +void psignal __P((struct proc *p, int sig)); +void setsigvec __P((struct proc *p, int signum, struct sigaction *sa)); +void sigexit __P((struct proc *p, int signum)); +void siginit __P((struct proc *p)); +void trapsignal __P((struct proc *p, int sig, u_long code)); + +/* + * Machine-dependent functions: + */ +void sendsig __P((sig_t action, int sig, int returnmask, u_long code)); +#endif /* KERNEL */ +#endif /* !_SYS_SIGNALVAR_H_ */ diff --git a/cpukit/libnetworking/sys/socket.h b/cpukit/libnetworking/sys/socket.h new file mode 100644 index 0000000000..7e0f6c7572 --- /dev/null +++ b/cpukit/libnetworking/sys/socket.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1982, 1985, 1986, 1988, 1993, 1994 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)socket.h 8.4 (Berkeley) 2/21/94 + * $Id$ + */ + +#ifndef _SYS_SOCKET_H_ +#define _SYS_SOCKET_H_ + +/* + * Definitions related to sockets: types, address families, options. + */ + +/* + * Types + */ +#define SOCK_STREAM 1 /* stream socket */ +#define SOCK_DGRAM 2 /* datagram socket */ +#define SOCK_RAW 3 /* raw-protocol interface */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequenced packet stream */ + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ +#define SO_TIMESTAMP 0x0400 /* timestamp received dgram traffic */ + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */ + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xffff /* options for socket level */ + +/* + * Address families. + */ +#define AF_UNSPEC 0 /* unspecified */ +#define AF_LOCAL 1 /* local to host (pipes, portals) */ +#define AF_UNIX AF_LOCAL /* backward compatibility */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_IMPLINK 3 /* arpanet imp addresses */ +#define AF_PUP 4 /* pup protocols: e.g. BSP */ +#define AF_CHAOS 5 /* mit CHAOS protocols */ +#define AF_NS 6 /* XEROX NS protocols */ +#define AF_ISO 7 /* ISO protocols */ +#define AF_OSI AF_ISO +#define AF_ECMA 8 /* European computer manufacturers */ +#define AF_DATAKIT 9 /* datakit protocols */ +#define AF_CCITT 10 /* CCITT protocols, X.25 etc */ +#define AF_SNA 11 /* IBM SNA */ +#define AF_DECnet 12 /* DECnet */ +#define AF_DLI 13 /* DEC Direct data link interface */ +#define AF_LAT 14 /* LAT */ +#define AF_HYLINK 15 /* NSC Hyperchannel */ +#define AF_APPLETALK 16 /* Apple Talk */ +#define AF_ROUTE 17 /* Internal Routing Protocol */ +#define AF_LINK 18 /* Link layer interface */ +#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */ +#define AF_COIP 20 /* connection-oriented IP, aka ST II */ +#define AF_CNT 21 /* Computer Network Technology */ +#define pseudo_AF_RTIP 22 /* Help Identify RTIP packets */ +#define AF_IPX 23 /* Novell Internet Protocol */ +#define AF_SIP 24 /* Simple Internet Protocol */ +#define pseudo_AF_PIP 25 /* Help Identify PIP packets */ +#define AF_ISDN 26 /* Integrated Services Digital Network*/ +#define AF_E164 AF_ISDN /* CCITT E.164 recommendation */ +#define pseudo_AF_KEY 27 /* Internal key-management function */ +#define AF_INET6 28 /* IPv6 */ + +#define AF_MAX 29 + +/* + * Structure used by kernel to store most + * addresses. + */ +struct sockaddr { + u_char sa_len; /* total length */ + u_char sa_family; /* address family */ + char sa_data[14]; /* actually longer; address value */ +}; + +/* + * Structure used by kernel to pass protocol + * information in raw sockets. + */ +struct sockproto { + u_short sp_family; /* address family */ + u_short sp_protocol; /* protocol */ +}; + +/* + * Protocol families, same as address families for now. + */ +#define PF_UNSPEC AF_UNSPEC +#define PF_LOCAL AF_LOCAL +#define PF_UNIX PF_LOCAL /* backward compatibility */ +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_ISO AF_ISO +#define PF_OSI AF_ISO +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_ROUTE AF_ROUTE +#define PF_LINK AF_LINK +#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */ +#define PF_COIP AF_COIP +#define PF_CNT AF_CNT +#define PF_SIP AF_SIP +#define PF_IPX AF_IPX /* same format as AF_NS */ +#define PF_RTIP pseudo_AF_RTIP /* same format as AF_INET */ +#define PF_PIP pseudo_AF_PIP +#define PF_ISDN AF_ISDN +#define PF_KEY pseudo_AF_KEY +#define PF_INET6 AF_INET6 + +#define PF_MAX AF_MAX + +/* + * Definitions for network related sysctl, CTL_NET. + * + * Second level is protocol family. + * Third level is protocol number. + * + * Further levels are defined by the individual families below. + */ +#define NET_MAXID AF_MAX + +#define CTL_NET_NAMES { \ + { 0, 0 }, \ + { "unix", CTLTYPE_NODE }, \ + { "inet", CTLTYPE_NODE }, \ + { "implink", CTLTYPE_NODE }, \ + { "pup", CTLTYPE_NODE }, \ + { "chaos", CTLTYPE_NODE }, \ + { "xerox_ns", CTLTYPE_NODE }, \ + { "iso", CTLTYPE_NODE }, \ + { "emca", CTLTYPE_NODE }, \ + { "datakit", CTLTYPE_NODE }, \ + { "ccitt", CTLTYPE_NODE }, \ + { "ibm_sna", CTLTYPE_NODE }, \ + { "decnet", CTLTYPE_NODE }, \ + { "dec_dli", CTLTYPE_NODE }, \ + { "lat", CTLTYPE_NODE }, \ + { "hylink", CTLTYPE_NODE }, \ + { "appletalk", CTLTYPE_NODE }, \ + { "route", CTLTYPE_NODE }, \ + { "link_layer", CTLTYPE_NODE }, \ + { "xtp", CTLTYPE_NODE }, \ + { "coip", CTLTYPE_NODE }, \ + { "cnt", CTLTYPE_NODE }, \ + { "rtip", CTLTYPE_NODE }, \ + { "ipx", CTLTYPE_NODE }, \ + { "sip", CTLTYPE_NODE }, \ + { "pip", CTLTYPE_NODE }, \ + { "isdn", CTLTYPE_NODE }, \ + { "key", CTLTYPE_NODE }, \ +} + +/* + * PF_ROUTE - Routing table + * + * Three additional levels are defined: + * Fourth: address family, 0 is wildcard + * Fifth: type of info, defined below + * Sixth: flag(s) to mask with for NET_RT_FLAGS + */ +#define NET_RT_DUMP 1 /* dump; may limit to a.f. */ +#define NET_RT_FLAGS 2 /* by flags, e.g. RESOLVING */ +#define NET_RT_IFLIST 3 /* survey interface list */ +#define NET_RT_MAXID 4 + +#define CTL_NET_RT_NAMES { \ + { 0, 0 }, \ + { "dump", CTLTYPE_STRUCT }, \ + { "flags", CTLTYPE_STRUCT }, \ + { "iflist", CTLTYPE_STRUCT }, \ +} + +/* + * Maximum queue length specifiable by listen. + */ +#define SOMAXCONN 128 + +/* + * Message header for recvmsg and sendmsg calls. + * Used value-result for recvmsg, value only for sendmsg. + */ +struct msghdr { + caddr_t msg_name; /* optional address */ + u_int msg_namelen; /* size of address */ + struct iovec *msg_iov; /* scatter/gather array */ + u_int msg_iovlen; /* # elements in msg_iov */ + caddr_t msg_control; /* ancillary data, see below */ + u_int msg_controllen; /* ancillary data buffer len */ + int msg_flags; /* flags on received message */ +}; + +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ +#define MSG_EOR 0x8 /* data completes record */ +#define MSG_TRUNC 0x10 /* data discarded before delivery */ +#define MSG_CTRUNC 0x20 /* control data lost before delivery */ +#define MSG_WAITALL 0x40 /* wait for full request or error */ +#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ +#define MSG_EOF 0x100 /* data completes connection */ +#define MSG_COMPAT 0x8000 /* used in sendit() */ + +/* + * Header for ancillary data objects in msg_control buffer. + * Used for additional information with/about a datagram + * not expressible by flags. The format is a sequence + * of message elements headed by cmsghdr structures. + */ +struct cmsghdr { + u_int cmsg_len; /* data byte count, including hdr */ + int cmsg_level; /* originating protocol */ + int cmsg_type; /* protocol-specific type */ +/* followed by u_char cmsg_data[]; */ +}; + +/* given pointer to struct cmsghdr, return pointer to data */ +#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1)) + +/* given pointer to struct cmsghdr, return pointer to next cmsghdr */ +#define CMSG_NXTHDR(mhdr, cmsg) \ + (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \ + (mhdr)->msg_control + (mhdr)->msg_controllen) ? \ + (struct cmsghdr *)NULL : \ + (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len))) + +#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) + +/* "Socket"-level control message types: */ +#define SCM_RIGHTS 0x01 /* access rights (array of int) */ +#define SCM_TIMESTAMP 0x02 /* timestamp (struct timeval) */ + +/* + * 4.3 compat sockaddr, move to compat file later + */ +struct osockaddr { + u_short sa_family; /* address family */ + char sa_data[14]; /* up to 14 bytes of direct address */ +}; + +/* + * 4.3-compat message header (move to compat file later). + */ +struct omsghdr { + caddr_t msg_name; /* optional address */ + int msg_namelen; /* size of address */ + struct iovec *msg_iov; /* scatter/gather array */ + int msg_iovlen; /* # elements in msg_iov */ + caddr_t msg_accrights; /* access rights sent/received */ + int msg_accrightslen; +}; + +#ifndef KERNEL + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int accept __P((int, struct sockaddr *, int *)); +int bind __P((int, const struct sockaddr *, int)); +int connect __P((int, const struct sockaddr *, int)); +int getpeername __P((int, struct sockaddr *, int *)); +int getsockname __P((int, struct sockaddr *, int *)); +int getsockopt __P((int, int, int, void *, int *)); +int listen __P((int, int)); +ssize_t recv __P((int, void *, size_t, int)); +ssize_t recvfrom __P((int, void *, size_t, int, struct sockaddr *, int *)); +ssize_t recvmsg __P((int, struct msghdr *, int)); +ssize_t send __P((int, const void *, size_t, int)); +ssize_t sendto __P((int, const void *, + size_t, int, const struct sockaddr *, int)); +ssize_t sendmsg __P((int, const struct msghdr *, int)); +int setsockopt __P((int, int, int, const void *, int)); +int shutdown __P((int, int)); +int socket __P((int, int, int)); +int socketpair __P((int, int, int, int *)); +__END_DECLS + +#else /* KERNEL */ +void pfctlinput __P((int, struct sockaddr *)); +#endif /* !KERNEL */ +#endif /* !_SYS_SOCKET_H_ */ diff --git a/cpukit/libnetworking/sys/socketvar.h b/cpukit/libnetworking/sys/socketvar.h new file mode 100644 index 0000000000..257fee012b --- /dev/null +++ b/cpukit/libnetworking/sys/socketvar.h @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)socketvar.h 8.3 (Berkeley) 2/19/95 + * $Id$ + */ + +#ifndef _SYS_SOCKETVAR_H_ +#define _SYS_SOCKETVAR_H_ + +#include <sys/queue.h> /* for TAILQ macros */ +#include <sys/select.h> /* for struct selinfo */ + +/* + * Kernel structure per socket. + * Contains send and receive buffer queues, + * handle on protocol and pointer to protocol + * private data and error information. + */ +struct socket { + short so_type; /* generic type, see socket.h */ + short so_options; /* from socket call, see socket.h */ + short so_linger; /* time to linger while closing */ + short so_state; /* internal state flags SS_*, below */ + caddr_t so_pcb; /* protocol control block */ + struct protosw *so_proto; /* protocol handle */ +/* + * Variables for connection queuing. + * Socket where accepts occur is so_head in all subsidiary sockets. + * If so_head is 0, socket is not related to an accept. + * For head socket so_q0 queues partially completed connections, + * while so_q is a queue of connections ready to be accepted. + * If a connection is aborted and it has so_head set, then + * it has to be pulled out of either so_q0 or so_q. + * We allow connections to queue up based on current queue lengths + * and limit on number of queued connections for this socket. + */ + struct socket *so_head; /* back pointer to accept socket */ + TAILQ_HEAD(, socket) so_incomp; /* queue of partial unaccepted connections */ + TAILQ_HEAD(, socket) so_comp; /* queue of complete unaccepted connections */ + TAILQ_ENTRY(socket) so_list; /* list of unaccepted connections */ + short so_qlen; /* number of unaccepted connections */ + short so_incqlen; /* number of unaccepted incomplete + connections */ + short so_qlimit; /* max number queued connections */ + short so_timeo; /* connection timeout */ + u_short so_error; /* error affecting connection */ + pid_t so_pgid; /* pgid for signals */ + u_long so_oobmark; /* chars to oob mark */ +/* + * Variables for socket buffering. + */ + struct sockbuf { + u_long sb_cc; /* actual chars in buffer */ + u_long sb_hiwat; /* max actual char count */ + u_long sb_mbcnt; /* chars of mbufs used */ + u_long sb_mbmax; /* max chars of mbufs to use */ + long sb_lowat; /* low water mark */ + struct mbuf *sb_mb; /* the mbuf chain */ + struct selinfo sb_sel; /* process selecting read/write */ + short sb_flags; /* flags, see below */ + short sb_timeo; /* timeout for read/write */ + } so_rcv, so_snd; +#define SB_MAX (256*1024) /* default for max chars in sockbuf */ +#define SB_LOCK 0x01 /* lock on data queue */ +#define SB_WANT 0x02 /* someone is waiting to lock */ +#define SB_WAIT 0x04 /* someone is waiting for data/space */ +#define SB_SEL 0x08 /* someone is selecting */ +#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ +#define SB_NOTIFY (SB_WAIT|SB_SEL|SB_ASYNC) +#define SB_NOINTR 0x40 /* operations not interruptible */ + + caddr_t so_tpcb; /* Wisc. protocol control block XXX */ + void (*so_upcall) __P((struct socket *so, caddr_t arg, int waitf)); + caddr_t so_upcallarg; /* Arg for above */ + uid_t so_uid; /* who opened the socket */ +}; + +/* + * Socket state bits. + */ +#define SS_NOFDREF 0x0001 /* no file table ref any more */ +#define SS_ISCONNECTED 0x0002 /* socket connected to a peer */ +#define SS_ISCONNECTING 0x0004 /* in process of connecting to peer */ +#define SS_ISDISCONNECTING 0x0008 /* in process of disconnecting */ +#define SS_CANTSENDMORE 0x0010 /* can't send more data to peer */ +#define SS_CANTRCVMORE 0x0020 /* can't receive more data from peer */ +#define SS_RCVATMARK 0x0040 /* at mark on input */ + +#define SS_PRIV 0x0080 /* privileged for broadcast, raw... */ +#define SS_NBIO 0x0100 /* non-blocking ops */ +#define SS_ASYNC 0x0200 /* async i/o notify */ +#define SS_ISCONFIRMING 0x0400 /* deciding to accept connection req */ + +#define SS_INCOMP 0x0800 /* unaccepted, incomplete connection */ +#define SS_COMP 0x1000 /* unaccepted, complete connection */ + + +/* + * Macros for sockets and socket buffering. + */ + +/* + * How much space is there in a socket buffer (so->so_snd or so->so_rcv)? + * This is problematical if the fields are unsigned, as the space might + * still be negative (cc > hiwat or mbcnt > mbmax). Should detect + * overflow and return 0. Should use "lmin" but it doesn't exist now. + */ +#define sbspace(sb) \ + ((long) imin((int)((sb)->sb_hiwat - (sb)->sb_cc), \ + (int)((sb)->sb_mbmax - (sb)->sb_mbcnt))) + +/* do we have to send all at once on a socket? */ +#define sosendallatonce(so) \ + ((so)->so_proto->pr_flags & PR_ATOMIC) + +/* can we read something from so? */ +#define soreadable(so) \ + ((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \ + ((so)->so_state & SS_CANTRCVMORE) || \ + (so)->so_comp.tqh_first || (so)->so_error) + +/* can we write something to so? */ +#define sowriteable(so) \ + ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat && \ + (((so)->so_state&SS_ISCONNECTED) || \ + ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0)) || \ + ((so)->so_state & SS_CANTSENDMORE) || \ + (so)->so_error) + +/* adjust counters in sb reflecting allocation of m */ +#define sballoc(sb, m) { \ + (sb)->sb_cc += (m)->m_len; \ + (sb)->sb_mbcnt += MSIZE; \ + if ((m)->m_flags & M_EXT) \ + (sb)->sb_mbcnt += (m)->m_ext.ext_size; \ +} + +/* adjust counters in sb reflecting freeing of m */ +#define sbfree(sb, m) { \ + (sb)->sb_cc -= (m)->m_len; \ + (sb)->sb_mbcnt -= MSIZE; \ + if ((m)->m_flags & M_EXT) \ + (sb)->sb_mbcnt -= (m)->m_ext.ext_size; \ +} + +/* + * Set lock on sockbuf sb; sleep if lock is already held. + * Unless SB_NOINTR is set on sockbuf, sleep is interruptible. + * Returns error without lock if sleep is interrupted. + */ +#define sblock(sb, wf) ((sb)->sb_flags & SB_LOCK ? \ + (((wf) == M_WAITOK) ? sb_lock(sb) : EWOULDBLOCK) : \ + ((sb)->sb_flags |= SB_LOCK), 0) + +/* release lock on sockbuf sb */ +#define sbunlock(sb) { \ + (sb)->sb_flags &= ~SB_LOCK; \ + if ((sb)->sb_flags & SB_WANT) { \ + (sb)->sb_flags &= ~SB_WANT; \ + wakeup((caddr_t)&(sb)->sb_flags); \ + } \ +} + +#define sorwakeup(so) { sowakeup((so), &(so)->so_rcv); \ + if ((so)->so_upcall) \ + (*((so)->so_upcall))((so), (so)->so_upcallarg, M_DONTWAIT); \ + } + +#define sowwakeup(so) sowakeup((so), &(so)->so_snd) + +#ifdef KERNEL +extern u_long sb_max; + +/* to catch callers missing new second argument to sonewconn: */ +#define sonewconn(head, connstatus) sonewconn1((head), (connstatus)) + +struct filedesc; +struct mbuf; +struct sockaddr; +struct stat; + +/* + * File operations on sockets. + */ +int soo_ioctl __P((struct file *fp, int cmd, caddr_t data, + struct proc *p)); +int soo_select __P((struct file *fp, int which, struct proc *p)); +int soo_stat __P((struct socket *so, struct stat *ub)); + +/* + * From uipc_socket and friends + */ +int getsock __P((struct filedesc *fdp, int fdes, struct file **fpp)); +int sockargs __P((struct mbuf **mp, caddr_t buf, int buflen, int type)); +void sbappend __P((struct sockbuf *sb, struct mbuf *m)); +int sbappendaddr __P((struct sockbuf *sb, struct sockaddr *asa, + struct mbuf *m0, struct mbuf *control)); +int sbappendcontrol __P((struct sockbuf *sb, struct mbuf *m0, + struct mbuf *control)); +void sbappendrecord __P((struct sockbuf *sb, struct mbuf *m0)); +void sbcheck __P((struct sockbuf *sb)); +void sbcompress __P((struct sockbuf *sb, struct mbuf *m, struct mbuf *n)); +struct mbuf * + sbcreatecontrol __P((caddr_t p, int size, int type, int level)); +void sbdrop __P((struct sockbuf *sb, int len)); +void sbdroprecord __P((struct sockbuf *sb)); +void sbflush __P((struct sockbuf *sb)); +void sbinsertoob __P((struct sockbuf *sb, struct mbuf *m0)); +void sbrelease __P((struct sockbuf *sb)); +int sbreserve __P((struct sockbuf *sb, u_long cc)); +int sbwait __P((struct sockbuf *sb)); +int sb_lock __P((struct sockbuf *sb)); +int soabort __P((struct socket *so)); +int soaccept __P((struct socket *so, struct mbuf *nam)); +int sobind __P((struct socket *so, struct mbuf *nam)); +void socantrcvmore __P((struct socket *so)); +void socantsendmore __P((struct socket *so)); +int soclose __P((struct socket *so)); +int soconnect __P((struct socket *so, struct mbuf *nam)); +int soconnect2 __P((struct socket *so1, struct socket *so2)); +int socreate __P((int dom, struct socket **aso, int type, int proto, + struct proc *p)); +int sodisconnect __P((struct socket *so)); +void sofree __P((struct socket *so)); +int sogetopt __P((struct socket *so, int level, int optname, + struct mbuf **mp)); +void sohasoutofband __P((struct socket *so)); +void soisconnected __P((struct socket *so)); +void soisconnecting __P((struct socket *so)); +void soisdisconnected __P((struct socket *so)); +void soisdisconnecting __P((struct socket *so)); +int solisten __P((struct socket *so, int backlog)); +struct socket * + sodropablereq __P((struct socket *head)); +struct socket * + sonewconn1 __P((struct socket *head, int connstatus)); +int soreceive __P((struct socket *so, struct mbuf **paddr, struct uio *uio, + struct mbuf **mp0, struct mbuf **controlp, int *flagsp)); +int soreserve __P((struct socket *so, u_long sndcc, u_long rcvcc)); +void sorflush __P((struct socket *so)); +int sosend __P((struct socket *so, struct mbuf *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags)); +int sosetopt __P((struct socket *so, int level, int optname, + struct mbuf *m0)); +int soshutdown __P((struct socket *so, int how)); +void sowakeup __P((struct socket *so, struct sockbuf *sb)); +#endif /* KERNEL */ + +#endif /* !_SYS_SOCKETVAR_H_ */ diff --git a/cpukit/libnetworking/sys/sysctl.h b/cpukit/libnetworking/sys/sysctl.h new file mode 100644 index 0000000000..b25ba43c4f --- /dev/null +++ b/cpukit/libnetworking/sys/sysctl.h @@ -0,0 +1,379 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Karels at Berkeley Software Design, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)sysctl.h 8.1 (Berkeley) 6/2/93 + * $Id$ + */ + +#ifndef _SYS_SYSCTL_H_ +#define _SYS_SYSCTL_H_ + +/* + * Definitions for sysctl call. The sysctl call uses a hierarchical name + * for objects that can be examined or modified. The name is expressed as + * a sequence of integers. Like a file path name, the meaning of each + * component depends on its place in the hierarchy. The top-level and kern + * identifiers are defined here, and other identifiers are defined in the + * respective subsystem header files. + */ + +#define CTL_MAXNAME 12 /* largest number of components supported */ + +/* + * Each subsystem defined by sysctl defines a list of variables + * for that subsystem. Each name is either a node with further + * levels defined below it, or it is a leaf of some particular + * type given below. Each sysctl level defines a set of name/type + * pairs to be used by sysctl(1) in manipulating the subsystem. + */ +struct ctlname { + char *ctl_name; /* subsystem name */ + int ctl_type; /* type of name */ +}; + +#define CTLTYPE 0xf /* Mask for the type */ +#define CTLTYPE_NODE 1 /* name is a node */ +#define CTLTYPE_INT 2 /* name describes an integer */ +#define CTLTYPE_STRING 3 /* name describes a string */ +#define CTLTYPE_QUAD 4 /* name describes a 64-bit number */ +#define CTLTYPE_OPAQUE 5 /* name describes a structure */ +#define CTLTYPE_STRUCT CTLTYPE_OPAQUE /* name describes a structure */ + +#define CTLFLAG_RD 0x80000000 /* Allow reads of variable */ +#define CTLFLAG_WR 0x40000000 /* Allow writes to the variable */ +#define CTLFLAG_RW (CTLFLAG_RD|CTLFLAG_WR) +#define CTLFLAG_NOLOCK 0x20000000 /* XXX Don't Lock */ +#define CTLFLAG_ANYBODY 0x10000000 /* All users can set this var */ + +/* + * USE THIS instead of a hardwired number from the categories below + * to get dynamically assigned sysctl entries using the linker-set + * technology. This is the way nearly all new sysctl variables should + * be implimented. + * e.g. SYSCTL_INT(_parent, OID_AUTO, name, CTLFLAG_RW, &variable, 0, ""); + */ +#define OID_AUTO (-1) + +#ifdef KERNEL +#define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, void *arg1, int arg2, \ + struct sysctl_req *req) + +/* + * This describes the access space for a sysctl request. This is needed + * so that we can use the interface from the kernel or from user-space. + */ +struct sysctl_req { + struct proc *p; + int lock; + void *oldptr; + int oldlen; + int oldidx; + int (*oldfunc)(struct sysctl_req *, const void *, int); + void *newptr; + int newlen; + int newidx; + int (*newfunc)(struct sysctl_req *, void *, int); +}; + +/* + * This describes one "oid" in the MIB tree. Potentially more nodes can + * be hidden behind it, expanded by the handler. + */ +struct sysctl_oid { + int oid_number; + int oid_kind; + void *oid_arg1; + int oid_arg2; + const char *oid_name; + int (*oid_handler) SYSCTL_HANDLER_ARGS; + const char *oid_fmt; +}; + +#define SYSCTL_IN(r, p, l) +#define SYSCTL_OUT(r, p, l) + +int sysctl_handle_int SYSCTL_HANDLER_ARGS; +int sysctl_handle_string SYSCTL_HANDLER_ARGS; +int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; + +/* This is the "raw" function for a mib-oid */ +#define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) + +/* This makes a node from which other oids can hang */ +#define SYSCTL_NODE(parent, nbr, name, access, handler, descr) + +/* This is a string len can be 0 to indicate '\0' termination */ +#define SYSCTL_STRING(parent, nbr, name, access, arg, len, descr) + +/* This is a integer, if ptr is NULL, val is returned */ +#define SYSCTL_INT(parent, nbr, name, access, ptr, val, descr) + +/* This is anything, specified by a pointer and a lenth */ +#define SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr) + +/* This is a struct, specified by a pointer and type */ +#define SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr) + +/* Needs a proc. Specify by pointer and arg */ +#define SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) +#endif /* KERNEL */ + +/* + * Top-level identifiers + */ +#define CTL_UNSPEC 0 /* unused */ +#define CTL_KERN 1 /* "high kernel": proc, limits */ +#define CTL_VM 2 /* virtual memory */ +#define CTL_VFS 3 /* file system, mount type is next */ +#define CTL_NET 4 /* network, see socket.h */ +#define CTL_DEBUG 5 /* debugging parameters */ +#define CTL_HW 6 /* generic cpu/io */ +#define CTL_MACHDEP 7 /* machine dependent */ +#define CTL_USER 8 /* user-level */ +#define CTL_MAXID 9 /* number of valid top-level ids */ + +#define CTL_NAMES { \ + { 0, 0 }, \ + { "kern", CTLTYPE_NODE }, \ + { "vm", CTLTYPE_NODE }, \ + { "vfs", CTLTYPE_NODE }, \ + { "net", CTLTYPE_NODE }, \ + { "debug", CTLTYPE_NODE }, \ + { "hw", CTLTYPE_NODE }, \ + { "machdep", CTLTYPE_NODE }, \ + { "user", CTLTYPE_NODE }, \ +} + +/* + * CTL_KERN identifiers + */ +#define KERN_OSTYPE 1 /* string: system version */ +#define KERN_OSRELEASE 2 /* string: system release */ +#define KERN_OSREV 3 /* int: system revision */ +#define KERN_VERSION 4 /* string: compile time info */ +#define KERN_MAXVNODES 5 /* int: max vnodes */ +#define KERN_MAXPROC 6 /* int: max processes */ +#define KERN_MAXFILES 7 /* int: max open files */ +#define KERN_ARGMAX 8 /* int: max arguments to exec */ +#define KERN_SECURELVL 9 /* int: system security level */ +#define KERN_HOSTNAME 10 /* string: hostname */ +#define KERN_HOSTID 11 /* int: host identifier */ +#define KERN_CLOCKRATE 12 /* struct: struct clockrate */ +#define KERN_VNODE 13 /* struct: vnode structures */ +#define KERN_PROC 14 /* struct: process entries */ +#define KERN_FILE 15 /* struct: file entries */ +#define KERN_PROF 16 /* node: kernel profiling info */ +#define KERN_POSIX1 17 /* int: POSIX.1 version */ +#define KERN_NGROUPS 18 /* int: # of supplemental group ids */ +#define KERN_JOB_CONTROL 19 /* int: is job control available */ +#define KERN_SAVED_IDS 20 /* int: saved set-user/group-ID */ +#define KERN_BOOTTIME 21 /* struct: time kernel was booted */ +#define KERN_NISDOMAINNAME 22 /* string: YP domain name */ +#define KERN_UPDATEINTERVAL 23 /* int: update process sleep time */ +#define KERN_OSRELDATE 24 /* int: OS release date */ +#define KERN_NTP_PLL 25 /* node: NTP PLL control */ +#define KERN_BOOTFILE 26 /* string: name of booted kernel */ +#define KERN_MAXFILESPERPROC 27 /* int: max open files per proc */ +#define KERN_MAXPROCPERUID 28 /* int: max processes per uid */ +#define KERN_DUMPDEV 29 /* dev_t: device to dump on */ +#define KERN_SOMAXCONN 30 /* int: max connections in listen q */ +#define KERN_MAXSOCKBUF 31 /* int: max size of a socket buffer */ +#define KERN_PS_STRINGS 32 /* int: address of PS_STRINGS */ +#define KERN_USRSTACK 33 /* int: address of USRSTACK */ +#define KERN_MAXID 34 /* number of valid kern ids */ + +#define CTL_KERN_NAMES { \ + { 0, 0 }, \ + { "ostype", CTLTYPE_STRING }, \ + { "osrelease", CTLTYPE_STRING }, \ + { "osrevision", CTLTYPE_INT }, \ + { "version", CTLTYPE_STRING }, \ + { "maxvnodes", CTLTYPE_INT }, \ + { "maxproc", CTLTYPE_INT }, \ + { "maxfiles", CTLTYPE_INT }, \ + { "argmax", CTLTYPE_INT }, \ + { "securelevel", CTLTYPE_INT }, \ + { "hostname", CTLTYPE_STRING }, \ + { "hostid", CTLTYPE_INT }, \ + { "clockrate", CTLTYPE_STRUCT }, \ + { "vnode", CTLTYPE_STRUCT }, \ + { "proc", CTLTYPE_STRUCT }, \ + { "file", CTLTYPE_STRUCT }, \ + { "profiling", CTLTYPE_NODE }, \ + { "posix1version", CTLTYPE_INT }, \ + { "ngroups", CTLTYPE_INT }, \ + { "job_control", CTLTYPE_INT }, \ + { "saved_ids", CTLTYPE_INT }, \ + { "boottime", CTLTYPE_STRUCT }, \ + { "nisdomainname", CTLTYPE_STRING }, \ + { "update", CTLTYPE_INT }, \ + { "osreldate", CTLTYPE_INT }, \ + { "ntp_pll", CTLTYPE_NODE }, \ + { "bootfile", CTLTYPE_STRING }, \ + { "maxfilesperproc", CTLTYPE_INT }, \ + { "maxprocperuid", CTLTYPE_INT }, \ + { "dumpdev", CTLTYPE_STRUCT }, /* we lie; don't print as int */ \ + { "somaxconn", CTLTYPE_INT }, \ + { "maxsockbuf", CTLTYPE_INT }, \ + { "ps_strings", CTLTYPE_INT }, \ + { "usrstack", CTLTYPE_INT }, \ +} + +/* + * CTL_VFS identifiers + */ +#define VFS_VFSCONF 0 /* get configured filesystems */ +#define VFS_MAXID 1 /* number of items */ + +#define CTL_VFS_NAMES { \ + { "vfsconf", CTLTYPE_STRUCT }, \ +} + +/* + * KERN_PROC subtypes + */ +#define KERN_PROC_ALL 0 /* everything */ +#define KERN_PROC_PID 1 /* by process id */ +#define KERN_PROC_PGRP 2 /* by process group id */ +#define KERN_PROC_SESSION 3 /* by session of pid */ +#define KERN_PROC_TTY 4 /* by controlling tty */ +#define KERN_PROC_UID 5 /* by effective uid */ +#define KERN_PROC_RUID 6 /* by real uid */ + +/* + * CTL_HW identifiers + */ +#define HW_MACHINE 1 /* string: machine class */ +#define HW_MODEL 2 /* string: specific machine model */ +#define HW_NCPU 3 /* int: number of cpus */ +#define HW_BYTEORDER 4 /* int: machine byte order */ +#define HW_PHYSMEM 5 /* int: total memory */ +#define HW_USERMEM 6 /* int: non-kernel memory */ +#define HW_PAGESIZE 7 /* int: software page size */ +#define HW_DISKNAMES 8 /* strings: disk drive names */ +#define HW_DISKSTATS 9 /* struct: diskstats[] */ +#define HW_FLOATINGPT 10 /* int: has HW floating point? */ +#define HW_MACHINE_ARCH 11 /* string: machine architecture */ +#define HW_MAXID 12 /* number of valid hw ids */ + +#define CTL_HW_NAMES { \ + { 0, 0 }, \ + { "machine", CTLTYPE_STRING }, \ + { "model", CTLTYPE_STRING }, \ + { "ncpu", CTLTYPE_INT }, \ + { "byteorder", CTLTYPE_INT }, \ + { "physmem", CTLTYPE_INT }, \ + { "usermem", CTLTYPE_INT }, \ + { "pagesize", CTLTYPE_INT }, \ + { "disknames", CTLTYPE_STRUCT }, \ + { "diskstats", CTLTYPE_STRUCT }, \ + { "floatingpoint", CTLTYPE_INT }, \ +} + +/* + * CTL_USER definitions + */ +#define USER_CS_PATH 1 /* string: _CS_PATH */ +#define USER_BC_BASE_MAX 2 /* int: BC_BASE_MAX */ +#define USER_BC_DIM_MAX 3 /* int: BC_DIM_MAX */ +#define USER_BC_SCALE_MAX 4 /* int: BC_SCALE_MAX */ +#define USER_BC_STRING_MAX 5 /* int: BC_STRING_MAX */ +#define USER_COLL_WEIGHTS_MAX 6 /* int: COLL_WEIGHTS_MAX */ +#define USER_EXPR_NEST_MAX 7 /* int: EXPR_NEST_MAX */ +#define USER_LINE_MAX 8 /* int: LINE_MAX */ +#define USER_RE_DUP_MAX 9 /* int: RE_DUP_MAX */ +#define USER_POSIX2_VERSION 10 /* int: POSIX2_VERSION */ +#define USER_POSIX2_C_BIND 11 /* int: POSIX2_C_BIND */ +#define USER_POSIX2_C_DEV 12 /* int: POSIX2_C_DEV */ +#define USER_POSIX2_CHAR_TERM 13 /* int: POSIX2_CHAR_TERM */ +#define USER_POSIX2_FORT_DEV 14 /* int: POSIX2_FORT_DEV */ +#define USER_POSIX2_FORT_RUN 15 /* int: POSIX2_FORT_RUN */ +#define USER_POSIX2_LOCALEDEF 16 /* int: POSIX2_LOCALEDEF */ +#define USER_POSIX2_SW_DEV 17 /* int: POSIX2_SW_DEV */ +#define USER_POSIX2_UPE 18 /* int: POSIX2_UPE */ +#define USER_STREAM_MAX 19 /* int: POSIX2_STREAM_MAX */ +#define USER_TZNAME_MAX 20 /* int: POSIX2_TZNAME_MAX */ +#define USER_MAXID 21 /* number of valid user ids */ + +#define CTL_USER_NAMES { \ + { 0, 0 }, \ + { "cs_path", CTLTYPE_STRING }, \ + { "bc_base_max", CTLTYPE_INT }, \ + { "bc_dim_max", CTLTYPE_INT }, \ + { "bc_scale_max", CTLTYPE_INT }, \ + { "bc_string_max", CTLTYPE_INT }, \ + { "coll_weights_max", CTLTYPE_INT }, \ + { "expr_nest_max", CTLTYPE_INT }, \ + { "line_max", CTLTYPE_INT }, \ + { "re_dup_max", CTLTYPE_INT }, \ + { "posix2_version", CTLTYPE_INT }, \ + { "posix2_c_bind", CTLTYPE_INT }, \ + { "posix2_c_dev", CTLTYPE_INT }, \ + { "posix2_char_term", CTLTYPE_INT }, \ + { "posix2_fort_dev", CTLTYPE_INT }, \ + { "posix2_fort_run", CTLTYPE_INT }, \ + { "posix2_localedef", CTLTYPE_INT }, \ + { "posix2_sw_dev", CTLTYPE_INT }, \ + { "posix2_upe", CTLTYPE_INT }, \ + { "stream_max", CTLTYPE_INT }, \ + { "tzname_max", CTLTYPE_INT }, \ +} + +#ifdef KERNEL + +extern char cpu_model[]; +extern char machine[]; +extern char osrelease[]; +extern char ostype[]; + +int kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, int *retval); +int userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval); +/* +int sysctl_clockrate __P((char *, size_t*)); +int sysctl_file __P((char *, size_t*)); +int sysctl_doproc __P((int *, u_int, char *, size_t*)); +int sysctl_doprof __P((int *, u_int, void *, size_t *, void *, size_t)); +*/ + +#else /* !KERNEL */ +#include <sys/cdefs.h> + +__BEGIN_DECLS +int sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); +int sysctlbyname __P((const char *, void *, size_t *, void *, size_t)); +__END_DECLS +#endif /* KERNEL */ + +#endif /* !_SYS_SYSCTL_H_ */ diff --git a/cpukit/libnetworking/sys/syslimits.h b/cpukit/libnetworking/sys/syslimits.h new file mode 100644 index 0000000000..3546e6b1d3 --- /dev/null +++ b/cpukit/libnetworking/sys/syslimits.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)syslimits.h 8.1 (Berkeley) 6/2/93 + * $Id$ + */ + +#ifndef _SYS_SYSLIMITS_H_ +#define _SYS_SYSLIMITS_H_ + +#define ARG_MAX 65536 /* max bytes for an exec function */ +#ifndef CHILD_MAX +#define CHILD_MAX 40 /* max simultaneous processes */ +#endif +#define LINK_MAX 32767 /* max file link count */ +#define MAX_CANON 255 /* max bytes in term canon input line */ +#define MAX_INPUT 255 /* max bytes in terminal input */ +#define NAME_MAX 255 /* max bytes in a file name */ +#define NGROUPS_MAX 16 /* max supplemental group id's */ +#ifndef OPEN_MAX +#define OPEN_MAX 64 /* max open files per process */ +#endif +#define PATH_MAX 1024 /* max bytes in pathname */ +#define PIPE_BUF 512 /* max bytes for atomic pipe writes */ + +#define BC_BASE_MAX 99 /* max ibase/obase values in bc(1) */ +#define BC_DIM_MAX 2048 /* max array elements in bc(1) */ +#define BC_SCALE_MAX 99 /* max scale value in bc(1) */ +#define BC_STRING_MAX 1000 /* max const string length in bc(1) */ +#define COLL_WEIGHTS_MAX 0 /* max weights for order keyword */ +#define EXPR_NEST_MAX 32 /* max expressions nested in expr(1) */ +#define LINE_MAX 2048 /* max bytes in an input line */ +#define RE_DUP_MAX 255 /* max RE's in interval notation */ + +#endif diff --git a/cpukit/libnetworking/sys/syslog.h b/cpukit/libnetworking/sys/syslog.h new file mode 100644 index 0000000000..724bee62c7 --- /dev/null +++ b/cpukit/libnetworking/sys/syslog.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)syslog.h 8.1 (Berkeley) 6/2/93 + * $Id$ + */ + +#ifndef _SYS_SYSLOG_H_ +#define _SYS_SYSLOG_H_ + +#define _PATH_LOG "/var/run/log" +#define _PATH_OLDLOG "/dev/log" /* backward compatibility */ + +/* + * priorities/facilities are encoded into a single 32-bit quantity, where the + * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility + * (0-big number). Both the priorities and the facilities map roughly + * one-to-one to strings in the syslogd(8) source code. This mapping is + * included in this file. + * + * priorities (these are ordered) + */ +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ + /* extract priority */ +#define LOG_PRI(p) ((p) & LOG_PRIMASK) +#define LOG_MAKEPRI(fac, pri) ((fac) | (pri)) + +#ifdef SYSLOG_NAMES +#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */ + /* mark "facility" */ +#define INTERNAL_MARK LOG_MAKEPRI((LOG_NFACILITIES<<3), 0) +typedef struct _code { + char *c_name; + int c_val; +} CODE; + +CODE prioritynames[] = { + { "alert", LOG_ALERT, }, + { "crit", LOG_CRIT, }, + { "debug", LOG_DEBUG, }, + { "emerg", LOG_EMERG, }, + { "err", LOG_ERR, }, + { "error", LOG_ERR, }, /* DEPRECATED */ + { "info", LOG_INFO, }, + { "none", INTERNAL_NOPRI, }, /* INTERNAL */ + { "notice", LOG_NOTICE, }, + { "panic", LOG_EMERG, }, /* DEPRECATED */ + { "warn", LOG_WARNING, }, /* DEPRECATED */ + { "warning", LOG_WARNING, }, + { NULL, -1, } +}; +#endif + +/* facility codes */ +#define LOG_KERN (0<<3) /* kernel messages */ +#define LOG_USER (1<<3) /* random user-level messages */ +#define LOG_MAIL (2<<3) /* mail system */ +#define LOG_DAEMON (3<<3) /* system daemons */ +#define LOG_AUTH (4<<3) /* security/authorization messages */ +#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ +#define LOG_LPR (6<<3) /* line printer subsystem */ +#define LOG_NEWS (7<<3) /* network news subsystem */ +#define LOG_UUCP (8<<3) /* UUCP subsystem */ +#define LOG_CRON (9<<3) /* clock daemon */ +#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ + /* Facility #10 clashes in DEC UNIX, where */ + /* it's defined as LOG_MEGASAFE for AdvFS */ + /* event logging. */ +#define LOG_FTP (11<<3) /* ftp daemon */ +#define LOG_NTP (12<<3) /* NTP subsystem */ + + /* other codes through 15 reserved for system use */ +#define LOG_LOCAL0 (16<<3) /* reserved for local use */ +#define LOG_LOCAL1 (17<<3) /* reserved for local use */ +#define LOG_LOCAL2 (18<<3) /* reserved for local use */ +#define LOG_LOCAL3 (19<<3) /* reserved for local use */ +#define LOG_LOCAL4 (20<<3) /* reserved for local use */ +#define LOG_LOCAL5 (21<<3) /* reserved for local use */ +#define LOG_LOCAL6 (22<<3) /* reserved for local use */ +#define LOG_LOCAL7 (23<<3) /* reserved for local use */ + +#define LOG_NFACILITIES 24 /* current number of facilities */ +#define LOG_FACMASK 0x03f8 /* mask to extract facility part */ + /* facility of pri */ +#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) + +#ifdef SYSLOG_NAMES +CODE facilitynames[] = { + { "auth", LOG_AUTH, }, + { "authpriv", LOG_AUTHPRIV, }, + { "cron", LOG_CRON, }, + { "daemon", LOG_DAEMON, }, + { "ftp", LOG_FTP, }, + { "kern", LOG_KERN, }, + { "lpr", LOG_LPR, }, + { "mail", LOG_MAIL, }, + { "mark", INTERNAL_MARK, }, /* INTERNAL */ + { "news", LOG_NEWS, }, + { "ntp", LOG_NTP, }, + { "security", LOG_AUTH, }, /* DEPRECATED */ + { "syslog", LOG_SYSLOG, }, + { "user", LOG_USER, }, + { "uucp", LOG_UUCP, }, + { "local0", LOG_LOCAL0, }, + { "local1", LOG_LOCAL1, }, + { "local2", LOG_LOCAL2, }, + { "local3", LOG_LOCAL3, }, + { "local4", LOG_LOCAL4, }, + { "local5", LOG_LOCAL5, }, + { "local6", LOG_LOCAL6, }, + { "local7", LOG_LOCAL7, }, + { NULL, -1, } +}; +#endif + +#ifdef KERNEL +#define LOG_PRINTF -1 /* pseudo-priority to indicate use of printf */ +#endif + +/* + * arguments to setlogmask. + */ +#define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */ +#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */ + +/* + * Option flags for openlog. + * + * LOG_ODELAY no longer does anything. + * LOG_NDELAY is the inverse of what it used to be. + */ +#define LOG_PID 0x01 /* log the pid with each message */ +#define LOG_CONS 0x02 /* log on the console if errors in sending */ +#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */ +#define LOG_NDELAY 0x08 /* don't delay open */ +#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ +#define LOG_PERROR 0x20 /* log to stderr as well */ + +#ifdef KERNEL + +#else /* not KERNEL */ + +#include <sys/cdefs.h> +#include <stdarg.h> + +__BEGIN_DECLS +void closelog __P((void)); +void openlog __P((const char *, int, int)); +int setlogmask __P((int)); +void syslog __P((int, const char *, ...)); +void vsyslog __P((int, const char *, va_list)); +__END_DECLS + +#endif /* !KERNEL */ + +#endif diff --git a/cpukit/libnetworking/sys/systm.h b/cpukit/libnetworking/sys/systm.h new file mode 100644 index 0000000000..7e14867e70 --- /dev/null +++ b/cpukit/libnetworking/sys/systm.h @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 1982, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)systm.h 8.7 (Berkeley) 3/29/95 + * $Id$ + */ + +#ifndef _SYS_SYSTM_H_ +#define _SYS_SYSTM_H_ + +#include <machine/cpufunc.h> + +extern int securelevel; /* system security level (see init(8)) */ + +extern int cold; /* nonzero if we are doing a cold boot */ +extern const char *panicstr; /* panic message */ +extern char version[]; /* system version */ +extern char copyright[]; /* system copyright */ + +extern int nblkdev; /* number of entries in bdevsw */ +extern int nchrdev; /* number of entries in cdevsw */ +extern struct swdevt *swdevt; /* swap-device information */ +extern int nswdev; /* number of swap devices */ +extern int nswap; /* size of swap space */ + +extern int selwait; /* select timeout address */ + +extern u_char curpriority; /* priority of current process */ + +extern int physmem; /* physical memory */ + +extern dev_t dumpdev; /* dump device */ +extern long dumplo; /* offset into dumpdev */ + +extern dev_t rootdev; /* root device */ +extern struct vnode *rootvp; /* vnode equivalent to above */ + +extern dev_t swapdev; /* swapping device */ +extern struct vnode *swapdev_vp;/* vnode equivalent to above */ + +extern int boothowto; /* reboot flags, from console subsystem */ +extern int bootverbose; /* nonzero to print verbose messages */ + +/* + * General function declarations. + */ +void Debugger __P((const char *msg)); +int nullop __P((void)); +int eopnotsupp __P((void)); +int einval __P((void)); +int seltrue __P((dev_t dev, int which, struct proc *p)); +int ureadc __P((int, struct uio *)); +void *hashinit __P((int count, int type, u_long *hashmask)); +void *phashinit __P((int count, int type, u_long *nentries)); + +void panic __P((const char *, ...)) __dead2; +void boot __P((int)) __dead2; +void cpu_boot __P((int)); +void tablefull __P((const char *)); +int addlog __P((const char *, ...)); +int kvprintf __P((char const *, void (*)(int, void*), void *, int, + _BSD_VA_LIST_)); +void log __P((int, const char *, ...)); +int printf __P((const char *, ...)); +int sprintf __P((char *buf, const char *, ...)); +void uprintf __P((const char *, ...)); +void ttyprintf __P((struct tty *, const char *, ...)); + +#define bcopy(f,t,n) memcpy((t),(f),(n)) +#define bzero(p,n) memset((p),(0),(n)) + +int copystr __P((const void *kfaddr, void *kdaddr, size_t len, + size_t *lencopied)); +int copyinstr __P((const void *udaddr, void *kaddr, size_t len, + size_t *lencopied)); +int copyin __P((const void *udaddr, void *kaddr, size_t len)); +int copyout __P((const void *kaddr, void *udaddr, size_t len)); + +int fubyte __P((const void *base)); +int fuibyte __P((const void *base)); +int subyte __P((void *base, int byte)); +int suibyte __P((void *base, int byte)); +int fuword __P((const void *base)); +int suword __P((void *base, int word)); +int susword __P((void *base, int word)); + +int hzto __P((struct timeval *tv)); +void realitexpire __P((void *)); + +struct clockframe; +void hardclock __P((struct clockframe *frame)); +void softclock __P((void)); +void statclock __P((struct clockframe *frame)); + +void startprofclock __P((struct proc *)); +void stopprofclock __P((struct proc *)); +void setstatclockrate __P((int hzrate)); + +void hardupdate __P((long)); +void hardpps __P((struct timeval *tvp, long usec)); + +#include <sys/libkern.h> + +/* Initialize the world */ +extern void consinit(void); +extern void usrinfoinit(void); +extern void cpu_initclocks(void); +extern void vntblinit(void); +extern void nchinit(void); + +/* Finalize the world. */ +void shutdown_nice __P((void)); + +/* + * Kernel to clock driver interface. + */ +void inittodr __P((time_t base)); +void resettodr __P((void)); +void startrtclock __P((void)); + +/* Timeouts */ +typedef void (timeout_t)(void *); /* actual timeout function type */ +typedef timeout_t *timeout_func_t; /* a pointer to this type */ + +void timeout(timeout_func_t, void *, int); +void untimeout(timeout_func_t, void *); +void logwakeup __P((void)); + +/* Various other callout lists that modules might want to know about */ +/* shutdown callout list definitions */ +typedef void (*bootlist_fn)(int,void *); +int at_shutdown(bootlist_fn function, void *arg, int); +int rm_at_shutdown(bootlist_fn function, void *arg); +#define SHUTDOWN_PRE_SYNC 0 +#define SHUTDOWN_POST_SYNC 1 + +/* forking */ /* XXX not yet */ +typedef void (*forklist_fn)(struct proc *parent,struct proc *child,int flags); +int at_fork(forklist_fn function); +int rm_at_fork(forklist_fn function); + +/* exiting */ +typedef void (*exitlist_fn)(struct proc *procp); +int at_exit(exitlist_fn function); +int rm_at_exit(exitlist_fn function); + +/* Not exactly a callout LIST, but a callout entry.. */ +/* Allow an external module to define a hardware watchdog tickler */ +/* Normally a process would do this, but there are times when the */ +/* kernel needs to be able to hold off the watchdog, when the process */ +/* is not active, e.g. when dumping core. Costs us a whole 4 bytes to */ +/* make this generic. the variable is in kern_shutdown.c */ +typedef void (*watchdog_tickle_fn)(void); +extern watchdog_tickle_fn wdog_tickler; + + +/* + * Common `proc' functions are declared here so that proc.h can be included + * less often. + */ +int tsleep __P((void *chan, int pri, char *wmesg, int timo)); +void wakeup __P((void *chan)); + +#endif /* !_SYS_SYSTM_H_ */ diff --git a/cpukit/libnetworking/sys/ttydefaults.h b/cpukit/libnetworking/sys/ttydefaults.h new file mode 100644 index 0000000000..68f0ddbe77 --- /dev/null +++ b/cpukit/libnetworking/sys/ttydefaults.h @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ttydefaults.h 8.4 (Berkeley) 1/21/94 + * $Id$ + */ + +/* + * System wide defaults for terminal state. + */ +#ifndef _SYS_TTYDEFAULTS_H_ +#define _SYS_TTYDEFAULTS_H_ + +/* + * Defaults on "first" open. + */ +#define TTYDEF_IFLAG (BRKINT | ICRNL | IMAXBEL | IXON | IXANY) +#define TTYDEF_OFLAG (OPOST | ONLCR) +#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL) +#define TTYDEF_CFLAG (CREAD | CS8 | HUPCL) +#define TTYDEF_SPEED (B9600) + +/* + * Control Character Defaults + */ +#define CTRL(x) (x&037) +#define CEOF CTRL('d') +#define CEOL 0xff /* XXX avoid _POSIX_VDISABLE */ +#define CERASE 0177 +#define CINTR CTRL('c') +#define CSTATUS CTRL('t') +#define CKILL CTRL('u') +#define CMIN 1 +#define CQUIT 034 /* FS, ^\ */ +#define CSUSP CTRL('z') +#define CTIME 0 +#define CDSUSP CTRL('y') +#define CSTART CTRL('q') +#define CSTOP CTRL('s') +#define CLNEXT CTRL('v') +#define CDISCARD CTRL('o') +#define CWERASE CTRL('w') +#define CREPRINT CTRL('r') +#define CEOT CEOF +/* compat */ +#define CBRK CEOL +#define CRPRNT CREPRINT +#define CFLUSH CDISCARD + +/* PROTECTED INCLUSION ENDS HERE */ +#endif /* !_SYS_TTYDEFAULTS_H_ */ + +/* + * #define TTYDEFCHARS to include an array of default control characters. + */ +#ifdef TTYDEFCHARS +static cc_t ttydefchars[NCCS] = { + CEOF, CEOL, CEOL, CERASE, CWERASE, CKILL, CREPRINT, + _POSIX_VDISABLE, CINTR, CQUIT, CSUSP, CDSUSP, CSTART, CSTOP, CLNEXT, + CDISCARD, CMIN, CTIME, CSTATUS, _POSIX_VDISABLE +}; +#undef TTYDEFCHARS +#endif diff --git a/cpukit/libnetworking/sys/ucred.h b/cpukit/libnetworking/sys/ucred.h new file mode 100644 index 0000000000..d3899c3b4c --- /dev/null +++ b/cpukit/libnetworking/sys/ucred.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)ucred.h 8.4 (Berkeley) 1/9/95 + * $Id$ + */ + +#ifndef _SYS_UCRED_H_ +#define _SYS_UCRED_H_ + +/* + * Credentials. + */ +struct ucred { + u_short cr_ref; /* reference count */ + uid_t cr_uid; /* effective user id */ + short cr_ngroups; /* number of groups */ + gid_t cr_groups[NGROUPS]; /* groups */ +}; +#define cr_gid cr_groups[0] +#define NOCRED ((struct ucred *)0) /* no credential available */ +#define FSCRED ((struct ucred *)-1) /* filesystem credential */ + +#ifdef KERNEL +#define crhold(cr) (cr)->cr_ref++ + +struct ucred *crcopy __P((struct ucred *cr)); +struct ucred *crdup __P((struct ucred *cr)); +void crfree __P((struct ucred *cr)); +struct ucred *crget __P((void)); +int suser __P((struct ucred *cred, u_short *acflag)); +int groupmember __P((gid_t gid, struct ucred *cred)); +#endif /* KERNEL */ + +#endif /* !_SYS_UCRED_H_ */ diff --git a/cpukit/libnetworking/sys/uio.h b/cpukit/libnetworking/sys/uio.h new file mode 100644 index 0000000000..305941500d --- /dev/null +++ b/cpukit/libnetworking/sys/uio.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1994 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)uio.h 8.5 (Berkeley) 2/22/94 + * $Id$ + */ + +#ifndef _SYS_UIO_H_ +#define _SYS_UIO_H_ + +/* + * XXX + * iov_base should be a void *. + */ +struct iovec { + char *iov_base; /* Base address. */ + size_t iov_len; /* Length. */ +}; + +enum uio_rw { UIO_READ, UIO_WRITE }; + +/* Segment flag values. */ +enum uio_seg { + UIO_USERSPACE, /* from user data space */ + UIO_SYSSPACE, /* from system space */ + UIO_USERISPACE, /* from user I space */ + UIO_NOCOPY /* don't copy, already in object */ +}; + +#ifdef KERNEL +struct uio { + struct iovec *uio_iov; + int uio_iovcnt; + off_t uio_offset; + int uio_resid; + enum uio_seg uio_segflg; + enum uio_rw uio_rw; + struct proc *uio_procp; +}; + +/* + * Limits + */ +#define UIO_MAXIOV 1024 /* max 1K of iov's */ +#define UIO_SMALLIOV 8 /* 8 on stack, else malloc */ +#endif /* KERNEL */ + +#ifdef KERNEL + +int uiomove __P((caddr_t, int, struct uio *)); + +#else /* !KERNEL */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +ssize_t readv __P((int, const struct iovec *, int)); +ssize_t writev __P((int, const struct iovec *, int)); +__END_DECLS + +#endif /* KERNEL */ + +#endif /* !_SYS_UIO_H_ */ diff --git a/cpukit/libnetworking/syslog.h b/cpukit/libnetworking/syslog.h new file mode 100644 index 0000000000..830b4928ad --- /dev/null +++ b/cpukit/libnetworking/syslog.h @@ -0,0 +1 @@ +#include <sys/syslog.h> diff --git a/cpukit/libnetworking/vm/vm.h b/cpukit/libnetworking/vm/vm.h new file mode 100644 index 0000000000..19ea10e5eb --- /dev/null +++ b/cpukit/libnetworking/vm/vm.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)vm.h 8.2 (Berkeley) 12/13/93 + * $Id$ + */ + +#ifndef VM_H +#define VM_H + +typedef char vm_inherit_t; /* XXX: inheritance codes */ +typedef u_char vm_prot_t; /* protection codes */ + +union vm_map_object; +typedef union vm_map_object vm_map_object_t; + +struct vm_map_entry; +typedef struct vm_map_entry *vm_map_entry_t; + +struct vm_map; +typedef struct vm_map *vm_map_t; + +struct vm_object; +typedef struct vm_object *vm_object_t; + +#ifndef KERNEL +/* + * This is defined in <sys/types.h> for the kernel so that non-vm kernel + * sources (mainly Mach-derived ones such as ddb) don't have to include + * vm stuff. Defining it there for applications might break things. + * Define it here for "applications" that include vm headers (e.g., + * genassym). + */ +typedef int boolean_t; + +/* + * This is defined in <sys/types.h> for the kernel so that vnode_if.h + * doesn't have to include <vm/vm.h>. + */ +struct vm_page; +typedef struct vm_page *vm_page_t; +#endif + +#endif /* VM_H */ diff --git a/cpukit/libnetworking/vm/vm_extern.h b/cpukit/libnetworking/vm/vm_extern.h new file mode 100644 index 0000000000..720d42dc28 --- /dev/null +++ b/cpukit/libnetworking/vm/vm_extern.h @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)vm_extern.h 8.2 (Berkeley) 1/12/94 + * $Id$ + */ + +#ifndef _VM_EXTERN_H_ +#define _VM_EXTERN_H_ + +struct buf; +struct proc; +struct vmspace; +struct vmtotal; +struct mount; +struct vnode; + +#ifdef KERNEL + +#ifdef TYPEDEF_FOR_UAP +int getpagesize __P((struct proc * p, void *, int *)); +int madvise __P((struct proc *, void *, int *)); +int mincore __P((struct proc *, void *, int *)); +int mprotect __P((struct proc *, void *, int *)); +int msync __P((struct proc *, void *, int *)); +int munmap __P((struct proc *, void *, int *)); +int obreak __P((struct proc *, void *, int *)); +int sbrk __P((struct proc *, void *, int *)); +int smmap __P((struct proc *, void *, int *)); +int sstk __P((struct proc *, void *, int *)); +int swapon __P((struct proc *, void *, int *)); +#endif + +void faultin __P((struct proc *p)); +int grow __P((struct proc *, u_int)); +int kernacc __P((caddr_t, int, int)); +vm_offset_t kmem_alloc __P((vm_map_t, vm_size_t)); +vm_offset_t kmem_alloc_pageable __P((vm_map_t, vm_size_t)); +vm_offset_t kmem_alloc_wait __P((vm_map_t, vm_size_t)); +void kmem_free __P((vm_map_t, vm_offset_t, vm_size_t)); +void kmem_free_wakeup __P((vm_map_t, vm_offset_t, vm_size_t)); +void kmem_init __P((vm_offset_t, vm_offset_t)); +vm_offset_t kmem_malloc __P((vm_map_t, vm_size_t, boolean_t)); +vm_map_t kmem_suballoc __P((vm_map_t, vm_offset_t *, vm_offset_t *, vm_size_t, boolean_t)); +void munmapfd __P((struct proc *, int)); +int pager_cache __P((vm_object_t, boolean_t)); +int swaponvp __P((struct proc *, struct vnode *, dev_t , u_long)); +void swapout_procs __P((void)); +int useracc __P((caddr_t, int, int)); +int vm_fault __P((vm_map_t, vm_offset_t, vm_prot_t, boolean_t)); +void vm_fault_copy_entry __P((vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t)); +void vm_fault_unwire __P((vm_map_t, vm_offset_t, vm_offset_t)); +int vm_fault_wire __P((vm_map_t, vm_offset_t, vm_offset_t)); +int vm_fault_user_wire __P((vm_map_t, vm_offset_t, vm_offset_t)); +int vm_fork __P((struct proc *, struct proc *)); +int vm_mmap __P((vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, caddr_t, vm_ooffset_t)); +vm_offset_t vm_page_alloc_contig __P((vm_offset_t, vm_offset_t, vm_offset_t, vm_offset_t)); +void vm_set_page_size __P((void)); +void vmmeter __P((void)); +struct vmspace *vmspace_alloc __P((vm_offset_t, vm_offset_t, int)); +struct vmspace *vmspace_fork __P((struct vmspace *)); +void vmspace_free __P((struct vmspace *)); +void vnode_pager_setsize __P((struct vnode *, vm_ooffset_t)); +void vnode_pager_umount __P((struct mount *)); +void vnode_pager_uncache __P((struct vnode *)); +void vslock __P((caddr_t, u_int)); +void vsunlock __P((caddr_t, u_int, int)); +void vm_object_print __P((/* db_expr_t */ int, boolean_t, /* db_expr_t */ int, + char *)); +void vm_fault_quick __P((caddr_t v, int prot)); + +#endif /* KERNEL */ + +#endif /* !_VM_EXTERN_H_ */ diff --git a/cpukit/libnetworking/vm/vm_kern.h b/cpukit/libnetworking/vm/vm_kern.h new file mode 100644 index 0000000000..b1e073dd3a --- /dev/null +++ b/cpukit/libnetworking/vm/vm_kern.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * from: @(#)vm_kern.h 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1987, 1990 Carnegie-Mellon University. + * All rights reserved. + * + * Authors: Avadis Tevanian, Jr., Michael Wayne Young + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id$ + */ + +#ifndef _VM_VM_KERN_H_ +#define _VM_VM_KERN_H_ 1 + +/* Kernel memory management definitions. */ +extern vm_map_t buffer_map; +extern vm_map_t kernel_map; +extern vm_map_t kmem_map; +extern vm_map_t mb_map; +extern int mb_map_full; +extern vm_map_t io_map; +extern vm_map_t clean_map; +extern vm_map_t phys_map; +extern vm_map_t exec_map; +extern vm_map_t u_map; + +extern vm_offset_t kernel_vm_end; + +#endif /* _VM_VM_KERN_H_ */ diff --git a/cpukit/libnetworking/vm/vm_param.h b/cpukit/libnetworking/vm/vm_param.h new file mode 100644 index 0000000000..f1cfca98ec --- /dev/null +++ b/cpukit/libnetworking/vm/vm_param.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * from: @(#)vm_param.h 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1987, 1990 Carnegie-Mellon University. + * All rights reserved. + * + * Authors: Avadis Tevanian, Jr., Michael Wayne Young + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id$ + */ + +/* + * Machine independent virtual memory parameters. + */ + +#ifndef _VM_PARAM_ +#define _VM_PARAM_ + +#include <machine/vmparam.h> + +/* + * The machine independent pages are refered to as PAGES. A page + * is some number of hardware pages, depending on the target machine. + */ +#define DEFAULT_PAGE_SIZE 4096 + +#if 0 + +/* + * All references to the size of a page should be done with PAGE_SIZE + * or PAGE_SHIFT. The fact they are variables is hidden here so that + * we can easily make them constant if we so desire. + */ +#ifndef PAGE_SIZE +#define PAGE_SIZE cnt.v_page_size /* size of page */ +#endif +#ifndef PAGE_MASK +#define PAGE_MASK page_mask /* size of page - 1 */ +#endif +#ifndef PAGE_SHIFT +#define PAGE_SHIFT page_shift /* bits to shift for pages */ +#endif + +#endif + +#ifdef KERNEL +extern vm_size_t page_mask; +extern int page_shift; + +#endif + +/* + * CTL_VM identifiers + */ +#define VM_METER 1 /* struct vmmeter */ +#define VM_LOADAVG 2 /* struct loadavg */ +#define VM_V_FREE_MIN 3 /* cnt.v_free_min */ +#define VM_V_FREE_TARGET 4 /* cnt.v_free_target */ +#define VM_V_FREE_RESERVED 5 /* cnt.v_free_reserved */ +#define VM_V_INACTIVE_TARGET 6 /* cnt.v_inactive_target */ +#define VM_V_CACHE_MIN 7 /* cnt.v_cache_max */ +#define VM_V_CACHE_MAX 8 /* cnt.v_cache_min */ +#define VM_V_PAGEOUT_FREE_MIN 9 /* cnt.v_pageout_free_min */ +#define VM_PAGEOUT_ALGORITHM 10 /* pageout algorithm */ +#define VM_SWAPPING_ENABLED 11 /* swapping enabled */ +#define VM_MAXID 12 /* number of valid vm ids */ + +#define CTL_VM_NAMES { \ + { 0, 0 }, \ + { "vmmeter", CTLTYPE_STRUCT }, \ + { "loadavg", CTLTYPE_STRUCT }, \ + { "v_free_min", CTLTYPE_INT }, \ + { "v_free_target", CTLTYPE_INT }, \ + { "v_free_reserved", CTLTYPE_INT }, \ + { "v_inactive_target", CTLTYPE_INT }, \ + { "v_cache_min", CTLTYPE_INT }, \ + { "v_cache_max", CTLTYPE_INT }, \ + { "v_pageout_free_min", CTLTYPE_INT}, \ + { "pageout_algorithm", CTLTYPE_INT}, \ + { "swapping_enabled", CTLTYPE_INT},\ +} + +/* + * Return values from the VM routines. + */ +#define KERN_SUCCESS 0 +#define KERN_INVALID_ADDRESS 1 +#define KERN_PROTECTION_FAILURE 2 +#define KERN_NO_SPACE 3 +#define KERN_INVALID_ARGUMENT 4 +#define KERN_FAILURE 5 +#define KERN_RESOURCE_SHORTAGE 6 +#define KERN_NOT_RECEIVER 7 +#define KERN_NO_ACCESS 8 + +#ifndef ASSEMBLER +/* + * Convert addresses to pages and vice versa. + * No rounding is used. + */ +#ifdef KERNEL +#define num_pages(x) \ + ((vm_offset_t)((((vm_offset_t)(x)) + PAGE_MASK) >> PAGE_SHIFT)) + +extern vm_size_t mem_size; /* size of physical memory (bytes) */ +extern vm_offset_t first_addr; /* first physical page */ +extern vm_offset_t last_addr; /* last physical page */ +#endif /* KERNEL */ +#endif /* ASSEMBLER */ +#endif /* _VM_PARAM_ */ |