diff options
author | Vijay Kumar Banerjee <vijay@rtems.org> | 2021-02-03 19:46:50 -0700 |
---|---|---|
committer | Vijay Kumar Banerjee <vijay@rtems.org> | 2021-02-03 19:46:50 -0700 |
commit | 98a30fcc163c015f432a5f2874399024228a53c7 (patch) | |
tree | bd8d781ae7bb890535981954b91691d5950270db |
Initial Commit: Add all files from RTEMS libnetworking directory
266 files changed, 73203 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ae86e49 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "rtems_waf"] + path = rtems_waf + url = git://git.rtems.org/rtems_waf.git @@ -0,0 +1,68 @@ +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. + +Initial Changes +=============== + +19-AUG-1998 snapshot + - Pulled BOOTP initialization out of rtems_glue. Applications which + don't used BOOTP are now about 5k smaller. + - Loopback interface is not installed by default, rather it is + attached like any other interface. Saves about 0.5 kbytes. + - Add rtems_bsdnet_show_if_stats(); + - Moved test programs from below freebsd directory. + +18-AUG-1998 snapshot + - Removed some include files that were already part of RTEMS. + - Cleaned up machine/types.h to prepare for inclusion in RTEMS source. + - Added syslog library routines -- much simpler than KA9Q version. + Sockets can be shared among tasks (as long as the send is + protected by a mutex) so there's no need for a Syslog Daemon. + +16-AUG-1998 snapshot + - Table-driven configuration (networkconfig.h). + - Cleaned up rtems_bsdnet.h. + - BOOTP now retries properly -- Note to Joel: + The dichotomy between RTEMS and UNIX error codes is + a real pain! + +14-AUG-1998 snapshot + - Added dummy getprotobyname() and getprotobynum() functions. + - Added socket ioctl. + - Added application-level entry to manipulate routing tables. + - Added non-BOOTP network initialization. + +13-AUG-1998 snapshot + - Changed some BOOTP addresses from sockaddr_in to inaddr; + - Get DNS information from BOOTP reply. + - Got DNS lookups working. + Bloatware comes to RTEMS -- invoking gethostbyname() drags in + and extra 40 kbytes of code! + - Added hostname lookup program. + +12-AUG-1998 snapshot + - Added startup delay to network initialization. + - More statistic-printing routines. + - Added TFTP driver and test program + - Modified TFTP test program to use networkconfig.h. + - Removed unused include files. + - Added from ftp://ftp.ca.FreeBSD.ORG/pub/FreeBSD/FreeBSD-current/src/lib/libc/net. + +11-AUG-1998 snapshot. + - Added getpeername() + - Added M68k versions of IP checksum code + - Added TCP timing program to snapshot. + +02-AUG-1998 snapshot. diff --git a/arpa/nameser.h b/arpa/nameser.h new file mode 100644 index 0000000..d499611 --- /dev/null +++ b/arpa/nameser.h @@ -0,0 +1,450 @@ +/* + * 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 + * $FreeBSD: src/include/arpa/nameser.h,v 1.16 2002/03/23 17:24:55 imp Exp $ + */ + + +#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 rr_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).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 */ + ns_t_opt = 41, /* OPT pseudo-RR, RFC2761 */ + /* 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(const u_char *); +u_long ns_get32(const u_char *); +void ns_put16(u_int, u_char *); +void ns_put32(u_long, u_char *); +int ns_initparse(const u_char *, int, ns_msg *); +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); +int ns_sprintrr(const ns_msg *, const ns_rr *, + const char *, const char *, char *, size_t); +int ns_sprintrrf(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(u_long, char *, size_t); +int ns_parse_ttl(const char *, u_long *); +int ns_name_ntop(const u_char *, char *, size_t); +int ns_name_pton(const char *, u_char *, size_t); +int ns_name_unpack(const u_char *, const u_char *, + const u_char *, u_char *, size_t); +int ns_name_pack(const u_char *, u_char *, int, + const u_char **, const u_char **); +int ns_name_uncompress(const u_char *, const u_char *, + const u_char *, char *, size_t); +int ns_name_compress(const char *, u_char *, size_t, + const u_char **, const u_char **); +int ns_name_skip(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/arpa/nameser_compat.h b/arpa/nameser_compat.h new file mode 100644 index 0000000..8fcceaa --- /dev/null +++ b/arpa/nameser_compat.h @@ -0,0 +1,193 @@ +/* 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 + */ + +#ifndef _ARPA_NAMESER_COMPAT_ +#define _ARPA_NAMESER_COMPAT_ + +#define __BIND 19950621 /* (DEAD) interface version stamp. */ + +#include <sys/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/bpfilter.h b/bpfilter.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/bpfilter.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/dev/mii/mii.h b/dev/mii/mii.h new file mode 100644 index 0000000..14e45b0 --- /dev/null +++ b/dev/mii/mii.h @@ -0,0 +1,206 @@ +/* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe, + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * 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 Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/dev/mii/mii.h,v 1.4 2002/04/29 11:57:28 phk Exp $ + */ + +#ifndef _DEV_MII_MII_H_ +#define _DEV_MII_MII_H_ + +/* + * Registers common to all PHYs. + */ + +#define MII_NPHY 32 /* max # of PHYs per MII */ + +/* + * MII commands, used if a device must drive the MII lines + * manually. + */ +#define MII_COMMAND_START 0x01 +#define MII_COMMAND_READ 0x02 +#define MII_COMMAND_WRITE 0x01 +#define MII_COMMAND_ACK 0x02 + +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define BMCR_RESET 0x8000 /* reset */ +#define BMCR_LOOP 0x4000 /* loopback */ +#define BMCR_SPEED0 0x2000 /* speed selection (LSB) */ +#define BMCR_AUTOEN 0x1000 /* autonegotiation enable */ +#define BMCR_PDOWN 0x0800 /* power down */ +#define BMCR_ISO 0x0400 /* isolate */ +#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */ +#define BMCR_FDX 0x0100 /* Set duplex mode */ +#define BMCR_CTEST 0x0080 /* collision test */ +#define BMCR_SPEED1 0x0040 /* speed selection (MSB) */ + +#define BMCR_S10 0x0000 /* 10 Mb/s */ +#define BMCR_S100 BMCR_SPEED0 /* 100 Mb/s */ +#define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */ + +#define BMCR_SPEED(x) ((x) & (BMCR_SPEED0|BMCR_SPEED1)) + +#define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define BMSR_100T4 0x8000 /* 100 base T4 capable */ +#define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */ +#define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */ +#define BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */ +#define BMSR_10THDX 0x0800 /* 10 base T half duplex capable */ +#define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */ +#define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */ +#define BMSR_EXTSTAT 0x0100 /* Extended status in register 15 */ +#define BMSR_MFPS 0x0040 /* MII Frame Preamble Suppression */ +#define BMSR_ACOMP 0x0020 /* Autonegotiation complete */ +#define BMSR_RFAULT 0x0010 /* Link partner fault */ +#define BMSR_ANEG 0x0008 /* Autonegotiation capable */ +#define BMSR_LINK 0x0004 /* Link status */ +#define BMSR_JABBER 0x0002 /* Jabber detected */ +#define BMSR_EXTCAP 0x0001 /* Extended capability */ + +/* + * Note that the EXTSTAT bit indicates that there is extended status + * info available in register 15, but 802.3 section 22.2.4.3 also + * states that that all 1000 Mb/s capable PHYs will set this bit to 1. + */ +#if 0 +#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \ + BMSR_10THDX|BMSR_ANEG) + +#else +/* NetBSD uses: */ +#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \ + BMSR_10TFDX|BMSR_10THDX|BMSR_100T2FDX|BMSR_100T2HDX) +#endif + +/* + * Convert BMSR media capabilities to ANAR bits for autonegotiation. + * Note the shift chopps off the BMSR_ANEG bit. + */ +#define BMSR_MEDIA_TO_ANAR(x) (((x) & BMSR_MEDIAMASK) >> 6) + +#define MII_PHYIDR1 0x02 /* ID register 1 (ro) */ + +#define MII_PHYIDR2 0x03 /* ID register 2 (ro) */ +#define IDR2_OUILSB 0xfc00 /* OUI LSB */ +#define IDR2_MODEL 0x03f0 /* vendor model */ +#define IDR2_REV 0x000f /* vendor revision */ + +#define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10)) +#define MII_MODEL(id2) (((id2) & IDR2_MODEL) >> 4) +#define MII_REV(id2) ((id2) & IDR2_REV) + +#define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANAR_NP 0x8000 /* Next page (ro) */ +#define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */ +#define ANAR_RF 0x2000 /* remote fault (ro) */ +#define ANAR_FC 0x0400 /* local device supports PAUSE */ +#define ANAR_T4 0x0200 /* local device supports 100bT4 */ +#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */ +#define ANAR_TX 0x0080 /* local device supports 100bTx */ +#define ANAR_10_FD 0x0040 /* local device supports 10bT FD */ +#define ANAR_10 0x0020 /* local device supports 10bT */ +#define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */ + +#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ +#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ +#define ANAR_X_PAUSE_NONE (0 << 7) +#define ANAR_X_PAUSE_SYM (1 << 7) +#define ANAR_X_PAUSE_ASYM (2 << 7) +#define ANAR_X_PAUSE_TOWARDS (3 << 7) + +#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANLPAR_NP 0x8000 /* Next page (ro) */ +#define ANLPAR_ACK 0x4000 /* link partner accepted ACK (ro) */ +#define ANLPAR_RF 0x2000 /* remote fault (ro) */ +#define ANLPAR_FC 0x0400 /* link partner supports PAUSE */ +#define ANLPAR_T4 0x0200 /* link partner supports 100bT4 */ +#define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */ +#define ANLPAR_TX 0x0080 /* link partner supports 100bTx */ +#define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */ +#define ANLPAR_10 0x0020 /* link partner supports 10bT */ +#define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */ + +#define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ +#define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ +#define ANLPAR_X_PAUSE_MASK (3 << 7) +#define ANLPAR_X_PAUSE_NONE (0 << 7) +#define ANLPAR_X_PAUSE_SYM (1 << 7) +#define ANLPAR_X_PAUSE_ASYM (2 << 7) +#define ANLPAR_X_PAUSE_TOWARDS (3 << 7) + +#define MII_ANER 0x06 /* Autonegotiation expansion (ro) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANER_MLF 0x0010 /* multiple link detection fault */ +#define ANER_LPNP 0x0008 /* link parter next page-able */ +#define ANER_NP 0x0004 /* next page-able */ +#define ANER_PAGE_RX 0x0002 /* Page received */ +#define ANER_LPAN 0x0001 /* link parter autoneg-able */ + +#define MII_ANNP 0x07 /* Autonegotiation next page */ + /* section 28.2.4.1 and 37.2.6.1 */ + +#define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */ + /* section 32.5.1 and 37.2.6.1 */ + + /* This is also the 1000baseT control register */ +#define MII_100T2CR 0x09 /* 100base-T2 control register */ +#define GTCR_TEST_MASK 0xe000 /* see 802.3ab ss. 40.6.1.1.2 */ +#define GTCR_MAN_MS 0x1000 /* enable manual master/slave control */ +#define GTCR_ADV_MS 0x0800 /* 1 = adv. master, 0 = adv. slave */ +#define GTCR_PORT_TYPE 0x0400 /* 1 = DCE, 0 = DTE (NIC) */ +#define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */ +#define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */ + + /* This is also the 1000baseT status register */ +#define MII_100T2SR 0x0a /* 100base-T2 status register */ +#define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */ +#define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */ +#define GTSR_LRS 0x2000 /* local rx status, 1 = ok */ +#define GTSR_RRS 0x1000 /* remove rx status, 1 = ok */ +#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */ +#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */ +#define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */ +#define GTSR_IDLE_ERR 0x00ff /* IDLE error count */ + +#define MII_EXTSR 0x0f /* Extended status register */ +#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */ +#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */ +#define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */ +#define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */ + +#define EXTSR_MEDIAMASK (EXTSR_1000XFDX|EXTSR_1000XHDX| \ + EXTSR_1000TFDX|EXTSR_1000THDX) + +#endif /* _DEV_MII_MII_H_ */ diff --git a/headers.am b/headers.am new file mode 100644 index 0000000..3d52fa2 --- /dev/null +++ b/headers.am @@ -0,0 +1,125 @@ +## In contrast to the other headers.am files, this file must be maintained by +## hand. + +include_HEADERS += libnetworking/ifaddrs.h +include_HEADERS += libnetworking/librtemsNfs.h +include_HEADERS += libnetworking/loop.h +include_HEADERS += libnetworking/resolv.h + +include_arpa_HEADERS += libnetworking/arpa/nameser.h +include_arpa_HEADERS += libnetworking/arpa/nameser_compat.h + +include_dev_mii_HEADERS += libnetworking/dev/mii/mii.h + +include_machine_HEADERS += libnetworking/machine/_align.h +include_machine_HEADERS += libnetworking/machine/_kernel_if.h +include_machine_HEADERS += libnetworking/machine/_kernel_lock.h +include_machine_HEADERS += libnetworking/machine/_kernel_socket.h +include_machine_HEADERS += libnetworking/machine/cpu.h +include_machine_HEADERS += libnetworking/machine/cpufunc.h +include_machine_HEADERS += libnetworking/machine/in_cksum.h +include_machine_HEADERS += libnetworking/machine/limits.h +include_machine_HEADERS += libnetworking/machine/vmparam.h + +include_net_HEADERS += libnetworking/net/bpf.h +include_net_HEADERS += libnetworking/net/ethernet.h +include_net_HEADERS += libnetworking/net/if_arp.h +include_net_HEADERS += libnetworking/net/if_dl.h +include_net_HEADERS += libnetworking/net/if_llc.h +include_net_HEADERS += libnetworking/net/if_media.h +include_net_HEADERS += libnetworking/net/if_ppp.h +include_net_HEADERS += libnetworking/net/if_pppvar.h +include_net_HEADERS += libnetworking/net/if_types.h +include_net_HEADERS += libnetworking/net/if_var.h +include_net_HEADERS += libnetworking/net/netisr.h +include_net_HEADERS += libnetworking/net/ppp_comp.h +include_net_HEADERS += libnetworking/net/ppp_defs.h +include_net_HEADERS += libnetworking/net/radix.h +include_net_HEADERS += libnetworking/net/raw_cb.h +include_net_HEADERS += libnetworking/net/route.h +include_net_HEADERS += libnetworking/net/slcompress.h + +include_netinet_HEADERS += libnetworking/netinet/icmp_var.h +include_netinet_HEADERS += libnetworking/netinet/if_ether.h +include_netinet_HEADERS += libnetworking/netinet/igmp.h +include_netinet_HEADERS += libnetworking/netinet/igmp_var.h +include_netinet_HEADERS += libnetworking/netinet/in_pcb.h +include_netinet_HEADERS += libnetworking/netinet/in_systm.h +include_netinet_HEADERS += libnetworking/netinet/in_var.h +include_netinet_HEADERS += libnetworking/netinet/ip.h +include_netinet_HEADERS += libnetworking/netinet/ip_fw.h +include_netinet_HEADERS += libnetworking/netinet/ip_icmp.h +include_netinet_HEADERS += libnetworking/netinet/ip_mroute.h +include_netinet_HEADERS += libnetworking/netinet/ip_var.h +include_netinet_HEADERS += libnetworking/netinet/tcp_debug.h +include_netinet_HEADERS += libnetworking/netinet/tcp_fsm.h +include_netinet_HEADERS += libnetworking/netinet/tcp_seq.h +include_netinet_HEADERS += libnetworking/netinet/tcp_timer.h +include_netinet_HEADERS += libnetworking/netinet/tcp_var.h +include_netinet_HEADERS += libnetworking/netinet/tcpip.h +include_netinet_HEADERS += libnetworking/netinet/udp.h +include_netinet_HEADERS += libnetworking/netinet/udp_var.h + +include_nfs_HEADERS += libnetworking/nfs/nfsproto.h +include_nfs_HEADERS += libnetworking/nfs/rpcv2.h +include_nfs_HEADERS += libnetworking/nfs/xdr_subs.h + +include_nfsclient_HEADERS += libnetworking/nfsclient/nfsargs.h +include_nfsclient_HEADERS += libnetworking/nfsclient/nfsdiskless.h + +include_rpc_HEADERS += libnetworking/rpc/auth.h +include_rpc_HEADERS += libnetworking/rpc/auth_unix.h +include_rpc_HEADERS += libnetworking/rpc/clnt.h +include_rpc_HEADERS += libnetworking/rpc/clnt_soc.h +include_rpc_HEADERS += libnetworking/rpc/clnt_stat.h +include_rpc_HEADERS += libnetworking/rpc/pmap_clnt.h +include_rpc_HEADERS += libnetworking/rpc/pmap_prot.h +include_rpc_HEADERS += libnetworking/rpc/pmap_rmt.h +include_rpc_HEADERS += libnetworking/rpc/rpc.h +include_rpc_HEADERS += libnetworking/rpc/rpc_com.h +include_rpc_HEADERS += libnetworking/rpc/rpc_msg.h +include_rpc_HEADERS += libnetworking/rpc/rpcent.h +include_rpc_HEADERS += libnetworking/rpc/svc.h +include_rpc_HEADERS += libnetworking/rpc/svc_auth.h +include_rpc_HEADERS += libnetworking/rpc/svc_soc.h +include_rpc_HEADERS += libnetworking/rpc/types.h +include_rpc_HEADERS += libnetworking/rpc/xdr.h + +include_rtems_HEADERS += libnetworking/rtems/bootp.h +include_rtems_HEADERS += libnetworking/rtems/dhcp.h +include_rtems_HEADERS += libnetworking/rtems/mkrootfs.h +include_rtems_HEADERS += libnetworking/rtems/rtems_bsdnet.h +include_rtems_HEADERS += libnetworking/rtems/rtems_bsdnet_internal.h +include_rtems_HEADERS += libnetworking/rtems/rtems_dhcp_failsafe.h +include_rtems_HEADERS += libnetworking/rtems/rtems_mii_ioctl.h +include_rtems_HEADERS += libnetworking/rtems/rtems_netdb.h +include_rtems_HEADERS += libnetworking/rtems/rtems_netinet_in.h +include_rtems_HEADERS += libnetworking/rtems/rtems_syscall.h + +include_rtems_bsdnet_HEADERS += libnetworking/rtems/bsdnet/_types.h +include_rtems_bsdnet_HEADERS += libnetworking/rtems/bsdnet/servers.h + +include_sys_HEADERS += libnetworking/sys/callout.h +include_sys_HEADERS += libnetworking/sys/conf.h +include_sys_HEADERS += libnetworking/sys/domain.h +include_sys_HEADERS += libnetworking/sys/kernel.h +include_sys_HEADERS += libnetworking/sys/libkern.h +include_sys_HEADERS += libnetworking/sys/linker_set.h +include_sys_HEADERS += libnetworking/sys/malloc.h +include_sys_HEADERS += libnetworking/sys/mbuf.h +include_sys_HEADERS += libnetworking/sys/mount.h +include_sys_HEADERS += libnetworking/sys/proc.h +include_sys_HEADERS += libnetworking/sys/protosw.h +include_sys_HEADERS += libnetworking/sys/reboot.h +include_sys_HEADERS += libnetworking/sys/resourcevar.h +include_sys_HEADERS += libnetworking/sys/selinfo.h +include_sys_HEADERS += libnetworking/sys/signalvar.h +include_sys_HEADERS += libnetworking/sys/socketvar.h +include_sys_HEADERS += libnetworking/sys/sysctl.h +include_sys_HEADERS += libnetworking/sys/systm.h +include_sys_HEADERS += libnetworking/sys/ucred.h + +include_vm_HEADERS += libnetworking/vm/vm.h +include_vm_HEADERS += libnetworking/vm/vm_extern.h +include_vm_HEADERS += libnetworking/vm/vm_kern.h +include_vm_HEADERS += libnetworking/vm/vm_param.h diff --git a/ifaddrs.h b/ifaddrs.h new file mode 100644 index 0000000..7d3aa95 --- /dev/null +++ b/ifaddrs.h @@ -0,0 +1,56 @@ +/* $FreeBSD: src/include/ifaddrs.h,v 1.3 2003/11/14 18:53:22 bms Exp $ */ + +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + u_int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in <net/if.h>. Note that if <net/if.h> is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include <sys/cdefs.h> + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **); +extern void freeifaddrs(struct ifaddrs *); +__END_DECLS + +#endif diff --git a/kern/kern_mib.c b/kern/kern_mib.c new file mode 100644 index 0000000..c429ad4 --- /dev/null +++ b/kern/kern_mib.c @@ -0,0 +1,384 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/*- + * Copyright (c) 1982, 1986, 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. + * + * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD + * project, to make these variables more userfriendly. + * + * 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. + * 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_sysctl.c 8.4 (Berkeley) 4/14/94 + * $FreeBSD: src/sys/kern/kern_mib.c,v 1.74 2005/02/28 21:42:56 wes Exp $ + */ + + +#ifndef __rtems__ +#include "opt_posix.h" +#endif + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#ifndef __rtems__ +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/jail.h> +#include <sys/smp.h> +#endif +#include <sys/unistd.h> + +#ifdef __rtems__ +char machine[] = "SET ME"; +char osrelease[] = RTEMS_VERSION; +char ostype[] = "RTEMS"; +#endif + +SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, + "Sysctl internal magic"); +SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, + "High kernel, proc, limits &c"); +#ifndef __rtems__ +SYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, + "Virtual memory"); +SYSCTL_NODE(, CTL_VFS, vfs, CTLFLAG_RW, 0, + "File system"); +#endif +SYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, + "Network, (see socket.h)"); +#ifndef __rtems__ +SYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, + "Debugging"); +SYSCTL_NODE(_debug, OID_AUTO, sizeof, CTLFLAG_RW, 0, + "Sizeof various things"); +SYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, + "hardware"); +SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, + "machine dependent"); +SYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, + "user-level"); +SYSCTL_NODE(, CTL_P1003_1B, p1003_1b, CTLFLAG_RW, 0, + "p1003_1b, (see p1003_1b.h)"); + +SYSCTL_NODE(, OID_AUTO, compat, CTLFLAG_RW, 0, + "Compatibility code"); +SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW, 0, + "Security"); +#ifdef REGRESSION +SYSCTL_NODE(, OID_AUTO, regression, CTLFLAG_RW, 0, + "Regression test MIB"); +#endif + +SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD, + kern_ident, 0, "Kernel identifier"); +#endif /* __rtems__ */ + +SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, + osrelease, 0, "Operating system release"); + +SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, + 0, BSD, "Operating system revision"); + +#ifndef __rtems__ +SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, + version, 0, "Kernel version"); +#endif + +SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, + ostype, 0, "Operating system type"); + +#ifndef __rtems__ +extern int osreldate; +SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, + &osreldate, 0, "Operating system release date"); + +SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, + &maxproc, 0, "Maximum number of processes"); + +SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW, + &maxprocperuid, 0, "Maximum processes allowed per userid"); + +SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RD, + &maxusers, 0, "Hint for kernel tuning"); + +SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, + 0, ARG_MAX, "Maximum bytes of argument to execve(2)"); + +SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, + 0, _POSIX_VERSION, "Version of POSIX attempting to comply to"); + +SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, + 0, NGROUPS_MAX, "Maximum number of groups a user can belong to"); + +SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, + 0, 1, "Whether job control is available"); + +#ifdef _POSIX_SAVED_IDS +SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, + 0, 1, "Whether saved set-group/user ID is available"); +#else +SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, + 0, 0, "Whether saved set-group/user ID is available"); +#endif + +char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ + +SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW, + kernelname, sizeof kernelname, "Name of kernel file booted"); + +#ifdef SMP +SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, + &mp_ncpus, 0, "Number of active CPUs"); +#else +SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, + 0, 1, "Number of active CPUs"); +#endif + +SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, + 0, BYTE_ORDER, "System byte order"); + +SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, + 0, PAGE_SIZE, "System memory page size"); + +static int +sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) +{ + u_long val; + + val = ctob(physmem); + return (sysctl_handle_long(oidp, &val, 0, req)); +} + +SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_ULONG | CTLFLAG_RD, + 0, 0, sysctl_hw_physmem, "LU", ""); + +static int +sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) +{ + u_long val; + + val = ctob(physmem - cnt.v_wire_count); + return (sysctl_handle_long(oidp, &val, 0, req)); +} + +SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_ULONG | CTLFLAG_RD, + 0, 0, sysctl_hw_usermem, "LU", ""); + +SYSCTL_ULONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, ""); + +static char machine_arch[] = MACHINE_ARCH; +SYSCTL_STRING(_hw, HW_MACHINE_ARCH, machine_arch, CTLFLAG_RD, + machine_arch, 0, "System architecture"); + +char hostname[MAXHOSTNAMELEN]; + +static int +sysctl_hostname(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + char tmphostname[MAXHOSTNAMELEN]; + int error; + + pr = req->td->td_ucred->cr_prison; + if (pr != NULL) { + if (!jail_set_hostname_allowed && req->newptr) + return (EPERM); + /* + * Process is in jail, so make a local copy of jail + * hostname to get/set so we don't have to hold the jail + * mutex during the sysctl copyin/copyout activities. + */ + mtx_lock(&pr->pr_mtx); + bcopy(pr->pr_host, tmphostname, MAXHOSTNAMELEN); + mtx_unlock(&pr->pr_mtx); + + error = sysctl_handle_string(oidp, tmphostname, + sizeof pr->pr_host, req); + + if (req->newptr != NULL && error == 0) { + /* + * Copy the locally set hostname to the jail, if + * appropriate. + */ + mtx_lock(&pr->pr_mtx); + bcopy(tmphostname, pr->pr_host, MAXHOSTNAMELEN); + mtx_unlock(&pr->pr_mtx); + } + } else + error = sysctl_handle_string(oidp, + hostname, sizeof hostname, req); + return (error); +} + +SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, + CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_PRISON, + 0, 0, sysctl_hostname, "A", "Hostname"); + +static int regression_securelevel_nonmonotonic = 0; + +#ifdef REGRESSION +SYSCTL_INT(_regression, OID_AUTO, securelevel_nonmonotonic, CTLFLAG_RW, + ®ression_securelevel_nonmonotonic, 0, "securelevel may be lowered"); +#endif + +int securelevel = -1; +struct mtx securelevel_mtx; + +MTX_SYSINIT(securelevel_lock, &securelevel_mtx, "securelevel mutex lock", + MTX_DEF); + +static int +sysctl_kern_securelvl(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int error, level; + + pr = req->td->td_ucred->cr_prison; + + /* + * If the process is in jail, return the maximum of the global and + * local levels; otherwise, return the global level. + */ + if (pr != NULL) { + mtx_lock(&pr->pr_mtx); + level = imax(securelevel, pr->pr_securelevel); + mtx_unlock(&pr->pr_mtx); + } else + level = securelevel; + error = sysctl_handle_int(oidp, &level, 0, req); + if (error || !req->newptr) + return (error); + /* + * Permit update only if the new securelevel exceeds the + * global level, and local level if any. + */ + if (pr != NULL) { + mtx_lock(&pr->pr_mtx); + if (!regression_securelevel_nonmonotonic && + (level < imax(securelevel, pr->pr_securelevel))) { + mtx_unlock(&pr->pr_mtx); + return (EPERM); + } + pr->pr_securelevel = level; + mtx_unlock(&pr->pr_mtx); + } else { + mtx_lock(&securelevel_mtx); + if (!regression_securelevel_nonmonotonic && + (level < securelevel)) { + mtx_unlock(&securelevel_mtx); + return (EPERM); + } + securelevel = level; + mtx_unlock(&securelevel_mtx); + } + return (error); +} + +SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, + CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_kern_securelvl, + "I", "Current secure level"); + +char domainname[MAXHOSTNAMELEN]; +SYSCTL_STRING(_kern, KERN_NISDOMAINNAME, domainname, CTLFLAG_RW, + &domainname, sizeof(domainname), "Name of the current YP/NIS domain"); + +u_long hostid; +SYSCTL_ULONG(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "Host ID"); + +/* + * This is really cheating. These actually live in the libc, something + * which I'm not quite sure is a good idea anyway, but in order for + * getnext and friends to actually work, we define dummies here. + */ +SYSCTL_STRING(_user, USER_CS_PATH, cs_path, CTLFLAG_RD, + "", 0, "PATH that finds all the standard utilities"); +SYSCTL_INT(_user, USER_BC_BASE_MAX, bc_base_max, CTLFLAG_RD, + 0, 0, "Max ibase/obase values in bc(1)"); +SYSCTL_INT(_user, USER_BC_DIM_MAX, bc_dim_max, CTLFLAG_RD, + 0, 0, "Max array size in bc(1)"); +SYSCTL_INT(_user, USER_BC_SCALE_MAX, bc_scale_max, CTLFLAG_RD, + 0, 0, "Max scale value in bc(1)"); +SYSCTL_INT(_user, USER_BC_STRING_MAX, bc_string_max, CTLFLAG_RD, + 0, 0, "Max string length in bc(1)"); +SYSCTL_INT(_user, USER_COLL_WEIGHTS_MAX, coll_weights_max, CTLFLAG_RD, + 0, 0, "Maximum number of weights assigned to an LC_COLLATE locale entry"); +SYSCTL_INT(_user, USER_EXPR_NEST_MAX, expr_nest_max, CTLFLAG_RD, 0, 0, ""); +SYSCTL_INT(_user, USER_LINE_MAX, line_max, CTLFLAG_RD, + 0, 0, "Max length (bytes) of a text-processing utility's input line"); +SYSCTL_INT(_user, USER_RE_DUP_MAX, re_dup_max, CTLFLAG_RD, + 0, 0, "Maximum number of repeats of a regexp permitted"); +SYSCTL_INT(_user, USER_POSIX2_VERSION, posix2_version, CTLFLAG_RD, + 0, 0, + "The version of POSIX 1003.2 with which the system attempts to comply"); +SYSCTL_INT(_user, USER_POSIX2_C_BIND, posix2_c_bind, CTLFLAG_RD, + 0, 0, "Whether C development supports the C bindings option"); +SYSCTL_INT(_user, USER_POSIX2_C_DEV, posix2_c_dev, CTLFLAG_RD, + 0, 0, "Whether system supports the C development utilities option"); +SYSCTL_INT(_user, USER_POSIX2_CHAR_TERM, posix2_char_term, CTLFLAG_RD, + 0, 0, ""); +SYSCTL_INT(_user, USER_POSIX2_FORT_DEV, posix2_fort_dev, CTLFLAG_RD, + 0, 0, "Whether system supports FORTRAN development utilities"); +SYSCTL_INT(_user, USER_POSIX2_FORT_RUN, posix2_fort_run, CTLFLAG_RD, + 0, 0, "Whether system supports FORTRAN runtime utilities"); +SYSCTL_INT(_user, USER_POSIX2_LOCALEDEF, posix2_localedef, CTLFLAG_RD, + 0, 0, "Whether system supports creation of locales"); +SYSCTL_INT(_user, USER_POSIX2_SW_DEV, posix2_sw_dev, CTLFLAG_RD, + 0, 0, "Whether system supports software development utilities"); +SYSCTL_INT(_user, USER_POSIX2_UPE, posix2_upe, CTLFLAG_RD, + 0, 0, "Whether system supports the user portability utilities"); +SYSCTL_INT(_user, USER_STREAM_MAX, stream_max, CTLFLAG_RD, + 0, 0, "Min Maximum number of streams a process may have open at one time"); +SYSCTL_INT(_user, USER_TZNAME_MAX, tzname_max, CTLFLAG_RD, + 0, 0, "Min Maximum number of types supported for timezone names"); + +#include <sys/vnode.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, vnode, CTLFLAG_RD, + 0, sizeof(struct vnode), "sizeof(struct vnode)"); + +SYSCTL_INT(_debug_sizeof, OID_AUTO, proc, CTLFLAG_RD, + 0, sizeof(struct proc), "sizeof(struct proc)"); + +#include <sys/conf.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD, + 0, sizeof(struct cdev), "sizeof(struct cdev)"); + +#include <sys/bio.h> +#include <sys/buf.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, bio, CTLFLAG_RD, + 0, sizeof(struct bio), "sizeof(struct bio)"); +SYSCTL_INT(_debug_sizeof, OID_AUTO, buf, CTLFLAG_RD, + 0, sizeof(struct buf), "sizeof(struct buf)"); + +#include <sys/user.h> +SYSCTL_INT(_debug_sizeof, OID_AUTO, kinfo_proc, CTLFLAG_RD, + 0, sizeof(struct kinfo_proc), "sizeof(struct kinfo_proc)"); + +#endif /* __rtems__ */ diff --git a/kern/kern_subr.c b/kern/kern_subr.c new file mode 100644 index 0000000..0c4b803 --- /dev/null +++ b/kern/kern_subr.c @@ -0,0 +1,157 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/uio.h> + +int +uiomove(void *cp, int n, 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: + 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); +} + +/* + * 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/kern/kern_sysctl.c b/kern/kern_sysctl.c new file mode 100644 index 0000000..c0a38f3 --- /dev/null +++ b/kern/kern_sysctl.c @@ -0,0 +1,1547 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/*- + * Copyright (c) 1982, 1986, 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. + * + * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD + * project, to make these variables more userfriendly. + * + * 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. + * 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_sysctl.c 8.4 (Berkeley) 4/14/94 + * $FreeBSD: src/sys/kern/kern_sysctl.c,v 1.135 2002/10/27 07:12:34 rwatson Exp $ + */ + +#include "opt_compat.h" +#include "opt_mac.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#ifndef __rtems__ +#include <sys/mac.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> +#include <sys/sysproto.h> +#else +#include <sys/queue.h> + +#include <stdio.h> /* for snprintf() */ +size_t strlcpy(char *, const char *, size_t); +#endif +#include <vm/vm.h> +#include <vm/vm_extern.h> + +#ifndef __rtems__ +static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic"); +static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids"); +static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer"); +#else +/* + * Currently these mean nothing on RTEMS. + */ +#define M_SYSCTLOID 1 +#define M_SYSCTLTMP 2 +#define M_ZERO 0 + +#define mtx_lock(l) +#define mtx_unlock(l) + +#endif + +#ifndef __rtems__ +/* + * Locking - this locks the sysctl tree in memory. + */ +static struct sx sysctllock; +#endif + +#ifdef __rtems__ +#define SYSCTL_LOCK() +#define SYSCTL_UNLOCK() +#define SYSCTL_INIT() +#else +#define SYSCTL_LOCK() sx_xlock(&sysctllock) +#define SYSCTL_UNLOCK() sx_xunlock(&sysctllock) +#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock") +#endif + +static int sysctl_root(struct sysctl_oid *oidp, const void *arg1, + intptr_t arg2, struct sysctl_req *req); + +struct sysctl_oid_list sysctl__children; /* root list */ + +static struct sysctl_oid * +sysctl_find_oidname(const char *name, struct sysctl_oid_list *list) +{ + struct sysctl_oid *oidp; + + SLIST_FOREACH(oidp, list, oid_link) { + if (strcmp(oidp->oid_name, name) == 0) { + return (oidp); + } + } + return (NULL); +} + +/* + * Initialization of the MIB tree. + * + * Order by number in each list. + */ + +void +sysctl_register_oid(struct sysctl_oid *oidp) +{ + struct sysctl_oid_list *parent = oidp->oid_parent; + struct sysctl_oid *p; + struct sysctl_oid *q; + + /* + * First check if another oid with the same name already + * exists in the parent's list. + */ + p = sysctl_find_oidname(oidp->oid_name, parent); + if (p != NULL) { + if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + p->oid_refcnt++; + return; + } else { + printf("can't re-use a leaf (%s)!\n", p->oid_name); + return; + } + } + /* + * If this oid has a number OID_AUTO, give it a number which + * is greater than any current oid. + * NOTE: DO NOT change the starting value here, change it in + * <sys/sysctl.h>, and make sure it is at least 256 to + * accomodate e.g. net.inet.raw as a static sysctl node. + */ + if (oidp->oid_number == OID_AUTO) { + static int32_t newoid = CTL_AUTO_START; + + oidp->oid_number = newoid++; + if (newoid == 0x7fffffff) + panic("out of oids"); + } +#if 0 + else if (oidp->oid_number >= CTL_AUTO_START) { + /* do not panic; this happens when unregistering sysctl sets */ + printf("static sysctl oid too high: %d", oidp->oid_number); + } +#endif + + /* + * Insert the oid into the parent's list in order. + */ + q = NULL; + SLIST_FOREACH(p, parent, oid_link) { + if (oidp->oid_number < p->oid_number) + break; + q = p; + } + if (q) + SLIST_INSERT_AFTER(q, oidp, oid_link); + else + SLIST_INSERT_HEAD(parent, oidp, oid_link); +} + +void +sysctl_unregister_oid(struct sysctl_oid *oidp) +{ + SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link); +} + +/* Initialize a new context to keep track of dynamically added sysctls. */ +int +sysctl_ctx_init(struct sysctl_ctx_list *c) +{ + + if (c == NULL) { + return (EINVAL); + } + TAILQ_INIT(c); + return (0); +} + +/* Free the context, and destroy all dynamic oids registered in this context */ +int +sysctl_ctx_free(struct sysctl_ctx_list *clist) +{ + struct sysctl_ctx_entry *e, *e1; + int error; + + error = 0; + /* + * First perform a "dry run" to check if it's ok to remove oids. + * XXX FIXME + * XXX This algorithm is a hack. But I don't know any + * XXX better solution for now... + */ + TAILQ_FOREACH(e, clist, link) { + error = sysctl_remove_oid(e->entry, 0, 0); + if (error) + break; + } + /* + * Restore deregistered entries, either from the end, + * or from the place where error occured. + * e contains the entry that was not unregistered + */ + if (error) + e1 = TAILQ_PREV(e, sysctl_ctx_list, link); + else + e1 = TAILQ_LAST(clist, sysctl_ctx_list); + while (e1 != NULL) { + sysctl_register_oid(e1->entry); + e1 = TAILQ_PREV(e1, sysctl_ctx_list, link); + } + if (error) + return(EBUSY); + /* Now really delete the entries */ + e = TAILQ_FIRST(clist); + while (e != NULL) { + e1 = TAILQ_NEXT(e, link); + error = sysctl_remove_oid(e->entry, 1, 0); + if (error) + panic("sysctl_remove_oid: corrupt tree, entry: %s", + e->entry->oid_name); + free(e, M_SYSCTLOID); + e = e1; + } + return (error); +} + +/* Add an entry to the context */ +struct sysctl_ctx_entry * +sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) +{ + struct sysctl_ctx_entry *e; + + if (clist == NULL || oidp == NULL) + return(NULL); + e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK); + e->entry = oidp; + TAILQ_INSERT_HEAD(clist, e, link); + return (e); +} + +/* Find an entry in the context */ +struct sysctl_ctx_entry * +sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) +{ + struct sysctl_ctx_entry *e; + + if (clist == NULL || oidp == NULL) + return(NULL); + TAILQ_FOREACH(e, clist, link) { + if(e->entry == oidp) + return(e); + } + return (e); +} + +/* + * Delete an entry from the context. + * NOTE: this function doesn't free oidp! You have to remove it + * with sysctl_remove_oid(). + */ +int +sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp) +{ + struct sysctl_ctx_entry *e; + + if (clist == NULL || oidp == NULL) + return (EINVAL); + e = sysctl_ctx_entry_find(clist, oidp); + if (e != NULL) { + TAILQ_REMOVE(clist, e, link); + free(e, M_SYSCTLOID); + return (0); + } else + return (ENOENT); +} + +/* + * Remove dynamically created sysctl trees. + * oidp - top of the tree to be removed + * del - if 0 - just deregister, otherwise free up entries as well + * recurse - if != 0 traverse the subtree to be deleted + */ +int +sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse) +{ + struct sysctl_oid *p; + int error; + + if (oidp == NULL) + return(EINVAL); + if ((oidp->oid_kind & CTLFLAG_DYN) == 0) { + printf("can't remove non-dynamic nodes!\n"); + return (EINVAL); + } + /* + * WARNING: normal method to do this should be through + * sysctl_ctx_free(). Use recursing as the last resort + * method to purge your sysctl tree of leftovers... + * However, if some other code still references these nodes, + * it will panic. + */ + if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + if (oidp->oid_refcnt == 1) { + SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) { + if (!recurse) + return (ENOTEMPTY); + error = sysctl_remove_oid(p, del, recurse); + if (error) + return (error); + } + if (del) + free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID); + } + } + if (oidp->oid_refcnt > 1 ) { + oidp->oid_refcnt--; + } else { + if (oidp->oid_refcnt == 0) { + printf("Warning: bad oid_refcnt=%u (%s)!\n", + oidp->oid_refcnt, oidp->oid_name); + return (EINVAL); + } + sysctl_unregister_oid(oidp); + if (del) { + if (oidp->descr) + free((void *)(uintptr_t)(const void *)oidp->descr, M_SYSCTLOID); + free((void *)(uintptr_t)(const void *)oidp->oid_name, + M_SYSCTLOID); + free(oidp, M_SYSCTLOID); + } + } + return (0); +} + +/* + * Create new sysctls at run time. + * clist may point to a valid context initialized with sysctl_ctx_init(). + */ +struct sysctl_oid * +sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, + int number, const char *name, int kind, void *arg1, int arg2, + int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr) +{ + struct sysctl_oid *oidp; + ssize_t len; + char *newname; + + /* You have to hook up somewhere.. */ + if (parent == NULL) + return(NULL); + /* Check if the node already exists, otherwise create it */ + oidp = sysctl_find_oidname(name, parent); + if (oidp != NULL) { + if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + oidp->oid_refcnt++; + /* Update the context */ + if (clist != NULL) + sysctl_ctx_entry_add(clist, oidp); + return (oidp); + } else { + printf("can't re-use a leaf (%s)!\n", name); + return (NULL); + } + } + oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO); + oidp->oid_parent = parent; + SLIST_NEXT(oidp, oid_link) = NULL; + oidp->oid_number = number; + oidp->oid_refcnt = 1; + len = strlen(name); + newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK); + bcopy(name, newname, len + 1); + newname[len] = '\0'; + oidp->oid_name = newname; + oidp->oid_handler = handler; + oidp->oid_kind = CTLFLAG_DYN | kind; + if ((kind & CTLTYPE) == CTLTYPE_NODE) { + /* Allocate space for children */ + SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list), + M_SYSCTLOID, M_WAITOK)); + SLIST_INIT(SYSCTL_CHILDREN(oidp)); + } else { + oidp->oid_arg1 = arg1; + oidp->oid_arg2 = arg2; + } + oidp->oid_fmt = fmt; + if (descr) { + int len = strlen(descr) + 1; + oidp->descr = malloc(len, M_SYSCTLOID, M_WAITOK); + if (oidp->descr) + strcpy((char *)(uintptr_t)(const void *)oidp->descr, descr); + } + /* Update the context, if used */ + if (clist != NULL) + sysctl_ctx_entry_add(clist, oidp); + /* Register this oid */ + sysctl_register_oid(oidp); + return (oidp); +} + +/* + * Register the kernel's oids on startup. + */ +SET_DECLARE(sysctl_set, struct sysctl_oid); + +#if defined(__rtems__) +void +#else +static void +#endif +sysctl_register_all(void *arg) +{ + struct sysctl_oid **oidp; + + SYSCTL_INIT(); + SET_FOREACH(oidp, sysctl_set) + sysctl_register_oid(*oidp); +} +SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0); + +/* + * "Staff-functions" + * + * These functions implement a presently undocumented interface + * used by the sysctl program to walk the tree, and get the type + * so it can print the value. + * This interface is under work and consideration, and should probably + * be killed with a big axe by the first person who can find the time. + * (be aware though, that the proper interface isn't as obvious as it + * may seem, there are various conflicting requirements. + * + * {0,0} printf the entire MIB-tree. + * {0,1,...} return the name of the "..." OID. + * {0,2,...} return the next OID. + * {0,3} return the OID of the name in "new" + * {0,4,...} return the kind & format info for the "..." OID. + * {0,5,...} return the description the "..." OID. + */ + +static void +sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i) +{ + int k; + struct sysctl_oid *oidp; + + SLIST_FOREACH(oidp, l, oid_link) { + + for (k=0; k<i; k++) + printf(" "); + + printf("%d %s ", oidp->oid_number, oidp->oid_name); + + printf("%c%c", + oidp->oid_kind & CTLFLAG_RD ? 'R':' ', + oidp->oid_kind & CTLFLAG_WR ? 'W':' '); + + if (oidp->oid_handler) + printf(" *Handler"); + + switch (oidp->oid_kind & CTLTYPE) { + case CTLTYPE_NODE: + printf(" Node\n"); + if (!oidp->oid_handler) { + sysctl_sysctl_debug_dump_node( + oidp->oid_arg1, i+2); + } + break; + case CTLTYPE_INT: printf(" Int\n"); break; + case CTLTYPE_STRING: printf(" String\n"); break; + case CTLTYPE_QUAD: printf(" Quad\n"); break; + case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break; + default: printf("\n"); + } + + } +} + +static int +sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS) +{ +#ifndef __rtems__ + int error; + + error = suser(req->td); + if (error) + return error; +#endif + sysctl_sysctl_debug_dump_node(&sysctl__children, 0); + return ENOENT; +} + +SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD, + 0, 0, sysctl_sysctl_debug, "-", ""); + +static int +sysctl_sysctl_name(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *) arg1; + u_int namelen = arg2; + int error = 0; + struct sysctl_oid *oid; + struct sysctl_oid_list *lsp = &sysctl__children, *lsp2; + char buf[10]; + + while (namelen) { + if (!lsp) { + snprintf(buf,sizeof(buf),"%d",*name); + if (req->oldidx) + error = SYSCTL_OUT(req, ".", 1); + if (!error) + error = SYSCTL_OUT(req, buf, strlen(buf)); + if (error) + return (error); + namelen--; + name++; + continue; + } + lsp2 = 0; + SLIST_FOREACH(oid, lsp, oid_link) { + if (oid->oid_number != *name) + continue; + + if (req->oldidx) + error = SYSCTL_OUT(req, ".", 1); + if (!error) + error = SYSCTL_OUT(req, oid->oid_name, + strlen(oid->oid_name)); + if (error) + return (error); + + namelen--; + name++; + + if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE) + break; + + if (oid->oid_handler) + break; + + lsp2 = (struct sysctl_oid_list *)oid->oid_arg1; + break; + } + lsp = lsp2; + } + return (SYSCTL_OUT(req, "", 1)); +} + +SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, ""); + +static int +sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, + int *next, int *len, int level, struct sysctl_oid **oidpp) +{ + struct sysctl_oid *oidp; + + *len = level; + SLIST_FOREACH(oidp, lsp, oid_link) { + *next = oidp->oid_number; + *oidpp = oidp; + + if (oidp->oid_kind & CTLFLAG_SKIP) + continue; + + if (!namelen) { + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + return 0; + if (oidp->oid_handler) + /* We really should call the handler here...*/ + return 0; + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1, + len, level+1, oidpp)) + return 0; + goto emptynode; + } + + if (oidp->oid_number < *name) + continue; + + if (oidp->oid_number > *name) { + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + return 0; + if (oidp->oid_handler) + return 0; + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, + next+1, len, level+1, oidpp)) + return (0); + goto next; + } + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + continue; + + if (oidp->oid_handler) + continue; + + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1, + len, level+1, oidpp)) + return (0); + next: + namelen = 1; + emptynode: + *len = level; + } + return 1; +} + +static int +sysctl_sysctl_next(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *) arg1; + u_int namelen = arg2; + int i, j, error; + struct sysctl_oid *oid; + struct sysctl_oid_list *lsp = &sysctl__children; + int newoid[CTL_MAXNAME]; + + i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid); + if (i) + return ENOENT; + error = SYSCTL_OUT(req, newoid, j * sizeof (int)); + return (error); +} + +SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, ""); + +static int +name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp) +{ + int i; + struct sysctl_oid *oidp; + struct sysctl_oid_list *lsp = &sysctl__children; + char *p; + + if (!*name) + return ENOENT; + + p = name + strlen(name) - 1 ; + if (*p == '.') + *p = '\0'; + + *len = 0; + + for (p = name; *p && *p != '.'; p++) + ; + i = *p; + if (i == '.') + *p = '\0'; + + oidp = SLIST_FIRST(lsp); + + while (oidp && *len < CTL_MAXNAME) { + if (strcmp(name, oidp->oid_name)) { + oidp = SLIST_NEXT(oidp, oid_link); + continue; + } + *oid++ = oidp->oid_number; + (*len)++; + + if (!i) { + if (oidpp) + *oidpp = oidp; + return (0); + } + + if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE) + break; + + if (oidp->oid_handler) + break; + + lsp = (struct sysctl_oid_list *)oidp->oid_arg1; + oidp = SLIST_FIRST(lsp); + name = p+1; + for (p = name; *p && *p != '.'; p++) + ; + i = *p; + if (i == '.') + *p = '\0'; + } + return ENOENT; +} + +static int +sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS) +{ + char *p; + int error, oid[CTL_MAXNAME], len=0; + struct sysctl_oid *op = 0; + + if (!req->newlen) + return ENOENT; + if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */ + return (ENAMETOOLONG); + + p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK); + + error = SYSCTL_IN(req, p, req->newlen); + if (error) { + free(p, M_SYSCTL); + return (error); + } + + p [req->newlen] = '\0'; + + error = name2oid(p, oid, &len, &op); + + free(p, M_SYSCTL); + + if (error) + return (error); + + error = SYSCTL_OUT(req, oid, len * sizeof *oid); + return (error); +} + +SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0, + sysctl_sysctl_name2oid, "I", ""); + +static int +sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS) +{ + struct sysctl_oid *oid; + int error; + + error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); + if (error) + return (error); + + if (!oid->oid_fmt) + return (ENOENT); + error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind)); + if (error) + return (error); + error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1); + return (error); +} + + +SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, ""); + +static int +sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS) +{ + struct sysctl_oid *oid; + int error; + + error = sysctl_find_oid(arg1, arg2, &oid, NULL, req); + if (error) + return (error); + + if (!oid->descr) + return (ENOENT); + error = SYSCTL_OUT(req, oid->descr, strlen(oid->descr) + 1); + return (error); +} + +SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, ""); + +/* + * Default "handler" functions. + */ + +/* + * Handle an int, signed or unsigned. + * Two cases: + * a variable: point arg1 at it. + * a constant: pass it in arg2. + */ + +int +sysctl_handle_int(SYSCTL_HANDLER_ARGS) +{ + int tmpout, error = 0; + + /* + * Attempt to get a coherent snapshot by making a copy of the data. + */ + if (arg1) + tmpout = *(int *)arg1; + else + tmpout = arg2; + error = SYSCTL_OUT(req, &tmpout, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + return (error); +} + +/* + * Handle a long, signed or unsigned. arg1 points to it. + */ + +int +sysctl_handle_long(SYSCTL_HANDLER_ARGS) +{ + int error = 0; + long tmpout; + + /* + * Attempt to get a coherent snapshot by making a copy of the data. + */ + if (!arg1) + return (EINVAL); + tmpout = *(long *)arg1; + error = SYSCTL_OUT(req, &tmpout, sizeof(long)); + + if (error || !req->newptr) + return (error); + + error = SYSCTL_IN(req, arg1, sizeof(long)); + return (error); +} + +/* + * Handle our generic '\0' terminated 'C' string. + * Two cases: + * a variable string: point arg1 at it, arg2 is max length. + * a constant string: point arg1 at it, arg2 is zero. + */ + +int +sysctl_handle_string(SYSCTL_HANDLER_ARGS) +{ + int error=0; + char *tmparg; + size_t outlen; + + /* + * Attempt to get a coherent snapshot by copying to a + * temporary kernel buffer. + */ +retry: + outlen = strlen((char *)arg1)+1; + tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK); + + if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) { + free(tmparg, M_SYSCTLTMP); + goto retry; + } + + error = SYSCTL_OUT(req, tmparg, outlen); + free(tmparg, M_SYSCTLTMP); + + if (error || !req->newptr) + return (error); + + if ((req->newlen - req->newidx) >= arg2) { + error = EINVAL; + } else { + arg2 = (req->newlen - req->newidx); + error = SYSCTL_IN(req, arg1, arg2); + ((char *)arg1)[arg2] = '\0'; + } + + return (error); +} + +/* + * Handle any kind of opaque data. + * arg1 points to it, arg2 is the size. + */ + +int +sysctl_handle_opaque(SYSCTL_HANDLER_ARGS) +{ + int error; + void *tmparg; + + /* + * Attempt to get a coherent snapshot, either by wiring the + * user space buffer or copying to a temporary kernel buffer + * depending on the size of the data. + */ + if (arg2 > PAGE_SIZE) { + sysctl_wire_old_buffer(req, arg2); + error = SYSCTL_OUT(req, arg1, arg2); + } else { + tmparg = malloc(arg2, M_SYSCTLTMP, M_WAITOK); + bcopy(arg1, tmparg, arg2); + error = SYSCTL_OUT(req, tmparg, arg2); + free(tmparg, M_SYSCTLTMP); + } + + if (error || !req->newptr) + return (error); + + error = SYSCTL_IN(req, arg1, arg2); + + return (error); +} + +/* + * Transfer functions to/from kernel space. + * XXX: rather untested at this point + */ +static int +sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) +{ + size_t i = 0; + + if (req->oldptr) { + i = l; + if (req->oldlen <= req->oldidx) + i = 0; + else + if (i > req->oldlen - req->oldidx) + i = req->oldlen - req->oldidx; + if (i > 0) + bcopy(p, (char *)req->oldptr + req->oldidx, i); + } + req->oldidx += l; + if (req->oldptr && i != l) + return (ENOMEM); + return (0); +} + +static int +sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l) +{ + if (!req->newptr) + return 0; + if (req->newlen - req->newidx < l) + return (EINVAL); + bcopy((char *)req->newptr + req->newidx, p, l); + req->newidx += l; + return (0); +} + +int +kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, + size_t *oldlenp, void *new, size_t newlen, size_t *retval) +{ + int error = 0; + struct sysctl_req req; + + bzero(&req, sizeof req); + + req.td = td; + + if (oldlenp) { + req.oldlen = *oldlenp; + } + + if (old) { + req.oldptr= old; + } + + if (new != NULL) { + req.newlen = newlen; + req.newptr = new; + } + + req.oldfunc = sysctl_old_kernel; + req.newfunc = sysctl_new_kernel; + req.lock = REQ_LOCKED; + + SYSCTL_LOCK(); + + error = sysctl_root(0, name, namelen, &req); + + if (req.lock == REQ_WIRED) +#ifdef __rtems__ + printf ("kern_sysctl: vsunlock needs to be called!\n"); +#else + vsunlock(req.oldptr, req.oldlen); +#endif + + SYSCTL_UNLOCK(); + + if (error && error != ENOMEM) + return (error); + + if (retval) { + if (req.oldptr && req.oldidx > req.oldlen) + *retval = req.oldlen; + else + *retval = req.oldidx; + } + return (error); +} + +int +kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp, + void *new, size_t newlen, size_t *retval) +{ + int oid[CTL_MAXNAME]; + size_t oidlen, plen; + int error; + + plen = 0; /* RTEMS - to avoid warnings */ + + oid[0] = 0; /* sysctl internal magic */ + oid[1] = 3; /* name2oid */ + oidlen = sizeof(oid); + + error = kernel_sysctl(td, oid, 2, oid, &oidlen, + (void *)name, strlen(name), &plen); + if (error) + return (error); + + error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp, + new, newlen, retval); + return (error); +} + +/* + * Transfer function to/from user space. + */ +static int +sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) +{ + int error = 0; + size_t i = 0; + +#ifndef __rtems__ + if (req->lock == 1 && req->oldptr) + WITNESS_SLEEP(1, NULL); +#endif + if (req->oldptr) { + i = l; + if (req->oldlen <= req->oldidx) + i = 0; + else + if (i > req->oldlen - req->oldidx) + i = req->oldlen - req->oldidx; + if (i > 0) + error = copyout(p, (char *)req->oldptr + req->oldidx, + i); + } + req->oldidx += l; + if (error) + return (error); + if (req->oldptr && i < l) + return (ENOMEM); + return (0); +} + +static int +sysctl_new_user(struct sysctl_req *req, void *p, size_t l) +{ + int error; + + if (!req->newptr) + return 0; + if (req->newlen - req->newidx < l) + return (EINVAL); + error = copyin((char *)req->newptr + req->newidx, p, l); + req->newidx += l; + return (error); +} + +/* + * Wire the user space destination buffer. If set to a value greater than + * zero, the len parameter limits the maximum amount of wired memory. + * + * XXX - The len parameter is currently ignored due to the lack of + * a place to save it in the sysctl_req structure so that the matching + * amount of memory can be unwired in the sysctl exit code. + */ +int +sysctl_wire_old_buffer(struct sysctl_req *req, size_t len) +{ + if (req->lock == REQ_LOCKED && req->oldptr && + req->oldfunc == sysctl_old_user) { +#ifndef __rtems__ + vslock(req->oldptr, req->oldlen); +#endif + req->lock = REQ_WIRED; + } + return (0); +} + +int +sysctl_find_oid(const int *name, u_int namelen, struct sysctl_oid **noid, + int *nindx, struct sysctl_req *req) +{ + struct sysctl_oid *oid; + int indx; + + oid = SLIST_FIRST(&sysctl__children); + indx = 0; + while (oid && indx < CTL_MAXNAME) { + if (oid->oid_number == name[indx]) { + indx++; + if (oid->oid_kind & CTLFLAG_NOLOCK) + req->lock = REQ_UNLOCKED; + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + if (oid->oid_handler != NULL || + indx == namelen) { + *noid = oid; + if (nindx != NULL) + *nindx = indx; + return (0); + } + oid = SLIST_FIRST( + (struct sysctl_oid_list *)oid->oid_arg1); + } else if (indx == namelen) { + *noid = oid; + if (nindx != NULL) + *nindx = indx; + return (0); + } else { + return (ENOTDIR); + } + } else { + oid = SLIST_NEXT(oid, oid_link); + } + } + return (ENOENT); +} + +/* + * Traverse our tree, and find the right node, execute whatever it points + * to, and return the resulting error code. + */ + +static int +sysctl_root(struct sysctl_oid *oidp, const void *arg1, intptr_t arg2, + struct sysctl_req *req) +{ + struct sysctl_oid *oid; + int error, indx; + + error = sysctl_find_oid(arg1, arg2, &oid, &indx, req); + if (error) + return (error); + + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + /* + * You can't call a sysctl when it's a node, but has + * no handler. Inform the user that it's a node. + * The indx may or may not be the same as namelen. + */ + if (oid->oid_handler == NULL) + return (EISDIR); + } + + /* Is this sysctl writable? */ + if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) + return (EPERM); + +#ifndef __rtems__ + KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL")); + + /* Is this sysctl sensitive to securelevels? */ + if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) { + error = securelevel_gt(req->td->td_ucred, 0); + if (error) + return (error); + } + + /* Is this sysctl writable by only privileged users? */ + if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) { + int flags; + + if (oid->oid_kind & CTLFLAG_PRISON) + flags = PRISON_ROOT; + else + flags = 0; + error = suser_cred(req->td->td_ucred, flags); + if (error) + return (error); + } +#endif + + if (!oid->oid_handler) + return EINVAL; + + if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) + error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx, + req); + else + error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2, + req); + return (error); +} + +#ifndef __rtems__ +#ifndef _SYS_SYSPROTO_H_ +struct sysctl_args { + int *name; + u_int namelen; + void *old; + size_t *oldlenp; + void *new; + size_t newlen; +}; +#endif + +/* + * MPSAFE + */ +int +__sysctl(struct thread *td, struct sysctl_args *uap) +{ + int error, name[CTL_MAXNAME]; + size_t j; + + if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) + return (EINVAL); + + error = copyin(uap->name, &name, uap->namelen * sizeof(int)); + if (error) + return (error); + + mtx_lock(&Giant); + + error = userland_sysctl(td, name, uap->namelen, + uap->old, uap->oldlenp, 0, + uap->new, uap->newlen, &j); + if (error && error != ENOMEM) + goto done2; + if (uap->oldlenp) { + int i = copyout(&j, uap->oldlenp, sizeof(j)); + if (i) + error = i; + } +done2: + mtx_unlock(&Giant); + return (error); +} +#endif /* __rtems__ */ + +/* + * This is used from various compatibility syscalls too. That's why name + * must be in kernel space. + */ +int +userland_sysctl(struct thread *td, const int *name, u_int namelen, void *old, + size_t *oldlenp, int inkernel, const void *new, size_t newlen, size_t *retval) +{ + int error = 0; + struct sysctl_req req, req2; + + bzero(&req, sizeof req); + + req.td = td; + + if (oldlenp) { + if (inkernel) { + req.oldlen = *oldlenp; + } else { + error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); + if (error) + return (error); + } + } + + if (old) { +#ifndef __rtems__ + if (!useracc(old, req.oldlen, VM_PROT_WRITE)) + return (EFAULT); +#endif + req.oldptr= old; + } + + if (new != NULL) { +#ifndef __rtems__ + if (!useracc(new, req.newlen, VM_PROT_READ)) + return (EFAULT); +#endif + req.newlen = newlen; + req.newptr = new; + } + + req.oldfunc = sysctl_old_user; + req.newfunc = sysctl_new_user; + req.lock = REQ_LOCKED; + + SYSCTL_LOCK(); + +#ifdef MAC + error = mac_check_system_sysctl(td->td_ucred, name, namelen, old, + oldlenp, inkernel, new, newlen); + if (error) { + SYSCTL_UNLOCK(); + return (error); + } +#endif + + do { + req2 = req; + error = sysctl_root(0, name, namelen, &req2); + } while (error == EAGAIN); + + req = req2; +#ifndef __rtems__ + if (req.lock == REQ_WIRED) + vsunlock(req.oldptr, req.oldlen); +#endif + + SYSCTL_UNLOCK(); + + if (error && error != ENOMEM) + return (error); + + if (retval) { + if (req.oldptr && req.oldidx > req.oldlen) + *retval = req.oldlen; + else + *retval = req.oldidx; + } + return (error); +} + +#ifdef COMPAT_43 +#include <sys/socket.h> +#include <vm/vm_param.h> + +#define KINFO_PROC (0<<8) +#define KINFO_RT (1<<8) +#define KINFO_VNODE (2<<8) +#define KINFO_FILE (3<<8) +#define KINFO_METER (4<<8) +#define KINFO_LOADAVG (5<<8) +#define KINFO_CLOCKRATE (6<<8) + +/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */ +#define KINFO_BSDI_SYSINFO (101<<8) + +/* + * XXX this is bloat, but I hope it's better here than on the potentially + * limited kernel stack... -Peter + */ + +static struct { + int bsdi_machine; /* "i386" on BSD/386 */ +/* ^^^ this is an offset to the string, relative to the struct start */ + char *pad0; + long pad1; + long pad2; + long pad3; + u_long pad4; + u_long pad5; + u_long pad6; + + int bsdi_ostype; /* "BSD/386" on BSD/386 */ + int bsdi_osrelease; /* "1.1" on BSD/386 */ + long pad7; + long pad8; + char *pad9; + + long pad10; + long pad11; + int pad12; + long pad13; + quad_t pad14; + long pad15; + + struct timeval pad16; + /* we dont set this, because BSDI's uname used gethostname() instead */ + int bsdi_hostname; /* hostname on BSD/386 */ + + /* the actual string data is appended here */ + +} bsdi_si; +/* + * this data is appended to the end of the bsdi_si structure during copyout. + * The "char *" offsets are relative to the base of the bsdi_si struct. + * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings + * should not exceed the length of the buffer here... (or else!! :-) + */ +static char bsdi_strings[80]; /* It had better be less than this! */ + +#ifndef _SYS_SYSPROTO_H_ +struct getkerninfo_args { + int op; + char *where; + size_t *size; + int arg; +}; +#endif + +/* + * MPSAFE + */ +int +ogetkerninfo(struct thread *td, struct getkerninfo_args *uap) +{ + int error, name[6]; + size_t size; + u_int needed = 0; + + mtx_lock(&Giant); + + switch (uap->op & 0xff00) { + + case KINFO_RT: + name[0] = CTL_NET; + name[1] = PF_ROUTE; + name[2] = 0; + name[3] = (uap->op & 0xff0000) >> 16; + name[4] = uap->op & 0xff; + name[5] = uap->arg; + error = userland_sysctl(td, name, 6, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_VNODE: + name[0] = CTL_KERN; + name[1] = KERN_VNODE; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_PROC: + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = uap->op & 0xff; + name[3] = uap->arg; + error = userland_sysctl(td, name, 4, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_FILE: + name[0] = CTL_KERN; + name[1] = KERN_FILE; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_METER: + name[0] = CTL_VM; + name[1] = VM_TOTAL; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_LOADAVG: + name[0] = CTL_VM; + name[1] = VM_LOADAVG; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_CLOCKRATE: + name[0] = CTL_KERN; + name[1] = KERN_CLOCKRATE; + error = userland_sysctl(td, name, 2, uap->where, uap->size, + 0, 0, 0, &size); + break; + + case KINFO_BSDI_SYSINFO: { + /* + * this is pretty crude, but it's just enough for uname() + * from BSDI's 1.x libc to work. + * + * *size gives the size of the buffer before the call, and + * the amount of data copied after a successful call. + * If successful, the return value is the amount of data + * available, which can be larger than *size. + * + * BSDI's 2.x product apparently fails with ENOMEM if *size + * is too small. + */ + + u_int left; + char *s; + + bzero((char *)&bsdi_si, sizeof(bsdi_si)); + bzero(bsdi_strings, sizeof(bsdi_strings)); + + s = bsdi_strings; + + bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si); + strcpy(s, ostype); + s += strlen(s) + 1; + + bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si); + strcpy(s, osrelease); + s += strlen(s) + 1; + + bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si); + strcpy(s, machine); + s += strlen(s) + 1; + + needed = sizeof(bsdi_si) + (s - bsdi_strings); + + if ((uap->where == NULL) || (uap->size == NULL)) { + /* process is asking how much buffer to supply.. */ + size = needed; + error = 0; + break; + } + + if ((error = copyin(uap->size, &size, sizeof(size))) != 0) + break; + + /* if too much buffer supplied, trim it down */ + if (size > needed) + size = needed; + + /* how much of the buffer is remaining */ + left = size; + + if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0) + break; + + /* is there any point in continuing? */ + if (left > sizeof(bsdi_si)) { + left -= sizeof(bsdi_si); + error = copyout(&bsdi_strings, + uap->where + sizeof(bsdi_si), left); + } + break; + } + + default: + error = EOPNOTSUPP; + break; + } + if (error == 0) { + td->td_retval[0] = needed ? needed : size; + if (uap->size) { + error = copyout(&size, uap->size, sizeof(size)); + } + } + mtx_unlock(&Giant); + return (error); +} +#endif /* COMPAT_43 */ diff --git a/kern/uipc_domain.c b/kern/uipc_domain.c new file mode 100644 index 0000000..2e4b151 --- /dev/null +++ b/kern/uipc_domain.c @@ -0,0 +1,220 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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 + */ + +#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. + */ + +#if !defined(__rtems__) +static int x_save_spl; /* used by kludge*/ +static void kludge_splimp(void *); +static void kludge_splx(void *); + void domaininit(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) +#endif + +static void pffasttimo(void *); +static void pfslowtimo(void *); + +struct domain *domains; + +#define ADDDOMAIN(x) { \ + __CONCAT(x,domain.dom_next) = domains; \ + domains = &__CONCAT(x,domain); \ +} + +/* ARGSUSED*/ +void +domaininit(void *dummy) +{ + register struct domain *dp; + 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); +} + + +#if !defined(__rtems__) +/* + * 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(void *udata) +{ + int *savesplp = udata; + + *savesplp = splimp(); +} + +static void +kludge_splx(void *udata) +{ + int *savesplp = udata; + + splx( *savesplp); +} +#endif /* !defined(__rtems__) */ + +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(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(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(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/kern/uipc_mbuf.c b/kern/uipc_mbuf.c new file mode 100644 index 0000000..2267ddb --- /dev/null +++ b/kern/uipc_mbuf.c @@ -0,0 +1,742 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#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> + +#if !defined(__rtems__) +static void mbinit (void *) __attribute__ ((unused)); +SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) +#endif + +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; + +/* "number of clusters of pages" */ +#define NCL_INIT 1 + +#define NMB_INIT 16 + +/* + * When MGET failes, ask protocols to free space when short of memory, + * then re-attempt to allocate an mbuf. + */ +struct mbuf * +m_retry(int i, int 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(int i, int 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); +} + +void +m_reclaim(void) +{ + 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(int nowait, int type) +{ + register struct mbuf *m; + + MGET(m, nowait, type); + return (m); +} + +struct mbuf * +m_gethdr(int nowait, int type) +{ + register struct mbuf *m; + + MGETHDR(m, nowait, type); + return (m); +} + +struct mbuf * +m_getclr(int nowait, int 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(struct mbuf *m) +{ + struct mbuf *n; + + MFREE(m, n); + return (n); +} + +void +m_freem(struct mbuf *mb) +{ + struct mbuf *n; + + if (mb == NULL) + return; + do { + MFREE(mb, n); + mb = n; + } while (mb); +} + +/* + * Mbuffer utility routines. + */ + +/* + * Lesser-used path for M_PREPEND: + * allocate new mbuf to prepend to chain, + * copy junk along. + */ +struct mbuf * +m_prepend(struct mbuf *m, int len, int 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(struct mbuf *m, int off0, uint32_t len, int wait) +{ + struct mbuf *n, **np; + 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 == NULL) + 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 == NULL) { + if (len != M_COPYALL) + panic("m_copym"); + break; + } + MGET(n, wait, m->m_type); + *np = n; + if (n == NULL) + 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 == NULL) + MCFail++; + return (top); +nospace: + m_freem(top); + MCFail++; + return (NULL); +} + +/* + * 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(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. Return -1 if requested + * size is bigger than available + */ +int +m_copydata(const struct mbuf *m, int off, int len, caddr_t cp) +{ + u_int count; + + if (off < 0 || len < 0) + panic("m_copydata"); + while (off > 0) { + if (m == 0) { + /*printf("m_copydata: offset > mbuf length ("); + while(m0) { + printf("[%d] ",m0->m_len); + m0 = m0->m_next; + } + printf(")\n");*/ + return -1; + } + if (off < m->m_len) + break; + off -= m->m_len; + m = m->m_next; + } + while (len > 0) { + if (m == 0) { + /*printf("m_copydata: length > mbuf length ("); + while(m0) { + printf("[%d] ",m0->m_len); + m0 = m0->m_next; + } + printf(")\n");*/ + + return -1; + } + 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; + } + return 0; +} + +/* + * 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(struct mbuf *m, struct mbuf *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(struct mbuf *mp, int req_len) +{ + int len = req_len; + struct mbuf *m; + 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(struct mbuf *n, int len) +{ + struct mbuf *m; + 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 == NULL) + 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 (NULL); +} + +/* + * 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(struct mbuf *m0, int len0, int wait) +{ + struct mbuf *m, *n; + u_int len = len0, remain; + + for (m = m0; m && len > m->m_len; m = m->m_next) + len -= m->m_len; + if (m == NULL) + return (NULL); + remain = m->m_len - len; + if (m0->m_flags & M_PKTHDR) { + MGETHDR(n, wait, m0->m_type); + if (n == NULL) + return (NULL); + 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 = NULL; + 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 = NULL; + return (n); +} +/* + * Routine to copy from device local memory into mbufs. + */ +struct mbuf * +m_devget(char *buf, int totlen, int off0, struct ifnet *ifp, + void (*copy)(char *from, caddr_t to, u_int len)) +{ + struct mbuf *m; + struct mbuf *top = NULL, **mp = ⊤ + int len; + int off = off0; + 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), (u_int)len); + else + bcopy(cp, mtod(m, caddr_t), (u_int)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. + */ +int +m_copyback(struct mbuf *m0, int off, int len, caddr_t cp) +{ + int mlen; + struct mbuf *m = m0, *n; + int totlen = 0; + + if (m0 == NULL) + return 0; + while (off > (mlen = m->m_len)) { + off -= mlen; + totlen += mlen; + if (m->m_next == NULL) { + n = m_getclr(M_DONTWAIT, m->m_type); + if (n == NULL) { + /*panic("m_copyback() : malformed chain\n");*/ + return -1; + } + 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), (u_int)mlen); + cp += mlen; + len -= mlen; + mlen += off; + off = 0; + totlen += mlen; + if (len == 0) { + /* m->m_len = mlen; */ + break; + } + if (m->m_next == NULL) { + n = m_get(M_DONTWAIT, m->m_type); + if (n == 0) { + /*panic("m_copyback() : malformed chain 2\n");*/ + return -1; + }; + n->m_len = min(MLEN, len); + m->m_next = n; + } + /* m->m_len = mlen; */ + m = m->m_next; + } +/*out:*/ + if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) + m->m_pkthdr.len = totlen; + return 0; +} diff --git a/kern/uipc_socket.c b/kern/uipc_socket.c new file mode 100644 index 0000000..c6220bd --- /dev/null +++ b/kern/uipc_socket.c @@ -0,0 +1,1139 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#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> +#include <sys/uio.h> +#include <limits.h> +#ifdef __rtems__ +/* + * This socket option was removed 1997 from the upstream FreeBSD network stack. + * Turn this feature into essentially dead code. + */ +#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */ + +#include <rtems/rtems_bsdnet.h> +#endif /* __rtems__ */ + +static int somaxconn = SOMAXCONN; +SYSCTL_INT(_kern, KIPC_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(int dom, struct socket **aso, 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_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(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(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(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); +} + +static void +rtems_socket_close_notify(struct socket *so) +{ + if (so->so_pgid) { + rtems_event_system_send(so->so_pgid, RTEMS_EVENT_SYSTEM_NETWORK_CLOSE); + } +} + +static void +rtems_sockbuf_close_notify(struct socket *so, struct sockbuf *sb) +{ + if (sb->sb_flags & SB_WAIT) { + rtems_event_system_send(sb->sb_sel.si_pid, + RTEMS_EVENT_SYSTEM_NETWORK_CLOSE); + } + + if (sb->sb_wakeup) + (*sb->sb_wakeup)(so, sb->sb_wakeuparg); +} + +/* + * Close a socket on last file table reference removal. + * Initiate disconnect if connected. + * Free socket when disconnect complete. + */ +int +soclose(struct socket *so) +{ + int s = splnet(); /* conservative */ + int error = 0; + + rtems_socket_close_notify(so); + rtems_sockbuf_close_notify(so, &so->so_snd); + rtems_sockbuf_close_notify(so, &so->so_rcv); + + 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(struct socket *so) +{ + + return (*so->so_proto->pr_usrreqs->pru_abort)(so); +} + +int +soaccept(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(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(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(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(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(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) { + if (error != ENXIO) + 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(struct socket *so, 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(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(struct socket *so, int level, int 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; + unsigned long val; + + if (m == NULL || m->m_len < sizeof (*tv)) { + error = EINVAL; + goto bad; + } + tv = mtod(m, struct timeval *); + if (tv->tv_sec >= (ULONG_MAX - hz) / hz) { + error = EDOM; + goto bad; + } + + val = tv->tv_sec * hz + tv->tv_usec / tick; + if ((val == 0) && (tv->tv_sec || tv->tv_usec)) + val = 1; + + 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; + + case SO_SNDWAKEUP: + case SO_RCVWAKEUP: + { + /* RTEMS addition. */ + struct sockwakeup *sw; + struct sockbuf *sb; + + if (m == NULL + || m->m_len != sizeof (struct sockwakeup)) { + error = EINVAL; + goto bad; + } + sw = mtod(m, struct sockwakeup *); + sb = (optname == SO_SNDWAKEUP + ? &so->so_snd + : &so->so_rcv); + sb->sb_wakeup = sw->sw_pfn; + sb->sb_wakeuparg = sw->sw_arg; + if (sw->sw_pfn) + sb->sb_flags |= SB_ASYNC; + else + sb->sb_flags &=~ SB_ASYNC; + 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(struct socket *so, int level, int 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: + { + unsigned long 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; + } + + case SO_SNDWAKEUP: + case SO_RCVWAKEUP: + { + struct sockbuf *sb; + struct sockwakeup *sw; + + /* RTEMS additions. */ + sb = (optname == SO_SNDWAKEUP + ? &so->so_snd + : &so->so_rcv); + m->m_len = sizeof (struct sockwakeup); + sw = mtod(m, struct sockwakeup *); + sw->sw_pfn = sb->sb_wakeup; + sw->sw_arg = sb->sb_wakeuparg; + break; + } + + default: + (void)m_free(m); + return (ENOPROTOOPT); + } + *mp = m; + return (0); + } +} + +void +sohasoutofband(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/kern/uipc_socket2.c b/kern/uipc_socket2.c new file mode 100644 index 0000000..137eb0f --- /dev/null +++ b/kern/uipc_socket2.c @@ -0,0 +1,939 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/file.h> +#include <sys/queue.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, KIPC_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, ""); + +#if defined(__rtems__) + void rtems_set_sb_efficiency( + u_long efficiency + ) + { + sb_efficiency = (efficiency == 0) ? 2 : efficiency; + } +#endif + +/* + * 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(struct socket *so) +{ + + so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); + so->so_state |= SS_ISCONNECTING; +} + +void +soisconnected(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(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(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(struct socket *head) +{ + register struct socket *so; + uint32_t 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(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; + (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(struct socket *so) +{ + + so->so_state |= SS_CANTSENDMORE; + sowwakeup(so); +} + +void +socantrcvmore(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(struct socket *so, u_long sndcc, u_long 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(struct sockbuf *sb, u_long cc) +{ + + if (cc > sb_max * MCLBYTES / (_SYS_MBUF_LEGACY_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(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(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(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 += _SYS_MBUF_LEGACY_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(struct sockbuf *sb, 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(struct sockbuf *sb, 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(struct sockbuf *sb, struct sockaddr *asa, + struct mbuf *m0, struct mbuf *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(struct sockbuf *sb, struct mbuf *m0, + struct mbuf *control) +{ + 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(struct sockbuf *sb, struct mbuf *m, struct mbuf *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(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(struct sockbuf *sb, 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(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(caddr_t p, int size, int type, int 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, intptr_t 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, intptr_t 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, intptr_t 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, intptr_t 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/lib/README b/lib/README new file mode 100644 index 0000000..787c24c --- /dev/null +++ b/lib/README @@ -0,0 +1 @@ +Sources from application-level (as opposed to kernel-level) libraries. diff --git a/lib/ftpfs.c b/lib/ftpfs.c new file mode 100644 index 0000000..5e0cb95 --- /dev/null +++ b/lib/ftpfs.c @@ -0,0 +1,1430 @@ +/** + * @file + * + * File Transfer Protocol file system (FTP client). + */ + +/* + * Copyright (c) 2009-2012 embedded brains GmbH. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * (c) Copyright 2002 + * Thomas Doerfler + * IMD Ingenieurbuero fuer Microcomputertechnik + * Herbststr. 8 + * 82178 Puchheim, Germany + * <Thomas.Doerfler@imd-systems.de> + * + * This code has been created after closly inspecting "tftpdriver.c" from Eric + * Norum. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <malloc.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include <rtems.h> +#include <rtems/ftpfs.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +#ifdef DEBUG + #define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else + #define DEBUG_PRINTF(...) +#endif + +/** + * Connection entry for each open file stream. + */ +typedef struct { + off_t file_size; + + /** + * Control connection socket. + */ + int ctrl_socket; + + uint32_t client_address; + + /** + * Data transfer socket. + */ + int data_socket; + + /** + * Current index into the reply buffer. + */ + size_t reply_current; + + /** + * End index of the reply buffer. + */ + size_t reply_end; + + /** + * Buffer for relpy data. + */ + char reply_buffer [128]; + + /** + * End of file flag. + */ + bool eof; + + bool write; + + /** + * Indicates if we should do a SIZE command. + * + * The first call to the rtems_ftpfs_fstat() handler is issued by the path + * evaluation to check for access permission. For this case we avoid the + * SIZE command. + */ + bool do_size_command; + + ino_t ino; + + const char *user; + + const char *password; + + const char *hostname; + + const char *filename; + + char buffer []; +} rtems_ftpfs_entry; + +/** + * Mount entry for each file system instance. + */ +typedef struct { + /** + * Verbose mode enabled or disabled. + */ + bool verbose; + + /** + * Timeout value + */ + struct timeval timeout; + + /** + * Inode counter. + */ + ino_t ino; +} rtems_ftpfs_mount_entry; + +static const rtems_filesystem_operations_table rtems_ftpfs_ops; + +static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers; + +static const rtems_filesystem_file_handlers_r rtems_ftpfs_root_handlers; + +static bool rtems_ftpfs_use_timeout(const struct timeval *to) +{ + return to->tv_sec != 0 || to->tv_usec != 0; +} + +static int rtems_ftpfs_set_connection_timeout( + int socket, + const struct timeval *to +) +{ + if (rtems_ftpfs_use_timeout(to)) { + int rv = 0; + + rv = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, to, sizeof(*to)); + if (rv != 0) { + return EIO; + } + + rv = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, to, sizeof(*to)); + if (rv != 0) { + return EIO; + } + } + + return 0; +} + +static rtems_status_code rtems_ftpfs_do_ioctl( + const char *mount_point, + ioctl_command_t req, + ... +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + int rv = 0; + int fd = 0; + va_list ap; + + if (mount_point == NULL) { + mount_point = RTEMS_FTPFS_MOUNT_POINT_DEFAULT; + } + + fd = open(mount_point, O_RDWR); + if (fd < 0) { + return RTEMS_INVALID_NAME; + } + + va_start(ap, req); + rv = ioctl(fd, req, va_arg(ap, void *)); + va_end(ap); + if (rv != 0) { + sc = RTEMS_INVALID_NUMBER; + } + + rv = close(fd); + if (rv != 0 && sc == RTEMS_SUCCESSFUL) { + sc = RTEMS_IO_ERROR; + } + + return sc; +} + +rtems_status_code rtems_ftpfs_get_verbose(const char *mount_point, bool *verbose) +{ + return rtems_ftpfs_do_ioctl( + mount_point, + RTEMS_FTPFS_IOCTL_GET_VERBOSE, + verbose + ); +} + +rtems_status_code rtems_ftpfs_set_verbose(const char *mount_point, bool verbose) +{ + return rtems_ftpfs_do_ioctl( + mount_point, + RTEMS_FTPFS_IOCTL_SET_VERBOSE, + &verbose + ); +} + +rtems_status_code rtems_ftpfs_get_timeout( + const char *mount_point, + struct timeval *timeout +) +{ + return rtems_ftpfs_do_ioctl( + mount_point, + RTEMS_FTPFS_IOCTL_GET_TIMEOUT, + timeout + ); +} + +rtems_status_code rtems_ftpfs_set_timeout( + const char *mount_point, + const struct timeval *timeout +) +{ + return rtems_ftpfs_do_ioctl( + mount_point, + RTEMS_FTPFS_IOCTL_SET_TIMEOUT, + timeout + ); +} + +typedef void (*rtems_ftpfs_reply_parser)( + const char * /* reply fragment */, + size_t /* reply fragment length */, + void * /* parser argument */ +); + +typedef enum { + RTEMS_FTPFS_REPLY_START, + RTEMS_FTPFS_REPLY_SINGLE_LINE, + RTEMS_FTPFS_REPLY_DONE, + RTEMS_FTPFS_REPLY_MULTI_LINE, + RTEMS_FTPFS_REPLY_MULTI_LINE_START +} rtems_ftpfs_reply_state; + +typedef enum { + RTEMS_FTPFS_REPLY_ERROR = 0, + RTEMS_FTPFS_REPLY_1 = '1', + RTEMS_FTPFS_REPLY_2 = '2', + RTEMS_FTPFS_REPLY_3 = '3', + RTEMS_FTPFS_REPLY_4 = '4', + RTEMS_FTPFS_REPLY_5 = '5' +} rtems_ftpfs_reply; + +#define RTEMS_FTPFS_REPLY_SIZE 3 + +static bool rtems_ftpfs_is_reply_code_valid(unsigned char *reply) +{ + return isdigit(reply [0]) && isdigit(reply [1]) && isdigit(reply [2]); +} + +static rtems_ftpfs_reply rtems_ftpfs_get_reply( + rtems_ftpfs_entry *e, + rtems_ftpfs_reply_parser parser, + void *parser_arg, + bool verbose +) +{ + rtems_ftpfs_reply_state state = RTEMS_FTPFS_REPLY_START; + unsigned char reply_code [RTEMS_FTPFS_REPLY_SIZE] = { 'a', 'a', 'a' }; + size_t reply_code_index = 0; + + while (state != RTEMS_FTPFS_REPLY_DONE) { + char *buf = NULL; + size_t i = 0; + size_t n = 0; + + /* Receive reply fragment from socket */ + if (e->reply_current == e->reply_end) { + ssize_t rv = 0; + + e->reply_current = 0; + e->reply_end = 0; + + rv = recv( + e->ctrl_socket, + &e->reply_buffer [0], + sizeof(e->reply_buffer), + 0 + ); + + if (rv > 0) { + e->reply_end = (size_t) rv; + } else { + return RTEMS_FTPFS_REPLY_ERROR; + } + } + + buf = &e->reply_buffer [e->reply_current]; + n = e->reply_end - e->reply_current; + + /* Invoke parser if necessary */ + if (parser != NULL) { + parser(buf, n, parser_arg); + } + + /* Parse reply fragment */ + for (i = 0; i < n && state != RTEMS_FTPFS_REPLY_DONE; ++i) { + char c = buf [i]; + + switch (state) { + case RTEMS_FTPFS_REPLY_START: + if (reply_code_index < RTEMS_FTPFS_REPLY_SIZE) { + reply_code [reply_code_index] = c; + ++reply_code_index; + } else if (rtems_ftpfs_is_reply_code_valid(reply_code)) { + if (c == '-') { + state = RTEMS_FTPFS_REPLY_MULTI_LINE; + } else { + state = RTEMS_FTPFS_REPLY_SINGLE_LINE; + } + } else { + return RTEMS_FTPFS_REPLY_ERROR; + } + break; + case RTEMS_FTPFS_REPLY_SINGLE_LINE: + if (c == '\n') { + state = RTEMS_FTPFS_REPLY_DONE; + } + break; + case RTEMS_FTPFS_REPLY_MULTI_LINE: + if (c == '\n') { + state = RTEMS_FTPFS_REPLY_MULTI_LINE_START; + reply_code_index = 0; + } + break; + case RTEMS_FTPFS_REPLY_MULTI_LINE_START: + if (reply_code_index < RTEMS_FTPFS_REPLY_SIZE) { + if (reply_code [reply_code_index] == c) { + ++reply_code_index; + } else { + state = RTEMS_FTPFS_REPLY_MULTI_LINE; + } + } else { + if (c == ' ') { + state = RTEMS_FTPFS_REPLY_SINGLE_LINE; + } else { + state = RTEMS_FTPFS_REPLY_MULTI_LINE; + } + } + break; + default: + return RTEMS_FTPFS_REPLY_ERROR; + } + } + + /* Be verbose if necessary */ + if (verbose) { + write(STDERR_FILENO, buf, i); + } + + /* Update reply index */ + e->reply_current += i; + } + + return reply_code [0]; +} + +static rtems_ftpfs_reply rtems_ftpfs_send_command_with_parser( + rtems_ftpfs_entry *e, + const char *cmd, + const char *arg, + rtems_ftpfs_reply_parser parser, + void *parser_arg, + bool verbose +) +{ + rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; + size_t cmd_len = strlen(cmd); + size_t arg_len = arg != NULL ? strlen(arg) : 0; + size_t len = cmd_len + arg_len + 2; + char *buf = malloc(len); + + if (buf != NULL) { + ssize_t n = 0; + char *buf_arg = buf + cmd_len; + char *buf_eol = buf_arg + arg_len; + + memcpy(buf, cmd, cmd_len); + memcpy(buf_arg, arg, arg_len); + buf_eol [0] = '\r'; + buf_eol [1] = '\n'; + + /* Send */ + n = send(e->ctrl_socket, buf, len, 0); + if (n == (ssize_t) len) { + if (verbose) { + write(STDERR_FILENO, buf, len); + } + + /* Reply */ + reply = rtems_ftpfs_get_reply(e, parser, parser_arg, verbose); + } + + free(buf); + } + + return reply; +} + +static rtems_ftpfs_reply rtems_ftpfs_send_command( + rtems_ftpfs_entry *e, + const char *cmd, + const char *arg, + bool verbose +) +{ + return rtems_ftpfs_send_command_with_parser( + e, + cmd, + arg, + NULL, + NULL, + verbose + ); +} + +typedef enum { + STATE_USER_NAME, + STATE_START_PASSWORD, + STATE_START_HOST_NAME, + STATE_START_HOST_NAME_OR_PATH, + STATE_START_PATH, + STATE_PASSWORD, + STATE_HOST_NAME, + STATE_DONE, + STATE_INVALID +} split_state; + +static int rtems_ftpfs_split_names ( + char *s, + const char **user, + const char **password, + const char **hostname, + const char **path +) +{ + split_state state = STATE_USER_NAME; + size_t len = strlen(s); + size_t i = 0; + + *user = s; + + for (i = 0; i < len; ++i) { + char c = s [i]; + + switch (state) { + case STATE_USER_NAME: + if (c == ':') { + state = STATE_START_PASSWORD; + s [i] = '\0'; + } else if (c == '@') { + state = STATE_START_HOST_NAME; + s [i] = '\0'; + } else if (c == '/') { + state = STATE_START_HOST_NAME_OR_PATH; + s [i] = '\0'; + } + break; + case STATE_START_PASSWORD: + state = STATE_PASSWORD; + *password = &s [i]; + --i; + break; + case STATE_START_HOST_NAME: + state = STATE_HOST_NAME; + *hostname = &s [i]; + --i; + break; + case STATE_START_HOST_NAME_OR_PATH: + if (c == '@') { + state = STATE_START_HOST_NAME; + } else { + state = STATE_DONE; + *path = &s [i]; + goto done; + } + break; + case STATE_START_PATH: + state = STATE_DONE; + *path = &s [i]; + goto done; + case STATE_PASSWORD: + if (c == '@') { + state = STATE_START_HOST_NAME; + s [i] = '\0'; + } else if (c == '/') { + state = STATE_START_HOST_NAME_OR_PATH; + s [i] = '\0'; + } + break; + case STATE_HOST_NAME: + if (c == '/') { + state = STATE_START_PATH; + s [i] = '\0'; + } + break; + default: + state = STATE_INVALID; + goto done; + } + } + +done: + + /* This is a special case with no username and password */ + if (*hostname == NULL) { + *hostname = &s [0]; + *user = "anonymous"; + *password = *user; + } + + /* If we have no password use the user name */ + if (*password == NULL) { + *password = *user; + } + + return state == STATE_DONE ? 0 : ENOENT; +} + +static socklen_t rtems_ftpfs_create_address( + struct sockaddr_in *sa, + unsigned long address, + unsigned short port +) +{ + memset(sa, 0, sizeof(*sa)); + + sa->sin_family = AF_INET; + sa->sin_addr.s_addr = address; + sa->sin_port = port; + sa->sin_len = sizeof(*sa); + + return sizeof(*sa); +} + +static int rtems_ftpfs_close_data_connection( + rtems_ftpfs_entry *e, + bool verbose, + bool error +) +{ + int eno = 0; + + /* Close data connection if necessary */ + if (e->data_socket >= 0) { + int rv = close(e->data_socket); + + e->data_socket = -1; + if (rv != 0) { + eno = EIO; + } + + /* For write connections we have to obtain the transfer reply */ + if (e->write && !error) { + rtems_ftpfs_reply reply = + rtems_ftpfs_get_reply(e, NULL, NULL, verbose); + + if (reply != RTEMS_FTPFS_REPLY_2) { + eno = EIO; + } + } + } + + return eno; +} + +static int rtems_ftpfs_open_ctrl_connection( + rtems_ftpfs_entry *e, + bool verbose, + const struct timeval *timeout +) +{ + int rv = 0; + int eno = 0; + rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; + struct in_addr address = { .s_addr = 0 }; + struct sockaddr_in sa; + socklen_t size = 0; + + /* Create the socket for the control connection */ + e->ctrl_socket = socket(AF_INET, SOCK_STREAM, 0); + if (e->ctrl_socket < 0) { + return ENOMEM; + } + + /* Set up the server address from the hostname */ + if (inet_aton(e->hostname, &address) == 0) { + /* Try to get the address by name */ + struct hostent *he = gethostbyname(e->hostname); + + if (he != NULL) { + memcpy(&address, he->h_addr, sizeof(address)); + } else { + return ENOENT; + } + } + rtems_ftpfs_create_address(&sa, address.s_addr, htons(RTEMS_FTPFS_CTRL_PORT)); + DEBUG_PRINTF("server = %s\n", inet_ntoa(sa.sin_addr)); + + /* Open control connection */ + rv = connect( + e->ctrl_socket, + (struct sockaddr *) &sa, + sizeof(sa) + ); + if (rv != 0) { + return ENOENT; + } + + /* Set control connection timeout */ + eno = rtems_ftpfs_set_connection_timeout(e->ctrl_socket, timeout); + if (eno != 0) { + return eno; + } + + /* Get client address */ + size = rtems_ftpfs_create_address(&sa, INADDR_ANY, 0); + rv = getsockname( + e->ctrl_socket, + (struct sockaddr *) &sa, + &size + ); + if (rv != 0) { + return ENOMEM; + } + e->client_address = ntohl(sa.sin_addr.s_addr); + DEBUG_PRINTF("client = %s\n", inet_ntoa(sa.sin_addr)); + + /* Now we should get a welcome message from the server */ + reply = rtems_ftpfs_get_reply(e, NULL, NULL, verbose); + if (reply != RTEMS_FTPFS_REPLY_2) { + return ENOENT; + } + + /* Send USER command */ + reply = rtems_ftpfs_send_command(e, "USER ", e->user, verbose); + if (reply == RTEMS_FTPFS_REPLY_3) { + /* Send PASS command */ + reply = rtems_ftpfs_send_command(e, "PASS ", e->password, verbose); + if (reply != RTEMS_FTPFS_REPLY_2) { + return EACCES; + } + + /* TODO: Some server may require an account */ + } else if (reply != RTEMS_FTPFS_REPLY_2) { + return EACCES; + } + + /* Send TYPE command to set binary mode for all data transfers */ + reply = rtems_ftpfs_send_command(e, "TYPE I", NULL, verbose); + if (reply != RTEMS_FTPFS_REPLY_2) { + return EIO; + } + + return 0; +} + +static int rtems_ftpfs_open_data_connection_active( + rtems_ftpfs_entry *e, + const char *file_command, + bool verbose, + const struct timeval *timeout +) +{ + int rv = 0; + int eno = 0; + rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; + struct sockaddr_in sa; + socklen_t size = 0; + int port_socket = -1; + char port_command [] = "PORT 000,000,000,000,000,000"; + uint16_t data_port = 0; + + /* Create port socket to establish a data data connection */ + port_socket = socket(AF_INET, SOCK_STREAM, 0); + if (port_socket < 0) { + eno = ENOMEM; + goto cleanup; + } + + /* Bind port socket */ + rtems_ftpfs_create_address(&sa, INADDR_ANY, 0); + rv = bind( + port_socket, + (struct sockaddr *) &sa, + sizeof(sa) + ); + if (rv != 0) { + eno = EBUSY; + goto cleanup; + } + + /* Get port number for data socket */ + size = rtems_ftpfs_create_address(&sa, INADDR_ANY, 0); + rv = getsockname( + port_socket, + (struct sockaddr *) &sa, + &size + ); + if (rv != 0) { + eno = ENOMEM; + goto cleanup; + } + data_port = ntohs(sa.sin_port); + + /* Send PORT command to set data connection port for server */ + snprintf( + port_command, + sizeof(port_command), + "PORT %lu,%lu,%lu,%lu,%lu,%lu", + (e->client_address >> 24) & 0xffUL, + (e->client_address >> 16) & 0xffUL, + (e->client_address >> 8) & 0xffUL, + (e->client_address >> 0) & 0xffUL, + (data_port >> 8) & 0xffUL, + (data_port >> 0) & 0xffUL + ); + reply = rtems_ftpfs_send_command(e, port_command, NULL, verbose); + if (reply != RTEMS_FTPFS_REPLY_2) { + eno = ENOTSUP; + goto cleanup; + } + + /* Listen on port socket for incoming data connections */ + rv = listen(port_socket, 1); + if (rv != 0) { + eno = EBUSY; + goto cleanup; + } + + /* Send RETR or STOR command with filename */ + reply = rtems_ftpfs_send_command(e, file_command, e->filename, verbose); + if (reply != RTEMS_FTPFS_REPLY_1) { + eno = EIO; + goto cleanup; + } + + /* Wait for connect on data connection if necessary */ + if (rtems_ftpfs_use_timeout(timeout)) { + struct timeval to = *timeout; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(port_socket, &fds); + + rv = select(port_socket + 1, &fds, NULL, NULL, &to); + if (rv <= 0) { + eno = EIO; + goto cleanup; + } + } + + /* Accept data connection */ + size = sizeof(sa); + e->data_socket = accept( + port_socket, + (struct sockaddr *) &sa, + &size + ); + if (e->data_socket < 0) { + eno = EIO; + goto cleanup; + } + +cleanup: + + /* Close port socket if necessary */ + if (port_socket >= 0) { + rv = close(port_socket); + if (rv != 0) { + eno = EIO; + } + } + + return eno; +} + +typedef enum { + RTEMS_FTPFS_PASV_START = 0, + RTEMS_FTPFS_PASV_JUNK, + RTEMS_FTPFS_PASV_DATA, + RTEMS_FTPFS_PASV_DONE +} rtems_ftpfs_pasv_state; + +typedef struct { + rtems_ftpfs_pasv_state state; + size_t index; + uint8_t data [6]; +} rtems_ftpfs_pasv_entry; + +static void rtems_ftpfs_pasv_parser( + const char* buf, + size_t len, + void *arg +) +{ + rtems_ftpfs_pasv_entry *pe = arg; + size_t i = 0; + + for (i = 0; i < len; ++i) { + int c = buf [i]; + + switch (pe->state) { + case RTEMS_FTPFS_PASV_START: + if (!isdigit(c)) { + pe->state = RTEMS_FTPFS_PASV_JUNK; + pe->index = 0; + } + break; + case RTEMS_FTPFS_PASV_JUNK: + if (isdigit(c)) { + pe->state = RTEMS_FTPFS_PASV_DATA; + pe->data [pe->index] = (uint8_t) (c - '0'); + } + break; + case RTEMS_FTPFS_PASV_DATA: + if (isdigit(c)) { + pe->data [pe->index] = + (uint8_t) (pe->data [pe->index] * 10 + c - '0'); + } else if (c == ',') { + ++pe->index; + if (pe->index < sizeof(pe->data)) { + pe->data [pe->index] = 0; + } else { + pe->state = RTEMS_FTPFS_PASV_DONE; + } + } else { + pe->state = RTEMS_FTPFS_PASV_DONE; + } + break; + default: + return; + } + } +} + +static int rtems_ftpfs_open_data_connection_passive( + rtems_ftpfs_entry *e, + const char *file_command, + bool verbose, + const struct timeval *timeout +) +{ + int rv = 0; + rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; + struct sockaddr_in sa; + uint32_t data_address = 0; + uint16_t data_port = 0; + rtems_ftpfs_pasv_entry pe; + + memset(&pe, 0, sizeof(pe)); + + /* Send PASV command */ + reply = rtems_ftpfs_send_command_with_parser( + e, + "PASV", + NULL, + rtems_ftpfs_pasv_parser, + &pe, + verbose + ); + if (reply != RTEMS_FTPFS_REPLY_2) { + return ENOTSUP; + } + data_address = ((uint32_t)(pe.data [0]) << 24) + + ((uint32_t)(pe.data [1]) << 16) + + ((uint32_t)(pe.data [2]) << 8) + + ((uint32_t)(pe.data [3])); + data_port = (uint16_t) ((pe.data [4] << 8) + pe.data [5]); + rtems_ftpfs_create_address(&sa, htonl(data_address), htons(data_port)); + DEBUG_PRINTF( + "server data = %s:%u\n", + inet_ntoa(sa.sin_addr), + (unsigned) ntohs(sa.sin_port) + ); + + /* Create data socket */ + e->data_socket = socket(AF_INET, SOCK_STREAM, 0); + if (e->data_socket < 0) { + return ENOMEM; + } + + /* Open data connection */ + rv = connect( + e->data_socket, + (struct sockaddr *) &sa, + sizeof(sa) + ); + if (rv != 0) { + return EIO; + } + + /* Send RETR or STOR command with filename */ + reply = rtems_ftpfs_send_command(e, file_command, e->filename, verbose); + if (reply != RTEMS_FTPFS_REPLY_1) { + return EIO; + } + + return 0; +} + +typedef enum { + RTEMS_FTPFS_SIZE_START = 0, + RTEMS_FTPFS_SIZE_SPACE, + RTEMS_FTPFS_SIZE_NUMBER, + RTEMS_FTPFS_SIZE_NL +} rtems_ftpfs_size_state; + +typedef struct { + rtems_ftpfs_size_state state; + size_t index; + off_t size; +} rtems_ftpfs_size_entry; + +static void rtems_ftpfs_size_parser( + const char* buf, + size_t len, + void *arg +) +{ + rtems_ftpfs_size_entry *se = arg; + size_t i = 0; + + for (i = 0; se->size >= 0 && i < len; ++i, ++se->index) { + int c = buf [i]; + + switch (se->state) { + case RTEMS_FTPFS_SIZE_START: + if (se->index == 2) { + se->state = RTEMS_FTPFS_SIZE_SPACE; + } + break; + case RTEMS_FTPFS_SIZE_SPACE: + if (c == ' ') { + se->state = RTEMS_FTPFS_SIZE_NUMBER; + } else { + se->size = -1; + } + break; + case RTEMS_FTPFS_SIZE_NUMBER: + if (isdigit(c)) { + se->size = 10 * se->size + c - '0'; + } else if (c == '\r') { + se->state = RTEMS_FTPFS_SIZE_NL; + } else { + se->size = -1; + } + break; + case RTEMS_FTPFS_SIZE_NL: + if (c != '\n') { + se->size = -1; + } + break; + default: + se->size = -1; + break; + } + } +} + +static void rtems_ftpfs_get_file_size(rtems_ftpfs_entry *e, bool verbose) +{ + if (e->file_size < 0) { + if (e->write) { + e->file_size = 0; + } else { + rtems_ftpfs_size_entry se; + rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR; + + memset(&se, 0, sizeof(se)); + + reply = rtems_ftpfs_send_command_with_parser( + e, + "SIZE ", + e->filename, + rtems_ftpfs_size_parser, + &se, + verbose + ); + if (reply == RTEMS_FTPFS_REPLY_2 && se.size >= 0) { + e->file_size = se.size; + } else { + e->file_size = 0; + } + } + } +} + +static int rtems_ftpfs_open( + rtems_libio_t *iop, + const char *path, + int oflag, + mode_t mode +) +{ + int eno = 0; + rtems_ftpfs_entry *e = iop->pathinfo.node_access; + rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; + bool verbose = me->verbose; + const struct timeval *timeout = &me->timeout; + + e->write = rtems_libio_iop_is_writeable(iop); + + /* Check for either read-only or write-only flags */ + if ( + rtems_libio_iop_is_writeable(iop) + && rtems_libio_iop_is_readable(iop) + ) { + eno = ENOTSUP; + } + + if (eno == 0) { + rtems_ftpfs_get_file_size(e, verbose); + } + + if (eno == 0) { + const char *file_command = e->write ? "STOR " : "RETR "; + + /* Open passive data connection */ + eno = rtems_ftpfs_open_data_connection_passive( + e, + file_command, + verbose, + timeout + ); + if (eno == ENOTSUP) { + /* Open active data connection */ + eno = rtems_ftpfs_open_data_connection_active( + e, + file_command, + verbose, + timeout + ); + } + } + + /* Set data connection timeout */ + if (eno == 0) { + eno = rtems_ftpfs_set_connection_timeout(e->data_socket, timeout); + } + + if (eno == 0) { + return 0; + } else { + rtems_ftpfs_close_data_connection(e, verbose, true); + + rtems_set_errno_and_return_minus_one(eno); + } +} + +static ssize_t rtems_ftpfs_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + rtems_ftpfs_entry *e = iop->pathinfo.node_access; + const rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; + bool verbose = me->verbose; + char *in = buffer; + size_t todo = count; + + if (e->eof) { + return 0; + } + + while (todo > 0) { + ssize_t rv = recv(e->data_socket, in, todo, 0); + + if (rv <= 0) { + if (rv == 0) { + rtems_ftpfs_reply reply = + rtems_ftpfs_get_reply(e, NULL, NULL, verbose); + + if (reply == RTEMS_FTPFS_REPLY_2) { + e->eof = true; + break; + } + } + + rtems_set_errno_and_return_minus_one(EIO); + } + + in += rv; + todo -= (size_t) rv; + } + + return (ssize_t) (count - todo); +} + +static ssize_t rtems_ftpfs_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + rtems_ftpfs_entry *e = iop->pathinfo.node_access; + const char *out = buffer; + size_t todo = count; + + while (todo > 0) { + ssize_t rv = send(e->data_socket, out, todo, 0); + + if (rv <= 0) { + if (rv == 0) { + break; + } else { + rtems_set_errno_and_return_minus_one(EIO); + } + } + + out += rv; + todo -= (size_t) rv; + + e->file_size += rv; + } + + return (ssize_t) (count - todo); +} + +static int rtems_ftpfs_close(rtems_libio_t *iop) +{ + rtems_ftpfs_entry *e = iop->pathinfo.node_access; + const rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; + int eno = rtems_ftpfs_close_data_connection(e, me->verbose, false); + + if (eno == 0) { + return 0; + } else { + rtems_set_errno_and_return_minus_one(eno); + } +} + +/* Dummy version to let fopen(*,"w") work properly */ +static int rtems_ftpfs_ftruncate(rtems_libio_t *iop, off_t count) +{ + return 0; +} + +static void rtems_ftpfs_eval_path( + rtems_filesystem_eval_path_context_t *self +) +{ + int eno = 0; + + rtems_filesystem_eval_path_eat_delimiter(self); + + if (rtems_filesystem_eval_path_has_path(self)) { + const char *path = rtems_filesystem_eval_path_get_path(self); + size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self); + rtems_ftpfs_entry *e = calloc(1, sizeof(*e) + pathlen + 1); + + rtems_filesystem_eval_path_clear_path(self); + + if (e != NULL) { + memcpy(e->buffer, path, pathlen); + + eno = rtems_ftpfs_split_names( + e->buffer, + &e->user, + &e->password, + &e->hostname, + &e->filename + ); + + DEBUG_PRINTF( + "user = '%s', password = '%s', filename = '%s'\n", + e->user, + e->password, + e->filename + ); + + if (eno == 0) { + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc(self); + rtems_ftpfs_mount_entry *me = currentloc->mt_entry->fs_info; + + rtems_libio_lock(); + ++me->ino; + e->ino = me->ino; + rtems_libio_unlock(); + + e->file_size = -1; + e->ctrl_socket = -1; + + eno = rtems_ftpfs_open_ctrl_connection( + e, + me->verbose, + &me->timeout + ); + if (eno == 0) { + currentloc->node_access = e; + currentloc->handlers = &rtems_ftpfs_handlers; + } + } + + if (eno != 0) { + free(e); + } + } else { + eno = ENOMEM; + } + } + + if (eno != 0) { + rtems_filesystem_eval_path_error(self, eno); + } +} + +static void rtems_ftpfs_free_node(const rtems_filesystem_location_info_t *loc) +{ + rtems_ftpfs_entry *e = loc->node_access; + + /* The root node handler has no entry */ + if (e != NULL) { + const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info; + + /* Close control connection if necessary */ + if (e->ctrl_socket >= 0) { + rtems_ftpfs_send_command(e, "QUIT", NULL, me->verbose); + + close(e->ctrl_socket); + } + + free(e); + } +} + +int rtems_ftpfs_initialize( + rtems_filesystem_mount_table_entry_t *e, + const void *d +) +{ + rtems_ftpfs_mount_entry *me = calloc(1, sizeof(*me)); + + /* Mount entry for FTP file system instance */ + e->fs_info = me; + if (e->fs_info == NULL) { + rtems_set_errno_and_return_minus_one(ENOMEM); + } + me->verbose = false; + me->timeout.tv_sec = 0; + me->timeout.tv_usec = 0; + + /* Set handler and oparations table */ + e->mt_fs_root->location.handlers = &rtems_ftpfs_root_handlers; + e->ops = &rtems_ftpfs_ops; + + /* We maintain no real file system nodes, so there is no real root */ + e->mt_fs_root->location.node_access = NULL; + + return 0; +} + +static void rtems_ftpfs_unmount_me( + rtems_filesystem_mount_table_entry_t *e +) +{ + free(e->fs_info); +} + +static int rtems_ftpfs_ioctl( + rtems_libio_t *iop, + ioctl_command_t command, + void *arg +) +{ + rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info; + bool *verbose = arg; + struct timeval *timeout = arg; + + if (arg == NULL) { + rtems_set_errno_and_return_minus_one(EINVAL); + } + + switch (command) { + case RTEMS_FTPFS_IOCTL_GET_VERBOSE: + *verbose = me->verbose; + break; + case RTEMS_FTPFS_IOCTL_SET_VERBOSE: + me->verbose = *verbose; + break; + case RTEMS_FTPFS_IOCTL_GET_TIMEOUT: + *timeout = me->timeout; + break; + case RTEMS_FTPFS_IOCTL_SET_TIMEOUT: + me->timeout = *timeout; + break; + default: + rtems_set_errno_and_return_minus_one(EINVAL); + } + + return 0; +} + +/* + * The stat() support is intended only for the cp shell command. Each request + * will return that we have a regular file with read, write and execute + * permissions for every one. The node index uses a global counter to support + * a remote to remote copy. This is not a very sophisticated method. + */ +static int rtems_ftpfs_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *st +) +{ + int eno = 0; + rtems_ftpfs_entry *e = loc->node_access; + + /* FIXME */ + st->st_ino = e->ino; + st->st_dev = rtems_filesystem_make_dev_t(0xcc494cd6U, 0x1d970b4dU); + + st->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO; + + if (e->do_size_command) { + const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info; + + rtems_ftpfs_get_file_size(e, me->verbose); + st->st_size = e->file_size; + } else { + e->do_size_command = true; + } + + if (eno == 0) { + return 0; + } else { + rtems_set_errno_and_return_minus_one(eno); + } +} + +static void rtems_ftpfs_lock_or_unlock( + const rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + /* Do nothing */ +} + +static const rtems_filesystem_operations_table rtems_ftpfs_ops = { + .lock_h = rtems_ftpfs_lock_or_unlock, + .unlock_h = rtems_ftpfs_lock_or_unlock, + .eval_path_h = rtems_ftpfs_eval_path, + .link_h = rtems_filesystem_default_link, + .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal, + .mknod_h = rtems_filesystem_default_mknod, + .rmnod_h = rtems_filesystem_default_rmnod, + .fchmod_h = rtems_filesystem_default_fchmod, + .chown_h = rtems_filesystem_default_chown, + .clonenod_h = rtems_filesystem_default_clonenode, + .freenod_h = rtems_ftpfs_free_node, + .mount_h = rtems_filesystem_default_mount, + .unmount_h = rtems_filesystem_default_unmount, + .fsunmount_me_h = rtems_ftpfs_unmount_me, + .utime_h = rtems_filesystem_default_utime, + .symlink_h = rtems_filesystem_default_symlink, + .readlink_h = rtems_filesystem_default_readlink, + .rename_h = rtems_filesystem_default_rename, + .statvfs_h = rtems_filesystem_default_statvfs +}; + +static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers = { + .open_h = rtems_ftpfs_open, + .close_h = rtems_ftpfs_close, + .read_h = rtems_ftpfs_read, + .write_h = rtems_ftpfs_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_ftpfs_fstat, + .ftruncate_h = rtems_ftpfs_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; + +static const rtems_filesystem_file_handlers_r rtems_ftpfs_root_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = rtems_filesystem_default_close, + .read_h = rtems_filesystem_default_read, + .write_h = rtems_filesystem_default_write, + .ioctl_h = rtems_ftpfs_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_filesystem_default_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; diff --git a/lib/getprotoby.c b/lib/getprotoby.c new file mode 100644 index 0000000..4eeec59 --- /dev/null +++ b/lib/getprotoby.c @@ -0,0 +1,48 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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_static (const char *name) +{ + int i; + + for (i = 0 ; i < (sizeof prototab / sizeof prototab[0]) ; i++) { + if (strcmp (name, prototab[i].p_name) == 0) + return (struct protoent *) &prototab[i]; + } + return NULL; +} + +/* + * Dummy version of BSD getprotobynumber() + */ +struct protoent * +getprotobynumber_static (int proto) +{ + int i; + + for (i = 0 ; i < (sizeof prototab / sizeof prototab[0]) ; i++) { + if (proto == prototab[i].p_proto) + return (struct protoent *) &prototab[i]; + } + return NULL; +} diff --git a/lib/rtems_bsdnet_ntp.c b/lib/rtems_bsdnet_ntp.c new file mode 100644 index 0000000..e675759 --- /dev/null +++ b/lib/rtems_bsdnet_ntp.c @@ -0,0 +1,219 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Synchronize with an NTP server + * + * This program may be distributed and used for any purpose. + * I ask only that you: + * 1. Leave this author information intact. + * 2. Document any changes you make. + * + * W. Eric Norum + * Canadian Light Source + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@cls.usask.ca + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> /* close */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <limits.h> +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/error.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <rtems/bsdnet/servers.h> + +/* + * RTEMS base: 1988, January 1 + * UNIX base: 1970, January 1 + * NTP base: 1900, January 1 + */ +#define UNIX_BASE_TO_NTP_BASE (uint32_t)(((70UL*365UL)+17UL) * (24UL*60UL*60UL)) + +struct ntpPacket { + struct ntpPacketSmall ntp; + char authenticator[96]; +}; + +static int +processPacket (struct ntpPacketSmall *p, int state, void *unused) +{ + time_t tbuf; + struct tm *lt; + rtems_time_of_day rt; + rtems_interval ticks_per_second; + + if ( state ) + return 0; + + ticks_per_second = rtems_clock_get_ticks_per_second(); + tbuf = ntohl (p->transmit_timestamp.integer) - UNIX_BASE_TO_NTP_BASE - rtems_bsdnet_timeoffset; + lt = gmtime (&tbuf); + rt.year = lt->tm_year + 1900; + rt.month = lt->tm_mon + 1; + rt.day = lt->tm_mday; + rt.hour = lt->tm_hour; + rt.minute = lt->tm_min; + rt.second = lt->tm_sec; + rt.ticks = ntohl (p->transmit_timestamp.fraction) / (ULONG_MAX / ticks_per_second); + if (rt.ticks >= ticks_per_second) + rt.ticks = ticks_per_second - 1; + rtems_clock_set (&rt); + return 0; +} + +static int +getServerTimespec(struct ntpPacketSmall *p, int state, void *usr_data) +{ +struct timespec *ts = usr_data; +unsigned long long tmp; + + if ( 0 == state ) { + ts->tv_sec = ntohl( p->transmit_timestamp.integer ); + ts->tv_sec -= rtems_bsdnet_timeoffset + UNIX_BASE_TO_NTP_BASE; + + tmp = 1000000000 * (unsigned long long)ntohl(p->transmit_timestamp.fraction); + + ts->tv_nsec = (unsigned long) (tmp>>32); + } + return 0; +} + +int rtems_bsdnet_ntp_retry_count = 5; +int rtems_bsdnet_ntp_timeout_secs = 5; +int rtems_bsdnet_ntp_bcast_timeout_secs = 80; + +static int +tryServer (int i, int s, rtems_bsdnet_ntp_callback_t callback, void *usr_data) +{ + int l = 0; + struct timeval tv; + socklen_t farlen; + struct sockaddr_in farAddr; + struct ntpPacketSmall packet; + + if (i < 0) + tv.tv_sec = rtems_bsdnet_ntp_bcast_timeout_secs; + else + tv.tv_sec = rtems_bsdnet_ntp_timeout_secs; + tv.tv_usec = 0; + if (setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) { + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't set socket receive timeout: %s\n", strerror (errno)); + close (s); + return -1; + } + if (i >= 0) { + memset (&farAddr, 0, sizeof farAddr); + farAddr.sin_family = AF_INET; + farAddr.sin_port = htons (123); + farAddr.sin_addr = rtems_bsdnet_ntpserver[i]; + memset (&packet, 0, sizeof packet); + packet.li_vn_mode = (3 << 3) | 3; /* NTP version 3, client */ + if ( callback( &packet, 1, usr_data ) ) + return -1; + l = sendto (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, sizeof farAddr); + if (l != sizeof packet) { + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't send: %s\n", strerror (errno)); + return -1; + } + } else { + if ( callback( &packet, -1, usr_data ) ) + return -1; + } + farlen = sizeof farAddr; + i = recvfrom (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, &farlen); + if (i == 0) + fprintf (stderr, "rtems_bsdnet_get_ntp() Unexpected EOF"); + if (i < 0) { + if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) + return -1; + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't receive: %s\n", strerror (errno)); + } + + if ( i >= sizeof packet && + (((packet.li_vn_mode & (0x7 << 3)) == (3 << 3)) || + ((packet.li_vn_mode & (0x7 << 3)) == (4 << 3))) && + ((packet.transmit_timestamp.integer != 0) || (packet.transmit_timestamp.fraction != 0)) && + 0 == callback( &packet, 0 , usr_data) ) + return 0; + + return -1; +} + +int rtems_bsdnet_get_ntp(int sock, rtems_bsdnet_ntp_callback_t callback, void *usr_data) +{ +int s = -1; +int i; +int retry; +struct sockaddr_in myAddr; +int reuseFlag; +int ret; + + if ( !callback ) + callback = getServerTimespec; + + if ( sock < 0 ) { + s = socket (AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't create socket: %s\n", strerror (errno)); + return -1; + } + reuseFlag = 1; + if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseFlag, sizeof reuseFlag) < 0) { + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't set socket reuse: %s\n", strerror (errno)); + close (s); + return -1; + } + memset (&myAddr, 0, sizeof myAddr); + myAddr.sin_family = AF_INET; + myAddr.sin_port = htons (123); + myAddr.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) { + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't bind socket: %s\n", strerror (errno)); + close (s); + return -1; + } + sock = s; + } + ret = -1; + for (retry = 0 ; (ret == -1) && (retry < rtems_bsdnet_ntp_retry_count) ; retry++) { + /* + * If there's no server we just have to wait + * and hope that there's an NTP broadcast + * server out there somewhere. + */ + if (rtems_bsdnet_ntpserver_count <= 0) { + ret = tryServer (-1, sock, callback, usr_data); + } + else { + for (i = 0 ; (ret == -1) && (i < rtems_bsdnet_ntpserver_count) ; i++) { + ret = tryServer (i, sock, callback, usr_data); + } + } + } + if ( s >= 0 ) + close (s); + return ret; +} + +int +rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority) +{ + if (interval != 0) { + fprintf (stderr, "Daemon-mode note yet supported.\n"); + errno = EINVAL; + return -1; + } + return rtems_bsdnet_get_ntp( -1, processPacket, 0); +} diff --git a/lib/syslog.c b/lib/syslog.c new file mode 100644 index 0000000..8e167a4 --- /dev/null +++ b/lib/syslog.c @@ -0,0 +1,170 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * RTEMS version of syslog and associated routines + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/thread.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> +#include <string.h> + +#include <unistd.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_recursive_mutex LogSemaphore = + RTEMS_RECURSIVE_MUTEX_INITIALIZER("syslog"); +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 *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 = snprintf (cbuf, sizeof (cbuf), "<%d>", pri); + msgp = cbuf + (cnt < sizeof (cbuf) ? cnt : sizeof (cbuf) - 1); + if (LogTag && cnt < sizeof (cbuf) - 1) + cnt += snprintf (cbuf + cnt, sizeof (cbuf) - cnt, "%s", LogTag); + if (LogStatus & LOG_PID && cnt < sizeof (cbuf) - 1) { + rtems_id tid; + rtems_task_ident (RTEMS_SELF, 0, &tid); + cnt += snprintf (cbuf + cnt, sizeof (cbuf) - cnt, "[%#lx]", (unsigned long)tid); + } + if (LogTag && cnt < sizeof (cbuf) - 1) + cnt += snprintf (cbuf + cnt, sizeof (cbuf) - cnt, ": "); + cnt += vsnprintf (cbuf + cnt, sizeof (cbuf) - cnt, fmt, ap); + if (cnt > sizeof (cbuf) - 1) + cnt = sizeof (cbuf) - 1; + while (cnt > 0 && 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)) { + /* + * 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); + + rtems_recursive_mutex_lock (&LogSemaphore); + /* + * Send the message + */ + if (sendto (LogFd, cbuf, cnt, 0, (struct sockaddr *)&farAddress, sizeof farAddress) >= 0) + sent = 1; + rtems_recursive_mutex_unlock (&LogSemaphore); + } + if (!sent && (LogStatus & LOG_CONS) && !(LogStatus & LOG_PERROR)) + printf ("%s\n", msgp); +} + +void +openlog (const char *ident, int logstat, int logfac) +{ + 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 = htons (SYSLOG_PORT);; + 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; + } +} + +void +closelog(void) +{ + if (LogFd >= 0) { + close (LogFd); + LogFd = -1; + } +} + +int +setlogmask (int pmask) +{ + int omask; + + omask = LogMask; + if (pmask != 0) + LogMask = pmask; + return (omask); +} diff --git a/lib/tftpDriver.c b/lib/tftpDriver.c new file mode 100644 index 0000000..7cbb402 --- /dev/null +++ b/lib/tftpDriver.c @@ -0,0 +1,1066 @@ +/* + * 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 + * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <malloc.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <rtems.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> +#include <rtems/tftp.h> +#include <rtems/thread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#ifdef RTEMS_NETWORKING +#include <rtems/rtems_bsdnet.h> +#endif + +#ifdef RTEMS_TFTP_DRIVER_DEBUG +int rtems_tftp_driver_debug = 1; +#endif + +/* + * Range of UDP ports to try + */ +#define UDP_PORT_BASE 3180 + +/* + * Default limits + */ +#define PACKET_FIRST_TIMEOUT_MILLISECONDS 400L +#define PACKET_TIMEOUT_MILLISECONDS 6000L +#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 { + uint16_t opcode; + char filename_mode[TFTP_BUFSIZE]; + } tftpRWRQ; + + /* + * DATA packet + */ + struct tftpDATA { + uint16_t opcode; + uint16_t blocknum; + uint8_t data[TFTP_BUFSIZE]; + } tftpDATA; + + /* + * ACK packet + */ + struct tftpACK { + uint16_t opcode; + uint16_t blocknum; + } tftpACK; + + /* + * ERROR packet + */ + struct tftpERROR { + uint16_t opcode; + uint16_t 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 transferred + */ + uint16_t 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; + int writing; +}; + +/* + * Flags for filesystem info. + */ +#define TFTPFS_VERBOSE (1 << 0) + +/* + * TFTP File system info. + */ +typedef struct tftpfs_info_s { + uint32_t flags; + rtems_mutex tftp_mutex; + int nStreams; + struct tftpStream ** volatile tftpStreams; +} tftpfs_info_t; + +#define tftpfs_info_mount_table(_mt) ((tftpfs_info_t*) ((_mt)->fs_info)) +#define tftpfs_info_pathloc(_pl) ((tftpfs_info_t*) ((_pl)->mt_entry->fs_info)) +#define tftpfs_info_iop(_iop) (tftpfs_info_pathloc (&((_iop)->pathinfo))) + +/* + * Number of streams open at the same time + */ + +static const rtems_filesystem_operations_table rtems_tftp_ops; +static const rtems_filesystem_file_handlers_r rtems_tftp_handlers; + +static bool rtems_tftp_is_directory( + const char *path, + size_t pathlen +) +{ + return path [pathlen - 1] == '/'; +} + +int rtems_tftpfs_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) +{ + const char *device = mt_entry->dev; + size_t devicelen = strlen (device); + tftpfs_info_t *fs = NULL; + char *root_path; + + if (devicelen == 0) { + root_path = malloc (1); + if (root_path == NULL) + goto error; + root_path [0] = '\0'; + } + else { + root_path = malloc (devicelen + 2); + if (root_path == NULL) + goto error; + + root_path = memcpy (root_path, device, devicelen); + root_path [devicelen] = '/'; + root_path [devicelen + 1] = '\0'; + } + + fs = malloc (sizeof (*fs)); + if (fs == NULL) + goto error; + fs->flags = 0; + fs->nStreams = 0; + fs->tftpStreams = 0; + + mt_entry->fs_info = fs; + mt_entry->mt_fs_root->location.node_access = root_path; + mt_entry->mt_fs_root->location.handlers = &rtems_tftp_handlers; + mt_entry->ops = &rtems_tftp_ops; + + /* + * Now allocate a semaphore for mutual exclusion. + * + * NOTE: This could be in an fsinfo for this filesystem type. + */ + + rtems_mutex_init (&fs->tftp_mutex, "TFTPFS"); + + if (data) { + char* config = (char*) data; + char* token; + char* saveptr; + token = strtok_r (config, " ", &saveptr); + while (token) { + if (strcmp (token, "verbose") == 0) + fs->flags |= TFTPFS_VERBOSE; + token = strtok_r (NULL, " ", &saveptr); + } + } + + return 0; + +error: + + free (fs); + free (root_path); + + rtems_set_errno_and_return_minus_one (ENOMEM); +} + +/* + * Release a stream and clear the pointer to it + */ +static void +releaseStream (tftpfs_info_t *fs, int s) +{ + if (fs->tftpStreams[s] && (fs->tftpStreams[s]->socket >= 0)) + close (fs->tftpStreams[s]->socket); + rtems_mutex_lock (&fs->tftp_mutex); + free (fs->tftpStreams[s]); + fs->tftpStreams[s] = NULL; + rtems_mutex_unlock (&fs->tftp_mutex); +} + +static void +rtems_tftpfs_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry) +{ + tftpfs_info_t *fs = tftpfs_info_mount_table (mt_entry); + int s; + for (s = 0; s < fs->nStreams; s++) + releaseStream (fs, s); + rtems_mutex_destroy (&fs->tftp_mutex); + free (fs); + free (mt_entry->mt_fs_root->location.node_access); +} + +/* + * Map error message + */ +static int +tftpErrno (struct tftpStream *tp) +{ + unsigned int tftpError; + static const int errorMap[] = { + EINVAL, + ENOENT, + EPERM, + ENOSPC, + EINVAL, + ENXIO, + EEXIST, + ESRCH, + }; + + tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode); + if (tftpError < (sizeof errorMap / sizeof errorMap[0])) + return errorMap[tftpError]; + else + return 1000 + tftpError; +} + +/* + * Send a message to make the other end shut up + */ +static void +sendStifle (struct tftpStream *tp, struct sockaddr_in *to) +{ + int len; + struct { + uint16_t opcode; + uint16_t errorCode; + char errorMessage[12]; + } msg; + + /* + * Create the error packet (Unknown transfer ID). + */ + msg.opcode = htons (TFTP_OPCODE_ERROR); + msg.errorCode = htons (5); + len = sizeof msg.opcode + sizeof msg.errorCode + 1; + len += sprintf (msg.errorMessage, "GO AWAY"); + + /* + * Send it + */ + sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to); +} + +/* + * Wait for a data packet + */ +static int +getPacket (struct tftpStream *tp, int retryCount) +{ + int len; + struct timeval tv; + + if (retryCount == 0) { + tv.tv_sec = PACKET_FIRST_TIMEOUT_MILLISECONDS / 1000L; + tv.tv_usec = (PACKET_FIRST_TIMEOUT_MILLISECONDS % 1000L) * 1000L; + } + else { + tv.tv_sec = PACKET_TIMEOUT_MILLISECONDS / 1000L; + tv.tv_usec = (PACKET_TIMEOUT_MILLISECONDS % 1000L) * 1000L; + } + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); + for (;;) { + union { + struct sockaddr s; + struct sockaddr_in i; + } from; + socklen_t fromlen = sizeof from; + len = recvfrom (tp->socket, &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; + tv.tv_usec = 0; + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); +#ifdef RTEMS_TFTP_DRIVER_DEBUG + if (rtems_tftp_driver_debug) { + if (len >= (int) sizeof tp->pkbuf.tftpACK) { + int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); + switch (opcode) { + default: + printf ("TFTP: OPCODE %d\n", opcode); + break; + + case TFTP_OPCODE_DATA: + printf ("TFTP: RECV %d\n", ntohs (tp->pkbuf.tftpDATA.blocknum)); + break; + + case TFTP_OPCODE_ACK: + printf ("TFTP: GOT ACK %d\n", ntohs (tp->pkbuf.tftpACK.blocknum)); + break; + } + } + else { + printf ("TFTP: %d-byte packet\n", len); + } + } +#endif + return len; +} + +/* + * Send an acknowledgement + */ +static int +sendAck (struct tftpStream *tp) +{ +#ifdef RTEMS_TFTP_DRIVER_DEBUG + if (rtems_tftp_driver_debug) + printf ("TFTP: ACK %d\n", tp->blocknum); +#endif + + /* + * 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; +} + +/* + * Convert a path to canonical form + */ +static void +fixPath (char *path) +{ + char *inp, *outp, *base; + + outp = inp = path; + base = NULL; + for (;;) { + if (inp[0] == '.') { + if (inp[1] == '\0') + break; + if (inp[1] == '/') { + inp += 2; + continue; + } + if (inp[1] == '.') { + if (inp[2] == '\0') { + if ((base != NULL) && (outp > base)) { + outp--; + while ((outp > base) && (outp[-1] != '/')) + outp--; + } + break; + } + if (inp[2] == '/') { + inp += 3; + if (base == NULL) + continue; + if (outp > base) { + outp--; + while ((outp > base) && (outp[-1] != '/')) + outp--; + } + continue; + } + } + } + if (base == NULL) + base = inp; + while (inp[0] != '/') { + if ((*outp++ = *inp++) == '\0') + return; + } + *outp++ = '/'; + while (inp[0] == '/') + inp++; + } + *outp = '\0'; + return; +} + +static void rtems_tftp_eval_path(rtems_filesystem_eval_path_context_t *self) +{ + int eval_flags = rtems_filesystem_eval_path_get_flags (self); + + if ((eval_flags & RTEMS_FS_MAKE) == 0) { + int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE; + + if ((eval_flags & rw) != rw) { + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc (self); + char *current = currentloc->node_access; + size_t currentlen = strlen (current); + const char *path = rtems_filesystem_eval_path_get_path (self); + size_t pathlen = rtems_filesystem_eval_path_get_pathlen (self); + size_t len = currentlen + pathlen; + + rtems_filesystem_eval_path_clear_path (self); + + current = realloc (current, len + 1); + if (current != NULL) { + memcpy (current + currentlen, path, pathlen); + current [len] = '\0'; + if (!rtems_tftp_is_directory (current, len)) { + fixPath (current); + } + currentloc->node_access = current; + } else { + rtems_filesystem_eval_path_error (self, ENOMEM); + } + } else { + rtems_filesystem_eval_path_error (self, EINVAL); + } + } else { + rtems_filesystem_eval_path_error (self, EIO); + } +} + +/* + * The routine which does most of the work for the IMFS open handler + */ +static int rtems_tftp_open_worker( + rtems_libio_t *iop, + char *full_path_name, + int oflag +) +{ + tftpfs_info_t *fs; + struct tftpStream *tp; + int retryCount; + struct in_addr farAddress; + int s; + int len; + char *cp1; + char *cp2; + char *remoteFilename; + rtems_interval now; + char *hostname; + + /* + * Get the file system info. + */ + fs = tftpfs_info_iop (iop); + + /* + * Extract the host name component + */ + if (*full_path_name == '/') + full_path_name++; + + hostname = full_path_name; + cp1 = strchr (full_path_name, ':'); + if (!cp1) { +#ifdef RTEMS_NETWORKING + hostname = "BOOTP_HOST"; +#endif + } else { + *cp1 = '\0'; + ++cp1; + } + + /* + * Convert hostname to Internet address + */ +#ifdef RTEMS_NETWORKING + if (strcmp (hostname, "BOOTP_HOST") == 0) + farAddress = rtems_bsdnet_bootp_server_address; + else +#endif + if (inet_aton (hostname, &farAddress) == 0) { + struct hostent *he = gethostbyname(hostname); + if (he == NULL) + return ENOENT; + memcpy (&farAddress, he->h_addr, sizeof (farAddress)); + } + + /* + * Extract file pathname component + */ +#ifdef RTEMS_NETWORKING + if (strcmp (cp1, "BOOTP_FILE") == 0) { + cp1 = rtems_bsdnet_bootp_boot_file_name; + } +#endif + if (*cp1 == '\0') + return ENOENT; + remoteFilename = cp1; + if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10)) + return ENOENT; + + /* + * Find a free stream + */ + rtems_mutex_lock (&fs->tftp_mutex); + for (s = 0 ; s < fs->nStreams ; s++) { + if (fs->tftpStreams[s] == NULL) + break; + } + if (s == fs->nStreams) { + /* + * Reallocate stream pointers + * Guard against the case where realloc() returns NULL. + */ + struct tftpStream **np; + + np = realloc (fs->tftpStreams, ++fs->nStreams * sizeof *fs->tftpStreams); + if (np == NULL) { + rtems_mutex_unlock (&fs->tftp_mutex); + return ENOMEM; + } + fs->tftpStreams = np; + } + tp = fs->tftpStreams[s] = malloc (sizeof (struct tftpStream)); + rtems_mutex_unlock (&fs->tftp_mutex); + if (tp == NULL) + return ENOMEM; + iop->data0 = s; + iop->data1 = tp; + + /* + * Create the socket + */ + if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + releaseStream (fs, s); + return ENOMEM; + } + + /* + * Bind the socket to a local address + */ + retryCount = 0; + now = rtems_clock_get_ticks_since_boot(); + for (;;) { + int try = (now + retryCount) % 10; + + tp->myAddress.sin_family = AF_INET; + tp->myAddress.sin_port = htons (UDP_PORT_BASE + fs->nStreams * try + s); + 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) { + releaseStream (fs, s); + return EBUSY; + } + } + + /* + * Set the UDP destination to the TFTP server + * port on the remote machine. + */ + tp->farAddress.sin_family = AF_INET; + tp->farAddress.sin_addr = farAddress; + tp->farAddress.sin_port = htons (69); + + /* + * Start the transfer + */ + tp->firstReply = 1; + retryCount = 0; + for (;;) { + /* + * Create the request + */ + if ((oflag & O_ACCMODE) == O_RDONLY) { + tp->writing = 0; + tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ); + } + else { + tp->writing = 1; + tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ); + } + cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode; + cp2 = (char *) 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) { + releaseStream (fs, s); + return EIO; + } + + /* + * Get reply + */ + len = getPacket (tp, retryCount); + if (len >= (int) sizeof tp->pkbuf.tftpACK) { + int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); + if (!tp->writing + && (opcode == TFTP_OPCODE_DATA) + && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) { + tp->nused = 0; + tp->blocknum = 1; + tp->nleft = len - 2 * sizeof (uint16_t ); + tp->eof = (tp->nleft < TFTP_BUFSIZE); + if (sendAck (tp) != 0) { + releaseStream (fs, s); + return EIO; + } + break; + } + if (tp->writing + && (opcode == TFTP_OPCODE_ACK) + && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) { + tp->nused = 0; + tp->blocknum = 1; + break; + } + if (opcode == TFTP_OPCODE_ERROR) { + int e = tftpErrno (tp); + releaseStream (fs, s); + return e; + } + } + + /* + * Keep trying + */ + if (++retryCount >= OPEN_RETRY_LIMIT) { + releaseStream (fs, s); + return EIO; + } + } + return 0; +} + +static int rtems_tftp_open( + rtems_libio_t *iop, + const char *new_name, + int oflag, + mode_t mode +) +{ + tftpfs_info_t *fs; + char *full_path_name; + int err; + + full_path_name = iop->pathinfo.node_access; + + if (rtems_tftp_is_directory (full_path_name, strlen (full_path_name))) { + rtems_set_errno_and_return_minus_one (ENOTSUP); + } + + /* + * Get the file system info. + */ + fs = tftpfs_info_iop (iop); + + if (fs->flags & TFTPFS_VERBOSE) + printf ("TFTPFS: %s\n", full_path_name); + + err = rtems_tftp_open_worker (iop, full_path_name, oflag); + if (err != 0) { + rtems_set_errno_and_return_minus_one (err); + } + + return 0; +} + +/* + * Read from a TFTP stream + */ +static ssize_t rtems_tftp_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + char *bp; + struct tftpStream *tp = iop->data1; + int retryCount; + int nwant; + + if (!tp) + rtems_set_errno_and_return_minus_one( EIO ); + + /* + * Read till user request is satisfied or EOF is reached + */ + bp = buffer; + nwant = count; + while (nwant) { + if (tp->nleft) { + int ncopy; + if (nwant < tp->nleft) + ncopy = nwant; + else + ncopy = tp->nleft; + memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy); + tp->nused += ncopy; + tp->nleft -= ncopy; + bp += ncopy; + nwant -= ncopy; + if (nwant == 0) + break; + } + if (tp->eof) + break; + + /* + * Wait for the next packet + */ + retryCount = 0; + for (;;) { + int len = getPacket (tp, retryCount); + if (len >= (int)sizeof tp->pkbuf.tftpACK) { + int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); + uint16_t nextBlock = tp->blocknum + 1; + if ((opcode == TFTP_OPCODE_DATA) + && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) { + tp->nused = 0; + tp->nleft = len - 2 * sizeof (uint16_t); + tp->eof = (tp->nleft < TFTP_BUFSIZE); + tp->blocknum++; + if (sendAck (tp) != 0) + rtems_set_errno_and_return_minus_one (EIO); + break; + } + if (opcode == TFTP_OPCODE_ERROR) + rtems_set_errno_and_return_minus_one (tftpErrno (tp)); + } + + /* + * Keep trying? + */ + if (++retryCount == IO_RETRY_LIMIT) + rtems_set_errno_and_return_minus_one (EIO); + if (sendAck (tp) != 0) + rtems_set_errno_and_return_minus_one (EIO); + } + } + return count - nwant; +} + +/* + * Flush a write buffer and wait for acknowledgement + */ +static int rtems_tftp_flush (struct tftpStream *tp) +{ + int wlen, rlen; + int retryCount = 0; + + wlen = tp->nused + 2 * sizeof (uint16_t ); + for (;;) { + tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA); + tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum); +#ifdef RTEMS_TFTP_DRIVER_DEBUG + if (rtems_tftp_driver_debug) + printf ("TFTP: SEND %d (%d)\n", tp->blocknum, tp->nused); +#endif + if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0, + (struct sockaddr *)&tp->farAddress, + sizeof tp->farAddress) < 0) + return EIO; + rlen = getPacket (tp, retryCount); + /* + * Our last packet won't necessarily be acknowledged! + */ + if ((rlen < 0) && (tp->nused < sizeof tp->pkbuf.tftpDATA.data)) + return 0; + if (rlen >= (int)sizeof tp->pkbuf.tftpACK) { + int opcode = ntohs (tp->pkbuf.tftpACK.opcode); + if ((opcode == TFTP_OPCODE_ACK) + && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) { + tp->nused = 0; + tp->blocknum++; + return 0; + } + if (opcode == TFTP_OPCODE_ERROR) + return tftpErrno (tp); + } + + /* + * Keep trying? + */ + if (++retryCount == IO_RETRY_LIMIT) + return EIO; + } +} + +/* + * Close a TFTP stream + */ +static int rtems_tftp_close( + rtems_libio_t *iop +) +{ + tftpfs_info_t *fs; + struct tftpStream *tp = iop->data1; + int e = 0; + + /* + * Get the file system info. + */ + fs = tftpfs_info_iop (iop); + + if (!tp) + rtems_set_errno_and_return_minus_one (EIO); + + if (tp->writing) + e = rtems_tftp_flush (tp); + if (!tp->eof && !tp->firstReply) { + /* + * Tell the other end to stop + */ + rtems_interval ticksPerSecond; + sendStifle (tp, &tp->farAddress); + ticksPerSecond = rtems_clock_get_ticks_per_second(); + rtems_task_wake_after (1 + ticksPerSecond / 10); + } + releaseStream (fs, iop->data0); + if (e) + rtems_set_errno_and_return_minus_one (e); + return 0; +} + +static ssize_t rtems_tftp_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + const char *bp; + struct tftpStream *tp = iop->data1; + int nleft, nfree, ncopy; + + /* + * Bail out if an error has occurred + */ + if (!tp->writing) + rtems_set_errno_and_return_minus_one (EIO); + + /* + * Write till user request is satisfied + * Notice that the buffer is flushed as soon as it is filled rather + * than waiting for the next write or a close. This ensures that + * the flush in close writes a less than full buffer so the far + * end can detect the end-of-file condition. + */ + bp = buffer; + nleft = count; + while (nleft) { + nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused; + if (nleft < nfree) + ncopy = nleft; + else + ncopy = nfree; + memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy); + tp->nused += ncopy; + nleft -= ncopy; + bp += ncopy; + if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) { + int e = rtems_tftp_flush (tp); + if (e) { + tp->writing = 0; + rtems_set_errno_and_return_minus_one (e); + } + } + } + return count; +} + +/* + * Dummy version to let fopen(xxxx,"w") work properly. + */ +static int rtems_tftp_ftruncate( + rtems_libio_t *iop RTEMS_UNUSED, + off_t count RTEMS_UNUSED +) +{ + return 0; +} + +static int rtems_tftp_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ + const char *path = loc->node_access; + size_t pathlen = strlen (path); + + buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO + | (rtems_tftp_is_directory (path, pathlen) ? S_IFDIR : S_IFREG); + + return 0; +} + +static int rtems_tftp_clone( + rtems_filesystem_location_info_t *loc +) +{ + int rv = 0; + + loc->node_access = strdup (loc->node_access); + + if (loc->node_access == NULL) { + errno = ENOMEM; + rv = -1; + } + + return rv; +} + +static void rtems_tftp_free_node_info( + const rtems_filesystem_location_info_t *loc +) +{ + free (loc->node_access); +} + +static bool rtems_tftp_are_nodes_equal( + const rtems_filesystem_location_info_t *a, + const rtems_filesystem_location_info_t *b +) +{ + return strcmp (a->node_access, b->node_access) == 0; +} + +static const rtems_filesystem_operations_table rtems_tftp_ops = { + .lock_h = rtems_filesystem_default_lock, + .unlock_h = rtems_filesystem_default_unlock, + .eval_path_h = rtems_tftp_eval_path, + .link_h = rtems_filesystem_default_link, + .are_nodes_equal_h = rtems_tftp_are_nodes_equal, + .mknod_h = rtems_filesystem_default_mknod, + .rmnod_h = rtems_filesystem_default_rmnod, + .fchmod_h = rtems_filesystem_default_fchmod, + .chown_h = rtems_filesystem_default_chown, + .clonenod_h = rtems_tftp_clone, + .freenod_h = rtems_tftp_free_node_info, + .mount_h = rtems_filesystem_default_mount, + .unmount_h = rtems_filesystem_default_unmount, + .fsunmount_me_h = rtems_tftpfs_shutdown, + .utime_h = rtems_filesystem_default_utime, + .symlink_h = rtems_filesystem_default_symlink, + .readlink_h = rtems_filesystem_default_readlink, + .rename_h = rtems_filesystem_default_rename, + .statvfs_h = rtems_filesystem_default_statvfs +}; + +static const rtems_filesystem_file_handlers_r rtems_tftp_handlers = { + .open_h = rtems_tftp_open, + .close_h = rtems_tftp_close, + .read_h = rtems_tftp_read, + .write_h = rtems_tftp_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_tftp_fstat, + .ftruncate_h = rtems_tftp_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; diff --git a/libc/base64.c b/libc/base64.c new file mode 100644 index 0000000..7369c36 --- /dev/null +++ b/libc/base64.c @@ -0,0 +1,318 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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( + 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/libc/byteorder.3 b/libc/byteorder.3 new file mode 100644 index 0000000..666521b --- /dev/null +++ b/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/libc/ethers.3 b/libc/ethers.3 new file mode 100644 index 0000000..888054e --- /dev/null +++ b/libc/ethers.3 @@ -0,0 +1,192 @@ +.\" 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. +.\" +.\" +.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/libc/gethostbydns.c b/libc/gethostbydns.c new file mode 100644 index 0000000..66f24e1 --- /dev/null +++ b/libc/gethostbydns.c @@ -0,0 +1,779 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * ++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-- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> + +#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> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#include <netdb.h> +#include <rtems/rtems_netdb.h> +#include <resolv.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> + +#include "res_config.h" + +void abort(void); /* to avoid warning */ + +#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(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; + +int _dns_ttl_; + +#ifdef DEBUG +static void +debugprintf( + char *msg, + int num) +{ + if (_res.options & RES_DEBUG) { + int save = errno; + + printf(msg, num); + errno = save; + } +} +#else +#define debugprintf(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( + const querybuf *answer, + int anslen, + const char *qname, + int qtype) +{ + const HEADER *hp; + const u_char *cp; + 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)(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) - ((uintptr_t)bp % sizeof(align)); + + if (bp + n >= &hostbuf[sizeof hostbuf]) { + debugprintf("size (%d) too big\n", n); + had_error++; + continue; + } + if (hap >= &h_addr_ptrs[MAXADDRS-1]) { + if (!toobig++) + debugprintf("Too many addresses (%d)\n", + MAXADDRS); + cp += n; + continue; + } + memcpy(*hap++ = bp, cp, n); + bp += n; + buflen -= n; + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return (NULL); + } + break; + default: + debugprintf("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); +} + +#if 0 +struct hostent * +__dns_getanswer(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)); +} +#endif + +struct hostent * +_gethostbydnsname( + 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((unsigned char)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((unsigned char)*cp) && *cp != '.') + break; + } + if ((isxdigit((unsigned char)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((unsigned char)*cp) && *cp != ':' && *cp != '.') + break; + } + + if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) { + debugprintf("res_search failed (%d)\n", n); + return (NULL); + } + return (gethostanswer(&buf, n, name, type)); +} + +struct hostent * +_gethostbydnsaddr( + const char *addr, /* XXX should have been def'd as u_char! */ + int len, + int 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) { + debugprintf("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; + memcpy(host_addr, 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( + 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(int stayopen) +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + if (stayopen) + _res.options |= RES_STAYOPEN | RES_USEVC; +} + +void +_endhostdnsent(void) +{ + _res.options &= ~(RES_STAYOPEN | RES_USEVC); + res_close(); +} diff --git a/libc/gethostbyht.c b/libc/gethostbyht.c new file mode 100644 index 0000000..50f3129 --- /dev/null +++ b/libc/gethostbyht.c @@ -0,0 +1,349 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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-- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <rtems/rtems_netdb.h> +#include <stdio.h> +#include <stdlib.h> /* realloc, malloc, free */ +#include <ctype.h> +#include <errno.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#include <arpa/nameser.h> /* XXX */ +#include <resolv.h> /* XXX */ +#include <sys/fcntl.h> + +#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; + +#ifdef _THREAD_SAFE +static char* hostmap = NULL; +static unsigned int hostlen = 0; +static char *cur; +#endif + +void +_sethosthtent(int f) +{ + if (!hostf) + hostf = fopen(_PATH_HOSTS, "r" ); + else + rewind(hostf); + stayopen = f; +} + +void +_endhosthtent(void) +{ + if (hostf && !stayopen) { + (void) fclose(hostf); + hostf = NULL; + } +} + +struct hostent * +gethostent(void) +{ + 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( + 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( + const char *addr, + int len, + int 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); +} + + +#ifdef _THREAD_SAFE +int +gethostent_r( + struct hostent *pe, + char *buf, + size_t len, + struct hostent **result, + int *h_errnop) +{ + char *dest; + char* last; + char* max=buf+len; + int aliasidx; + int curlen; + int rv; + + if (pe == NULL || buf == NULL || result == NULL || h_errnop == NULL) { + if (h_errnop != NULL) { + *h_errnop = NETDB_INTERNAL; + } + return EINVAL; + } + + *result = NULL; + *h_errnop = NETDB_INTERNAL; + rv = -1; + + if (!hostf) { + rv = ENOENT; + return rv; + } + fseek(hostf,0,SEEK_END); + curlen=ftell(hostf); + fseek(hostf,0,SEEK_SET); + + if (curlen > hostlen) { + if (hostmap) { + hostmap = realloc(hostmap,curlen); + } + else { + hostmap = malloc(curlen); + } + } + hostlen = curlen; + + if (hostmap) { + if (fread(hostmap,hostlen,1,hostf) != hostlen) { + hostmap=0; goto error; + } + cur=hostmap; + } + last=hostmap+hostlen; +again: + if ((size_t)len<sizeof(struct hostent)+11*sizeof(char*)) goto nospace; + dest=buf; + pe->h_name=0; + pe->h_aliases=(char**)dest; pe->h_aliases[0]=0; dest+=10*sizeof(char*); + pe->h_addr_list=(char**)dest; dest+=2*sizeof(char**); + if (cur>=last) { + rv = ERANGE; + return rv; + } + if (*cur=='#' || *cur=='\n') goto parseerror; + /* first, the ip number */ + pe->h_name=cur; + while (cur<last && !isspace((unsigned char)*cur)) cur++; + if (cur>=last) { + rv = ERANGE; + return rv; + } + if (*cur=='\n') goto parseerror; + { + char save=*cur; + *cur=0; + pe->h_addr_list[0]=dest; + pe->h_addr_list[1]=0; + if (max-dest<16) goto nospace; + if (inet_pton(AF_INET6,pe->h_name,dest)>0) { + pe->h_addrtype=AF_INET6; + pe->h_length=16; + dest+=16; + } else if (inet_pton(AF_INET,pe->h_name,dest)>0) { + pe->h_addrtype=AF_INET; + pe->h_length=4; + dest+=4; + } else { + *cur=save; + goto parseerror; + } + *cur=save; + } + ++cur; + /* now the aliases */ + for (aliasidx=0;aliasidx<9;++aliasidx) { + while (cur<last && isblank((unsigned char)*cur)) ++cur; + pe->h_aliases[aliasidx]=cur; + while (cur<last && !isspace((unsigned char)*cur)) ++cur; + { + char *from=pe->h_aliases[aliasidx]; + int len=cur-from; + if (max-dest<len+2) goto nospace; + pe->h_aliases[aliasidx]=dest; + memmove(dest,from,(size_t)(cur-from)); + dest+=len; + *dest=0; ++dest; + } + if (*cur=='\n') { ++cur; ++aliasidx; break; } + if (cur>=last || !isblank((unsigned char)*cur)) break; + cur++; + } + pe->h_aliases[aliasidx]=0; + pe->h_name=pe->h_aliases[0]; + pe->h_aliases++; + *result = pe; + *h_errnop = 0; + rv = 0; + return rv; +parseerror: + while (cur<last && *cur!='\n') cur++; + cur++; + goto again; +nospace: + rv=ERANGE; + goto __error; +error: + rv=ENOMEM; +__error: + if (hostmap!=NULL) free(hostmap); + hostmap=NULL; + return rv; +} +#endif diff --git a/libc/gethostbyname.3 b/libc/gethostbyname.3 new file mode 100644 index 0000000..7fd997e --- /dev/null +++ b/libc/gethostbyname.3 @@ -0,0 +1,304 @@ +.\" 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 +.\" +.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/libc/gethostbynis.c b/libc/gethostbynis.c new file mode 100644 index 0000000..11cb020 --- /dev/null +++ b/libc/gethostbynis.c @@ -0,0 +1,144 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <rtems/rtems_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( + 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( + const char *name, + int af) +{ + return _gethostbynis(name, "hosts.byname", af); +} + +struct hostent * +_gethostbynisaddr( + const char *addr, + int len, + int af) +{ + return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af); +} diff --git a/libc/gethostnamadr.c b/libc/gethostnamadr.c new file mode 100644 index 0000000..dfb760a --- /dev/null +++ b/libc/gethostnamadr.c @@ -0,0 +1,447 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <rtems/rtems_netdb.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#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(void) +{ + 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((unsigned char)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; +} + +int gethostbyaddr_r(const void *addr, socklen_t len, int type, + struct hostent *ret, char *buf, size_t buflen, + struct hostent **result, int *h_errnop) +{ + #warning "implement a proper gethostbyaddr_r" + + *result = gethostbyaddr( addr, len, type ); + if ( *result ) + return 0; + return -1; +} + +struct hostent * +gethostbyaddr(const void *addr, socklen_t 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; +} + +void +sethostent(int stayopen) +{ + _sethosthtent(stayopen); + _sethostdnsent(stayopen); +} + +void +endhostent(void) +{ + _endhosthtent(); + _endhostdnsent(); +} + +#ifdef _THREAD_SAFE + +/* return length of decoded data or -1 */ +static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest, + unsigned int maxlen,unsigned char* behindpacket) { + unsigned char *tmp; + unsigned char *max=dest+maxlen; + unsigned char *after=packet+offset; + int ok=0; + for (tmp=after; maxlen>0&&*tmp; ) { + if (tmp>=behindpacket) return -1; + if ((*tmp>>6)==3) { /* goofy DNS decompression */ + unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1); + if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */ + if (after<tmp+2) after=tmp+2; + tmp=packet+ofs; + ok=0; + } else { + unsigned int duh; + if (dest+*tmp+1>max) return -1; + if (tmp+*tmp+1>=behindpacket) return -1; + for (duh=*tmp; duh>0; --duh) + *dest++=*++tmp; + *dest++='.'; ok=1; + ++tmp; + if (tmp>after) { after=tmp; if (!*tmp) ++after; } + } + } + if (ok) --dest; + *dest=0; + return after-packet; +} + +static int __dns_gethostbyx_r( + const char* name, + struct hostent* result, + char *buf, size_t buflen, + struct hostent **RESULT, + int *h_errnop, + int lookfor) +{ + + int names,ips; + unsigned char *cur; + unsigned char *max; + unsigned char inpkg[1500]; + char* tmp; + int size; + + if (lookfor==1) { + result->h_addrtype=AF_INET; + result->h_length=4; + } else { + result->h_addrtype=AF_INET6; + result->h_length=16; + } + result->h_aliases=(char**)(buf+8*sizeof(char*)); + result->h_addr_list=(char**)buf; + result->h_aliases[0]=0; + + cur=(unsigned char*)buf+16*sizeof(char*); + max=(unsigned char*)buf+buflen; + names=ips=0; + + if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) { +invalidpacket: + *h_errnop=HOST_NOT_FOUND; + return -1; + } + { + tmp=(char*)inpkg+12; + { + char Name[257]; + unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5]; + while (q>0) { + if (tmp>(char*)inpkg+size) goto invalidpacket; + while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; } + tmp+=5; + --q; + } + if (tmp>(char*)inpkg+size) goto invalidpacket; + q=((unsigned short)inpkg[6]<<8)+inpkg[7]; + if (q<1) goto nodata; + while (q>0) { + int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size); + if (decofs<0) break; + tmp=(char*)inpkg+decofs; + --q; + if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */ + tmp[2]!=0 || tmp[3]!=1) { /* CLASS != IN */ + if (tmp[1]==5) { /* CNAME */ + tmp+=10; + decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size); + if (decofs<0) break; + tmp=(char*)inpkg+decofs; + } else + break; + continue; + } + tmp+=10; /* skip type, class, TTL and length */ + { + int slen; + if (lookfor==1 || lookfor==28) /* A or AAAA*/ { + slen=strlen(Name); + if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; } + } else if (lookfor==12) /* PTR */ { + decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size); + if (decofs<0) break; + tmp=(char*)inpkg+decofs; + slen=strlen(Name); + } else + slen=strlen(Name); + strcpy((char*)cur,Name); + if (names==0) + result->h_name=(char*)cur; + else + result->h_aliases[names-1]=(char*)cur; + result->h_aliases[names]=0; + if (names<8) ++names; +/* cur+=slen+1; */ + cur+=(slen|3)+1; + result->h_addr_list[ips++] = (char*)cur; + if (lookfor==1) /* A */ { + *(int*)cur=*(int*)tmp; + cur+=4; + result->h_addr_list[ips]=0; + } else if (lookfor==28) /* AAAA */ { + { + int k; + for (k=0; k<16; ++k) cur[k]=tmp[k]; + } + cur+=16; + result->h_addr_list[ips]=0; + } + } +/* puts(Name); */ + } + } + } + if (!names) { +nodata: + *h_errnop=NO_DATA; + return -1; + } + *h_errnop=0; + *RESULT=result; + return 0; +} + + + + +int gethostbyname_r(const char* name, + struct hostent* result, + char *buf, + size_t buflen, + struct hostent **RESULT, + int *h_errnop) +{ + uintptr_t current = (uintptr_t) buf; + uintptr_t end = current + buflen; + size_t L=strlen(name); + + *RESULT = NULL; + *h_errnop = 0; + + result->h_name = (char *) current; + current += L + 1; + if (current > end) { *h_errnop = ERANGE; return 1; } + strcpy(result->h_name, name); + + current += sizeof(char **); + current -= current & (sizeof(char **) - 1); + result->h_addr_list = (char **) current; + current += 2 * sizeof(char **); + result->h_aliases = (char **) current; + current += sizeof(char **); + if (current > end) { *h_errnop = ERANGE; return 1; } + result->h_addr_list [0]= (char *) current; + current += 16; + result->h_addr_list [1] = NULL; + result->h_aliases [0] = NULL; + if (current > end) { *h_errnop = ERANGE; return 1; } + if (inet_pton(AF_INET,name,result->h_addr_list[0])) { + result->h_addrtype=AF_INET; + result->h_length=4; + *RESULT=result; + return 0; + } else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) { + result->h_addrtype=AF_INET6; + result->h_length=16; + *RESULT=result; + return 0; + } + + + { + struct hostent* r; + struct hostent* he_buf = (struct hostent *)buf; + char *work_buf = buf + sizeof(struct hostent); + size_t remain_len = buflen - sizeof(struct hostent); + int he_errno; + + sethostent(0); + while (gethostent_r(he_buf, work_buf, remain_len, &r, &he_errno) == 0) { + int i; + if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) { /* found it! */ +found: + memmove(result,r,sizeof(struct hostent)); + *RESULT=result; + endhostent(); + return 0; + } + for (i=0; i<16; ++i) { + if (r->h_aliases[i]) { + if (!strcasecmp(r->h_aliases[i],name)) goto found; + } else break; + } + } + endhostent(); + } + + return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1); +} + +#endif + diff --git a/libc/getifaddrs.c b/libc/getifaddrs.c new file mode 100644 index 0000000..354b3f2 --- /dev/null +++ b/libc/getifaddrs.c @@ -0,0 +1,421 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */ + +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp + */ +/* + * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform + * try-and-error for region size. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#ifdef NET_RT_IFLIST +#include <sys/param.h> +#include <net/route.h> +#include <sys/sysctl.h> +#include <net/if_dl.h> +#endif + +#include <errno.h> +#include <ifaddrs.h> +#include <stdlib.h> +#include <string.h> + +#if !defined(AF_LINK) +#define SA_LEN(sa) sizeof(struct sockaddr) +#endif + +#if !defined(SA_LEN) +#define SA_LEN(sa) (sa)->sa_len +#endif + +#define SALIGN (sizeof(long) - 1) +#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) + +#ifndef ALIGNBYTES +/* + * On systems with a routing socket, ALIGNBYTES should match the value + * that the kernel uses when building the messages. + */ +#define ALIGNBYTES XXX +#endif +#ifndef ALIGN +#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES) +#endif + +#if _BSDI_VERSION >= 199701 +#define HAVE_IFM_DATA +#endif + +#if _BSDI_VERSION >= 199802 +/* ifam_data is very specific to recent versions of bsdi */ +#define HAVE_IFAM_DATA +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +#define HAVE_IFM_DATA +#endif + +#define MAX_SYSCTL_TRY 5 + +int +getifaddrs(struct ifaddrs **pif) +{ + int icnt = 1; + int dcnt = 0; + int ncnt = 0; +#ifdef NET_RT_IFLIST + int ntry = 0; + int mib[6]; + size_t needed; + char *buf; + char *next; + struct ifaddrs *cif = 0; + char *p, *p0; + struct rt_msghdr *rtm; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + struct sockaddr_dl *dl; + struct sockaddr *sa; + struct ifaddrs *ifa, *ift; + u_short idx = 0; +#else /* NET_RT_IFLIST */ + char buf[1024]; + int m, sock; + struct ifconf ifc; + struct ifreq *ifr; + struct ifreq *lifr; +#endif /* NET_RT_IFLIST */ + int i; + size_t len, alen; + char *data; + char *names; + +#ifdef NET_RT_IFLIST + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; /* protocol */ + mib[3] = 0; /* wildcard address family */ + mib[4] = NET_RT_IFLIST; + mib[5] = 0; /* no flags */ + do { + /* + * We'll try to get addresses several times in case that + * the number of addresses is unexpectedly increased during + * the two sysctl calls. This should rarely happen, but we'll + * try to do our best for applications that assume success of + * this library (which should usually be the case). + * Portability note: since FreeBSD does not add margin of + * memory at the first sysctl, the possibility of failure on + * the second sysctl call is a bit higher. + */ + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return (-1); + if ((buf = malloc(needed)) == NULL) + return (-1); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + free(buf); + return (-1); + } + free(buf); + buf = NULL; + } + } while (buf == NULL); + + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)(void *)next; + if (rtm->rtm_version != RTM_VERSION) + continue; + switch (rtm->rtm_type) { + case RTM_IFINFO: + ifm = (struct if_msghdr *)(void *)rtm; + if (ifm->ifm_addrs & RTA_IFP) { + idx = ifm->ifm_index; + ++icnt; + dl = (struct sockaddr_dl *)(void *)(ifm + 1); + dcnt += SA_RLEN((struct sockaddr *)(void*)dl) + + ALIGNBYTES; +#ifdef HAVE_IFM_DATA + dcnt += sizeof(ifm->ifm_data); +#endif /* HAVE_IFM_DATA */ + ncnt += dl->sdl_nlen + 1; + } else + idx = 0; + break; + + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)(void *)rtm; + if (idx && ifam->ifam_index != idx) + abort(); /* this cannot happen */ + +#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) + if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) + break; + p = (char *)(void *)(ifam + 1); + ++icnt; +#ifdef HAVE_IFAM_DATA + dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES; +#endif /* HAVE_IFAM_DATA */ + /* Scan to look for length of address */ + alen = 0; + for (p0 = p, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)(void *)p; + len = SA_RLEN(sa); + if (i == RTAX_IFA) { + alen = len; + break; + } + p += len; + } + for (p = p0, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)(void *)p; + len = SA_RLEN(sa); + if (i == RTAX_NETMASK && SA_LEN(sa) == 0) + dcnt += alen; + else + dcnt += len; + p += len; + } + break; + } + } +#else /* NET_RT_IFLIST */ + ifc.ifc_buf = buf; + ifc.ifc_len = sizeof(buf); + + if ((sock = _socket(AF_INET, SOCK_STREAM, 0)) < 0) + return (-1); + i = _ioctl(sock, SIOCGIFCONF, (char *)&ifc); + _close(sock); + if (i < 0) + return (-1); + + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + + sa = &ifr->ifr_addr; + ++icnt; + dcnt += SA_RLEN(sa); + ncnt += sizeof(ifr->ifr_name) + 1; + + if (SA_LEN(sa) < sizeof(*sa)) + ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); + else + ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); + } +#endif /* NET_RT_IFLIST */ + + if (icnt + dcnt + ncnt == 1) { + *pif = NULL; + free(buf); + return (0); + } + data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); + if (data == NULL) { + free(buf); + return(-1); + } + + ifa = (struct ifaddrs *)(void *)data; + data += sizeof(struct ifaddrs) * icnt; + names = data + dcnt; + + memset(ifa, 0, sizeof(struct ifaddrs) * icnt); + ift = ifa; + +#ifdef NET_RT_IFLIST + idx = 0; + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)(void *)next; + if (rtm->rtm_version != RTM_VERSION) + continue; + switch (rtm->rtm_type) { + case RTM_IFINFO: + ifm = (struct if_msghdr *)(void *)rtm; + if (ifm->ifm_addrs & RTA_IFP) { + idx = ifm->ifm_index; + dl = (struct sockaddr_dl *)(void *)(ifm + 1); + + cif = ift; + ift->ifa_name = names; + ift->ifa_flags = (int)ifm->ifm_flags; + memcpy(names, dl->sdl_data, + (size_t)dl->sdl_nlen); + names[dl->sdl_nlen] = 0; + names += dl->sdl_nlen + 1; + + ift->ifa_addr = (struct sockaddr *)(void *)data; + memcpy(data, dl, + (size_t)SA_LEN((struct sockaddr *) + (void *)dl)); + data += SA_RLEN((struct sockaddr *)(void *)dl); + +#ifdef HAVE_IFM_DATA + /* ifm_data needs to be aligned */ + ift->ifa_data = data = (void *)ALIGN(data); + memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data)); + data += sizeof(ifm->ifm_data); +#else /* HAVE_IFM_DATA */ + ift->ifa_data = NULL; +#endif /* HAVE_IFM_DATA */ + + ift = (ift->ifa_next = ift + 1); + } else + idx = 0; + break; + + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)(void *)rtm; + if (idx && ifam->ifam_index != idx) + abort(); /* this cannot happen */ + + if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) + break; + ift->ifa_name = cif->ifa_name; + ift->ifa_flags = cif->ifa_flags; + ift->ifa_data = NULL; + p = (char *)(void *)(ifam + 1); + /* Scan to look for length of address */ + alen = 0; + for (p0 = p, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)(void *)p; + len = SA_RLEN(sa); + if (i == RTAX_IFA) { + alen = len; + break; + } + p += len; + } + for (p = p0, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)(void *)p; + len = SA_RLEN(sa); + switch (i) { + case RTAX_IFA: + ift->ifa_addr = + (struct sockaddr *)(void *)data; + memcpy(data, p, len); + data += len; + break; + + case RTAX_NETMASK: + ift->ifa_netmask = + (struct sockaddr *)(void *)data; + if (SA_LEN(sa) == 0) { + memset(data, 0, alen); + data += alen; + break; + } + memcpy(data, p, len); + data += len; + break; + + case RTAX_BRD: + ift->ifa_broadaddr = + (struct sockaddr *)(void *)data; + memcpy(data, p, len); + data += len; + break; + } + p += len; + } + +#ifdef HAVE_IFAM_DATA + /* ifam_data needs to be aligned */ + ift->ifa_data = data = (void *)ALIGN(data); + memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data)); + data += sizeof(ifam->ifam_data); +#endif /* HAVE_IFAM_DATA */ + + ift = (ift->ifa_next = ift + 1); + break; + } + } + + free(buf); +#else /* NET_RT_IFLIST */ + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + + ift->ifa_name = names; + names[sizeof(ifr->ifr_name)] = 0; + strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name)); + while (*names++) + ; + + ift->ifa_addr = (struct sockaddr *)data; + sa = &ifr->ifr_addr; + memcpy(data, sa, SA_LEN(sa)); + data += SA_RLEN(sa); + + ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); + ift = (ift->ifa_next = ift + 1); + } +#endif /* NET_RT_IFLIST */ + if (--ift >= ifa) { + ift->ifa_next = NULL; + *pif = ifa; + } else { + *pif = NULL; + free(ifa); + } + return (0); +} + +void +freeifaddrs(struct ifaddrs *ifp) +{ + + free(ifp); +} diff --git a/libc/getnameinfo.c b/libc/getnameinfo.c new file mode 100644 index 0000000..2955bf4 --- /dev/null +++ b/libc/getnameinfo.c @@ -0,0 +1,61 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <netdb.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> + +int +getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, + size_t nodelen, char *service, size_t servicelen, int flags) +{ + int af; + const struct sockaddr_in *sa_in = (const struct sockaddr_in *)sa; + + (void) salen; + + af = sa->sa_family; + if (af != AF_INET) { + return EAI_FAMILY; + } + + if ((flags & NI_NAMEREQD) != 0) { + return EAI_NONAME; + } + + /* FIXME: This return just the address value. Try resolving instead. */ + if (node != NULL && nodelen > 0) { + if (inet_ntop(af, &sa_in->sin_addr, node, nodelen) == NULL) { + return EAI_FAIL; + } + } + + if (service != NULL && servicelen > 0) { + in_port_t port = ntohs(sa_in->sin_port); + int rv; + + rv = snprintf(service, servicelen, "%u", port); + if (rv <= 0) { + return EAI_FAIL; + } else if ((unsigned)rv >= servicelen) { + return EAI_OVERFLOW; + } + } + + return 0; +} diff --git a/libc/getnetbydns.c b/libc/getnetbydns.c new file mode 100644 index 0000000..f093347 --- /dev/null +++ b/libc/getnetbydns.c @@ -0,0 +1,313 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <rtems/rtems_netdb.h> +#include <resolv.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> + +#include "res_config.h" + +#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( + 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( + 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( + 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( + int stayopen) +{ + if (stayopen) + _res.options |= RES_STAYOPEN | RES_USEVC; +} + +void +_endnetdnsent(void) +{ + _res.options &= ~(RES_STAYOPEN | RES_USEVC); + res_close(); +} diff --git a/libc/getnetbyht.c b/libc/getnetbyht.c new file mode 100644 index 0000000..b41220e --- /dev/null +++ b/libc/getnetbyht.c @@ -0,0 +1,175 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <rtems/rtems_netdb.h> +#include <stdio.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +#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(int f) +{ + + if (netf == NULL) + netf = fopen(_PATH_NETWORKS, "r" ); + else + rewind(netf); + _net_stayopen |= f; +} + +void +_endnethtent(void) +{ + + if (netf) { + fclose(netf); + netf = NULL; + } + _net_stayopen = 0; +} + +struct netent * +getnetent(void) +{ + 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(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( + unsigned long net, + 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/libc/getnetbynis.c b/libc/getnetbynis.c new file mode 100644 index 0000000..c2e4094 --- /dev/null +++ b/libc/getnetbynis.c @@ -0,0 +1,179 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <rtems/rtems_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( + 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( + const char *name) +{ + return _getnetbynis(name, "networks.byname", AF_INET); +} + +struct netent * +_getnetbynisaddr( + 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/libc/getnetent.3 b/libc/getnetent.3 new file mode 100644 index 0000000..8fb13c0 --- /dev/null +++ b/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/libc/getnetnamadr.c b/libc/getnetnamadr.c new file mode 100644 index 0000000..f16572e --- /dev/null +++ b/libc/getnetnamadr.c @@ -0,0 +1,193 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <rtems/rtems_netdb.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> /* for strcasecmp */ +#endif + +#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(void) +{ + 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((unsigned char)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(uint32_t 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(int stayopen) +{ + _setnethtent(stayopen); + _setnetdnsent(stayopen); +} + +void +endnetent(void) +{ + _endnethtent(); + _endnetdnsent(); +} diff --git a/libc/getproto.c b/libc/getproto.c new file mode 100644 index 0000000..23bab62 --- /dev/null +++ b/libc/getproto.c @@ -0,0 +1,62 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <netdb.h> + +extern int _proto_stayopen; + +extern struct protoent * getprotobynumber_static(int); + +struct protoent * +getprotobynumber( + int proto ) +{ + register struct protoent *p; + + setprotoent(_proto_stayopen); + while ( (p = getprotoent()) ) + if (p->p_proto == proto) + break; + if (!_proto_stayopen) + endprotoent(); + + if ( !p ) + p = getprotobynumber_static(proto); + return (p); +} diff --git a/libc/getprotoent.3 b/libc/getprotoent.3 new file mode 100644 index 0000000..dbf3d1a --- /dev/null +++ b/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/libc/getprotoent.c b/libc/getprotoent.c new file mode 100644 index 0000000..6b3ef18 --- /dev/null +++ b/libc/getprotoent.c @@ -0,0 +1,121 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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( + int f) +{ + if (protof == NULL) + protof = fopen(_PATH_PROTOCOLS, "r" ); + else + rewind(protof); + _proto_stayopen |= f; +} + +void +endprotoent(void) +{ + if (protof) { + fclose(protof); + protof = NULL; + } + _proto_stayopen = 0; +} + +struct protoent * +getprotoent(void) +{ + 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/libc/getprotoname.c b/libc/getprotoname.c new file mode 100644 index 0000000..e0e57fb --- /dev/null +++ b/libc/getprotoname.c @@ -0,0 +1,69 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <netdb.h> +#include <string.h> + +extern int _proto_stayopen; + +extern struct protoent *getprotobyname_static(const char *); + +struct protoent * +getprotobyname( + 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(); + + if ( !p ) + p = getprotobyname_static(name); + return (p); +} diff --git a/libc/getservbyname.c b/libc/getservbyname.c new file mode 100644 index 0000000..bb662c2 --- /dev/null +++ b/libc/getservbyname.c @@ -0,0 +1,101 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <netdb.h> +#include <string.h> + +extern int _serv_stayopen; + +int getservbyname_r( + const char *name, + const char *proto, + struct servent *result_buf, + char *buf, + size_t buflen, + struct servent **result +) +{ + #warning "implement a proper getservbyport_r" + + *result = getservbyname(name, proto); + if ( *result ) + return 0; + + return -1; +} + + +struct servent * +getservbyname( + const char *name, + const char *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/libc/getservbyport.c b/libc/getservbyport.c new file mode 100644 index 0000000..4a47e84 --- /dev/null +++ b/libc/getservbyport.c @@ -0,0 +1,94 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <netdb.h> +#include <string.h> + +extern int _serv_stayopen; + +int getservbyport_r( + int port, + const char *proto, + struct servent *result_buf, + char *buf, + size_t buflen, + struct servent **result +) +{ + #warning "implement a proper getservbyport_r" + + *result = getservbyport(port, proto); + if ( *result ) + return 0; + + return -1; +} + +struct servent * +getservbyport( + 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/libc/getservent.3 b/libc/getservent.3 new file mode 100644 index 0000000..32a0a8d --- /dev/null +++ b/libc/getservent.3 @@ -0,0 +1,155 @@ +.\" 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 +.\" +.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/libc/getservent.c b/libc/getservent.c new file mode 100644 index 0000000..f79a0ed --- /dev/null +++ b/libc/getservent.c @@ -0,0 +1,281 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.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( + int f) +{ + if (servf == NULL) + servf = fopen(_PATH_SERVICES, "r" ); + else + rewind(servf); + _serv_stayopen |= f; +} + +void +endservent(void) +{ + if (servf) { + fclose(servf); + servf = NULL; + } + _serv_stayopen = 0; +} + +struct servent * +getservent(void) +{ + 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/libc/herror.c b/libc/herror.c new file mode 100644 index 0000000..d65d607 --- /dev/null +++ b/libc/herror.c @@ -0,0 +1,129 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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(void) +{ + static int the_h_errno; + + return &the_h_errno; +} + +#define HERROR_USE_WRITEV + +/* + * herror -- + * print the error indicated by the h_errno value. + */ +void +herror(const char *s) +{ +#if defined(HERROR_USE_WRITEV) + 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 + /* + * no writev implementation available + */ + 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(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/libc/if_indextoname.c b/libc/if_indextoname.c new file mode 100644 index 0000000..467c2eb --- /dev/null +++ b/libc/if_indextoname.c @@ -0,0 +1,93 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $KAME: if_indextoname.c,v 1.7 2000/11/08 03:09:30 itojun Exp $ */ + +/*- + * Copyright (c) 1997, 2000 + * Berkeley Software Design, Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI Id: if_indextoname.c,v 2.3 2000/04/17 22:38:05 dab Exp + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if_dl.h> +#include <net/if.h> +#include <ifaddrs.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +/* + * From RFC 2533: + * + * The second function maps an interface index into its corresponding + * name. + * + * #include <net/if.h> + * + * char *if_indextoname(unsigned int ifindex, char *ifname); + * + * The ifname argument must point to a buffer of at least IF_NAMESIZE + * bytes into which the interface name corresponding to the specified + * index is returned. (IF_NAMESIZE is also defined in <net/if.h> and + * its value includes a terminating null byte at the end of the + * interface name.) This pointer is also the return value of the + * function. If there is no interface corresponding to the specified + * index, NULL is returned, and errno is set to ENXIO, if there was a + * system error (such as running out of memory), if_indextoname returns + * NULL and errno would be set to the proper value (e.g., ENOMEM). + */ + +char * +if_indextoname(unsigned int ifindex, char *ifname) +{ + struct ifaddrs *ifaddrs, *ifa; + int error = 0; + + if (getifaddrs(&ifaddrs) < 0) + return(NULL); /* getifaddrs properly set errno */ + + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_LINK && + ifindex == ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index) + break; + } + + if (ifa == NULL) { + error = ENXIO; + ifname = NULL; + } + else + strncpy(ifname, ifa->ifa_name, IFNAMSIZ); + + freeifaddrs(ifaddrs); + + errno = error; + return(ifname); +} diff --git a/libc/if_nameindex.c b/libc/if_nameindex.c new file mode 100644 index 0000000..7c7777f --- /dev/null +++ b/libc/if_nameindex.c @@ -0,0 +1,152 @@ +#include <machine/rtems-bsd-user-space.h> + +/* $KAME: if_nameindex.c,v 1.8 2000/11/24 08:20:01 itojun Exp $ */ + +/*- + * Copyright (c) 1997, 2000 + * Berkeley Software Design, Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if_dl.h> +#include <net/if.h> +#include <ifaddrs.h> +#include <stdlib.h> +#include <string.h> + +/* + * From RFC 2553: + * + * 4.3 Return All Interface Names and Indexes + * + * The if_nameindex structure holds the information about a single + * interface and is defined as a result of including the <net/if.h> + * header. + * + * struct if_nameindex { + * unsigned int if_index; + * char *if_name; + * }; + * + * The final function returns an array of if_nameindex structures, one + * structure per interface. + * + * struct if_nameindex *if_nameindex(void); + * + * The end of the array of structures is indicated by a structure with + * an if_index of 0 and an if_name of NULL. The function returns a NULL + * pointer upon an error, and would set errno to the appropriate value. + * + * The memory used for this array of structures along with the interface + * names pointed to by the if_name members is obtained dynamically. + * This memory is freed by the next function. + * + * 4.4. Free Memory + * + * The following function frees the dynamic memory that was allocated by + * if_nameindex(). + * + * #include <net/if.h> + * + * void if_freenameindex(struct if_nameindex *ptr); + * + * The argument to this function must be a pointer that was returned by + * if_nameindex(). + */ + +struct if_nameindex * +if_nameindex(void) +{ + struct ifaddrs *ifaddrs, *ifa; + unsigned int ni; + int nbytes; + struct if_nameindex *ifni, *ifni2; + char *cp; + + if (getifaddrs(&ifaddrs) < 0) + return(NULL); + + /* + * First, find out how many interfaces there are, and how + * much space we need for the string names. + */ + ni = 0; + nbytes = 0; + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_LINK) { + nbytes += strlen(ifa->ifa_name) + 1; + ni++; + } + } + + /* + * Next, allocate a chunk of memory, use the first part + * for the array of structures, and the last part for + * the strings. + */ + cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes); + ifni = (struct if_nameindex *)cp; + if (ifni == NULL) + goto out; + cp += (ni + 1) * sizeof(struct if_nameindex); + + /* + * Now just loop through the list of interfaces again, + * filling in the if_nameindex array and making copies + * of all the strings. + */ + ifni2 = ifni; + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_LINK) { + ifni2->if_index = + ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index; + ifni2->if_name = cp; + strcpy(cp, ifa->ifa_name); + ifni2++; + cp += strlen(cp) + 1; + } + } + /* + * Finally, don't forget to terminate the array. + */ + ifni2->if_index = 0; + ifni2->if_name = NULL; +out: + freeifaddrs(ifaddrs); + return(ifni); +} + +void +if_freenameindex(struct if_nameindex *ptr) +{ + free(ptr); +} diff --git a/libc/inet.3 b/libc/inet.3 new file mode 100644 index 0000000..501f3db --- /dev/null +++ b/libc/inet.3 @@ -0,0 +1,209 @@ +.\" 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 +.\" +.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/libc/inet_addr.c b/libc/inet_addr.c new file mode 100644 index 0000000..d014266 --- /dev/null +++ b/libc/inet_addr.c @@ -0,0 +1,218 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. 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 (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static const char rcsid[] = "$Id: inet_addr.c,v 1.5 2005/04/27 04:56:19 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: head/lib/libc/inet/inet_addr.c 314436 2017-02-28 23:42:47Z imp $"); + +#include "port_before.h" + +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <ctype.h> + +#include "port_after.h" + +/*% + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +in_addr_t /* XXX should be struct in_addr :( */ +inet_addr(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(const char *cp, struct in_addr *addr) { + u_long val; + int base, n; + char c; + u_int8_t parts[4]; + u_int8_t *pp = parts; + int digit; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit((unsigned char)c)) + return (0); + val = 0; base = 10; digit = 0; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else { + base = 8; + digit = 1 ; + } + } + for (;;) { + if (isascii(c) && isdigit((unsigned char)c)) { + if (base == 8 && (c == '8' || c == '9')) + return (0); + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if (base == 16 && isascii(c) && + isxdigit((unsigned char)c)) { + val = (val << 4) | + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } 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 || val > 0xffU) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c))) + return (0); + /* + * Did we get a valid digit? + */ + if (!digit) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + case 1: /*%< a -- 32 bits */ + break; + + case 2: /*%< a.b -- 8.24 bits */ + if (val > 0xffffffU) + return (0); + val |= parts[0] << 24; + break; + + case 3: /*%< a.b.c -- 8.8.16 bits */ + if (val > 0xffffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /*%< a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr != NULL) + addr->s_addr = htonl(val); + return (1); +} + +#ifndef __rtems__ +/* + * Weak aliases for applications that use certain private entry points, + * and fail to include <arpa/inet.h>. + */ +#undef inet_addr +__weak_reference(__inet_addr, inet_addr); +#undef inet_aton +__weak_reference(__inet_aton, inet_aton); +#endif /* __rtems__ */ + +/*! \file */ diff --git a/libc/inet_lnaof.c b/libc/inet_lnaof.c new file mode 100644 index 0000000..c88331d --- /dev/null +++ b/libc/inet_lnaof.c @@ -0,0 +1,61 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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. + */ +in_addr_t +inet_lnaof( + 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/libc/inet_makeaddr.c b/libc/inet_makeaddr.c new file mode 100644 index 0000000..4805af7 --- /dev/null +++ b/libc/inet_makeaddr.c @@ -0,0 +1,65 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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( + in_addr_t net, + in_addr_t 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/libc/inet_netof.c b/libc/inet_netof.c new file mode 100644 index 0000000..175f24f --- /dev/null +++ b/libc/inet_netof.c @@ -0,0 +1,60 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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. + */ +in_addr_t +inet_netof( + 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/libc/inet_network.c b/libc/inet_network.c new file mode 100644 index 0000000..d838dc0 --- /dev/null +++ b/libc/inet_network.c @@ -0,0 +1,92 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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. + */ +in_addr_t +inet_network( + 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((unsigned char)c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isxdigit((unsigned char)c)) { + val = (val << 4) + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + if (pp >= parts + 3) + return (INADDR_NONE); + *pp++ = val, cp++; + goto again; + } + if (*cp && !isspace((unsigned char)*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/libc/inet_ntoa.c b/libc/inet_ntoa.c new file mode 100644 index 0000000..c67678b --- /dev/null +++ b/libc/inet_ntoa.c @@ -0,0 +1,82 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. 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 const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: inet_ntoa.c,v 1.2 2005/04/27 04:56:21 sra Exp $"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: head/lib/libc/inet/inet_ntoa.c 314436 2017-02-28 23:42:47Z imp $"); + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <string.h> + +#include "port_after.h" + +/*% + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +/*const*/ char * +inet_ntoa(struct in_addr in) { + static char ret[18]; + + strcpy(ret, "[inet_ntoa error]"); + (void) inet_ntop(AF_INET, &in, ret, sizeof ret); + return (ret); +} + +char * +inet_ntoa_r(struct in_addr in, char *buf, socklen_t size) +{ + + (void) inet_ntop(AF_INET, &in, buf, size); + return (buf); +} + +#ifndef __rtems__ +/* + * Weak aliases for applications that use certain private entry points, + * and fail to include <arpa/inet.h>. + */ +#undef inet_ntoa +__weak_reference(__inet_ntoa, inet_ntoa); +__weak_reference(__inet_ntoa_r, inet_ntoa_r); +#endif /* __rtems__ */ + +/*! \file */ diff --git a/libc/inet_ntop.c b/libc/inet_ntop.c new file mode 100644 index 0000000..d070ce8 --- /dev/null +++ b/libc/inet_ntop.c @@ -0,0 +1,208 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: head/lib/libc/inet/inet_ntop.c 298226 2016-04-18 21:05:15Z avos $"); + +#include "port_before.h" + +#include <sys/param.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> + +#include "port_after.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 const char *inet_ntop4(const u_char *src, char *dst, socklen_t size); +static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size); + +/* const 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(int af, const void * __restrict src, char * __restrict dst, + socklen_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 + * 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(const u_char *src, char *dst, socklen_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + int l; + + l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || (socklen_t) l >= size) { + errno = ENOSPC; + return (NULL); + } + strlcpy(dst, tmp, size); + 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(const u_char *src, char *dst, socklen_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; + best.len = 0; + cur.base = -1; + cur.len = 0; + 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 == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) { + errno = ENOSPC; + 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 ((socklen_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +#ifndef __rtems__ +/* + * Weak aliases for applications that use certain private entry points, + * and fail to include <arpa/inet.h>. + */ +#undef inet_ntop +__weak_reference(__inet_ntop, inet_ntop); +#endif /* __rtems__ */ + +/*! \file */ diff --git a/libc/inet_pton.c b/libc/inet_pton.c new file mode 100644 index 0000000..de87cf5 --- /dev/null +++ b/libc/inet_pton.c @@ -0,0 +1,216 @@ +#include <machine/rtems-bsd-user-space.h> + +/* 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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(const char *src, u_char *dst); +static int inet_pton6(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( + 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( + 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( + 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/libc/linkaddr.3 b/libc/linkaddr.3 new file mode 100644 index 0000000..6fd61c7 --- /dev/null +++ b/libc/linkaddr.3 @@ -0,0 +1,137 @@ +.\" 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 +.\" +.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/libc/linkaddr.c b/libc/linkaddr.c new file mode 100644 index 0000000..dee7cb7 --- /dev/null +++ b/libc/linkaddr.c @@ -0,0 +1,164 @@ +#include <machine/rtems-bsd-user-space.h> + +/*- + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if_dl.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +/* 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( + const char *addr, + struct sockaddr_dl *sdl) +{ + char *cp = sdl->sdl_data; + char *cplim = sdl->sdl_len + (char *)sdl; + int byte = 0, state = NAMING, + new=0; /* new=0 to avoid warning */ + + 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( + const struct sockaddr_dl *sdl) +{ + static char obuf[64]; + char *out = obuf; + int i; + u_char *in = (u_char *)LLADDR(sdl); + u_char *inlim = in + sdl->sdl_alen; + int firsttime = 1; + + if (sdl->sdl_nlen) { + memcpy(obuf, sdl->sdl_data, 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/libc/map_v4v6.c b/libc/map_v4v6.c new file mode 100644 index 0000000..529262d --- /dev/null +++ b/libc/map_v4v6.c @@ -0,0 +1,128 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * ++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-- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <rtems/rtems_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(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. */ + memcpy(tmp, src, 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. */ + memcpy((void*)p, tmp, INADDRSZ); +} + +void +_map_v4v6_hostent( + 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) - ((uintptr_t)*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/libc/ns.3 b/libc/ns.3 new file mode 100644 index 0000000..71e60af --- /dev/null +++ b/libc/ns.3 @@ -0,0 +1,130 @@ +.\" 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 +.\" +.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/libc/ns_name.c b/libc/ns_name.c new file mode 100644 index 0000000..2032171 --- /dev/null +++ b/libc/ns_name.c @@ -0,0 +1,595 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#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, 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/libc/ns_netint.c b/libc/ns_netint.c new file mode 100644 index 0000000..da28e68 --- /dev/null +++ b/libc/ns_netint.c @@ -0,0 +1,56 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +/* Import. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/libc/ns_parse.c b/libc/ns_parse.c new file mode 100644 index 0000000..c82c90c --- /dev/null +++ b/libc/ns_parse.c @@ -0,0 +1,192 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#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->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/libc/ns_print.c b/libc/ns_print.c new file mode 100644 index 0000000..0760f99 --- /dev/null +++ b/libc/ns_print.c @@ -0,0 +1,748 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +/* Import. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#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/libc/ns_ttl.c b/libc/ns_ttl.c new file mode 100644 index 0000000..df86747 --- /dev/null +++ b/libc/ns_ttl.c @@ -0,0 +1,153 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +/* Import. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 *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/libc/nsap_addr.c b/libc/nsap_addr.c new file mode 100644 index 0000000..deaa127 --- /dev/null +++ b/libc/nsap_addr.c @@ -0,0 +1,107 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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( + int c) +{ + return (c - (((c >= '0') && (c <= '9')) ? '0' : '7')); +} + +u_int +inet_nsap_addr( + 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( + int binlen, + const u_char *binary, + 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/libc/port_after.h b/libc/port_after.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libc/port_after.h diff --git a/libc/port_before.h b/libc/port_before.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libc/port_before.h diff --git a/libc/rcmd.3 b/libc/rcmd.3 new file mode 100644 index 0000000..a09f13c --- /dev/null +++ b/libc/rcmd.3 @@ -0,0 +1,203 @@ +.\" 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 +.\" +.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/libc/rcmd.c b/libc/rcmd.c new file mode 100644 index 0000000..2bb3b72 --- /dev/null +++ b/libc/rcmd.c @@ -0,0 +1,550 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_DECL_RCMD + +#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> +#include <rpc/rpc.h> +#include <sys/select.h> +#ifdef YP +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +#ifndef __rtems__ +extern int innetgr( const char *, const char *, const char *, const char * ); +#endif + +#define max(a, b) ((a > b) ? a : b) + +#ifdef __rtems__ +int rresvport(int *alport); +#define bzero(a,s) memset((a),0,(s)) +#define bcmp memcmp +#define bcopy(s,d,i) memcpy(d,s,i) +#else /* __rtems__ */ + +int __ivaliduser(FILE *, u_int32_t, const char *, const char *); +static int __icheckhost(const struct sockaddr *, socklen_t, const char *); + +#endif + +int +rcmd( + char **ahost, + int rport, + const char *locuser, + const char *remuser, + const char *cmd, + int *fd2p ) +{ + struct hostent *hp; + struct sockaddr_in sin, from; + fd_set reads; +#ifndef __rtems__ + long oldmask; +#endif + 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; +#ifndef __rtems__ + oldmask = sigblock(sigmask(SIGURG)); +#endif + 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)); +#ifndef __rtems__ + sigsetmask(oldmask); +#endif + 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)); +#ifndef __rtems__ + sigsetmask(oldmask); +#endif + return (-1); + } + lport--; + if (fd2p == 0) { + write(s, "", 1); + lport = 0; + } else { + char num[8]; + int s2 = rresvport(&lport), s3; + socklen_t 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; + } +#ifndef __rtems__ + sigsetmask(oldmask); +#endif + return (s); +bad2: + if (lport) + (void)close(*fd2p); +bad: + (void)close(s); +#ifndef __rtems__ + sigsetmask(oldmask); +#endif + return (-1); +} + +int +rresvport(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); +} + +#ifndef __rtems__ +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); +} +#endif +#endif diff --git a/libc/recv.c b/libc/recv.c new file mode 100644 index 0000000..a3325d3 --- /dev/null +++ b/libc/recv.c @@ -0,0 +1,53 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stddef.h> + +ssize_t +recv( + int s, + void *buf, + size_t len, + int flags ) +{ + return (recvfrom(s, buf, len, flags, NULL, 0)); +} diff --git a/libc/res_comp.c b/libc/res_comp.c new file mode 100644 index 0000000..e24d99d --- /dev/null +++ b/libc/res_comp.c @@ -0,0 +1,252 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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> + +#include "res_config.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(const char *dn) +{ + int 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); + } + 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(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(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(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/libc/res_config.h b/libc/res_config.h new file mode 100644 index 0000000..83bf217 --- /dev/null +++ b/libc/res_config.h @@ -0,0 +1,16 @@ +#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 */ + +#if defined(__rtems__) +u_int16_t _getshort(const u_char *src); +u_int32_t _getlong(const u_char *src); +int gethostname (char *name, size_t namelen); +int sethostname (const char *name, size_t namelen); +int issetugid (void); +#endif diff --git a/libc/res_data.c b/libc/res_data.c new file mode 100644 index 0000000..35138a5 --- /dev/null +++ b/libc/res_data.c @@ -0,0 +1,85 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/libc/res_debug.c b/libc/res_debug.c new file mode 100644 index 0000000..f211806 --- /dev/null +++ b/libc/res_debug.c @@ -0,0 +1,973 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> + +#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> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#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 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( + const u_char *cp, + const u_char *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", NULL}, + {C_CHAOS, "CHAOS", NULL}, + {C_HS, "HS", NULL}, + {C_HS, "HESIOD", NULL}, + {C_ANY, "ANY", NULL}, + {C_NONE, "NONE", NULL}, + {C_IN, (char *)0, NULL} +}; + +/* + * Names of message sections. + */ +const struct res_sym __p_default_section_syms[] = { + {ns_s_qd, "QUERY", NULL}, + {ns_s_an, "ANSWER", NULL}, + {ns_s_ns, "AUTHORITY", NULL}, + {ns_s_ar, "ADDITIONAL", NULL}, + {0, (char *)0, NULL} +}; + +const struct res_sym __p_update_section_syms[] = { + {S_ZONE, "ZONE", NULL}, + {S_PREREQ, "PREREQUISITE", NULL}, + {S_UPDATE, "UPDATE", NULL}, + {S_ADDT, "ADDITIONAL", NULL}, + {0, (char *)0, NULL} +}; + +/* + * 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, "%" PRIu32, (uint32_t) 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 uint32_t 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( + u_int8_t prec) +{ + static char retbuf[sizeof "90000000.00"]; + unsigned long val; + uint32_t 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( + const char **strptr) +{ + unsigned int mval = 0, cmval = 0; + u_int8_t retval = 0; + const char *cp; + int exponent; + int mantissa; + + cp = *strptr; + + while (isdigit((unsigned char)*cp)) + mval = mval * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit((unsigned char)*cp)) { + cmval = (*cp++ - '0') * 10; + if (isdigit((unsigned char)*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( + char **latlonstrptr, + int *which ) +{ + char *cp; + u_int32_t retval; + int deg = 0, min = 0, secs = 0, secsfrac = 0; + + cp = *latlonstrptr; + + while (isdigit((unsigned char)*cp)) + deg = deg * 10 + (*cp++ - '0'); + + while (isspace((unsigned char)*cp)) + cp++; + + if (!(isdigit((unsigned char)*cp))) + goto fndhemi; + + while (isdigit((unsigned char)*cp)) + min = min * 10 + (*cp++ - '0'); + + while (isspace((unsigned char)*cp)) + cp++; + + if (!(isdigit((unsigned char)*cp))) + goto fndhemi; + + while (isdigit((unsigned char)*cp)) + secs = secs * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal seconds */ + cp++; + if (isdigit((unsigned char)*cp)) { + secsfrac = (*cp++ - '0') * 100; + if (isdigit((unsigned char)*cp)) { + secsfrac += (*cp++ - '0') * 10; + if (isdigit((unsigned char)*cp)) { + secsfrac += (*cp++ - '0'); + } + } + } + } + + while (!isspace((unsigned char)*cp)) /* if any trailing garbage */ + cp++; + + while (isspace((unsigned char)*cp)) + cp++; + + fndhemi: + switch (*cp) { + case 'N': case 'n': + case 'E': case 'e': + retval = ((u_int32_t)1<<31) + + (((((deg * 60) + min) * 60) + secs) * 1000) + + secsfrac; + break; + case 'S': case 's': + case 'W': case 'w': + retval = ((u_int32_t)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((unsigned char)*cp)) /* if any trailing garbage */ + cp++; + + while (isspace((unsigned char)*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( + 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((char **)&cp, &which1); + + lltemp2 = latlon2ul((char **)&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((unsigned char)*cp)) + altmeters = altmeters * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal meters */ + cp++; + if (isdigit((unsigned char)*cp)) { + altfrac = (*cp++ - '0') * 10; + if (isdigit((unsigned char)*cp)) { + altfrac += (*cp++ - '0'); + } + } + } + + alt = (10000000 + (altsign * (altmeters * 100 + altfrac))); + + while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace((unsigned char)*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + siz = precsize_aton(&cp); + + while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace((unsigned char)*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + hp = precsize_aton(&cp); + + while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace((unsigned char)*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( + 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 - ((u_int32_t)1<<31)); + + GETLONG(templ, cp); + longval = (templ - ((u_int32_t)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/libc/res_init.c b/libc/res_init.c new file mode 100644 index 0000000..0a260a1 --- /dev/null +++ b/libc/res_init.c @@ -0,0 +1,503 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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" + +/* + * RTEMS -- set up name servers from global variable + */ +#include <rtems/rtems_bsdnet_internal.h> +#include <rtems/bsdnet/servers.h> + +static void res_setoptions(char *, char *); + +#ifdef RESOLVSORT +static const char sort_mask[] = "/&"; +#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) +static u_int32_t net_mask(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(void) +{ + FILE *fp; + char *cp, **pp; + 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 + */ + { + 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((unsigned char)*cp) && !isspace((unsigned char)*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((unsigned char)*cp) && !isspace((unsigned char)*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( + char *options, + char *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( /* XXX - should really use system's version of this */ + struct in_addr in) +{ + 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(void) +{ + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} diff --git a/libc/res_mkquery.c b/libc/res_mkquery.c new file mode 100644 index 0000000..c0ffebd --- /dev/null +++ b/libc/res_mkquery.c @@ -0,0 +1,199 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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( + int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int 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/libc/res_mkupdate.c b/libc/res_mkupdate.c new file mode 100644 index 0000000..664788d --- /dev/null +++ b/libc/res_mkupdate.c @@ -0,0 +1,414 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 *cp, *sp2, *startp, *endp; + int n, i, soanum, multiline; + ns_updrec *rrecp; + 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; + 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 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/libc/res_query.c b/libc/res_query.c new file mode 100644 index 0000000..706c0ef --- /dev/null +++ b/libc/res_query.c @@ -0,0 +1,412 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +#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( + const char *name, /* domain name */ + int class, int 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( + const char *name, /* domain name */ + int class, int 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( + const char *name, const char *domain, + int class, int 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(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((unsigned char)*cp1); ++cp1) + ; + if (!*cp1) + break; + *cp1 = '\0'; + if (!strcasecmp(buf, name)) { + while (isspace((unsigned char)*++cp1)) + ; + if (!*cp1) + break; + for (cp2 = cp1 + 1; *cp2 && !isspace((unsigned char)*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/libc/res_send.c b/libc/res_send.c new file mode 100644 index 0000000..1ae1b38 --- /dev/null +++ b/libc/res_send.c @@ -0,0 +1,941 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Send query to name server and wait for reply. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#ifndef NOSELECT +#include <sys/select.h> +#endif +#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> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#include <unistd.h> +#if !defined(__rtems__) +#include <poll.h> +#endif + +/* RTEMS now has writev */ +#define USE_WRITEV + +#include "res_config.h" + +#if !defined(__rtems__) + +#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 +#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 *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 *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( + res_send_qhook hook) +{ + + Qhook = hook; +} + +void +res_send_setrhook( + 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( + 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( + const char *name, + int type, int class, + const u_char *buf, const u_char *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( + const u_char *buf1, const u_char *eom1, + const u_char *buf2, const u_char *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( + 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; +#if defined(USE_WRITEV) + struct iovec iov[2]; +#endif + 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 defined(USE_WRITEV) + 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; +#ifndef NOSELECT + fd_set dsmask, *dsmaskp; + int dsmasklen; +#endif + struct sockaddr_in from; + socklen_t 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, "%s", ""), + 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(void) +{ + if (s >= 0) { + (void) close(s); + s = -1; + connected = 0; + vc = 0; + } +} diff --git a/libc/res_stubs.c b/libc/res_stubs.c new file mode 100644 index 0000000..19966b5 --- /dev/null +++ b/libc/res_stubs.c @@ -0,0 +1,81 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +/* + * 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. :-( + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/cdefs.h> + +#ifndef __rtems__ +__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); +#endif /* __rtems__ */ + +__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/libc/res_update.c b/libc/res_update.c new file mode 100644 index 0000000..54a3af7 --- /dev/null +++ b/libc/res_update.c @@ -0,0 +1,521 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * 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> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +/* + * 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/libc/resolver.3 b/libc/resolver.3 new file mode 100644 index 0000000..818acf2 --- /dev/null +++ b/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/libc/send.c b/libc/send.c new file mode 100644 index 0000000..4aba73a --- /dev/null +++ b/libc/send.c @@ -0,0 +1,53 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stddef.h> + +ssize_t +send( + int s, + const void *msg, + size_t len, + int flags ) +{ + return (sendto(s, msg, len, flags, NULL, 0)); +} diff --git a/librtemsNfs.h b/librtemsNfs.h new file mode 100644 index 0000000..ce83d03 --- /dev/null +++ b/librtemsNfs.h @@ -0,0 +1,231 @@ +/** + * @file + * + * @ingroup RTEMSFileSystemNFS + * + * @brief This header file provides interfaces of the NFSv2 client. + */ + +/* + * Author: Till Straumann <strauman@slac.stanford.edu> 2002-2003 + * + * Authorship + * ---------- + * This software (NFS-2 client implementation for RTEMS) was created by + * Till Straumann <strauman@slac.stanford.edu>, 2002-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The NFS-2 client implementation for RTEMS was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#ifndef LIB_RTEMS_NFS_CLIENT_H +#define LIB_RTEMS_NFS_CLIENT_H + +/** + * @defgroup RTEMSFileSystemNFS NFSv2 Client + * + * @ingroup FileSystemTypesAndMount + * + * @{ + */ + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <sys/stat.h> +#include <dirent.h> +#include <netdb.h> +#include <ctype.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** RPCIO driver interface. + * If you need RPCIO for other purposes than NFS + * you may want to include <rpcio.h> +#include "rpcio.h" + */ + +/** Priority of daemon; may be setup prior to calling rpcUdpInit(); + * otherwise the network task priority from the rtems_bsdnet_config + * is used... + */ +extern rtems_task_priority rpciodPriority; + +#ifdef RTEMS_SMP +/** CPU affinity of daemon; may be setup prior to calling rpcUdpInit(); + * otherwise the network task CPU affinity from the rtems_bsdnet_config + * is used... + */ +extern const cpu_set_t *rpciodCpuset; +extern size_t rpciodCpusetSize; +#endif + +/** + * @brief Sets the XIDs of the RPC transaction hash table. + * + * The active RPC transactions are stored in a hash table. Each table entry + * contains the XID of its corresponding transaction. The XID consists of two + * parts. The lower part is determined by the hash table index. The upper + * part is incremented in each send operation. + * + * This function sets the upper part of the XID in all hash table entries. + * This can be used to ensure that the XIDs are not reused in a short interval + * for example during a boot process or after resets. + * + * @param[in] xid The upper part is used to set the upper XID part of the hash + * table entries. + */ +void +rpcSetXIDs(uint32_t xid); + +/** Initialize the driver. + * + * Note, called in nfsfs initialise when mount is called. + * + * @retval 0 on success, -1 on failure + */ +int +rpcUdpInit(void); + +/** + * @brief RPC cleanup and stop. + * + * @retval 0 on success, nonzero if still in use + */ +int +rpcUdpCleanup(void); + +/** NFS driver interface */ + +/** + * @brief Initialize the NFS driver. + * + * The RPCIO driver must have been initialized prior to calling this. + * + * Note, called in nfsfs initialise when mount is called with defaults. + * + * ARGS: depth of the small and big + * transaction pools, i.e. how + * many transactions (buffers) + * should always be kept around. + * + * (If more transactions are needed, + * they are created and destroyed + * on the fly). + * + * Supply zero values to have the + * driver chose reasonable defaults. + * + * @retval 0 Successful operation. + * @retval -1 An error occurred. The errno is set to indicate the error. + */ +int +nfsInit(int smallPoolDepth, int bigPoolDepth); + +/** + * @brief Driver cleanup code. + * + * @retval 0 on success, nonzero if still in use + */ +int +nfsCleanup(void); + +/** + * @brief Dump a list of the currently mounted NFS to a file. + * + * Dump a list of the currently mounted NFS to a file + * (stdout is used in case f==NULL) + */ +int +nfsMountsShow(FILE *f); + +/** + * @brief Filesystem mount table mount handler. + * + * Filesystem mount table mount handler. Do not call, use the mount call. + */ +int +rtems_nfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data); + +/** + * @brief A utility routine to find the path leading to a + * rtems_filesystem_location_info_t node. + * + * This should really be present in libcsupport... + * + * @param[in] 'loc' and a buffer 'buf' (length 'len') to hold the path. + * + * @param[out] path copied into 'buf' + * + * @retval 0 on success, RTEMS error code on error. + */ +rtems_status_code +rtems_filesystem_resolve_location(char *buf, int len, rtems_filesystem_location_info_t *loc); + +/** + * @brief Set the timeout (initial default: 10s) for NFS and mount calls. + * + * Set the timeout (initial default: 10s) for NFS and mount calls. + * + * @retval 0 on success, nonzero if the requested timeout is less than + * a clock tick or if the system clock rate cannot be determined. + */ + +int +nfsSetTimeout(uint32_t timeout_ms); + +/** Read current timeout (in milliseconds) */ +uint32_t +nfsGetTimeout(void); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif @@ -0,0 +1,16 @@ +#ifndef _RTEMS_BSDNET_LOOP_H +#define _RTEMS_BSDNET_LOOP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NLOOP 1 + +void rtems_bsdnet_initialize_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_BSDNET_LOOP_H */ diff --git a/machine/_align.h b/machine/_align.h new file mode 100644 index 0000000..fa26a54 --- /dev/null +++ b/machine/_align.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _MACHINE_INCLUDE__ALIGN_H_ +#define _MACHINE_INCLUDE__ALIGN_H_ + +#include <sys/_types.h> + +#define _ALIGNBYTES (sizeof(long long) - 1) +#define _ALIGN(_p) (((__uintptr_t)(_p) + _ALIGNBYTES) & ~_ALIGNBYTES) + +#endif /* !_MACHINE_INCLUDE__ALIGN_H_ */ diff --git a/machine/_kernel_if.h b/machine/_kernel_if.h new file mode 100644 index 0000000..b360a41 --- /dev/null +++ b/machine/_kernel_if.h @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * 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. 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 + * $FreeBSD: head/sys/net/if.h 333502 2018-05-11 20:08:28Z mmacy $ + */ + +#if !defined(_NET_IF_H_) || !defined(_KERNEL) +#error "must be included via <net/if.h> in kernel space" +#endif + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_IFADDR); +MALLOC_DECLARE(M_IFMADDR); +#endif + +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ diff --git a/machine/_kernel_lock.h b/machine/_kernel_lock.h new file mode 100644 index 0000000..710cecc --- /dev/null +++ b/machine/_kernel_lock.h @@ -0,0 +1 @@ +/* Empty */ diff --git a/machine/_kernel_socket.h b/machine/_kernel_socket.h new file mode 100644 index 0000000..e9acc74 --- /dev/null +++ b/machine/_kernel_socket.h @@ -0,0 +1,83 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * 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. 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 + * $FreeBSD: head/sys/sys/socket.h 334719 2018-06-06 15:45:57Z sbruno $ + */ + +#if !defined(_SYS_SOCKET_H_) || !defined(_KERNEL) +#error "must be included via <sys/socket.h> in kernel space" +#endif + +/* + * Flags for accept1(), kern_accept4() and solisten_dequeue, in addition + * to SOCK_CLOEXEC and SOCK_NONBLOCK. + */ +#define ACCEPT4_INHERIT 0x1 +#define ACCEPT4_COMPAT 0x2 + +#define MSG_SOCALLBCK 0x00010000 /* for use by socket callbacks - soreceive (TCP) */ + +#define MSG_MORETOCOME 0x00100000 /* additional data pending */ + +#define CMSG_ALIGN(n) _ALIGN(n) + +#define SF_READAHEAD(flags) ((flags) >> 16) + +struct socket; + +struct tcpcb *so_sototcpcb(struct socket *so); +struct inpcb *so_sotoinpcb(struct socket *so); +struct sockbuf *so_sockbuf_snd(struct socket *); +struct sockbuf *so_sockbuf_rcv(struct socket *); + +int so_state_get(const struct socket *); +void so_state_set(struct socket *, int); + +int so_options_get(const struct socket *); +void so_options_set(struct socket *, int); + +int so_error_get(const struct socket *); +void so_error_set(struct socket *, int); + +int so_linger_get(const struct socket *); +void so_linger_set(struct socket *, int); + +struct protosw *so_protosw_get(const struct socket *); +void so_protosw_set(struct socket *, struct protosw *); + +void so_sorwakeup_locked(struct socket *so); +void so_sowwakeup_locked(struct socket *so); + +void so_sorwakeup(struct socket *so); +void so_sowwakeup(struct socket *so); + +void so_lock(struct socket *so); +void so_unlock(struct socket *so); diff --git a/machine/cpu.h b/machine/cpu.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/machine/cpu.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/machine/cpufunc.h b/machine/cpufunc.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/machine/cpufunc.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/machine/in_cksum.h b/machine/in_cksum.h new file mode 100644 index 0000000..67dafb6 --- /dev/null +++ b/machine/in_cksum.h @@ -0,0 +1,295 @@ +/* + * Nios II version by Jeffrey O. Hill + * + * Copyright 2012. Los Alamos National Security, LLC. + * The Nios II specific part was produced under U.S. Government contract + * DE-AC52-06NA25396 for Los Alamos National Laboratory (LANL), + * which is operated by Los Alamos National Security, LLC for + * the U.S. Department of Energy. The U.S. Government has rights + * to use, reproduce, and distribute this software. NEITHER THE + * GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY + * WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR + * THE USE OF THIS SOFTWARE. + * + * Copyright (c) 1990 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 tahoe: in_cksum.c 1.2 86/01/05 + * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 + * from: Id: in_cksum.c,v 1.8 1995/12/03 18:35:19 bde Exp + */ + +#ifndef _MACHINE_IN_CKSUM_H_ +#define _MACHINE_IN_CKSUM_H_ 1 + +#include <sys/cdefs.h> +#include <netinet/ip.h> /* struct ip */ + +/* + * It it useful to have an Internet checksum routine which is inlineable + * and optimized specifically for the task of computing IP header checksums + * in the normal case (where there are no options and the header length is + * therefore always exactly five 32-bit words. + */ + +/* + * Optimized version for the i386 family + */ + +#if (defined(__GNUC__) && defined(__i386__)) + +static __inline u_int +in_cksum_hdr(const struct ip *ip) +{ + register u_int sum = ((const uint32_t*)ip)[0]; + register u_int tmp; + + __asm__ __volatile__( + " addl %2, %0 \n" + " adcl %3, %0 \n" + " adcl %4, %0 \n" + " adcl %5, %0 \n" + " adcl $0, %0 \n" + " movl %0, %1 \n" + " roll $16, %0 \n" + " addl %1, %0 \n" + :"+&r"(sum),"=&r"(tmp) + :"g"(((const uint32_t*)ip)[1]), + "g"(((const uint32_t*)ip)[2]), + "g"(((const uint32_t*)ip)[3]), + "g"(((const uint32_t*)ip)[4]), + "m"(*ip) + :"cc" + ); + + return (~sum) >>16; +} + +static __inline void +in_cksum_update(struct ip *ip) +{ + int __tmpsum; + __tmpsum = (int)ntohs(ip->ip_sum) + 256; + ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); +} + +/* + * Optimized version for the MC68xxx and Coldfire families + */ + +#elif (defined(__GNUC__) && (defined(__mc68000__) || defined(__m68k__))) + +static __inline__ u_int +in_cksum_hdr(const struct ip *ip) +{ + register u_int *ap = (u_int *)ip; + register u_int sum = *ap++; + register u_int tmp; + + __asm__ __volatile__("addl %2@+,%0\n\t" + "movel %2@+,%1\n\t" + "addxl %1,%0\n\t" + "movel %2@+,%1\n\t" + "addxl %1,%0\n\t" + "movel %2@,%1\n\t" + "addxl %1,%0\n\t" + "moveq #0,%1\n\t" + "addxl %1,%0\n" : + "=d" (sum), "=d" (tmp), "=a" (ap) : + "0" (sum), "2" (ap), "m"(*ip)); + sum = (sum & 0xffff) + (sum >> 16); + if (sum > 0xffff) + sum -= 0xffff; + return ~sum & 0xffff; +} + +/* + * Optimized version for the PowerPC family + */ + +#elif (defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__))) + +static __inline u_int +in_cksum_hdr(const struct ip *ip) +{ +register u_int sum, tmp; + __asm__ __volatile__( + " lwz %0, 0(%2) \n" + " lwz %1, 4(%2) \n" + " addc %0, %0, %1 \n" /* generate carry (XER[CA]) */ + " lwz %1, 8(%2) \n" + " adde %0, %0, %1 \n" /* add + generate */ + " lwz %1, 12(%2) \n" + " adde %0, %0, %1 \n" + " lwz %1, 16(%2) \n" + " adde %0, %0, %1 \n" + " addze %0, %0 \n" /* mop up XER[CA] */ + " rotlwi %1, %0,16 \n" /* word-swapped copy in %1 */ + " add %0, %0, %1 \n" /* see comment below */ + " not %0, %0 \n" + " srwi %0, %0, 16 \n" + :"=&r"(sum),"=&r"(tmp):"b"(ip), "m"(*ip):"xer" + ); + /* Note: if 'add' generates a carry out of the lower 16 bits + * then this is automatically added to the upper 16 bits + * where the correct result is found. (Stolen from linux.) + * %0 : upper-word lower-word + * + %1 : lower-word upper-word + * = word-sum word-sum + * ^+inter-word-carry + */ + return sum; +} + +static __inline void +in_cksum_update(struct ip *ip) +{ + int __tmpsum; + __tmpsum = (int)ntohs(ip->ip_sum) + 256; + ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); +} + +/* + * SPARC Version + */ + +#elif (defined(__GNUC__) && defined(__sparc__)) + +static __inline u_int +in_cksum_hdr(const struct ip *ip) +{ + register u_int sum = 0; + register u_int tmp_o2; + register u_int tmp_o3; + + __asm__ __volatile__ (" \ + ld [%0], %1 ; \ + ld [%0+4], %2 ; \ + ld [%0+8], %3 ; \ + addcc %1, %2, %1 ; \ + ld [%0+12], %2 ; \ + addxcc %1, %3, %1 ; \ + ld [%0+16], %3 ; \ + addxcc %1, %2, %1 ; \ + addxcc %1, %3, %1 ; \ + set 0x0ffff, %3 ; \ + srl %1, 16, %2 ; \ + and %1, %3, %1 ; \ + addx %1, %2, %1 ; \ + srl %1, 16, %2 ; \ + add %1, %2, %1 ; \ + not %1 ; \ + and %1, %3, %1 ; \ + " : "=r" (ip), "=r" (sum), "=r" (tmp_o2), "=r" (tmp_o3) + : "0" (ip), "1" (sum), "m"(*ip) + ); + return sum; +} + +#define in_cksum_update(ip) \ + do { \ + int __tmpsum; \ + __tmpsum = (int)ntohs(ip->ip_sum) + 256; \ + ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); \ + } while(0) + +/* + * Optimized version for the Altera Nios II softcore + */ +#elif defined ( __GNUC__ ) && defined ( __nios2__ ) + +static inline uint32_t _NIOS2_Add_ones_complement ( const uint32_t a, + const uint32_t b ) +{ + uint32_t sum; + uint32_t C; + __asm__ __volatile__ ( + " add %0, %2, %3 \n" /* sum <= a + b */ + " cmpltu %1, %0, %2 \n" /* C <= carryBit32 */ + " add %0, %1, %0 \n" /* sum <= sum + C */ + : "=&r"(sum), "=&r"(C) + : "r"(a), "r"(b) + ); + return sum; +} + +static inline uint16_t _NIOS2_Add_ones_complement_word_halves + ( const uint32_t a ) +{ + uint16_t sum; + uint32_t tmp; + __asm__ __volatile__ ( + " roli %1, %2, 16 \n" /* tmp <= a rotate left 16 */ + " add %1, %2, %1 \n" /* tmp <= a + tmp + carryBit16 */ + " srli %0, %1, 16 \n" /* sum <= tmp shift right 16 */ + : "=&r"(sum),"=&r"(tmp) + : "r"(a) + ); + return sum; +} + +static __inline u_int in_cksum_hdr ( const struct ip * pHdrIP ) +{ + const uint32_t * const pWd = ( const uint32_t * ) pHdrIP; + uint32_t sum = pWd[0]; + sum = _NIOS2_Add_ones_complement ( sum, pWd[1] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[2] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[3] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[4] ); + sum = _NIOS2_Add_ones_complement_word_halves ( sum ); + sum ^= 0xffff; + return sum; +} + +static __inline void in_cksum_update ( struct ip * pHdrIP ) +{ + uint32_t __tmpsum = ntohs ( pHdrIP->ip_sum ); + __tmpsum += 256u; + __tmpsum += __tmpsum >> 16u; + pHdrIP->ip_sum = htons ( ( uint16_t ) __tmpsum ); +} + +/* + * Here is the generic, portable, inefficient algorithm. + */ + +#else +u_int in_cksum_hdr(const struct ip *); +#define in_cksum_update(ip) \ + do { \ + int __tmpsum; \ + __tmpsum = (int)ntohs(ip->ip_sum) + 256; \ + ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); \ + } while(0) + +#endif + +#endif /* _MACHINE_IN_CKSUM_H_ */ diff --git a/machine/limits.h b/machine/limits.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/machine/limits.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/machine/rtems-bsd-kernel-space.h b/machine/rtems-bsd-kernel-space.h new file mode 100644 index 0000000..6debe20 --- /dev/null +++ b/machine/rtems-bsd-kernel-space.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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. + */ + +#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_KERNEL_SPACE_H_ +#define _RTEMS_BSD_MACHINE_RTEMS_BSD_KERNEL_SPACE_H_ + +#define BOOTP_COMPAT 1 +#define DIAGNOSTIC 1 +#define INET 1 +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1 +#define _KERNEL 1 +#define NFS 1 + +#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_KERNEL_SPACE_H_ */ diff --git a/machine/rtems-bsd-user-space.h b/machine/rtems-bsd-user-space.h new file mode 100644 index 0000000..4cd313a --- /dev/null +++ b/machine/rtems-bsd-user-space.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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. + */ + +#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_USER_SPACE_H_ +#define _RTEMS_BSD_MACHINE_RTEMS_BSD_USER_SPACE_H_ + +#define NOPOLL 1 +#define NOSELECT 1 +#define _THREAD_SAFE 1 + +#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_USER_SPACE_H_ */ + diff --git a/machine/vmparam.h b/machine/vmparam.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/machine/vmparam.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/net/bpf.h b/net/bpf.h new file mode 100644 index 0000000..caac044 --- /dev/null +++ b/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 + */ + +#ifndef _NET_BPF_H_ +#define _NET_BPF_H_ + +#include <sys/time.h> /* struct timeval */ + +/* 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(struct bpf_insn *, int); +void bpf_tap(struct ifnet *, u_char *, u_int); +void bpf_mtap(struct ifnet *, struct mbuf *); +void bpfattach(struct ifnet *, u_int, u_int); +void bpfilterattach(int); +u_int bpf_filter(const 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 /* _NET_BPF_H_ */ diff --git a/net/ethernet.h b/net/ethernet.h new file mode 100644 index 0000000..86a89fc --- /dev/null +++ b/net/ethernet.h @@ -0,0 +1,384 @@ +/* + * Fundamental constants relating to ethernet. + * + * $FreeBSD: src/sys/net/ethernet.h,v 1.24 2004/10/05 19:28:52 sam Exp $ + * + */ + + +#ifndef _NET_ETHERNET_H_ +#define _NET_ETHERNET_H_ + +/* + * Some basic Ethernet constants. + */ +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHER_TYPE_LEN 2 /* length of the Ethernet type field */ +#define ETHER_CRC_LEN 4 /* length of the Ethernet CRC */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN) +#define ETHER_MIN_LEN 64 /* minimum frame len, including CRC */ +#define ETHER_MAX_LEN 1518 /* maximum frame len, including CRC */ +#define ETHER_MAX_LEN_JUMBO 9018 /* max jumbo frame len, including CRC */ + +#define ETHER_VLAN_ENCAP_LEN 4 /* len of 802.1Q VLAN encapsulation */ +/* + * Mbuf adjust factor to force 32-bit alignment of IP header. + * Drivers should do m_adj(m, ETHER_ALIGN) when setting up a + * receive so the upper layers get the IP header properly aligned + * past the 14-byte Ethernet header. + */ +#define ETHER_ALIGN 2 /* driver adjust for IP hdr alignment */ + +/* + * Compute the maximum frame size based on ethertype (i.e. possible + * encapsulation) and whether or not an FCS is present. + */ +#define ETHER_MAX_FRAME(ifp, etype, hasfcs) \ + ((ifp)->if_mtu + ETHER_HDR_LEN + \ + ((hasfcs) ? ETHER_CRC_LEN : 0) + \ + (((etype) == ETHERTYPE_VLAN) ? ETHER_VLAN_ENCAP_LEN : 0)) + +/* + * Ethernet-specific mbuf flags. + */ +#define M_HASFCS M_PROTO5 /* FCS included at end of frame */ + +/* + * Ethernet CRC32 polynomials (big- and little-endian verions). + */ +#define ETHER_CRC_POLY_LE 0xedb88320 +#define ETHER_CRC_POLY_BE 0x04c11db6 + +/* + * 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]; +}; + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +/* + * NOTE: 0x0000-0x05DC (0..1500) are generally IEEE 802.3 length fields. + * However, there are some conflicts. + */ + +#define ETHERTYPE_8023 0x0004 /* IEEE 802.3 packet */ + /* 0x0101 .. 0x1FF Experimental */ +#define ETHERTYPE_PUP 0x0200 /* Xerox PUP protocol - see 0A00 */ +#define ETHERTYPE_PUPAT 0x0200 /* PUP Address Translation - see 0A01 */ +#define ETHERTYPE_SPRITE 0x0500 /* ??? */ + /* 0x0400 Nixdorf */ +#define ETHERTYPE_NS 0x0600 /* XNS */ +#define ETHERTYPE_NSAT 0x0601 /* XNS Address Translation (3Mb only) */ +#define ETHERTYPE_DLOG1 0x0660 /* DLOG (?) */ +#define ETHERTYPE_DLOG2 0x0661 /* DLOG (?) */ +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#define ETHERTYPE_X75 0x0801 /* X.75 Internet */ +#define ETHERTYPE_NBS 0x0802 /* NBS Internet */ +#define ETHERTYPE_ECMA 0x0803 /* ECMA Internet */ +#define ETHERTYPE_CHAOS 0x0804 /* CHAOSnet */ +#define ETHERTYPE_X25 0x0805 /* X.25 Level 3 */ +#define ETHERTYPE_ARP 0x0806 /* Address resolution protocol */ +#define ETHERTYPE_NSCOMPAT 0x0807 /* XNS Compatibility */ +#define ETHERTYPE_FRARP 0x0808 /* Frame Relay ARP (RFC1701) */ + /* 0x081C Symbolics Private */ + /* 0x0888 - 0x088A Xyplex */ +#define ETHERTYPE_UBDEBUG 0x0900 /* Ungermann-Bass network debugger */ +#define ETHERTYPE_IEEEPUP 0x0A00 /* Xerox IEEE802.3 PUP */ +#define ETHERTYPE_IEEEPUPAT 0x0A01 /* Xerox IEEE802.3 PUP Address Translation */ +#define ETHERTYPE_VINES 0x0BAD /* Banyan VINES */ +#define ETHERTYPE_VINESLOOP 0x0BAE /* Banyan VINES Loopback */ +#define ETHERTYPE_VINESECHO 0x0BAF /* Banyan VINES Echo */ + +/* 0x1000 - 0x100F Berkeley Trailer */ +/* + * 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 ETHERTYPE_DCA 0x1234 /* DCA - Multicast */ +#define ETHERTYPE_VALID 0x1600 /* VALID system protocol */ +#define ETHERTYPE_DOGFIGHT 0x1989 /* Artificial Horizons ("Aviator" dogfight simulator [on Sun]) */ +#define ETHERTYPE_RCL 0x1995 /* Datapoint Corporation (RCL lan protocol) */ + + /* The following 3C0x types + are unregistered: */ +#define ETHERTYPE_NBPVCD 0x3C00 /* 3Com NBP virtual circuit datagram (like XNS SPP) not registered */ +#define ETHERTYPE_NBPSCD 0x3C01 /* 3Com NBP System control datagram not registered */ +#define ETHERTYPE_NBPCREQ 0x3C02 /* 3Com NBP Connect request (virtual cct) not registered */ +#define ETHERTYPE_NBPCRSP 0x3C03 /* 3Com NBP Connect repsonse not registered */ +#define ETHERTYPE_NBPCC 0x3C04 /* 3Com NBP Connect complete not registered */ +#define ETHERTYPE_NBPCLREQ 0x3C05 /* 3Com NBP Close request (virtual cct) not registered */ +#define ETHERTYPE_NBPCLRSP 0x3C06 /* 3Com NBP Close response not registered */ +#define ETHERTYPE_NBPDG 0x3C07 /* 3Com NBP Datagram (like XNS IDP) not registered */ +#define ETHERTYPE_NBPDGB 0x3C08 /* 3Com NBP Datagram broadcast not registered */ +#define ETHERTYPE_NBPCLAIM 0x3C09 /* 3Com NBP Claim NetBIOS name not registered */ +#define ETHERTYPE_NBPDLTE 0x3C0A /* 3Com NBP Delete Netbios name not registered */ +#define ETHERTYPE_NBPRAS 0x3C0B /* 3Com NBP Remote adaptor status request not registered */ +#define ETHERTYPE_NBPRAR 0x3C0C /* 3Com NBP Remote adaptor response not registered */ +#define ETHERTYPE_NBPRST 0x3C0D /* 3Com NBP Reset not registered */ + +#define ETHERTYPE_PCS 0x4242 /* PCS Basic Block Protocol */ +#define ETHERTYPE_IMLBLDIAG 0x424C /* Information Modes Little Big LAN diagnostic */ +#define ETHERTYPE_DIDDLE 0x4321 /* THD - Diddle */ +#define ETHERTYPE_IMLBL 0x4C42 /* Information Modes Little Big LAN */ +#define ETHERTYPE_SIMNET 0x5208 /* BBN Simnet Private */ +#define ETHERTYPE_DECEXPER 0x6000 /* DEC Unassigned, experimental */ +#define ETHERTYPE_MOPDL 0x6001 /* DEC MOP dump/load */ +#define ETHERTYPE_MOPRC 0x6002 /* DEC MOP remote console */ +#define ETHERTYPE_DECnet 0x6003 /* DEC DECNET Phase IV route */ +#define ETHERTYPE_DN ETHERTYPE_DECnet /* libpcap, tcpdump */ +#define ETHERTYPE_LAT 0x6004 /* DEC LAT */ +#define ETHERTYPE_DECDIAG 0x6005 /* DEC diagnostic protocol (at interface initialization?) */ +#define ETHERTYPE_DECCUST 0x6006 /* DEC customer protocol */ +#define ETHERTYPE_SCA 0x6007 /* DEC LAVC, SCA */ +#define ETHERTYPE_AMBER 0x6008 /* DEC AMBER */ +#define ETHERTYPE_DECMUMPS 0x6009 /* DEC MUMPS */ + /* 0x6010 - 0x6014 3Com Corporation */ +#define ETHERTYPE_TRANSETHER 0x6558 /* Trans Ether Bridging (RFC1701)*/ +#define ETHERTYPE_RAWFR 0x6559 /* Raw Frame Relay (RFC1701) */ +#define ETHERTYPE_UBDL 0x7000 /* Ungermann-Bass download */ +#define ETHERTYPE_UBNIU 0x7001 /* Ungermann-Bass NIUs */ +#define ETHERTYPE_UBDIAGLOOP 0x7002 /* Ungermann-Bass diagnostic/loopback */ +#define ETHERTYPE_UBNMC 0x7003 /* Ungermann-Bass ??? (NMC to/from UB Bridge) */ +#define ETHERTYPE_UBBST 0x7005 /* Ungermann-Bass Bridge Spanning Tree */ +#define ETHERTYPE_OS9 0x7007 /* OS/9 Microware */ +#define ETHERTYPE_OS9NET 0x7009 /* OS/9 Net? */ + /* 0x7020 - 0x7029 LRT (England) (now Sintrom) */ +#define ETHERTYPE_RACAL 0x7030 /* Racal-Interlan */ +#define ETHERTYPE_PRIMENTS 0x7031 /* Prime NTS (Network Terminal Service) */ +#define ETHERTYPE_CABLETRON 0x7034 /* Cabletron */ +#define ETHERTYPE_CRONUSVLN 0x8003 /* Cronus VLN */ +#define ETHERTYPE_CRONUS 0x8004 /* Cronus Direct */ +#define ETHERTYPE_HP 0x8005 /* HP Probe */ +#define ETHERTYPE_NESTAR 0x8006 /* Nestar */ +#define ETHERTYPE_ATTSTANFORD 0x8008 /* AT&T/Stanford (local use) */ +#define ETHERTYPE_EXCELAN 0x8010 /* Excelan */ +#define ETHERTYPE_SG_DIAG 0x8013 /* SGI diagnostic type */ +#define ETHERTYPE_SG_NETGAMES 0x8014 /* SGI network games */ +#define ETHERTYPE_SG_RESV 0x8015 /* SGI reserved type */ +#define ETHERTYPE_SG_BOUNCE 0x8016 /* SGI bounce server */ +#define ETHERTYPE_APOLLODOMAIN 0x8019 /* Apollo DOMAIN */ +#define ETHERTYPE_TYMSHARE 0x802E /* Tymeshare */ +#define ETHERTYPE_TIGAN 0x802F /* Tigan, Inc. */ +#define ETHERTYPE_REVARP 0x8035 /* Reverse addr resolution protocol */ +#define ETHERTYPE_AEONIC 0x8036 /* Aeonic Systems */ +#define ETHERTYPE_IPXNEW 0x8037 /* IPX (Novell Netware?) */ +#define ETHERTYPE_LANBRIDGE 0x8038 /* DEC LANBridge */ +#define ETHERTYPE_DSMD 0x8039 /* DEC DSM/DDP */ +#define ETHERTYPE_ARGONAUT 0x803A /* DEC Argonaut Console */ +#define ETHERTYPE_VAXELN 0x803B /* DEC VAXELN */ +#define ETHERTYPE_DECDNS 0x803C /* DEC DNS Naming Service */ +#define ETHERTYPE_ENCRYPT 0x803D /* DEC Ethernet Encryption */ +#define ETHERTYPE_DECDTS 0x803E /* DEC Distributed Time Service */ +#define ETHERTYPE_DECLTM 0x803F /* DEC LAN Traffic Monitor */ +#define ETHERTYPE_DECNETBIOS 0x8040 /* DEC PATHWORKS DECnet NETBIOS Emulation */ +#define ETHERTYPE_DECLAST 0x8041 /* DEC Local Area System Transport */ + /* 0x8042 DEC Unassigned */ +#define ETHERTYPE_PLANNING 0x8044 /* Planning Research Corp. */ + /* 0x8046 - 0x8047 AT&T */ +#define ETHERTYPE_DECAM 0x8048 /* DEC Availability Manager for Distributed Systems DECamds (but someone at DEC says not) */ +#define ETHERTYPE_EXPERDATA 0x8049 /* ExperData */ +#define ETHERTYPE_VEXP 0x805B /* Stanford V Kernel exp. */ +#define ETHERTYPE_VPROD 0x805C /* Stanford V Kernel prod. */ +#define ETHERTYPE_ES 0x805D /* Evans & Sutherland */ +#define ETHERTYPE_LITTLE 0x8060 /* Little Machines */ +#define ETHERTYPE_COUNTERPOINT 0x8062 /* Counterpoint Computers */ + /* 0x8065 - 0x8066 Univ. of Mass @ Amherst */ +#define ETHERTYPE_VEECO 0x8067 /* Veeco Integrated Auto. */ +#define ETHERTYPE_GENDYN 0x8068 /* General Dynamics */ +#define ETHERTYPE_ATT 0x8069 /* AT&T */ +#define ETHERTYPE_AUTOPHON 0x806A /* Autophon */ +#define ETHERTYPE_COMDESIGN 0x806C /* ComDesign */ +#define ETHERTYPE_COMPUGRAPHIC 0x806D /* Compugraphic Corporation */ + /* 0x806E - 0x8077 Landmark Graphics Corp. */ +#define ETHERTYPE_MATRA 0x807A /* Matra */ +#define ETHERTYPE_DDE 0x807B /* Dansk Data Elektronik */ +#define ETHERTYPE_MERIT 0x807C /* Merit Internodal (or Univ of Michigan?) */ + /* 0x807D - 0x807F Vitalink Communications */ +#define ETHERTYPE_VLTLMAN 0x8080 /* Vitalink TransLAN III Management */ + /* 0x8081 - 0x8083 Counterpoint Computers */ + /* 0x8088 - 0x808A Xyplex */ +#define ETHERTYPE_ATALK 0x809B /* AppleTalk */ +#define ETHERTYPE_AT ETHERTYPE_ATALK /* old NetBSD */ +#define ETHERTYPE_APPLETALK ETHERTYPE_ATALK /* HP-UX */ + /* 0x809C - 0x809E Datability */ +#define ETHERTYPE_SPIDER 0x809F /* Spider Systems Ltd. */ + /* 0x80A3 Nixdorf */ + /* 0x80A4 - 0x80B3 Siemens Gammasonics Inc. */ + /* 0x80C0 - 0x80C3 DCA (Digital Comm. Assoc.) Data Exchange Cluster */ + /* 0x80C4 - 0x80C5 Banyan Systems */ +#define ETHERTYPE_PACER 0x80C6 /* Pacer Software */ +#define ETHERTYPE_APPLITEK 0x80C7 /* Applitek Corporation */ + /* 0x80C8 - 0x80CC Intergraph Corporation */ + /* 0x80CD - 0x80CE Harris Corporation */ + /* 0x80CF - 0x80D2 Taylor Instrument */ + /* 0x80D3 - 0x80D4 Rosemount Corporation */ +#define ETHERTYPE_SNA 0x80D5 /* IBM SNA Services over Ethernet */ +#define ETHERTYPE_VARIAN 0x80DD /* Varian Associates */ + /* 0x80DE - 0x80DF TRFS (Integrated Solutions Transparent Remote File System) */ + /* 0x80E0 - 0x80E3 Allen-Bradley */ + /* 0x80E4 - 0x80F0 Datability */ +#define ETHERTYPE_RETIX 0x80F2 /* Retix */ +#define ETHERTYPE_AARP 0x80F3 /* AppleTalk AARP */ + /* 0x80F4 - 0x80F5 Kinetics */ +#define ETHERTYPE_APOLLO 0x80F7 /* Apollo Computer */ +#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging (XXX conflicts) */ + /* 0x80FF - 0x8101 Wellfleet Communications (XXX conflicts) */ +#define ETHERTYPE_BOFL 0x8102 /* Wellfleet; BOFL (Breath OF Life) pkts [every 5-10 secs.] */ +#define ETHERTYPE_WELLFLEET 0x8103 /* Wellfleet Communications */ + /* 0x8107 - 0x8109 Symbolics Private */ +#define ETHERTYPE_TALARIS 0x812B /* Talaris */ +#define ETHERTYPE_WATERLOO 0x8130 /* Waterloo Microsystems Inc. (XXX which?) */ +#define ETHERTYPE_HAYES 0x8130 /* Hayes Microcomputers (XXX which?) */ +#define ETHERTYPE_VGLAB 0x8131 /* VG Laboratory Systems */ + /* 0x8132 - 0x8137 Bridge Communications */ +#define ETHERTYPE_IPX 0x8137 /* Novell (old) NetWare IPX (ECONFIG E option) */ +#define ETHERTYPE_NOVELL 0x8138 /* Novell, Inc. */ + /* 0x8139 - 0x813D KTI */ +#define ETHERTYPE_MUMPS 0x813F /* M/MUMPS data sharing */ +#define ETHERTYPE_AMOEBA 0x8145 /* Vrije Universiteit (NL) Amoeba 4 RPC (obsolete) */ +#define ETHERTYPE_FLIP 0x8146 /* Vrije Universiteit (NL) FLIP (Fast Local Internet Protocol) */ +#define ETHERTYPE_VURESERVED 0x8147 /* Vrije Universiteit (NL) [reserved] */ +#define ETHERTYPE_LOGICRAFT 0x8148 /* Logicraft */ +#define ETHERTYPE_NCD 0x8149 /* Network Computing Devices */ +#define ETHERTYPE_ALPHA 0x814A /* Alpha Micro */ +#define ETHERTYPE_SNMP 0x814C /* SNMP over Ethernet (see RFC1089) */ + /* 0x814D - 0x814E BIIN */ +#define ETHERTYPE_TEC 0x814F /* Technically Elite Concepts */ +#define ETHERTYPE_RATIONAL 0x8150 /* Rational Corp */ + /* 0x8151 - 0x8153 Qualcomm */ + /* 0x815C - 0x815E Computer Protocol Pty Ltd */ + /* 0x8164 - 0x8166 Charles River Data Systems */ +#define ETHERTYPE_XTP 0x817D /* Protocol Engines XTP */ +#define ETHERTYPE_SGITW 0x817E /* SGI/Time Warner prop. */ +#define ETHERTYPE_HIPPI_FP 0x8180 /* HIPPI-FP encapsulation */ +#define ETHERTYPE_STP 0x8181 /* Scheduled Transfer STP, HIPPI-ST */ + /* 0x8182 - 0x8183 Reserved for HIPPI-6400 */ + /* 0x8184 - 0x818C SGI prop. */ +#define ETHERTYPE_MOTOROLA 0x818D /* Motorola */ +#define ETHERTYPE_NETBEUI 0x8191 /* PowerLAN NetBIOS/NetBEUI (PC) */ + /* 0x819A - 0x81A3 RAD Network Devices */ + /* 0x81B7 - 0x81B9 Xyplex */ + /* 0x81CC - 0x81D5 Apricot Computers */ + /* 0x81D6 - 0x81DD Artisoft Lantastic */ + /* 0x81E6 - 0x81EF Polygon */ + /* 0x81F0 - 0x81F2 Comsat Labs */ + /* 0x81F3 - 0x81F5 SAIC */ + /* 0x81F6 - 0x81F8 VG Analytical */ + /* 0x8203 - 0x8205 QNX Software Systems Ltd. */ + /* 0x8221 - 0x8222 Ascom Banking Systems */ + /* 0x823E - 0x8240 Advanced Encryption Systems */ + /* 0x8263 - 0x826A Charles River Data Systems */ + /* 0x827F - 0x8282 Athena Programming */ + /* 0x829A - 0x829B Inst Ind Info Tech */ + /* 0x829C - 0x82AB Taurus Controls */ + /* 0x82AC - 0x8693 Walker Richer & Quinn */ +#define ETHERTYPE_ACCTON 0x8390 /* Accton Technologies (unregistered) */ +#define ETHERTYPE_TALARISMC 0x852B /* Talaris multicast */ +#define ETHERTYPE_KALPANA 0x8582 /* Kalpana */ + /* 0x8694 - 0x869D Idea Courier */ + /* 0x869E - 0x86A1 Computer Network Tech */ + /* 0x86A3 - 0x86AC Gateway Communications */ +#define ETHERTYPE_SECTRA 0x86DB /* SECTRA */ +#define ETHERTYPE_IPV6 0x86DD /* IP protocol version 6 */ +#define ETHERTYPE_DELTACON 0x86DE /* Delta Controls */ +#define ETHERTYPE_ATOMIC 0x86DF /* ATOMIC */ + /* 0x86E0 - 0x86EF Landis & Gyr Powers */ + /* 0x8700 - 0x8710 Motorola */ +#define ETHERTYPE_RDP 0x8739 /* Control Technology Inc. RDP Without IP */ +#define ETHERTYPE_MICP 0x873A /* Control Technology Inc. Mcast Industrial Ctrl Proto. */ + /* 0x873B - 0x873C Control Technology Inc. Proprietary */ +#define ETHERTYPE_TCPCOMP 0x876B /* TCP/IP Compression (RFC1701) */ +#define ETHERTYPE_IPAS 0x876C /* IP Autonomous Systems (RFC1701) */ +#define ETHERTYPE_SECUREDATA 0x876D /* Secure Data (RFC1701) */ +#define ETHERTYPE_FLOWCONTROL 0x8808 /* 802.3x flow control packet */ +#define ETHERTYPE_PPP 0x880B /* PPP (obsolete by PPPOE) */ +#define ETHERTYPE_HITACHI 0x8820 /* Hitachi Cable (Optoelectronic Systems Laboratory) */ +#define ETHERTYPE_MPLS 0x8847 /* MPLS Unicast */ +#define ETHERTYPE_MPLS_MCAST 0x8848 /* MPLS Multicast */ +#define ETHERTYPE_AXIS 0x8856 /* Axis Communications AB proprietary bootstrap/config */ +#define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETHERTYPE_LANPROBE 0x8888 /* HP LanProbe test? */ +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#define ETHERTYPE_LOOPBACK 0x9000 /* Loopback: used to test interfaces */ +#define ETHERTYPE_LBACK ETHERTYPE_LOOPBACK /* DEC MOP loopback */ +#define ETHERTYPE_XNSSM 0x9001 /* 3Com (Formerly Bridge Communications), XNS Systems Management */ +#define ETHERTYPE_TCPSM 0x9002 /* 3Com (Formerly Bridge Communications), TCP/IP Systems Management */ +#define ETHERTYPE_BCLOOP 0x9003 /* 3Com (Formerly Bridge Communications), loopback detection */ +#define ETHERTYPE_DEBNI 0xAAAA /* DECNET? Used by VAX 6220 DEBNI */ +#define ETHERTYPE_SONIX 0xFAF5 /* Sonix Arpeggio */ +#define ETHERTYPE_VITAL 0xFF00 /* BBN VITAL-LanBridge cache wakeups */ + /* 0xFF00 - 0xFFOF ISC Bunker Ramo */ + +#define ETHERTYPE_MAX 0xFFFF /* Maximum valid ethernet type, reserved */ + +/* + * 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) +#define ETHERMTU_JUMBO (ETHER_MAX_LEN_JUMBO - ETHER_HDR_LEN - ETHER_CRC_LEN) + +#ifdef _KERNEL + +struct ifnet; +struct mbuf; +struct rtentry; +struct sockaddr; + +extern uint32_t ether_crc32_le(const uint8_t *, size_t); +extern uint32_t ether_crc32_be(const uint8_t *, size_t); +extern void ether_demux(struct ifnet *, struct mbuf *); +extern void ether_ifattach(struct ifnet *); +extern void ether_ifdetach(struct ifnet *); +extern int ether_ioctl(struct ifnet *, ioctl_command_t, caddr_t); +extern void ether_input (struct ifnet *, struct ether_header *, struct mbuf *); +extern int ether_output(struct ifnet *, + struct mbuf *, struct sockaddr *, struct rtentry *); +extern int ether_output_frame(struct ifnet *, struct mbuf *); +extern char *ether_sprintf(const u_int8_t *); + +#else /* _KERNEL */ + +#include <sys/cdefs.h> + +/* + * Ethernet address conversion/parsing routines. + */ +__BEGIN_DECLS +struct ether_addr *ether_aton(const char *); +int ether_hostton(const char *, struct ether_addr *); +int ether_line(const char *, struct ether_addr *, char *); +char *ether_ntoa(const struct ether_addr *); +int ether_ntohost(char *, const struct ether_addr *); +__END_DECLS + +#endif /* !_KERNEL */ + +#endif /* !_NET_ETHERNET_H_ */ diff --git a/net/if.c b/net/if.c new file mode 100644 index 0000000..dcef1e8 --- /dev/null +++ b/net/if.c @@ -0,0 +1,789 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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.5 (Berkeley) 1/9/95 + * $FreeBSD: src/sys/net/if.c,v 1.226 2005/04/15 01:51:26 cperciva Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/sockio.h> +#include <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/if_var.h> +#include <net/radix.h> +#ifdef __rtems__ +#include <rtems/rtems_bsdnet.h> +#endif /* __rtems__ */ + +/* + * System initialization + */ + +static int ifconf(u_long, caddr_t); + void ifinit(void *); +static void if_qflush(struct ifqueue *); +static void if_slowtimo(void *); +static void link_rtrequest(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(void *dummy) +{ + 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(struct ifnet *ifp) +{ + unsigned socksize, ifasize; + int namelen, masklen; + char workbuf[64]; + struct ifnet **p = &ifnet; + struct sockaddr_dl *sdl; + 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) ((uintptr_t)((void*)&((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(struct sockaddr *addr) +{ + struct ifnet *ifp; + 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(struct sockaddr *addr) +{ + struct ifnet *ifp; + 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(struct sockaddr *addr) +{ + struct ifnet *ifp; + 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) { + 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) { + 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; /* next address! */ + /* + * If the netmask of what we just found + * is more specific than what we had before + * (if we had one) then remember the new one + * before continuing to search + * for an even better one. + */ + 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(struct sockaddr *addr, struct ifnet *ifp) +{ + struct ifaddr *ifa; + char *cp, *cp2, *cp3; + 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(int cmd, struct rtentry *rt, struct sockaddr *sa) +{ + 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(struct ifnet *ifp) +{ + 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(struct ifnet *ifp) +{ + + ifp->if_flags |= IFF_UP; + microtime(&ifp->if_lastchange); +#ifdef notyet + 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(struct ifqueue *ifq) +{ + 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(void *arg) +{ + 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. + */ +static struct ifnet * +ifunit(char *name) +{ + char *cp; + 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(struct socket *so, u_long cmd, caddr_t data, struct proc *p) +{ + struct rtems_tap_ifreq *tr; + struct ifnet *ifp; + struct ifreq *ifr; + int error; + + switch (cmd) { + + case SIOCGIFCONF: + case OSIOCGIFCONF: + return (ifconf(cmd, data)); + } + tr = (struct rtems_tap_ifreq *)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 > 65535L) + 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 == NULL) + return (EOPNOTSUPP); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return error; + + case SIOCGIFMEDIA: + if (ifp->if_ioctl == NULL) + 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 + + /* + * RTEMS additions for setting/getting `tap' function + */ + case SIOCSIFTAP: + ifp->if_tap = tr->ifr_tap; + return 0; + + case SIOCGIFTAP: + tr->ifr_tap = ifp->if_tap; + return 0; + } + 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(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(u_long cmd, caddr_t data) +{ + struct ifconf *ifc = (struct ifconf *)data; + struct ifnet *ifp = ifnet; + struct ifaddr *ifa; + struct ifreq ifr; + char *ifrpc; + int space = ifc->ifc_len, error = 0; + + ifrpc = (char*)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)ifrpc, + sizeof (ifr)); + if (error) + break; + space -= sizeof (ifr); ifrpc+=sizeof(ifr); + } else + for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { + 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)ifrpc, + sizeof (ifr)); + ifrpc+=sizeof(ifr); + } else +#endif + if (sa->sa_len <= sizeof(*sa)) { + ifr.ifr_addr = *sa; + error = copyout((caddr_t)&ifr, (caddr_t)ifrpc, + sizeof (ifr)); + ifrpc+=sizeof(ifr); + } else { + space -= sa->sa_len - sizeof(*sa); + if (space < sizeof (ifr)) + break; + error = copyout((caddr_t)&ifr, (caddr_t)ifrpc, + sizeof (ifr.ifr_name)); + ifrpc+=sizeof(ifr.ifr_name); + if (error == 0) + error = copyout((caddr_t)sa, + (caddr_t)ifrpc, sa->sa_len); + ifrpc += sa->sa_len; + } + 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/net/if_arp.h b/net/if_arp.h new file mode 100644 index 0000000..7fbd36f --- /dev/null +++ b/net/if_arp.h @@ -0,0 +1,130 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/if_arp.h,v 1.21 2005/01/07 01:45:34 imp Exp $ + */ + + +#ifndef _NET_IF_ARP_H_ +#define _NET_IF_ARP_H_ + +#include <sys/socket.h> /* struct sockaddr */ + +/* + * 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_IEEE802 6 /* token-ring hardware format */ +#define ARPHRD_ARCNET 7 /* arcnet hardware format */ +#define ARPHRD_FRELAY 15 /* frame relay hardware format */ +#define ARPHRD_IEEE1394 24 /* firewire 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 +}; + +#define ar_sha(ap) (((caddr_t)((ap)+1)) + 0) +#define ar_spa(ap) (((caddr_t)((ap)+1)) + (ap)->ar_hln) +#define ar_tha(ap) (((caddr_t)((ap)+1)) + (ap)->ar_hln + (ap)->ar_pln) +#define ar_tpa(ap) (((caddr_t)((ap)+1)) + 2*(ap)->ar_hln + (ap)->ar_pln) + +#define arphdr_len2(ar_hln, ar_pln) \ + (sizeof(struct arphdr) + 2*(ar_hln) + 2*(ar_pln)) +#define arphdr_len(ap) (arphdr_len2((ap)->ar_hln, (ap)->ar_pln)) + +/* + * 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 */ + +#ifdef _KERNEL +#include <net/if_var.h> +/* + * Structure shared between the ethernet driver modules and + * the address resolution code. For example, each ec_softc or il_softc + * begins with this structure. + * The code is written so that each *_softc _must_ begin with a + * struct arpcom, which in turn _must_ begin with a struct ifnet. + */ +struct arpcom { + /* + * The ifnet struct _must_ be at the head of this structure. + */ + struct ifnet ac_if; /* network-visible interface */ + u_char ac_enaddr[6]; /* ethernet hardware address */ +#if defined(__rtems__) +/* Cruft from ancient BSD - should be removed once RTEMS is updated */ + struct ether_multi *ac_multiaddrs; /* list of ether multicast addrs */ + int ac_multicnt; /* length of ac_multiaddrs list */ +#else + int now_unused; /* XXX was length of ac_multiaddrs list */ + void *ac_netgraph; /* ng_ether(4) netgraph node info */ +#endif +}; +#define IFP2AC(ifp) ((struct arpcom *)(ifp)) + +#endif + +#endif /* !_NET_IF_ARP_H_ */ diff --git a/net/if_dl.h b/net/if_dl.h new file mode 100644 index 0000000..4048528 --- /dev/null +++ b/net/if_dl.h @@ -0,0 +1,83 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/if_dl.h,v 1.14 2005/01/07 01:45:34 imp Exp $ + */ + + +#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_LINK */ + 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[46]; /* 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(const char *, struct sockaddr_dl *); +char *link_ntoa(const struct sockaddr_dl *); +__END_DECLS + +#endif /* !_KERNEL */ + +#endif diff --git a/net/if_ethersubr.c b/net/if_ethersubr.c new file mode 100644 index 0000000..258bdda --- /dev/null +++ b/net/if_ethersubr.c @@ -0,0 +1,896 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/if_ethersubr.c,v 1.189 2005/03/06 22:59:40 sobomax Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opt_atalk.h" +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipx.h" +#include "opt_bdg.h" +#include "opt_mac.h" +#include "opt_netgraph.h" + +#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/sockio.h> +#include <errno.h> +#include <sys/syslog.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_arp.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> + +#if defined(INET) || defined(INET6) +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> +#include <netinet/ip_fw.h> +#ifndef __rtems__ +#include <netinet/ip_dummynet.h> +#endif +#endif +#ifdef INET6 +#include <netinet6/nd6.h> +#endif + +#ifdef DEV_CARP +#include <netinet/ip_carp.h> +#endif + +#ifdef IPX +#include <netipx/ipx.h> +#include <netipx/ipx_if.h> +#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) do { error = (e); goto bad;} while (0) + +/* + * 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(struct ifnet *ifp, struct mbuf *m, + struct sockaddr *dst, struct rtentry *rt0) +{ + short type; + int s, error = 0; + u_char edst[6]; + register struct rtentry *rt; + struct mbuf *mcopy = (struct mbuf *)0; + register struct ether_header *eh; + int len = m->m_pkthdr.len; + struct arpcom *ac = (struct arpcom *)ifp; +#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); + 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 */ + + 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 == NULL) + 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(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) +{ + register struct ifqueue *inq; + u_short ether_type; + int s; +#if defined(NETATALK) + 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++; + + /* + * RTEMS addition -- allow application to `tap into' + * the incoming packet stream. + */ + if (ifp->if_tap && (*ifp->if_tap)(ifp, eh, m)) { + m_freem(m); + return; + } + + 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 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: +#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); +} + +/* + * Convert Ethernet address to printable (loggable) representation. + * The static buffer isn't a really huge problem since this code + * is protected by the RTEMS network mutex. + */ +char * +ether_sprintf(const u_char *ap) +{ + static char buf[32]; + char *b = buf; + int i; + + for (i = 0; i < ETHER_ADDR_LEN; i++, b+=3) + sprintf(b, "%02x:", *ap++); + *--b = '\0'; + return buf; +} + +/* + * Perform common duties while attaching to interface list + */ +void +ether_ifattach(struct ifnet *ifp) +{ + struct ifaddr *ifa; + struct sockaddr_dl *sdl; + + ifp->if_type = IFT_ETHER; + ifp->if_addrlen = ETHER_ADDR_LEN; + ifp->if_hdrlen = ETHER_HDR_LEN; + 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; + } +} + +#if defined(__rtems__) +u_char ether_ipmulticast_min[6] = + { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; +u_char ether_ipmulticast_max[6] = + { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; +#else +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 }; +#endif + +/* + * Add an Ethernet multicast address or range of addresses to the list for a + * given interface. + */ +int +ether_addmulti(struct ifreq *ifr, 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(struct ifreq *ifr, 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_DECL(_net_link); +SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); + +#if 0 +/* + * This is for reference. We have a table-driven version + * of the little-endian crc32 generator, which is faster + * than the double-loop. + */ +uint32_t +ether_crc32_le(const uint8_t *buf, size_t len) +{ + size_t i; + uint32_t crc; + int bit; + uint8_t data; + + crc = 0xffffffff; /* initial value */ + + for (i = 0; i < len; i++) { + for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) + carry = (crc ^ data) & 1; + crc >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_LE); + } + + return (crc); +} +#else +uint32_t +ether_crc32_le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + size_t i; + uint32_t crc; + + crc = 0xffffffff; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return (crc); +} +#endif + +uint32_t +ether_crc32_be(const uint8_t *buf, size_t len) +{ + size_t i; + uint32_t crc, carry; + int bit; + uint8_t data; + + crc = 0xffffffff; /* initial value */ + + for (i = 0; i < len; i++) { + for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) { + carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01); + crc <<= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + } + } + + return (crc); +} + +int +ether_ioctl(struct ifnet *ifp, ioctl_command_t 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: + { + 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 + 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; + default: + error = EINVAL; /* XXX netbsd has ENOTTY??? */ + break; + } + return (error); +} diff --git a/net/if_llc.h b/net/if_llc.h new file mode 100644 index 0000000..5f95f3f --- /dev/null +++ b/net/if_llc.h @@ -0,0 +1,163 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/if_llc.h,v 1.13 2006/12/01 17:50:11 imp Exp $ + */ + + +#ifndef _NET_IF_LLC_H_ +#define _NET_IF_LLC_H_ + +#ifndef __packed +#if defined(__GNUC__) +#define __packed __attribute__((packed)) +#else +#define __packed +#endif +#endif + +/* + * 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_int8_t llc_dsap; + u_int8_t llc_ssap; + union { + struct { + u_int8_t control; + u_int8_t format_id; + u_int8_t class; + u_int8_t window_x2; + } __packed type_u; + struct { + u_int8_t num_snd_x2; + u_int8_t num_rcv_x2; + } __packed type_i; + struct { + u_int8_t control; + u_int8_t num_rcv_x2; + } __packed type_s; + struct { + u_int8_t control; + /* + * We cannot put the following fields in a structure because + * the structure rounding might cause padding. + */ + u_int8_t frmr_rej_pdu0; + u_int8_t frmr_rej_pdu1; + u_int8_t frmr_control; + u_int8_t frmr_control_ext; + u_int8_t frmr_cause; + } __packed type_frmr; + struct { + u_int8_t control; + u_int8_t org_code[3]; + u_int16_t ether_type; + } __packed type_snap; + struct { + u_int8_t control; + u_int8_t control_ext; + } __packed type_raw; + } __packed llc_un; +} __packed; + +struct frmrinfo { + u_int8_t frmr_rej_pdu0; + u_int8_t frmr_rej_pdu1; + u_int8_t frmr_control; + u_int8_t frmr_control_ext; + u_int8_t frmr_cause; +} __packed; + +#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.frmr_rej_pdu0 +#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1 +#define llc_frmr_control llc_un.type_frmr.frmr_control +#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext +#define llc_frmr_cause llc_un.type_frmr.frmr_cause +#define llc_snap llc_un.type_snap + +/* + * Don't use sizeof(struct llc_un) for LLC header sizes + */ +#define LLC_ISFRAMELEN 4 +#define LLC_UFRAMELEN 3 +#define LLC_FRMRLEN 7 +#define LLC_SNAPFRAMELEN 8 + +/* + * 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 /* _NET_IF_LLC_H_ */ diff --git a/net/if_loop.c b/net/if_loop.c new file mode 100644 index 0000000..6440a48 --- /dev/null +++ b/net/if_loop.c @@ -0,0 +1,287 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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.2 (Berkeley) 1/9/95 + * $FreeBSD: src/sys/net/if_loop.c,v 1.104 2005/02/24 01:34:01 sam Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Loopback interface driver for protocol testing and timing. + */ +#include "loop.h" +#if NLOOP > 0 + +#include "opt_atalk.h" +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipx.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <errno.h> +#include <sys/sockio.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 INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#endif + +#ifdef NETATALK +#include <netatalk/at.h> +#include <netatalk/at_var.h> +#endif + +static int loioctl(struct ifnet *, ioctl_command_t, caddr_t); +static void lortrequest(int, struct rtentry *, struct sockaddr *); + +#ifdef TINY_LOMTU +#define LOMTU (1024+512) +#elif defined(LARGE_LOMTU) +#define LOMTU 131072 +#else +#define LOMTU 16384 +#endif + +struct ifnet loif[NLOOP]; + +void +rtems_bsdnet_initialize_loop(void) +{ + 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; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + if_attach(ifp); +#if NBPFILTER > 0 + bpfattach(ifp, DLT_NULL, sizeof(u_int)); +#endif + } +} + +int +looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + 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); + } + + /* Let BPF see incoming packet */ + 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 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); +} + +static void +lortrequest(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 = 3L * (long)LOMTU; + } +} + +/* + * Process an ioctl request. + */ +static int +loioctl(struct ifnet *ifp, ioctl_command_t 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 +#ifdef INET6 + case AF_INET6: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + } + return (error); +} +#endif /* NLOOP > 0 */ diff --git a/net/if_media.h b/net/if_media.h new file mode 100644 index 0000000..9a2b179 --- /dev/null +++ b/net/if_media.h @@ -0,0 +1,531 @@ +/* $NetBSD: if_media.h,v 1.3 1997/03/26 01:19:27 thorpej Exp $ */ +/* $FreeBSD: src/sys/net/if_media.h,v 1.26 2004/01/26 11:52:32 harti Exp $ */ + +/* + * Copyright (c) 1997 + * Jonathan Stone and Jason R. Thorpe. All rights reserved. + * + * This software is derived from information provided by Matt Thomas. + * + * 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 Jonathan Stone + * and Jason R. Thorpe for the NetBSD Project. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_MEDIA_H_ +#define _NET_IF_MEDIA_H_ + +/* + * Prototypes and definitions for BSD/OS-compatible network interface + * media selection. + * + * Where it is safe to do so, this code strays slightly from the BSD/OS + * design. Software which uses the API (device drivers, basically) + * shouldn't notice any difference. + * + * Many thanks to Matt Thomas for providing the information necessary + * to implement this interface. + */ + +#ifdef _KERNEL + +#include <sys/queue.h> + +/* + * Driver callbacks for media status and change requests. + */ +typedef int (*ifm_change_cb_t)(struct ifnet *ifp); +typedef void (*ifm_stat_cb_t)(struct ifnet *ifp, struct ifmediareq *req); + +/* + * In-kernel representation of a single supported media type. + */ +struct ifmedia_entry { + LIST_ENTRY(ifmedia_entry) ifm_list; + int ifm_media; /* description of this media attachment */ + int ifm_data; /* for driver-specific use */ + void *ifm_aux; /* for driver-specific use */ +}; + +/* + * One of these goes into a network interface's softc structure. + * It is used to keep general media state. + */ +struct ifmedia { + int ifm_mask; /* mask of changes we don't care about */ + int ifm_media; /* current user-set media word */ + struct ifmedia_entry *ifm_cur; /* currently selected media */ + LIST_HEAD(, ifmedia_entry) ifm_list; /* list of all supported media */ + ifm_change_cb_t ifm_change; /* media change driver callback */ + ifm_stat_cb_t ifm_status; /* media status driver callback */ +}; + +/* Initialize an interface's struct if_media field. */ +void ifmedia_init(struct ifmedia *ifm, int dontcare_mask, + ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback); + +/* Remove all mediums from a struct ifmedia. */ +void ifmedia_removeall( struct ifmedia *ifm); + +/* Add one supported medium to a struct ifmedia. */ +void ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux); + +/* Add an array (of ifmedia_entry) media to a struct ifmedia. */ +void ifmedia_list_add(struct ifmedia *mp, struct ifmedia_entry *lp, + int count); + +/* Set default media type on initialization. */ +void ifmedia_set(struct ifmedia *ifm, int mword); + +/* Common ioctl function for getting/setting media, called by driver. */ +int ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, + struct ifmedia *ifm, u_long cmd); + +#endif /*_KERNEL */ + +/* + * if_media Options word: + * Bits Use + * ---- ------- + * 0-4 Media variant + * 5-7 Media type + * 8-15 Type specific options + * 16-18 Mode (for multi-mode devices) + * 19 RFU + * 20-27 Shared (global) options + * 28-31 Instance + */ + +/* + * Ethernet + */ +#define IFM_ETHER 0x00000020 +#define IFM_10_T 3 /* 10BaseT - RJ45 */ +#define IFM_10_2 4 /* 10Base2 - Thinnet */ +#define IFM_10_5 5 /* 10Base5 - AUI */ +#define IFM_100_TX 6 /* 100BaseTX - RJ45 */ +#define IFM_100_FX 7 /* 100BaseFX - Fiber */ +#define IFM_100_T4 8 /* 100BaseT4 - 4 pair cat 3 */ +#define IFM_100_VG 9 /* 100VG-AnyLAN */ +#define IFM_100_T2 10 /* 100BaseT2 */ +#define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */ +#define IFM_10_STP 12 /* 10BaseT over shielded TP */ +#define IFM_10_FL 13 /* 10BaseFL - Fiber */ +#define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */ +#define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */ +#define IFM_1000_T 16 /* 1000baseT - 4 pair cat 5 */ +#define IFM_HPNA_1 17 /* HomePNA 1.0 (1Mb/s) */ +/* note 31 is the max! */ + +#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */ + +/* + * Token ring + */ +#define IFM_TOKEN 0x00000040 +#define IFM_TOK_STP4 3 /* Shielded twisted pair 4m - DB9 */ +#define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */ +#define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */ +#define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */ +#define IFM_TOK_STP100 7 /* Shielded twisted pair 100m - DB9 */ +#define IFM_TOK_UTP100 8 /* Unshielded twisted pair 100m - RJ45 */ +#define IFM_TOK_ETR 0x00000200 /* Early token release */ +#define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */ +#define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */ +#define IFM_TOK_DTR 0x00002000 /* Dedicated token ring */ +#define IFM_TOK_CLASSIC 0x00004000 /* Classic token ring */ +#define IFM_TOK_AUTO 0x00008000 /* Automatic Dedicate/Classic token ring */ + +/* + * FDDI + */ +#define IFM_FDDI 0x00000060 +#define IFM_FDDI_SMF 3 /* Single-mode fiber */ +#define IFM_FDDI_MMF 4 /* Multi-mode fiber */ +#define IFM_FDDI_UTP 5 /* CDDI / UTP */ +#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */ + +/* + * IEEE 802.11 Wireless + */ +#define IFM_IEEE80211 0x00000080 +/* NB: 0,1,2 are auto, manual, none defined below */ +#define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */ +#define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */ +#define IFM_IEEE80211_DS1 5 /* Direct Sequence 1Mbps */ +#define IFM_IEEE80211_DS2 6 /* Direct Sequence 2Mbps */ +#define IFM_IEEE80211_DS5 7 /* Direct Sequence 5.5Mbps */ +#define IFM_IEEE80211_DS11 8 /* Direct Sequence 11Mbps */ +#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */ +#define IFM_IEEE80211_OFDM6 10 /* OFDM 6Mbps */ +#define IFM_IEEE80211_OFDM9 11 /* OFDM 9Mbps */ +#define IFM_IEEE80211_OFDM12 12 /* OFDM 12Mbps */ +#define IFM_IEEE80211_OFDM18 13 /* OFDM 18Mbps */ +#define IFM_IEEE80211_OFDM24 14 /* OFDM 24Mbps */ +#define IFM_IEEE80211_OFDM36 15 /* OFDM 36Mbps */ +#define IFM_IEEE80211_OFDM48 16 /* OFDM 48Mbps */ +#define IFM_IEEE80211_OFDM54 17 /* OFDM 54Mbps */ +#define IFM_IEEE80211_OFDM72 18 /* OFDM 72Mbps */ + +#define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */ +#define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */ +#define IFM_IEEE80211_IBSS 0x00000400 /* Operate in IBSS mode */ +#define IFM_IEEE80211_IBSSMASTER 0x00000800 /* Operate as an IBSS master */ +#define IFM_IEEE80211_TURBO 0x00001000 /* Operate in turbo mode */ +#define IFM_IEEE80211_MONITOR 0x00002000 /* Operate in monitor mode */ + +/* operating mode for multi-mode devices */ +#define IFM_IEEE80211_11A 0x00010000 /* 5Ghz, OFDM mode */ +#define IFM_IEEE80211_11B 0x00020000 /* Direct Sequence mode */ +#define IFM_IEEE80211_11G 0x00030000 /* 2Ghz, CCK mode */ +#define IFM_IEEE80211_FH 0x00040000 /* 2Ghz, GFSK mode */ + +/* + * ATM + */ +#define IFM_ATM 0x000000a0 +#define IFM_ATM_UNKNOWN 3 +#define IFM_ATM_UTP_25 4 +#define IFM_ATM_TAXI_100 5 +#define IFM_ATM_TAXI_140 6 +#define IFM_ATM_MM_155 7 +#define IFM_ATM_SM_155 8 +#define IFM_ATM_UTP_155 9 +#define IFM_ATM_MM_622 10 +#define IFM_ATM_SM_622 11 +#define IFM_ATM_VIRTUAL 12 +#define IFM_ATM_SDH 0x00000100 /* SDH instead of SONET */ +#define IFM_ATM_NOSCRAMB 0x00000200 /* no scrambling */ +#define IFM_ATM_UNASSIGNED 0x00000400 /* unassigned cells */ + +/* + * Shared media sub-types + */ +#define IFM_AUTO 0 /* Autoselect best media */ +#define IFM_MANUAL 1 /* Jumper/dipswitch selects media */ +#define IFM_NONE 2 /* Deselect all media */ + +/* + * Shared options + */ +#define IFM_FDX 0x00100000 /* Force full duplex */ +#define IFM_HDX 0x00200000 /* Force half duplex */ +#define IFM_FLAG0 0x01000000 /* Driver defined flag */ +#define IFM_FLAG1 0x02000000 /* Driver defined flag */ +#define IFM_FLAG2 0x04000000 /* Driver defined flag */ +#define IFM_LOOP 0x08000000 /* Put hardware in loopback */ + +/* + * Masks + */ +#define IFM_NMASK 0x000000e0 /* Network type */ +#define IFM_TMASK 0x0000001f /* Media sub-type */ +#define IFM_IMASK 0xf0000000 /* Instance */ +#define IFM_ISHIFT 28 /* Instance shift */ +#define IFM_OMASK 0x0000ff00 /* Type specific options */ +#define IFM_MMASK 0x00070000 /* Mode */ +#define IFM_MSHIFT 16 /* Mode shift */ +#define IFM_GMASK 0x0ff00000 /* Global options */ + +/* + * Status bits + */ +/* + * FIXME: This is a hack to get the libbsdport interface drivers working. See + * also rtems_mii_ioctl.h. + */ +#define IFM_AVALID IFM_FLAG0 /* Active bit valid */ +#define IFM_ACTIVE IFM_FLAG0 /* Interface attached to working net */ + +/* + * Macros to extract various bits of information from the media word. + */ +#define IFM_TYPE(x) ((x) & IFM_NMASK) +#define IFM_SUBTYPE(x) ((x) & IFM_TMASK) +#define IFM_TYPE_OPTIONS(x) ((x) & IFM_OMASK) +#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT) +#define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK)) +#define IFM_MODE(x) ((x) & IFM_MMASK) + +#define IFM_INST_MAX IFM_INST(IFM_IMASK) + +/* + * Macro to create a media word. + */ +#define IFM_MAKEWORD(type, subtype, options, instance) \ + ((type) | (subtype) | (options) | ((uint32_t)(instance) << IFM_ISHIFT)) +#define IFM_MAKEMODE(mode) \ + (((mode) << IFM_MSHIFT) & IFM_MMASK) + +/* + * NetBSD extension not defined in the BSDI API. This is used in various + * places to get the canonical description for a given type/subtype. + * + * NOTE: all but the top-level type descriptions must contain NO whitespace! + * Otherwise, parsing these in ifconfig(8) would be a nightmare. + */ +struct ifmedia_description { + int ifmt_word; /* word value; may be masked */ + const char *ifmt_string; /* description */ +}; + +#define IFM_TYPE_DESCRIPTIONS { \ + { IFM_ETHER, "Ethernet" }, \ + { IFM_TOKEN, "Token ring" }, \ + { IFM_FDDI, "FDDI" }, \ + { IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \ + { IFM_ATM, "ATM" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_DESCRIPTIONS { \ + { IFM_10_T, "10baseT/UTP" }, \ + { IFM_10_2, "10base2/BNC" }, \ + { IFM_10_5, "10base5/AUI" }, \ + { IFM_100_TX, "100baseTX" }, \ + { IFM_100_FX, "100baseFX" }, \ + { IFM_100_T4, "100baseT4" }, \ + { IFM_100_VG, "100baseVG" }, \ + { IFM_100_T2, "100baseT2" }, \ + { IFM_10_STP, "10baseSTP" }, \ + { IFM_10_FL, "10baseFL" }, \ + { IFM_1000_SX, "1000baseSX" }, \ + { IFM_1000_LX, "1000baseLX" }, \ + { IFM_1000_CX, "1000baseCX" }, \ + { IFM_1000_T, "1000baseTX" }, \ + { IFM_1000_T, "1000baseT" }, \ + { IFM_HPNA_1, "homePNA" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_ALIASES { \ + { IFM_10_T, "UTP" }, \ + { IFM_10_T, "10UTP" }, \ + { IFM_10_2, "BNC" }, \ + { IFM_10_2, "10BNC" }, \ + { IFM_10_5, "AUI" }, \ + { IFM_10_5, "10AUI" }, \ + { IFM_100_TX, "100TX" }, \ + { IFM_100_T4, "100T4" }, \ + { IFM_100_VG, "100VG" }, \ + { IFM_100_T2, "100T2" }, \ + { IFM_10_STP, "10STP" }, \ + { IFM_10_FL, "10FL" }, \ + { IFM_1000_SX, "1000SX" }, \ + { IFM_1000_LX, "1000LX" }, \ + { IFM_1000_CX, "1000CX" }, \ + { IFM_1000_T, "1000TX" }, \ + { IFM_1000_T, "1000T" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS { \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_DESCRIPTIONS { \ + { IFM_TOK_STP4, "DB9/4Mbit" }, \ + { IFM_TOK_STP16, "DB9/16Mbit" }, \ + { IFM_TOK_UTP4, "UTP/4Mbit" }, \ + { IFM_TOK_UTP16, "UTP/16Mbit" }, \ + { IFM_TOK_STP100, "STP/100Mbit" }, \ + { IFM_TOK_UTP100, "UTP/100Mbit" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_ALIASES { \ + { IFM_TOK_STP4, "4STP" }, \ + { IFM_TOK_STP16, "16STP" }, \ + { IFM_TOK_UTP4, "4UTP" }, \ + { IFM_TOK_UTP16, "16UTP" }, \ + { IFM_TOK_STP100, "100STP" }, \ + { IFM_TOK_UTP100, "100UTP" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS { \ + { IFM_TOK_ETR, "EarlyTokenRelease" }, \ + { IFM_TOK_SRCRT, "SourceRouting" }, \ + { IFM_TOK_ALLR, "AllRoutes" }, \ + { IFM_TOK_DTR, "Dedicated" }, \ + { IFM_TOK_CLASSIC,"Classic" }, \ + { IFM_TOK_AUTO, " " }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_DESCRIPTIONS { \ + { IFM_FDDI_SMF, "Single-mode" }, \ + { IFM_FDDI_MMF, "Multi-mode" }, \ + { IFM_FDDI_UTP, "UTP" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_ALIASES { \ + { IFM_FDDI_SMF, "SMF" }, \ + { IFM_FDDI_MMF, "MMF" }, \ + { IFM_FDDI_UTP, "CDDI" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS { \ + { IFM_FDDI_DA, "Dual-attach" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_DESCRIPTIONS { \ + { IFM_IEEE80211_FH1, "FH/1Mbps" }, \ + { IFM_IEEE80211_FH2, "FH/2Mbps" }, \ + { IFM_IEEE80211_DS1, "DS/1Mbps" }, \ + { IFM_IEEE80211_DS2, "DS/2Mbps" }, \ + { IFM_IEEE80211_DS5, "DS/5.5Mbps" }, \ + { IFM_IEEE80211_DS11, "DS/11Mbps" }, \ + { IFM_IEEE80211_DS22, "DS/22Mbps" }, \ + { IFM_IEEE80211_OFDM6, "OFDM/6Mbps" }, \ + { IFM_IEEE80211_OFDM9, "OFDM/9Mbps" }, \ + { IFM_IEEE80211_OFDM12, "OFDM/12Mbps" }, \ + { IFM_IEEE80211_OFDM18, "OFDM/18Mbps" }, \ + { IFM_IEEE80211_OFDM24, "OFDM/24Mbps" }, \ + { IFM_IEEE80211_OFDM36, "OFDM/36Mbps" }, \ + { IFM_IEEE80211_OFDM48, "OFDM/48Mbps" }, \ + { IFM_IEEE80211_OFDM54, "OFDM/54Mbps" }, \ + { IFM_IEEE80211_OFDM72, "OFDM/72Mbps" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_ALIASES { \ + { IFM_IEEE80211_FH1, "FH1" }, \ + { IFM_IEEE80211_FH2, "FH2" }, \ + { IFM_IEEE80211_FH1, "FrequencyHopping/1Mbps" }, \ + { IFM_IEEE80211_FH2, "FrequencyHopping/2Mbps" }, \ + { IFM_IEEE80211_DS1, "DS1" }, \ + { IFM_IEEE80211_DS2, "DS2" }, \ + { IFM_IEEE80211_DS5, "DS5.5" }, \ + { IFM_IEEE80211_DS11, "DS11" }, \ + { IFM_IEEE80211_DS22, "DS22" }, \ + { IFM_IEEE80211_DS1, "DirectSequence/1Mbps" }, \ + { IFM_IEEE80211_DS2, "DirectSequence/2Mbps" }, \ + { IFM_IEEE80211_DS5, "DirectSequence/5.5Mbps" }, \ + { IFM_IEEE80211_DS11, "DirectSequence/11Mbps" }, \ + { IFM_IEEE80211_DS22, "DirectSequence/22Mbps" }, \ + { IFM_IEEE80211_OFDM6, "OFDM6" }, \ + { IFM_IEEE80211_OFDM9, "OFDM9" }, \ + { IFM_IEEE80211_OFDM12, "OFDM12" }, \ + { IFM_IEEE80211_OFDM18, "OFDM18" }, \ + { IFM_IEEE80211_OFDM24, "OFDM24" }, \ + { IFM_IEEE80211_OFDM36, "OFDM36" }, \ + { IFM_IEEE80211_OFDM48, "OFDM48" }, \ + { IFM_IEEE80211_OFDM54, "OFDM54" }, \ + { IFM_IEEE80211_OFDM72, "OFDM72" }, \ + { IFM_IEEE80211_DS1, "CCK1" }, \ + { IFM_IEEE80211_DS2, "CCK2" }, \ + { IFM_IEEE80211_DS5, "CCK5.5" }, \ + { IFM_IEEE80211_DS11, "CCK11" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS { \ + { IFM_IEEE80211_ADHOC, "adhoc" }, \ + { IFM_IEEE80211_HOSTAP, "hostap" }, \ + { IFM_IEEE80211_IBSS, "ibss" }, \ + { IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \ + { IFM_IEEE80211_TURBO, "turbo" }, \ + { IFM_IEEE80211_MONITOR, "monitor" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS { \ + { IFM_AUTO, "autoselect" }, \ + { IFM_IEEE80211_11A, "11a" }, \ + { IFM_IEEE80211_11B, "11b" }, \ + { IFM_IEEE80211_11G, "11g" }, \ + { IFM_IEEE80211_FH, "fh" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_MODE_ALIASES { \ + { IFM_AUTO, "auto" }, \ + { 0, NULL }, \ +} + +# define IFM_SUBTYPE_ATM_DESCRIPTIONS { \ + { IFM_ATM_UNKNOWN, "Unknown" }, \ + { IFM_ATM_UTP_25, "UTP/25.6MBit" }, \ + { IFM_ATM_TAXI_100, "Taxi/100MBit" }, \ + { IFM_ATM_TAXI_140, "Taxi/140MBit" }, \ + { IFM_ATM_MM_155, "Multi-mode/155MBit" }, \ + { IFM_ATM_SM_155, "Single-mode/155MBit" }, \ + { IFM_ATM_UTP_155, "UTP/155MBit" }, \ + { IFM_ATM_MM_622, "Multi-mode/622MBit" }, \ + { IFM_ATM_SM_622, "Single-mode/622MBit" }, \ + { IFM_ATM_VIRTUAL, "Virtual" }, \ + { 0, NULL }, \ +} + +# define IFM_SUBTYPE_ATM_ALIASES { \ + { IFM_ATM_UNKNOWN, "UNKNOWN" }, \ + { IFM_ATM_UTP_25, "UTP-25" }, \ + { IFM_ATM_TAXI_100, "TAXI-100" }, \ + { IFM_ATM_TAXI_140, "TAXI-140" }, \ + { IFM_ATM_MM_155, "MM-155" }, \ + { IFM_ATM_SM_155, "SM-155" }, \ + { IFM_ATM_UTP_155, "UTP-155" }, \ + { IFM_ATM_MM_622, "MM-622" }, \ + { IFM_ATM_SM_622, "SM-622" }, \ + { IFM_ATM_VIRTUAL, "VIRTUAL" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS { \ + { IFM_ATM_SDH, "SDH" }, \ + { IFM_ATM_NOSCRAMB, "Noscramb" }, \ + { IFM_ATM_UNASSIGNED, "Unassigned" }, \ + { 0, NULL }, \ +} + + +#define IFM_SUBTYPE_SHARED_DESCRIPTIONS { \ + { IFM_AUTO, "autoselect" }, \ + { IFM_MANUAL, "manual" }, \ + { IFM_NONE, "none" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_SHARED_ALIASES { \ + { IFM_AUTO, "auto" }, \ + { 0, NULL }, \ +} + +#define IFM_SHARED_OPTION_DESCRIPTIONS { \ + { IFM_FDX, "full-duplex" }, \ + { IFM_HDX, "half-duplex" }, \ + { IFM_FLAG0, "flag0" }, \ + { IFM_FLAG1, "flag1" }, \ + { IFM_FLAG2, "flag2" }, \ + { IFM_LOOP, "hw-loopback" }, \ + { 0, NULL }, \ +} + +#endif /* _NET_IF_MEDIA_H_ */ diff --git a/net/if_ppp.c b/net/if_ppp.c new file mode 100644 index 0000000..adc0901 --- /dev/null +++ b/net/if_ppp.c @@ -0,0 +1,1768 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. + */ + +/*- + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Drew D. Perkins + * Carnegie Mellon University + * 4910 Forbes Ave. + * Pittsburgh, PA 15213 + * (412) 268-8576 + * ddp@andrew.cmu.edu + * + * Based on: + * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 + * + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Serial Line interface + * + * Rick Adams + * Center for Seismic Studies + * 1300 N 17th Street, Suite 1450 + * Arlington, Virginia 22209 + * (703)276-7900 + * rick@seismo.ARPA + * seismo!rick + * + * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). + * Converted to 4.3BSD Beta by Chris Torek. + * Other changes made at Berkeley, based in part on code by Kirk Smith. + * + * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) + * Added VJ tcp header compression; more unified ioctls + * + * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). + * Cleaned up a lot of the mbuf-related code to fix bugs that + * caused system crashes and packet corruption. Changed pppstart + * so that it doesn't just give up with a collision if the whole + * packet doesn't fit in the output ring buffer. + * + * Added priority queueing for interactive IP packets, following + * the model of if_sl.c, plus hooks for bpf. + * Paul Mackerras (paulus@cs.anu.edu.au). + */ + +/* $FreeBSD: src/sys/net/if_ppp.c,v 1.109 2005/10/12 19:52:16 thompsa Exp $ */ +/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ +/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opt_inet.h" +#include "opt_ipx.h" +#include "opt_mac.h" +#include "opt_ppp.h" + +#if NPPP > 0 + +#include <termios.h> +#include <rtems/termiostypes.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/rtemspppd.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/filio.h> +#include <sys/sockio.h> +#include <sys/kernel.h> +#include <sys/time.h> +#include <sys/malloc.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#ifdef PPP_FILTER +#include <net/bpf.h> +#endif + +#if INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#ifdef VJC +#include <net/slcompress.h> +#endif + +#include <net/ppp_defs.h> +#include <net/if_ppp.h> +#include <net/if_pppvar.h> +#include <machine/cpu.h> + +#define splsoftnet splnet + +#ifdef PPP_COMPRESS +#define PACKETPTR struct mbuf * +#include <net/ppp-comp.h> +#endif + +static struct ppp_softc ppp_softc[NPPP]; + +static int pppsioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data); +static void ppp_requeue(struct ppp_softc *); +#ifdef PPP_COMPRESS +static void ppp_ccp(struct ppp_softc *, struct mbuf *m, int rcvd); +static void ppp_ccp_closed(struct ppp_softc *); +#endif +static struct mbuf *ppp_inproc(struct ppp_softc *, struct mbuf *); +static void pppdumpm(struct mbuf *m0); + +/* + * Some useful mbuf macros not in mbuf.h. + */ +#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) + +#define M_DATASTART(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ + (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) + +#define M_DATASIZE(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ + (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) + +/* + * We steal two bits in the mbuf m_flags, to mark high-priority packets + * for output, and received packets following lost/corrupted packets. + */ +#define M_HIGHPRI 0x2000 /* output packet for sc_fastq */ +#define M_ERRMARK 0x4000 /* steal a bit in mbuf m_flags */ + + +#ifdef PPP_COMPRESS +/* + * List of compressors we know about. + * We leave some space so maybe we can modload compressors. + */ + +extern struct compressor ppp_bsd_compress; +extern struct compressor ppp_deflate, ppp_deflate_draft; + +struct compressor *ppp_compressors[8] = { +#if DO_BSD_COMPRESS + &ppp_bsd_compress, +#endif +#if DO_DEFLATE + &ppp_deflate, + &ppp_deflate_draft, +#endif + NULL +}; +#endif /* PPP_COMPRESS */ + +extern struct ifqueue ipintrq; +static struct timeval ppp_time; + +#ifndef __rtems__ +TEXT_SET(pseudo_set, ppp_rxdaemon); +#endif + +static int +ppp_unit(struct ppp_softc *sc) +{ + return sc->sc_if.if_unit; +} + +static rtems_task ppp_rxdaemon(rtems_task_argument arg) +{ + rtems_event_set events; + rtems_interrupt_level level; + struct ppp_softc *sc = (struct ppp_softc *)arg; + struct mbuf *mp = (struct mbuf *)0; + struct mbuf *m; + + /* enter processing loop */ + while ( 1 ) { + /* wait for event */ + rtems_event_receive(RX_PACKET|RX_MBUF|RX_EMPTY,RTEMS_WAIT|RTEMS_EVENT_ANY,RTEMS_NO_TIMEOUT,&events); + if ( events & RX_EMPTY ) { + printf("RX: QUEUE is EMPTY\n"); + events &= ~RX_EMPTY; + } + + if ( events ) { + /* get the network semaphore */ + rtems_bsdnet_semaphore_obtain(); + + /* check to see if new packet was received */ + if ( events & RX_PACKET ) { + /* get received packet mbuf chain */ + rtems_interrupt_disable(level); + IF_DEQUEUE(&sc->sc_rawq, m); + rtems_interrupt_enable(level); + + /* ensure packet was retrieved */ + if ( m != (struct mbuf *)0 ) { + /* process the received packet */ + mp = ppp_inproc(sc, m); + } + } + + /* allocate a new mbuf to replace one */ + if ( mp == NULL ) { + pppallocmbuf(sc, &mp); + } + + /* place mbuf on freeq */ + rtems_interrupt_disable(level); + IF_ENQUEUE(&sc->sc_freeq, mp); + rtems_interrupt_enable(level); + mp = (struct mbuf *)0; + + /* release the network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* check to see if queue is empty */ + if ( sc->sc_rawq.ifq_head ) { + /* queue is not empty - post another event */ + rtems_event_send(sc->sc_rxtask, RX_PACKET); + } + } + } +} + +static rtems_task ppp_txdaemon(rtems_task_argument arg) +{ + rtems_event_set events; + int iprocess = (int )0; + struct ppp_softc *sc = (struct ppp_softc *)arg; +#ifdef LALL_X + struct mbuf *mp; +#endif + struct mbuf *mf; + struct mbuf *m; + struct rtems_termios_tty *tp; + + int frag; + + /* enter processing loop */ + while ( 1 ) { + /* wait for event */ + rtems_event_receive(TX_PACKET|TX_TRANSMIT,RTEMS_WAIT|RTEMS_EVENT_ANY,RTEMS_NO_TIMEOUT,&events); + if ( events & TX_TRANSMIT ) { + /* received event from interrupt handler - free current mbuf */ + rtems_bsdnet_semaphore_obtain(); + + m_freem(sc->sc_outm); + + rtems_bsdnet_semaphore_release(); + + /* chain is done - clear the values */ + sc->sc_outm = (struct mbuf *)0; + sc->sc_outmc = (struct mbuf *)0; + + /* now set flag to fake receive of TX_PACKET event */ + /* this will check to see if we have any pending packets */ + events |= TX_PACKET; + } + + /* received event from pppasyncstart */ + if ( events & TX_PACKET ) { + /* ensure we are not busy */ + if ( sc->sc_outm == (struct mbuf *)0 ) { + /* try dequeuing a packet */ + sc->sc_outm = ppp_dequeue(sc); + if ( sc->sc_outm == NULL ) { + /* clear output flags */ + sc->sc_outflag = 0; + sc->sc_if.if_flags &= ~IFF_OACTIVE; + } + else { + /* set flag to start process */ + iprocess = 1; + sc->sc_outflag = SC_TX_BUSY; + sc->sc_if.if_flags |= IFF_OACTIVE; + } + } + } + + /* check to see if there is any processing required */ + if ( iprocess ) { + /* clear process flag */ + iprocess = (int)0; + frag=0; + + /* initialize output values */ + sc->sc_outfcs = PPP_INITFCS; + sc->sc_outbuf = (u_char *)0; + sc->sc_outlen = (short )0; + sc->sc_outoff = (short )0; + sc->sc_outfcslen = (short )0; + +/* printf("Start Transmit Packet..\n"); */ + + /* loop over all mbufs in chain */ + mf = NULL; +#ifdef LALL_X + mp = NULL; +#endif + m = sc->sc_outm; + + sc->sc_outmc = m; + sc->sc_outlen = m->m_len; + sc->sc_outbuf = mtod(m, u_char *); + + while (( m != (struct mbuf *)0 ) && ( m->m_len > 0 )) { + frag++; + + /* update the FCS value and then check next packet length */ + if(m->m_len){ + sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); + } + + if(( m->m_next != NULL ) && ( m->m_next->m_len == 0 )) { + if(mf){ + printf(" if_ppp.c : MBUF Error !!!!\n"); + } + else{ + mf = m->m_next; + m->m_next = NULL; + } + } + +#ifdef LALL_X + /* check next packet to see if it is empty */ + while (( m->m_next != NULL ) && ( m->m_next->m_len == 0 )) { + /* next mbuf is zero length */ + /* add empty mbuf to free chain */ + if ( mp == NULL ) { + /* item is head of free list */ + mf = m->m_next; + mp = mf; + } + else { + /* add item to end of the free list */ + mp->m_next = m->m_next; + mp = m->m_next; + } + + /* remove empty item from process chain */ + m->m_next = m->m_next->m_next; + mp->m_next = NULL; + } +#endif + /* move to next packet */ + m = m->m_next; + } + + /* ensure there is data to be sent out */ + tp = (struct rtems_termios_tty *)sc->sc_devp; + if (( tp != NULL ) && ( sc->sc_outmc != (struct mbuf *)0 )) { + /* place FCS value into buffer */ + sc->sc_outfcsbuf[sc->sc_outfcslen++] = ~sc->sc_outfcs & 0xff; + sc->sc_outfcsbuf[sc->sc_outfcslen++] = (~sc->sc_outfcs >> 8) & 0xff; + microtime(&sc->sc_if.if_lastchange); + + /* write out frame byte to start the transmission */ + sc->sc_outchar = (u_char)PPP_FLAG; + (*tp->handler.write)(tp->device_context, (char *)&sc->sc_outchar, 1); + } + + /* check to see if we need to free some empty mbufs */ + if ( mf != (struct mbuf *)0 ) { + /* free empty mbufs */ + rtems_bsdnet_semaphore_obtain(); + m_freem(mf); + rtems_bsdnet_semaphore_release(); + } + } + } +} + +static void ppp_init(struct ppp_softc *sc) +{ + rtems_status_code status; + uint32_t priority = 100; + + /* determine priority value */ + if ( rtems_bsdnet_config.network_task_priority ) { + priority = rtems_bsdnet_config.network_task_priority; + } + + /* check to see if we need to start up daemons */ + if ( sc->sc_rxtask == 0 ) { + /* start rx daemon task */ + status = rtems_task_create(rtems_build_name('R','x','P','0'+ppp_unit(sc)), priority, 2048, + RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), + RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL, + &sc->sc_rxtask); + if (status != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(status); + } + else { + status = rtems_task_start(sc->sc_rxtask, ppp_rxdaemon, (rtems_task_argument)sc); + if (status != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(status); + } + } + + /* start tx daemon task */ + status = rtems_task_create(rtems_build_name('T','x','P','0'+ppp_unit(sc)), priority, 2048, + RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), + RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL, + &sc->sc_txtask); + if (status != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(status); + } + else { + status = rtems_task_start(sc->sc_txtask, ppp_txdaemon, (rtems_task_argument)sc); + if (status != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(status); + } + } + } + + /* mark driver running and output inactive */ + /* ilya: IFF_RUNNING flag will be marked after the IPCP goes up */ +/* sc->sc_if.if_flags |= IFF_RUNNING; */ +} + +/* + * Called from boot code to establish ppp interfaces. + */ +int rtems_ppp_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching) +{ +/* int i = (int)0; */ + struct ppp_softc *sc; + char *name; + int number; + + + number = rtems_bsdnet_parse_driver_name (config, &name); + + if (!attaching || (number >= NPPP)) + return 0; + + sc = &ppp_softc[number]; + + if (sc->sc_if.if_name != NULL) + return 0; /* interface is already attached */ + +/* for (sc = ppp_softc; i < NPPP; sc++) { */ + sc->sc_if.if_name = name /*"ppp"*/; + sc->sc_if.if_unit = number /*i++*/; + sc->sc_if.if_mtu = PPP_MTU; + sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + sc->sc_if.if_type = IFT_PPP; + sc->sc_if.if_hdrlen = PPP_HDRLEN; + sc->sc_if.if_ioctl = pppsioctl; + sc->sc_if.if_output = pppoutput; + sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; + sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; + sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; + sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN; + sc->sc_freeq.ifq_maxlen = NUM_MBUFQ; + + /* initialize and attach */ + ppp_init(sc); + if_attach(&sc->sc_if); +#if NBPFILTER > 0 + bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN); +#endif +/* } */ + + return ( 1 ); +} + +/* + * Allocate a ppp interface unit and initialize it. + */ +struct ppp_softc * +pppalloc(pid_t pid) +{ + int nppp, i; + struct ppp_softc *sc; + + for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) + if (sc->sc_xfer == pid) { + sc->sc_xfer = 0; + return sc; + } + for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) + if (sc->sc_devp == NULL) + break; + if (nppp >= NPPP) + return NULL; + + sc->sc_flags = 0; + sc->sc_mru = PPP_MRU; + sc->sc_relinq = NULL; + bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats)); +#ifdef VJC + MALLOC(sc->sc_comp, struct vjcompress *, sizeof(struct vjcompress), + M_DEVBUF, M_NOWAIT); + if (sc->sc_comp) + sl_compress_init(sc->sc_comp, -1); +#endif +#ifdef PPP_COMPRESS + sc->sc_xc_state = NULL; + sc->sc_rc_state = NULL; +#endif /* PPP_COMPRESS */ + for (i = 0; i < NUM_NP; ++i) + sc->sc_npmode[i] = NPMODE_ERROR; + sc->sc_npqueue = NULL; + sc->sc_npqtail = &sc->sc_npqueue; + microtime(&ppp_time); + sc->sc_last_sent = sc->sc_last_recv = ppp_time.tv_sec; + + return sc; +} + +/* + * Deallocate a ppp unit. Must be called at splsoftnet or higher. + */ +void +pppdealloc(struct ppp_softc *sc) +{ + struct mbuf *m; + rtems_interrupt_level level; + + if_down(&sc->sc_if); + sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); + sc->sc_devp = NULL; + sc->sc_xfer = 0; + + rtems_interrupt_disable(level); + if ( sc->sc_m != NULL ) { + m_freem(sc->sc_m); + sc->sc_m = (struct mbuf *)0; + } + if ( sc->sc_outm != NULL ) { + m_freem(sc->sc_outm); + sc->sc_outm = (struct mbuf *)0; + sc->sc_outmc = (struct mbuf *)0; + sc->sc_outflag = 0; + } + do { + IF_DEQUEUE(&sc->sc_freeq, m); + if (m != NULL) { + m_freem(m); + } + } while ( m != NULL ); + do { + IF_DEQUEUE(&sc->sc_rawq, m); + if (m != NULL) { + m_freem(m); + } + } while ( m != NULL ); + rtems_interrupt_enable(level); + + for (;;) { + IF_DEQUEUE(&sc->sc_inq, m); + if (m == NULL) + break; + m_freem(m); + } + for (;;) { + IF_DEQUEUE(&sc->sc_fastq, m); + if (m == NULL) + break; + m_freem(m); + } + while ((m = sc->sc_npqueue) != NULL) { + sc->sc_npqueue = m->m_nextpkt; + m_freem(m); + } +#ifdef PPP_COMPRESS + ppp_ccp_closed(sc); + sc->sc_xc_state = NULL; + sc->sc_rc_state = NULL; +#endif /* PPP_COMPRESS */ +#ifdef PPP_FILTER + if (sc->sc_pass_filt.bf_insns != 0) { + FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF); + sc->sc_pass_filt.bf_insns = 0; + sc->sc_pass_filt.bf_len = 0; + } + if (sc->sc_active_filt.bf_insns != 0) { + FREE(sc->sc_active_filt.bf_insns, M_DEVBUF); + sc->sc_active_filt.bf_insns = 0; + sc->sc_active_filt.bf_len = 0; + } +#endif /* PPP_FILTER */ +#ifdef VJC + if (sc->sc_comp != 0) { + FREE(sc->sc_comp, M_DEVBUF); + sc->sc_comp = 0; + } +#endif +} + +/* + * Ioctl routine for generic ppp devices. + */ +int +pppioctl(struct ppp_softc *sc, ioctl_command_t cmd, caddr_t data, + int flag, struct proc *p) +{ + int s, flags, mru, npx, taskid; + struct npioctl *npi; + time_t t; +#ifdef PPP_FILTER + int error; + struct bpf_program *bp, *nbp; + struct bpf_insn *newcode, *oldcode; + int newcodelen; +#endif /* PPP_FILTER */ +#ifdef PPP_COMPRESS + int nb; + struct ppp_option_data *odp; + struct compressor **cp; + u_char ccp_option[CCP_MAX_OPTION_LENGTH]; +#endif + + switch (cmd) { + case FIONREAD: + *(int *)data = sc->sc_inq.ifq_len; + break; + + case PPPIOCSTASK: + taskid = *(int *)data; + sc->sc_pppdtask = taskid; + break; + + case PPPIOCGUNIT: + *(int *)data = ppp_unit(sc); + break; + + case PPPIOCGFLAGS: + *(u_int *)data = sc->sc_flags; + break; + + case PPPIOCSFLAGS: + flags = *(int *)data & SC_MASK; + s = splsoftnet(); +#ifdef PPP_COMPRESS + if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN)) + ppp_ccp_closed(sc); +#endif + s = splimp(); + sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; + splx(s); + break; + + case PPPIOCSMRU: + mru = *(int *)data; + if ( mru >= MCLBYTES ) { + /* error - currently only handle 1 culster sized MRU */ + /* if we want to handle up to PPP_MAXMRU then we */ + /* need to reallocate all mbufs on the freeq */ + /* this can only be done with iterrupts disabled */ + return ( -1 ); + } + else if ( mru >= PPP_MRU ) { + /* update the size */ + sc->sc_mru = mru; + } + break; + + case PPPIOCGMRU: + *(int *)data = sc->sc_mru; + break; + +#ifdef VJC + case PPPIOCSMAXCID: + if (sc->sc_comp) { + s = splsoftnet(); + sl_compress_init(sc->sc_comp, *(int *)data); + splx(s); + } + break; +#endif + + case PPPIOCXFERUNIT: + sc->sc_xfer = 0; /* Always root p->p_pid;*/ + break; + +#ifdef PPP_COMPRESS + case PPPIOCSCOMPRESS: + odp = (struct ppp_option_data *) data; + nb = odp->length; + if (nb > sizeof(ccp_option)) + nb = sizeof(ccp_option); + if ((error = copyin(odp->ptr, ccp_option, nb)) != 0) + return (error); + if (ccp_option[1] < 2) /* preliminary check on the length byte */ + return (EINVAL); + for (cp = ppp_compressors; *cp != NULL; ++cp) + if ((*cp)->compress_proto == ccp_option[0]) { + /* + * Found a handler for the protocol - try to allocate + * a compressor or decompressor. + */ + error = 0; + if (odp->transmit) { + s = splsoftnet(); + if (sc->sc_xc_state != NULL) + (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); + sc->sc_xcomp = *cp; + sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); + if (sc->sc_xc_state == NULL) { + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: comp_alloc failed\n", + ppp_unit(sc)); + error = ENOBUFS; + } + splimp(); + sc->sc_flags &= ~SC_COMP_RUN; + splx(s); + } else { + s = splsoftnet(); + if (sc->sc_rc_state != NULL) + (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); + sc->sc_rcomp = *cp; + sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); + if (sc->sc_rc_state == NULL) { + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: decomp_alloc failed\n", + ppp_unit(sc)); + error = ENOBUFS; + } + splimp(); + sc->sc_flags &= ~SC_DECOMP_RUN; + splx(s); + } + return (error); + } + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: no compressor for [%x %x %x], %x\n", + ppp_unit(sc), ccp_option[0], ccp_option[1], + ccp_option[2], nb); + return (EINVAL); /* no handler found */ +#endif /* PPP_COMPRESS */ + + case PPPIOCGNPMODE: + case PPPIOCSNPMODE: + npi = (struct npioctl *) data; + switch (npi->protocol) { + case PPP_IP: + npx = NP_IP; + break; + default: + return EINVAL; + } + if (cmd == PPPIOCGNPMODE) { + npi->mode = sc->sc_npmode[npx]; + } else { + if (npi->mode != sc->sc_npmode[npx]) { + s = splsoftnet(); + sc->sc_npmode[npx] = npi->mode; + if (npi->mode != NPMODE_QUEUE) { + ppp_requeue(sc); + (*sc->sc_start)(sc); + } + splx(s); + } + } + break; + + case PPPIOCGIDLE: + s = splsoftnet(); + microtime(&ppp_time); + t = ppp_time.tv_sec; + ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent; + ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv; + splx(s); + break; + +#ifdef PPP_FILTER + case PPPIOCSPASS: + case PPPIOCSACTIVE: + nbp = (struct bpf_program *) data; + if ((unsigned) nbp->bf_len > BPF_MAXINSNS) + return EINVAL; + newcodelen = nbp->bf_len * sizeof(struct bpf_insn); + if (newcodelen != 0) { + MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK); + if (newcode == 0) { + return EINVAL; /* or sumpin */ + } + if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode, + newcodelen)) != 0) { + FREE(newcode, M_DEVBUF); + return error; + } + if (!bpf_validate(newcode, nbp->bf_len)) { + FREE(newcode, M_DEVBUF); + return EINVAL; + } + } else + newcode = 0; + bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt; + oldcode = bp->bf_insns; + s = splimp(); + bp->bf_len = nbp->bf_len; + bp->bf_insns = newcode; + splx(s); + if (oldcode != 0) + FREE(oldcode, M_DEVBUF); + break; +#endif + + default: + return (-1); + } + return (0); +} + +/* + * Process an ioctl request to the ppp network interface. + */ +static int +pppsioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data) +{ + /*struct proc *p = curproc;*/ /* XXX */ + register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; + register struct ifaddr *ifa = (struct ifaddr *)data; + register struct ifreq *ifr = (struct ifreq *)data; + struct ppp_stats *psp; +#ifdef PPP_COMPRESS + struct ppp_comp_stats *pcp; +#endif + int s = splimp(), error = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_RUNNING) == 0) + ifp->if_flags &= ~IFF_UP; + break; + + case SIOCSIFADDR: + if (ifa->ifa_addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + break; + + case SIOCSIFDSTADDR: + if (ifa->ifa_addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + break; + + case SIOCSIFMTU: + sc->sc_if.if_mtu = ifr->ifr_mtu; + break; + + case SIOCGIFMTU: + ifr->ifr_mtu = sc->sc_if.if_mtu; + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; + break; + } + switch(ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: + break; +#endif + default: + error = EAFNOSUPPORT; + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + printf(" MRU:%-8u", sc->sc_mru); + printf(" Bytes received:%-8u", sc->sc_stats.ppp_ibytes); + printf(" Packets received:%-8u", sc->sc_stats.ppp_ipackets); + printf(" Receive errors:%-8u\n", sc->sc_stats.ppp_ierrors); + printf(" Bytes sent:%-8u", sc->sc_stats.ppp_obytes); + printf(" Packets sent:%-8u", sc->sc_stats.ppp_opackets); + printf(" Transmit errors:%-8u\n", sc->sc_stats.ppp_oerrors); + break; + + case SIOCGPPPSTATS: + psp = &((struct ifpppstatsreq *) data)->stats; + bzero(psp, sizeof(*psp)); + psp->p = sc->sc_stats; +#if defined(VJC) && !defined(SL_NO_STATS) + if (sc->sc_comp) { + psp->vj.vjs_packets = sc->sc_comp->sls_packets; + psp->vj.vjs_compressed = sc->sc_comp->sls_compressed; + psp->vj.vjs_searches = sc->sc_comp->sls_searches; + psp->vj.vjs_misses = sc->sc_comp->sls_misses; + psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin; + psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin; + psp->vj.vjs_errorin = sc->sc_comp->sls_errorin; + psp->vj.vjs_tossed = sc->sc_comp->sls_tossed; + } +#endif /* VJC */ + break; + +#ifdef PPP_COMPRESS + case SIOCGPPPCSTATS: + pcp = &((struct ifpppcstatsreq *) data)->stats; + bzero(pcp, sizeof(*pcp)); + if (sc->sc_xc_state != NULL) + (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c); + if (sc->sc_rc_state != NULL) + (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d); + break; +#endif /* PPP_COMPRESS */ + + default: + error = EINVAL; + } + splx(s); + return (error); +} + +/* + * Queue a packet. Start transmission if not active. + * Packet is placed in Information field of PPP frame. + */ +int +pppoutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, + struct rtentry *rtp) +{ + register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; + int protocol, address, control; + u_char *cp; + int s, error; + struct ip *ip; + struct ifqueue *ifq; + enum NPmode mode; + int len; + struct mbuf *m; + + if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 + || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) { + error = ENETDOWN; /* sort of */ + goto bad; + } + + /* + * Compute PPP header. + */ + m0->m_flags &= ~M_HIGHPRI; + switch (dst->sa_family) { +#ifdef INET + case AF_INET: + address = PPP_ALLSTATIONS; + control = PPP_UI; + protocol = PPP_IP; + mode = sc->sc_npmode[NP_IP]; + + /* + * If this packet has the "low delay" bit set in the IP header, + * put it on the fastq instead. + */ + ip = mtod(m0, struct ip *); + if (ip->ip_tos & IPTOS_LOWDELAY) + m0->m_flags |= M_HIGHPRI; + break; +#endif + case AF_UNSPEC: + address = PPP_ADDRESS(dst->sa_data); + control = PPP_CONTROL(dst->sa_data); + protocol = PPP_PROTOCOL(dst->sa_data); + mode = NPMODE_PASS; + break; + default: + printf("ppp%d: af%d not supported\n", ppp_unit(sc), dst->sa_family); + error = EAFNOSUPPORT; + goto bad; + } + + /* + * Drop this packet, or return an error, if necessary. + */ + if (mode == NPMODE_ERROR) { + error = ENETDOWN; + goto bad; + } + if (mode == NPMODE_DROP) { + error = 0; + goto bad; + } + + /* + * Add PPP header. If no space in first mbuf, allocate another. + * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) + */ + if (M_LEADINGSPACE(m0) < PPP_HDRLEN) { + m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT); + if (m0 == 0) { + error = ENOBUFS; + goto bad; + } + m0->m_len = 0; + } else + m0->m_data -= PPP_HDRLEN; + + cp = mtod(m0, u_char *); + *cp++ = address; + *cp++ = control; + *cp++ = protocol >> 8; + *cp++ = protocol & 0xff; + m0->m_len += PPP_HDRLEN; + + len = 0; + for (m = m0; m != 0; m = m->m_next) + len += m->m_len; + + if (sc->sc_flags & SC_LOG_OUTPKT) { + printf("ppp%d output: ", ppp_unit(sc)); + pppdumpm(m0); + } + + if ((protocol & 0x8000) == 0) { +#ifdef PPP_FILTER + /* + * Apply the pass and active filters to the packet, + * but only if it is a data packet. + */ + *mtod(m0, u_char *) = 1; /* indicates outbound */ + if (sc->sc_pass_filt.bf_insns != 0 + && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0, + len, 0) == 0) { + error = 0; /* drop this packet */ + goto bad; + } + + /* + * Update the time we sent the most recent packet. + */ + if (sc->sc_active_filt.bf_insns == 0 + || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0)) + sc->sc_last_sent = time.tv_sec; + + *mtod(m0, u_char *) = address; +#else + /* + * Update the time we sent the most recent data packet. + */ + microtime(&ppp_time); + sc->sc_last_sent = ppp_time.tv_sec; +#endif /* PPP_FILTER */ + } + +#if NBPFILTER > 0 + /* + * See if bpf wants to look at the packet. + */ + if (sc->sc_bpf) + bpf_mtap(sc->sc_bpf, m0); +#endif + + /* + * Put the packet on the appropriate queue. + */ + s = splsoftnet(); + if (mode == NPMODE_QUEUE) { + /* XXX we should limit the number of packets on this queue */ + *sc->sc_npqtail = m0; + m0->m_nextpkt = NULL; + sc->sc_npqtail = &m0->m_nextpkt; + } else { + ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd; + if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { + IF_DROP(ifq); + splx(s); + sc->sc_if.if_oerrors++; + sc->sc_stats.ppp_oerrors++; + error = ENOBUFS; + goto bad; + } + IF_ENQUEUE(ifq, m0); + (*sc->sc_start)(sc); + } + ifp->if_lastchange = ppp_time; + ifp->if_opackets++; + ifp->if_obytes += len; + + splx(s); + return (0); + +bad: + m_freem(m0); + return (error); +} + +/* + * After a change in the NPmode for some NP, move packets from the + * npqueue to the send queue or the fast queue as appropriate. + * Should be called at spl[soft]net. + */ +static void +ppp_requeue(struct ppp_softc *sc) +{ + struct mbuf *m, **mpp; + struct ifqueue *ifq; + enum NPmode mode; + + for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) { + switch (PPP_PROTOCOL(mtod(m, u_char *))) { + case PPP_IP: + mode = sc->sc_npmode[NP_IP]; + break; + default: + mode = NPMODE_PASS; + } + + switch (mode) { + case NPMODE_PASS: + /* + * This packet can now go on one of the queues to be sent. + */ + *mpp = m->m_nextpkt; + m->m_nextpkt = NULL; + ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd; + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + sc->sc_if.if_oerrors++; + sc->sc_stats.ppp_oerrors++; + } else + IF_ENQUEUE(ifq, m); + break; + + case NPMODE_DROP: + case NPMODE_ERROR: + *mpp = m->m_nextpkt; + m_freem(m); + break; + + case NPMODE_QUEUE: + mpp = &m->m_nextpkt; + break; + } + } + sc->sc_npqtail = mpp; +} + +/* + * Get a packet to send. This procedure is intended to be called at + * splsoftnet, since it may involve time-consuming operations such as + * applying VJ compression, packet compression, address/control and/or + * protocol field compression to the packet. + */ +struct mbuf * +ppp_dequeue(struct ppp_softc *sc) +{ +#ifdef PPP_COMPRESS + struct mbuf *mp; +#endif + struct mbuf *m; + u_char *cp; + int address, control, protocol; + + /* + * Grab a packet to send: first try the fast queue, then the + * normal queue. + */ + rtems_bsdnet_semaphore_obtain(); + IF_DEQUEUE(&sc->sc_fastq, m); + if (m == NULL) + IF_DEQUEUE(&sc->sc_if.if_snd, m); + rtems_bsdnet_semaphore_release(); + + if (m == NULL) + return NULL; + + ++sc->sc_stats.ppp_opackets; + + /* + * Extract the ppp header of the new packet. + * The ppp header will be in one mbuf. + */ + cp = mtod(m, u_char *); + address = PPP_ADDRESS(cp); + control = PPP_CONTROL(cp); + protocol = PPP_PROTOCOL(cp); + + switch (protocol) { + case PPP_IP: +#ifdef VJC + /* + * If the packet is a TCP/IP packet, see if we can compress it. + */ + if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) { + struct ip *ip; + int type; + + mp = m; + ip = (struct ip *) (cp + PPP_HDRLEN); + if (mp->m_len <= PPP_HDRLEN) { + mp = mp->m_next; + if (mp == NULL) + break; + ip = mtod(mp, struct ip *); + } + /* this code assumes the IP/TCP header is in one non-shared mbuf */ + if (ip->ip_p == IPPROTO_TCP) { + type = sl_compress_tcp(mp, ip, sc->sc_comp, + !(sc->sc_flags & SC_NO_TCP_CCID)); + switch (type) { + case TYPE_UNCOMPRESSED_TCP: + protocol = PPP_VJC_UNCOMP; + break; + case TYPE_COMPRESSED_TCP: + protocol = PPP_VJC_COMP; + cp = mtod(m, u_char *); + cp[0] = address; /* header has moved */ + cp[1] = control; + cp[2] = 0; + break; + } + cp[3] = protocol; /* update protocol in PPP header */ + } + } +#endif /* VJC */ + break; + +#ifdef PPP_COMPRESS + case PPP_CCP: + ppp_ccp(sc, m, 0); + break; +#endif /* PPP_COMPRESS */ + } + +#ifdef PPP_COMPRESS + if (protocol != PPP_LCP && protocol != PPP_CCP + && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) { + struct mbuf *mcomp = NULL; + int slen, clen; + + slen = 0; + for (mp = m; mp != NULL; mp = mp->m_next) + slen += mp->m_len; + clen = (*sc->sc_xcomp->compress) + (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN); + if (mcomp != NULL) { + if (sc->sc_flags & SC_CCP_UP) { + /* Send the compressed packet instead of the original. */ + m_freem(m); + m = mcomp; + cp = mtod(m, u_char *); + protocol = cp[3]; + } else { + /* Can't transmit compressed packets until CCP is up. */ + m_freem(mcomp); + } + } + } +#endif /* PPP_COMPRESS */ + + /* + * Compress the address/control and protocol, if possible. + */ + if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && + control == PPP_UI && protocol != PPP_ALLSTATIONS && + protocol != PPP_LCP) { + /* can compress address/control */ + m->m_data += 2; + m->m_len -= 2; + } + if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) { + /* can compress protocol */ + if (mtod(m, u_char *) == cp) { + cp[2] = cp[1]; /* move address/control up */ + cp[1] = cp[0]; + } + ++m->m_data; + --m->m_len; + } + + return m; +} + +#ifdef PPP_COMPRESS +/* + * Handle a CCP packet. `rcvd' is 1 if the packet was received, + * 0 if it is about to be transmitted. + */ +static void +ppp_ccp(struct ppp_softc *sc, struct mbuf *m, int rcvd) +{ + u_char *dp, *ep; + struct mbuf *mp; + int slen, s; + + /* + * Get a pointer to the data after the PPP header. + */ + if (m->m_len <= PPP_HDRLEN) { + mp = m->m_next; + if (mp == NULL) + return; + dp = (mp != NULL)? mtod(mp, u_char *): NULL; + } else { + mp = m; + dp = mtod(mp, u_char *) + PPP_HDRLEN; + } + + ep = mtod(mp, u_char *) + mp->m_len; + if (dp + CCP_HDRLEN > ep) + return; + slen = CCP_LENGTH(dp); + if (dp + slen > ep) { + if (sc->sc_flags & SC_DEBUG) + printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n", + dp, slen, mtod(mp, u_char *), mp->m_len); + return; + } + + switch (CCP_CODE(dp)) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + /* CCP must be going down - disable compression */ + if (sc->sc_flags & SC_CCP_UP) { + s = splimp(); + sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); + splx(s); + } + break; + + case CCP_CONFACK: + if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP) + && slen >= CCP_HDRLEN + CCP_OPT_MINLEN + && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) { + if (!rcvd) { + /* we're agreeing to send compressed packets. */ + if (sc->sc_xc_state != NULL + && (*sc->sc_xcomp->comp_init) + (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, + ppp_unit(sc), 0, sc->sc_flags & SC_DEBUG)) { + s = splimp(); + sc->sc_flags |= SC_COMP_RUN; + splx(s); + } + } else { + /* peer is agreeing to send compressed packets. */ + if (sc->sc_rc_state != NULL + && (*sc->sc_rcomp->decomp_init) + (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, + ppp_unit(sc), 0, sc->sc_mru, + sc->sc_flags & SC_DEBUG)) { + s = splimp(); + sc->sc_flags |= SC_DECOMP_RUN; + sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR); + splx(s); + } + } + } + break; + + case CCP_RESETACK: + if (sc->sc_flags & SC_CCP_UP) { + if (!rcvd) { + if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) + (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state); + } else { + if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { + (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state); + s = splimp(); + sc->sc_flags &= ~SC_DC_ERROR; + splx(s); + } + } + } + break; + } +} + +/* + * CCP is down; free (de)compressor state if necessary. + */ +static void +ppp_ccp_closed(struct ppp_softc *sc) +{ + if (sc->sc_xc_state) { + (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); + sc->sc_xc_state = NULL; + } + if (sc->sc_rc_state) { + (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); + sc->sc_rc_state = NULL; + } +} +#endif /* PPP_COMPRESS */ + +/* + * Process a received PPP packet, doing decompression as necessary. + * Should be called at splsoftnet. + */ +#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ + TYPE_UNCOMPRESSED_TCP) + +static struct mbuf * +ppp_inproc(struct ppp_softc *sc, struct mbuf *m) +{ + struct mbuf *mf = (struct mbuf *)0; + struct ifnet *ifp = &sc->sc_if; + struct ifqueue *inq; + int s, ilen, proto, rv; + u_char *cp; +#ifdef VJC + u_char adrs, ctrl; +#endif + struct mbuf *mp; +#ifdef PPP_COMPRESS + struct mbuf *dmp = NULL; +#endif +#ifdef VJC + u_char *iphdr; + u_int hlen; + int xlen; +#endif + + sc->sc_stats.ppp_ipackets++; + + if (sc->sc_flags & SC_LOG_INPKT) { + ilen = 0; + for (mp = m; mp != NULL; mp = mp->m_next) + ilen += mp->m_len; + printf("ppp%d: got %d bytes\n", ppp_unit(sc), ilen); + pppdumpm(m); + } + + cp = mtod(m, u_char *); +#ifdef VJC + adrs = PPP_ADDRESS(cp); + ctrl = PPP_CONTROL(cp); +#endif + proto = PPP_PROTOCOL(cp); + + if (m->m_flags & M_ERRMARK) { + m->m_flags &= ~M_ERRMARK; + s = splimp(); + sc->sc_flags |= SC_VJ_RESET; + splx(s); + } + +#ifdef PPP_COMPRESS + /* + * Decompress this packet if necessary, update the receiver's + * dictionary, or take appropriate action on a CCP packet. + */ + if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN) + && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) { + /* decompress this packet */ + rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp); + if (rv == DECOMP_OK) { + m_freem(m); + if (dmp == NULL) { + /* no error, but no decompressed packet produced */ + return mf; + } + m = dmp; + cp = mtod(m, u_char *); + proto = PPP_PROTOCOL(cp); + + } else { + /* + * An error has occurred in decompression. + * Pass the compressed packet up to pppd, which may take + * CCP down or issue a Reset-Req. + */ + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: decompress failed %d\n", ppp_unit(sc), rv); + s = splimp(); + sc->sc_flags |= SC_VJ_RESET; + if (rv == DECOMP_ERROR) + sc->sc_flags |= SC_DC_ERROR; + else + sc->sc_flags |= SC_DC_FERROR; + splx(s); + } + + } else { + if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { + (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m); + } + if (proto == PPP_CCP) { + ppp_ccp(sc, m, 1); + } + } +#endif + + ilen = 0; + for (mp = m; mp != NULL; mp = mp->m_next) + ilen += mp->m_len; + +#ifdef VJC + if (sc->sc_flags & SC_VJ_RESET) { + /* + * If we've missed a packet, we must toss subsequent compressed + * packets which don't have an explicit connection ID. + */ + if (sc->sc_comp) + sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp); + s = splimp(); + sc->sc_flags &= ~SC_VJ_RESET; + splx(s); + } + + /* + * See if we have a VJ-compressed packet to uncompress. + */ + if (proto == PPP_VJC_COMP) { + if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) + goto bad; + + xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, + ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP, + sc->sc_comp, &iphdr, &hlen); + + if (xlen <= 0) { + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: VJ uncompress failed on type comp\n", + ppp_unit(sc)); + goto bad; + } + + /* Copy the PPP and IP headers into a new mbuf. */ + MGETHDR(mp, M_DONTWAIT, MT_DATA); + if (mp == NULL) + goto bad; + mp->m_len = 0; + mp->m_next = NULL; + if (hlen + PPP_HDRLEN > MHLEN) { + MCLGET(mp, M_DONTWAIT); + if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) { + m_freem(mp); + goto bad; /* lose if big headers and no clusters */ + } + } +#ifdef MAC + mac_create_mbuf_from_mbuf(m, mp); +#endif + cp = mtod(mp, u_char *); + cp[0] = adrs; + cp[1] = ctrl; + cp[2] = 0; + cp[3] = PPP_IP; + proto = PPP_IP; + bcopy(iphdr, cp + PPP_HDRLEN, hlen); + mp->m_len = hlen + PPP_HDRLEN; + + /* + * Trim the PPP and VJ headers off the old mbuf + * and stick the new and old mbufs together. + */ + m->m_data += PPP_HDRLEN + xlen; + m->m_len -= PPP_HDRLEN + xlen; + if (m->m_len <= M_TRAILINGSPACE(mp)) { + bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len); + mp->m_len += m->m_len; + MFREE(m, mp->m_next); + } else + mp->m_next = m; + m = mp; + ilen += hlen - xlen; + + } else if (proto == PPP_VJC_UNCOMP) { + if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) + goto bad; + + xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, + ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP, + sc->sc_comp, &iphdr, &hlen); + + if (xlen < 0) { + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: VJ uncompress failed on type uncomp\n", + ppp_unit(sc)); + goto bad; + } + + proto = PPP_IP; + cp[3] = PPP_IP; + } +#endif /* VJC */ + + /* + * If the packet will fit in a header mbuf, don't waste a + * whole cluster on it. + */ + if (ilen <= MHLEN && M_IS_CLUSTER(m)) { + MGETHDR(mp, M_DONTWAIT, MT_DATA); + if (mp != NULL) { + m_copydata(m, 0, ilen, mtod(mp, caddr_t)); + /* instead of freeing - return cluster mbuf so it can be reused */ + /* m_freem(m); */ + mf = m; + m = mp; + m->m_len = ilen; + } + } + m->m_pkthdr.len = ilen; + m->m_pkthdr.rcvif = ifp; + + if ((proto & 0x8000) == 0) { +#ifdef PPP_FILTER + /* + * See whether we want to pass this packet, and + * if it counts as link activity. + */ + adrs = *mtod(m, u_char *); /* save address field */ + *mtod(m, u_char *) = 0; /* indicate inbound */ + if (sc->sc_pass_filt.bf_insns != 0 + && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m, + ilen, 0) == 0) { + /* drop this packet */ + m_freem(m); + return mf; + } + if (sc->sc_active_filt.bf_insns == 0 + || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0)) + sc->sc_last_recv = time.tv_sec; + + *mtod(m, u_char *) = adrs; +#else + /* + * Record the time that we received this packet. + */ + microtime(&ppp_time); + sc->sc_last_recv = ppp_time.tv_sec; +#endif /* PPP_FILTER */ + } + +#if NBPFILTER > 0 + /* See if bpf wants to look at the packet. */ + if (sc->sc_bpf) + bpf_mtap(sc->sc_bpf, m); +#endif + + rv = 0; + switch (proto) { +#ifdef INET + case PPP_IP: + /* + * IP packet - take off the ppp header and pass it up to IP. + */ + if ((ifp->if_flags & IFF_UP) == 0 + || sc->sc_npmode[NP_IP] != NPMODE_PASS) { + /* interface is down - drop the packet. */ + m_freem(m); + return mf; + } + m->m_pkthdr.len -= PPP_HDRLEN; + m->m_data += PPP_HDRLEN; + m->m_len -= PPP_HDRLEN; + schednetisr(NETISR_IP); + inq = &ipintrq; + break; +#endif + + default: + /* + * Some other protocol - place on input queue for read(). + */ + inq = &sc->sc_inq; + rv = 1; + break; + } + + /* + * Put the packet on the appropriate input queue. + */ + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + splx(s); + if (sc->sc_flags & SC_DEBUG) + printf("ppp%d: input queue full\n", ppp_unit(sc)); + ifp->if_iqdrops++; + goto bad; + } + IF_ENQUEUE(inq, m); + splx(s); + + ifp->if_ipackets++; + ifp->if_ibytes += ilen; + microtime(&ppp_time); + ifp->if_lastchange = ppp_time; + + if (rv) { + (*sc->sc_ctlp)(sc); + } + + return mf; + + bad: + m_freem(m); + sc->sc_if.if_ierrors++; + sc->sc_stats.ppp_ierrors++; + return mf; +} + +#define MAX_DUMP_BYTES 128 + +static void +pppdumpm(struct mbuf *m0) +{ + char buf[3*MAX_DUMP_BYTES+4]; + char *bp = buf; + struct mbuf *m; + static char digits[] = "0123456789abcdef"; + + for (m = m0; m; m = m->m_next) { + int l = m->m_len; + u_char *rptr = (u_char *)m->m_data; + + while (l--) { + if (bp > buf + sizeof(buf) - 4) + goto done; + *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ + *bp++ = digits[*rptr++ & 0xf]; + } + + if (m->m_next) { + if (bp > buf + sizeof(buf) - 3) + goto done; + *bp++ = '|'; + } else + *bp++ = ' '; + } +done: + if (m) + *bp++ = '>'; + *bp = 0; + printf("%s\n", buf); +} + +#endif /* NPPP > 0 */ diff --git a/net/if_ppp.h b/net/if_ppp.h new file mode 100644 index 0000000..c8dcfc8 --- /dev/null +++ b/net/if_ppp.h @@ -0,0 +1,141 @@ +/* + * if_ppp.h - Point-to-Point Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $FreeBSD: src/sys/net/if_ppp.h,v 1.15 2005/01/07 01:45:34 imp Exp $ + */ + + +#ifndef _IF_PPP_H_ +#define _IF_PPP_H_ + +#include <net/ppp_defs.h> /* NPmode */ +#include <net/if.h> /* IFNAMSIZ */ + +/* + * Packet sizes + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#define PPP_MAXMRU 65000 /* Largest MRU we allow */ +#define PPP_MAXMTU 16384 /* Largest MTU we allow */ + +/* + * Bit definitions for flags. + */ +#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */ +#define SC_COMP_AC 0x00000002 /* header compression (output) */ +#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */ +#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */ +#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */ +#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */ +#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */ +#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */ +#define SC_DEBUG 0x00010000 /* enable debug messages */ +#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */ +#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */ +#define SC_LOG_RAWIN 0x00080000 /* log all chars received */ +#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */ +#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */ +#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */ +#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */ +#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */ +#define SC_SYNC 0x00200000 /* use synchronous HDLC framing */ +#define SC_MASK 0x0fff00ff /* bits that user can change */ + +/* + * State bits in sc_flags, not changeable by user. + */ +#define SC_TIMEOUT 0x00000400 /* timeout is currently pending */ +#define SC_VJ_RESET 0x00000800 /* need to reset VJ decomp */ +#define SC_COMP_RUN 0x00001000 /* compressor has been initiated */ +#define SC_DECOMP_RUN 0x00002000 /* decompressor has been initiated */ +#define SC_DC_ERROR 0x00004000 /* non-fatal decomp error detected */ +#define SC_DC_FERROR 0x00008000 /* fatal decomp error detected */ +#define SC_TBUSY 0x10000000 /* xmitter doesn't need a packet yet */ +#define SC_PKTLOST 0x20000000 /* have lost or dropped a packet */ +#define SC_FLUSH 0x40000000 /* flush input until next PPP_FLAG */ +#define SC_ESCAPED 0x80000000 /* saw a PPP_ESCAPE */ + +/* + * Ioctl definitions. + */ + +struct npioctl { + int protocol; /* PPP procotol, e.g. PPP_IP */ + enum NPmode mode; +}; + +/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */ +struct ppp_option_data { + u_char *ptr; + u_int length; + int transmit; +}; + +struct ifpppstatsreq { + char ifr_name[IFNAMSIZ]; + struct ppp_stats stats; +}; + +struct ifpppcstatsreq { + char ifr_name[IFNAMSIZ]; + struct ppp_comp_stats stats; +}; + +/* + * Ioctl definitions. + */ + +#define PPPIOCSTASK _IOW('t', 91, int) /* set pppd task id */ +#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */ +#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */ +#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */ +#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */ +#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */ +#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */ +#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */ +#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */ +#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */ +#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */ +#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */ +#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */ +#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */ +#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data) +#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */ +#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */ +#define PPPIOCGIDLE _IOR('t', 74, struct ppp_idle) /* get idle time */ +#ifdef PPP_FILTER +#define PPPIOCSPASS _IOW('t', 71, struct bpf_program) /* set pass filter */ +#define PPPIOCSACTIVE _IOW('t', 70, struct bpf_program) /* set active filt */ +#endif /* PPP_FILTER */ + +/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */ +#define PPPIOCGMTU _IOR('t', 73, int) /* get interface MTU */ +#define PPPIOCSMTU _IOW('t', 72, int) /* set interface MTU */ + +/* + * These two are interface ioctls so that pppstats can do them on + * a socket without having to open the serial device. + */ +#define SIOCGPPPSTATS _IOWR('i', 123, struct ifpppstatsreq) +#define SIOCGPPPCSTATS _IOWR('i', 122, struct ifpppcstatsreq) + +#if !defined(ifr_mtu) +#define ifr_mtu ifr_ifru.ifru_metric +#endif + +#endif /* _IF_PPP_H_ */ diff --git a/net/if_pppvar.h b/net/if_pppvar.h new file mode 100644 index 0000000..9d708a4 --- /dev/null +++ b/net/if_pppvar.h @@ -0,0 +1,161 @@ +/* + * if_pppvar.h - private structures and declarations for PPP. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $FreeBSD: src/sys/net/if_pppvar.h,v 1.26 2006/12/05 18:54:21 ume Exp $ + */ + + +#ifndef _NET_IF_PPPVAR_H_ +#define _NET_IF_PPPVAR_H_ + +#include <net/if_var.h> /* struct ifnet */ +#include <net/ppp_defs.h> /* struct pppstat */ +#include <rtems/rtems/types.h> /* rtems_id */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct proc; + +/* + * Supported network protocols. These values are used for + * indexing sc_npmode. + */ +#define NP_IP 0 /* Internet Protocol */ +#define NUM_NP 1 /* Number of NPs. */ +#define NUM_MBUFQ 64 + + +/* + * Structure describing each ppp unit. + */ +struct ppp_softc { + struct ifnet sc_if; /* network-visible interface */ + u_int sc_flags; /* control/status bits; see if_ppp.h */ + void *sc_devp; /* pointer to device-dep structure */ + void (*sc_start)(struct ppp_softc *); /* start output proc */ + void (*sc_ctlp)(struct ppp_softc *); /* rcvd control pkt */ + void (*sc_relinq)(struct ppp_softc *); /* relinquish ifunit */ + short sc_mru; /* max receive unit */ + pid_t sc_xfer; /* used in transferring unit */ + struct ifqueue sc_rawq; /* received packets */ + struct ifqueue sc_inq; /* queue of input packets for daemon */ + struct ifqueue sc_fastq; /* interactive output packet q */ + struct mbuf *sc_npqueue; /* output packets not to be sent yet */ + struct mbuf **sc_npqtail; /* ptr to last next ptr in npqueue */ + struct pppstat sc_stats; /* count of bytes/pkts sent/rcvd */ + caddr_t sc_bpf; /* hook for BPF */ + enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */ + struct compressor *sc_xcomp; /* transmit compressor */ + void *sc_xc_state; /* transmit compressor state */ + struct compressor *sc_rcomp; /* receive decompressor */ + void *sc_rc_state; /* receive decompressor state */ + time_t sc_last_sent; /* time (secs) last NP pkt sent */ + time_t sc_last_recv; /* time (secs) last NP pkt rcvd */ +#ifdef PPP_FILTER + struct bpf_program sc_pass_filt; /* filter for packets to pass */ + struct bpf_program sc_active_filt; /* filter for "non-idle" packets */ +#endif /* PPP_FILTER */ +#ifdef VJC + struct vjcompress *sc_comp; /* vjc control buffer */ +#endif + + /* Device-dependent part for async lines. */ + ext_accm sc_asyncmap; /* async control character map */ + u_long sc_rasyncmap; /* receive async control char map */ + struct mbuf *sc_outm; /* mbuf chain currently being output */ + struct mbuf *sc_outmc; /* mbuf currently being output */ + struct mbuf *sc_m; /* pointer to input mbuf chain */ + struct mbuf *sc_mc; /* pointer to current input mbuf */ + char *sc_mp; /* ptr to next char in input mbuf */ + short sc_ilen; /* length of input packet so far */ + u_short sc_fcs; /* FCS so far (input) */ + u_short sc_outfcs; /* FCS so far for output packet */ + u_char sc_rawin[16]; /* chars as received */ + int sc_rawin_count; /* # in sc_rawin */ + + struct ifqueue sc_freeq; /* free packets */ + short sc_outoff; /* output packet byte offset */ + short sc_outflag; /* output status flag */ + short sc_outlen; /* length of output packet */ + short sc_outfcslen; /* length of output fcs data */ + u_char sc_outfcsbuf[8]; /* output packet fcs buffer */ + u_char *sc_outbuf; /* pointer to output data */ + u_char sc_outchar; + + rtems_id sc_rxtask; + rtems_id sc_txtask; + rtems_id sc_pppdtask; +}; + +struct ppp_softc *pppalloc(pid_t pid); +void pppdealloc(struct ppp_softc *sc); +int pppoutput(struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *); +int pppioctl(struct ppp_softc *sc, ioctl_command_t cmd, caddr_t data, + int flag, struct proc *p); +struct mbuf *ppp_dequeue(struct ppp_softc *sc); +u_short pppfcs(u_short fcs, u_char *cp, int len); +void pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp); + + +/* define event values */ +#define RX_PACKET RTEMS_EVENT_1 +#define RX_MBUF RTEMS_EVENT_2 +#define RX_EMPTY RTEMS_EVENT_3 +#define TX_PACKET RTEMS_EVENT_1 +#define TX_TRANSMIT RTEMS_EVENT_2 +#define PPPD_EVENT RTEMS_EVENT_31 + +/* define out flag values */ +#define SC_TX_BUSY 0x0001 +#define SC_TX_FCS 0x0002 +#define SC_TX_ESCAPE 0x0004 +#define SC_TX_LASTCHAR 0x0008 +#define SC_TX_PENDING 0x0010 + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_IF_PPPVAR_H_ */ + diff --git a/net/if_types.h b/net/if_types.h new file mode 100644 index 0000000..aa924d3 --- /dev/null +++ b/net/if_types.h @@ -0,0 +1,252 @@ +/* + * 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. + * 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.3 (Berkeley) 4/28/95 + * $FreeBSD: src/sys/net/if_types.h,v 1.18 2005/02/22 13:04:03 glebius Exp $ + * $NetBSD: if_types.h,v 1.16 2000/04/19 06:30:53 itojun Exp $ + */ + + +#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, originally + * documented in RFC1573, now maintained as: + * + * ftp.isi.edu/in-notes/iana/assignments/smi-numbers + */ + +#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 CSMA/CD */ +#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 */ +#define IFT_IEEE80212 0x37 /* 100BaseVG */ +#define IFT_FIBRECHANNEL 0x38 /* Fibre Channel */ +#define IFT_HIPPIINTERFACE 0x39 /* HIPPI interfaces */ +#define IFT_FRAMERELAYINTERCONNECT 0x3a /* Obsolete, use either 0x20 or 0x2c */ +#define IFT_AFLANE8023 0x3b /* ATM Emulated LAN for 802.3 */ +#define IFT_AFLANE8025 0x3c /* ATM Emulated LAN for 802.5 */ +#define IFT_CCTEMUL 0x3d /* ATM Emulated circuit */ +#define IFT_FASTETHER 0x3e /* Fast Ethernet (100BaseT) */ +#define IFT_ISDN 0x3f /* ISDN and X.25 */ +#define IFT_V11 0x40 /* CCITT V.11/X.21 */ +#define IFT_V36 0x41 /* CCITT V.36 */ +#define IFT_G703AT64K 0x42 /* CCITT G703 at 64Kbps */ +#define IFT_G703AT2MB 0x43 /* Obsolete see DS1-MIB */ +#define IFT_QLLC 0x44 /* SNA QLLC */ +#define IFT_FASTETHERFX 0x45 /* Fast Ethernet (100BaseFX) */ +#define IFT_CHANNEL 0x46 /* channel */ +#define IFT_IEEE80211 0x47 /* radio spread spectrum */ +#define IFT_IBM370PARCHAN 0x48 /* IBM System 360/370 OEMI Channel */ +#define IFT_ESCON 0x49 /* IBM Enterprise Systems Connection */ +#define IFT_DLSW 0x4a /* Data Link Switching */ +#define IFT_ISDNS 0x4b /* ISDN S/T interface */ +#define IFT_ISDNU 0x4c /* ISDN U interface */ +#define IFT_LAPD 0x4d /* Link Access Protocol D */ +#define IFT_IPSWITCH 0x4e /* IP Switching Objects */ +#define IFT_RSRB 0x4f /* Remote Source Route Bridging */ +#define IFT_ATMLOGICAL 0x50 /* ATM Logical Port */ +#define IFT_DS0 0x51 /* Digital Signal Level 0 */ +#define IFT_DS0BUNDLE 0x52 /* group of ds0s on the same ds1 */ +#define IFT_BSC 0x53 /* Bisynchronous Protocol */ +#define IFT_ASYNC 0x54 /* Asynchronous Protocol */ +#define IFT_CNR 0x55 /* Combat Net Radio */ +#define IFT_ISO88025DTR 0x56 /* ISO 802.5r DTR */ +#define IFT_EPLRS 0x57 /* Ext Pos Loc Report Sys */ +#define IFT_ARAP 0x58 /* Appletalk Remote Access Protocol */ +#define IFT_PROPCNLS 0x59 /* Proprietary Connectionless Protocol*/ +#define IFT_HOSTPAD 0x5a /* CCITT-ITU X.29 PAD Protocol */ +#define IFT_TERMPAD 0x5b /* CCITT-ITU X.3 PAD Facility */ +#define IFT_FRAMERELAYMPI 0x5c /* Multiproto Interconnect over FR */ +#define IFT_X213 0x5d /* CCITT-ITU X213 */ +#define IFT_ADSL 0x5e /* Asymmetric Digital Subscriber Loop */ +#define IFT_RADSL 0x5f /* Rate-Adapt. Digital Subscriber Loop*/ +#define IFT_SDSL 0x60 /* Symmetric Digital Subscriber Loop */ +#define IFT_VDSL 0x61 /* Very H-Speed Digital Subscrib. Loop*/ +#define IFT_ISO88025CRFPINT 0x62 /* ISO 802.5 CRFP */ +#define IFT_MYRINET 0x63 /* Myricom Myrinet */ +#define IFT_VOICEEM 0x64 /* voice recEive and transMit */ +#define IFT_VOICEFXO 0x65 /* voice Foreign Exchange Office */ +#define IFT_VOICEFXS 0x66 /* voice Foreign Exchange Station */ +#define IFT_VOICEENCAP 0x67 /* voice encapsulation */ +#define IFT_VOICEOVERIP 0x68 /* voice over IP encapsulation */ +#define IFT_ATMDXI 0x69 /* ATM DXI */ +#define IFT_ATMFUNI 0x6a /* ATM FUNI */ +#define IFT_ATMIMA 0x6b /* ATM IMA */ +#define IFT_PPPMULTILINKBUNDLE 0x6c /* PPP Multilink Bundle */ +#define IFT_IPOVERCDLC 0x6d /* IBM ipOverCdlc */ +#define IFT_IPOVERCLAW 0x6e /* IBM Common Link Access to Workstn */ +#define IFT_STACKTOSTACK 0x6f /* IBM stackToStack */ +#define IFT_VIRTUALIPADDRESS 0x70 /* IBM VIPA */ +#define IFT_MPC 0x71 /* IBM multi-protocol channel support */ +#define IFT_IPOVERATM 0x72 /* IBM ipOverAtm */ +#define IFT_ISO88025FIBER 0x73 /* ISO 802.5j Fiber Token Ring */ +#define IFT_TDLC 0x74 /* IBM twinaxial data link control */ +#define IFT_GIGABITETHERNET 0x75 /* Gigabit Ethernet */ +#define IFT_HDLC 0x76 /* HDLC */ +#define IFT_LAPF 0x77 /* LAP F */ +#define IFT_V37 0x78 /* V.37 */ +#define IFT_X25MLP 0x79 /* Multi-Link Protocol */ +#define IFT_X25HUNTGROUP 0x7a /* X25 Hunt Group */ +#define IFT_TRANSPHDLC 0x7b /* Transp HDLC */ +#define IFT_INTERLEAVE 0x7c /* Interleave channel */ +#define IFT_FAST 0x7d /* Fast channel */ +#define IFT_IP 0x7e /* IP (for APPN HPR in IP networks) */ +#define IFT_DOCSCABLEMACLAYER 0x7f /* CATV Mac Layer */ +#define IFT_DOCSCABLEDOWNSTREAM 0x80 /* CATV Downstream interface */ +#define IFT_DOCSCABLEUPSTREAM 0x81 /* CATV Upstream interface */ +#define IFT_A12MPPSWITCH 0x82 /* Avalon Parallel Processor */ +#define IFT_TUNNEL 0x83 /* Encapsulation interface */ +#define IFT_COFFEE 0x84 /* coffee pot */ +#define IFT_CES 0x85 /* Circiut Emulation Service */ +#define IFT_ATMSUBINTERFACE 0x86 /* (x) ATM Sub Interface */ +#define IFT_L2VLAN 0x87 /* Layer 2 Virtual LAN using 802.1Q */ +#define IFT_L3IPVLAN 0x88 /* Layer 3 Virtual LAN - IP Protocol */ +#define IFT_L3IPXVLAN 0x89 /* Layer 3 Virtual LAN - IPX Prot. */ +#define IFT_DIGITALPOWERLINE 0x8a /* IP over Power Lines */ +#define IFT_MEDIAMAILOVERIP 0x8b /* (xxx) Multimedia Mail over IP */ +#define IFT_DTM 0x8c /* Dynamic synchronous Transfer Mode */ +#define IFT_DCN 0x8d /* Data Communications Network */ +#define IFT_IPFORWARD 0x8e /* IP Forwarding Interface */ +#define IFT_MSDSL 0x8f /* Multi-rate Symmetric DSL */ +#define IFT_IEEE1394 0x90 /* IEEE1394 High Performance SerialBus*/ +#define IFT_IFGSN 0x91 /* HIPPI-6400 */ +#define IFT_DVBRCCMACLAYER 0x92 /* DVB-RCC MAC Layer */ +#define IFT_DVBRCCDOWNSTREAM 0x93 /* DVB-RCC Downstream Channel */ +#define IFT_DVBRCCUPSTREAM 0x94 /* DVB-RCC Upstream Channel */ +#define IFT_ATMVIRTUAL 0x95 /* ATM Virtual Interface */ +#define IFT_MPLSTUNNEL 0x96 /* MPLS Tunnel Virtual Interface */ +#define IFT_SRP 0x97 /* Spatial Reuse Protocol */ +#define IFT_VOICEOVERATM 0x98 /* Voice over ATM */ +#define IFT_VOICEOVERFRAMERELAY 0x99 /* Voice Over Frame Relay */ +#define IFT_IDSL 0x9a /* Digital Subscriber Loop over ISDN */ +#define IFT_COMPOSITELINK 0x9b /* Avici Composite Link Interface */ +#define IFT_SS7SIGLINK 0x9c /* SS7 Signaling Link */ +#define IFT_PROPWIRELESSP2P 0x9d /* Prop. P2P wireless interface */ +#define IFT_FRFORWARD 0x9e /* Frame forward Interface */ +#define IFT_RFC1483 0x9f /* Multiprotocol over ATM AAL5 */ +#define IFT_USB 0xa0 /* USB Interface */ +#define IFT_IEEE8023ADLAG 0xa1 /* IEEE 802.3ad Link Aggregate*/ +#define IFT_BGPPOLICYACCOUNTING 0xa2 /* BGP Policy Accounting */ +#define IFT_FRF16MFRBUNDLE 0xa3 /* FRF.16 Multilik Frame Relay*/ +#define IFT_H323GATEKEEPER 0xa4 /* H323 Gatekeeper */ +#define IFT_H323PROXY 0xa5 /* H323 Voice and Video Proxy */ +#define IFT_MPLS 0xa6 /* MPLS */ +#define IFT_MFSIGLINK 0xa7 /* Multi-frequency signaling link */ +#define IFT_HDSL2 0xa8 /* High Bit-Rate DSL, 2nd gen. */ +#define IFT_SHDSL 0xa9 /* Multirate HDSL2 */ +#define IFT_DS1FDL 0xaa /* Facility Data Link (4Kbps) on a DS1*/ +#define IFT_POS 0xab /* Packet over SONET/SDH Interface */ +#define IFT_DVBASILN 0xac /* DVB-ASI Input */ +#define IFT_DVBASIOUT 0xad /* DVB-ASI Output */ +#define IFT_PLC 0xae /* Power Line Communications */ +#define IFT_NFAS 0xaf /* Non-Facility Associated Signaling */ +#define IFT_TR008 0xb0 /* TROO8 */ +#define IFT_GR303RDT 0xb1 /* Remote Digital Terminal */ +#define IFT_GR303IDT 0xb2 /* Integrated Digital Terminal */ +#define IFT_ISUP 0xb3 /* ISUP */ +#define IFT_PROPDOCSWIRELESSMACLAYER 0xb4 /* prop/Wireless MAC Layer */ +#define IFT_PROPDOCSWIRELESSDOWNSTREAM 0xb5 /* prop/Wireless Downstream */ +#define IFT_PROPDOCSWIRELESSUPSTREAM 0xb6 /* prop/Wireless Upstream */ +#define IFT_HIPERLAN2 0xb7 /* HIPERLAN Type 2 Radio Interface */ +#define IFT_PROPBWAP2MP 0xb8 /* PropBroadbandWirelessAccess P2MP*/ +#define IFT_SONETOVERHEADCHANNEL 0xb9 /* SONET Overhead Channel */ +#define IFT_DIGITALWRAPPEROVERHEADCHANNEL 0xba /* Digital Wrapper Overhead */ +#define IFT_AAL2 0xbb /* ATM adaptation layer 2 */ +#define IFT_RADIOMAC 0xbc /* MAC layer over radio links */ +#define IFT_ATMRADIO 0xbd /* ATM over radio links */ +#define IFT_IMT 0xbe /* Inter-Machine Trunks */ +#define IFT_MVL 0xbf /* Multiple Virtual Lines DSL */ +#define IFT_REACHDSL 0xc0 /* Long Reach DSL */ +#define IFT_FRDLCIENDPT 0xc1 /* Frame Relay DLCI End Point */ +#define IFT_ATMVCIENDPT 0xc2 /* ATM VCI End Point */ +#define IFT_OPTICALCHANNEL 0xc3 /* Optical Channel */ +#define IFT_OPTICALTRANSPORT 0xc4 /* Optical Transport */ + +#define IFT_STF 0xd7 /* 6to4 interface */ + +/* not based on IANA assignments */ +#define IFT_GIF 0xf0 +#define IFT_PVC 0xf1 +#define IFT_FAITH 0xf2 +#define IFT_PFLOG 0xf6 +#define IFT_PFSYNC 0xf7 +#define IFT_CARP 0xf8 /* Common Address Redundancy Protocol */ +#endif /* !_NET_IF_TYPES_H_ */ diff --git a/net/if_var.h b/net/if_var.h new file mode 100644 index 0000000..222862c --- /dev/null +++ b/net/if_var.h @@ -0,0 +1,256 @@ +/* + * 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. + * 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: @(#)if.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_var.h,v 1.107 2006/06/19 22:20:44 mlaier Exp $ + */ + + +#ifndef _NET_IF_VAR_H_ +#define _NET_IF_VAR_H_ + +#include <net/if.h> /* struct if_data */ +#include <sys/ioccom.h> /* ioctl_command_t */ + +/* + * 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 an 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 an 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 + */ + +/* + * Forward structure declarations for function prototypes [sic]. + */ +struct mbuf; +#ifndef __rtems__ +struct thread; +#endif +struct rtentry; +struct rt_addrinfo; +struct socket; +struct ether_header; +#ifndef __rtems__ +struct carp_if; +#endif + +#include <sys/queue.h> /* get TAILQ macros */ + +/* + * 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 */ + int if_flags; /* up/down, broadcast, etc. */ + 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) */ + (struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); + void (*if_start) /* initiate output routine */ + (struct ifnet *); + int (*if_ioctl) /* ioctl routine */ + (struct ifnet *, ioctl_command_t, caddr_t); + void (*if_watchdog) /* timer routine */ + (struct ifnet *); + int (*if_poll_recv) /* polled receive routine */ + (struct ifnet *, int *); + int (*if_poll_xmit) /* polled transmit routine */ + (struct ifnet *, int *); + void (*if_poll_intren) /* polled interrupt reenable routine */ + (struct ifnet *); + void (*if_poll_slowinput) /* input routine for slow devices */ + (struct ifnet *, struct mbuf *); + void (*if_init) /* Init routine */ + (void *); + int (*if_tap) /* Packet filter routine */ + (struct ifnet *, struct ether_header *, struct mbuf *); + struct ifqueue if_snd; /* output queue */ + struct ifqueue *if_poll_slowq; /* input queue for slow devices */ +}; + +typedef void if_init_f_t(void *); + +/* + * XXX These aliases are terribly dangerous because they could apply + * to anything. + */ +#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 *)NULL) + +/* + * 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) do { \ + (m)->m_nextpkt = NULL; \ + if ((ifq)->ifq_tail == NULL) \ + (ifq)->ifq_head = m; \ + else \ + (ifq)->ifq_tail->m_nextpkt = m; \ + (ifq)->ifq_tail = m; \ + (ifq)->ifq_len++; \ +} while (0) + +#define IF_PREPEND(ifq, m) do { \ + (m)->m_nextpkt = (ifq)->ifq_head; \ + if ((ifq)->ifq_tail == NULL) \ + (ifq)->ifq_tail = (m); \ + (ifq)->ifq_head = (m); \ + (ifq)->ifq_len++; \ +} while (0) + +#define IF_DEQUEUE(ifq, m) do { \ + (m) = (ifq)->ifq_head; \ + if (m) { \ + if (((ifq)->ifq_head = (m)->m_nextpkt) == NULL) \ + (ifq)->ifq_tail = NULL; \ + (m)->m_nextpkt = NULL; \ + (ifq)->ifq_len--; \ + } \ +} while (0) + +/* + * 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 */ + (int, struct rtentry *, struct sockaddr *); + u_short ifa_flags; /* mostly rt_flags for cloning */ + u_int ifa_refcnt; /* references to this structure */ + int ifa_metric; /* cost of going out this interface */ + int (*ifa_claim_addr) /* check if an addr goes to this if */ + (struct ifaddr *, struct sockaddr *); + +}; +#define IFA_ROUTE RTF_UP /* route installed */ + +#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 if_attach(struct ifnet *); +void if_down(struct ifnet *); +void if_up(struct ifnet *); +/*void ifinit(void);*/ /* declared in systm.h for main() */ +int ifioctl(struct socket *, u_long, caddr_t, struct proc *); +int ifpromisc(struct ifnet *, int); + +struct ifaddr *ifa_ifwithaddr(struct sockaddr *); +struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *); +struct ifaddr *ifa_ifwithnet(struct sockaddr *); +struct ifaddr *ifa_ifwithroute(int, struct sockaddr *, struct sockaddr *); +struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *); + +#endif /* _KERNEL */ + +#endif /* !_NET_IF_VAR_H_ */ diff --git a/net/netisr.h b/net/netisr.h new file mode 100644 index 0000000..eb204e7 --- /dev/null +++ b/net/netisr.h @@ -0,0 +1,74 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/netisr.h,v 1.33 2005/01/07 01:45:35 imp Exp $ + */ + + +#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). + */ + +/* + * 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_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_USB 25 /* USB soft interrupt */ +#define NETISR_PPP 26 /* PPP soft interrupt */ + +#ifndef LOCORE +#ifdef _KERNEL + +#define NETISR_SET(num, isr) /* FIXME: dummy, should be removed */ + +extern volatile unsigned int netisr; /* scheduling bits for network */ +#define schednetisr(anisr) rtems_bsdnet_schednetisr(anisr) + +#endif +#endif + +#endif diff --git a/net/ppp_comp.h b/net/ppp_comp.h new file mode 100644 index 0000000..c78997d --- /dev/null +++ b/net/ppp_comp.h @@ -0,0 +1,165 @@ +/* + * ppp-comp.h - Definitions for doing PPP packet compression. + */ +/* + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * $FreeBSD: src/sys/net/ppp_comp.h,v 1.12 2005/01/07 01:45:35 imp Exp $ + */ + + +#ifndef _NET_PPP_COMP_H +#define _NET_PPP_COMP_H + +/* + * The following symbols control whether we include code for + * various compression methods. + */ +#ifndef DO_BSD_COMPRESS +#define DO_BSD_COMPRESS 0 /* by default, include BSD-Compress */ +#endif +#ifndef DO_DEFLATE +#define DO_DEFLATE 0 /* by default, include Deflate */ +#endif +#define DO_PREDICTOR_1 0 +#define DO_PREDICTOR_2 0 + +/* + * Structure giving methods for compression/decompression. + */ +#ifdef PACKETPTR +struct compressor { + int compress_proto; /* CCP compression protocol number */ + + /* Allocate space for a compressor (transmit side) */ + void *(*comp_alloc)(u_char *options, int opt_len); + /* Free space used by a compressor */ + void (*comp_free)(void *state); + /* Initialize a compressor */ + int (*comp_init)(void *state, u_char *options, int opt_len, + int unit, int hdrlen, int debug); + /* Reset a compressor */ + void (*comp_reset)(void *state); + /* Compress a packet */ + int (*compress)(void *state, PACKETPTR *mret, PACKETPTR mp, + int orig_len, int max_len); + /* Return compression statistics */ + void (*comp_stat)(void *state, struct compstat *stats); + + /* Allocate space for a decompressor (receive side) */ + void *(*decomp_alloc)(u_char *options, int opt_len); + /* Free space used by a decompressor */ + void (*decomp_free)(void *state); + /* Initialize a decompressor */ + int (*decomp_init)(void *state, u_char *options, int opt_len, + int unit, int hdrlen, int mru, int debug); + /* Reset a decompressor */ + void (*decomp_reset)(void *state); + /* Decompress a packet. */ + int (*decompress)(void *state, PACKETPTR mp, PACKETPTR *dmpp); + /* Update state for an incompressible packet received */ + void (*incomp)(void *state, PACKETPTR mp); + /* Return decompression statistics */ + void (*decomp_stat)(void *state, struct compstat *stats); +}; +#endif /* PACKETPTR */ + +/* + * Return values for decompress routine. + * We need to make these distinctions so that we can disable certain + * useful functionality, namely sending a CCP reset-request as a result + * of an error detected after decompression. This is to avoid infringing + * a patent held by Motorola. + * Don't you just lurve software patents. + */ +#define DECOMP_OK 0 /* everything went OK */ +#define DECOMP_ERROR 1 /* error detected before decomp. */ +#define DECOMP_FATALERROR 2 /* error detected after decomp. */ + +/* + * CCP codes. + */ +#define CCP_CONFREQ 1 +#define CCP_CONFACK 2 +#define CCP_TERMREQ 5 +#define CCP_TERMACK 6 +#define CCP_RESETREQ 14 +#define CCP_RESETACK 15 + +/* + * Max # bytes for a CCP option + */ +#define CCP_MAX_OPTION_LENGTH 32 + +/* + * Parts of a CCP packet. + */ +#define CCP_CODE(dp) ((dp)[0]) +#define CCP_ID(dp) ((dp)[1]) +#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) +#define CCP_HDRLEN 4 + +#define CCP_OPT_CODE(dp) ((dp)[0]) +#define CCP_OPT_LENGTH(dp) ((dp)[1]) +#define CCP_OPT_MINLEN 2 + +/* + * Definitions for BSD-Compress. + */ +#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ +#define CILEN_BSD_COMPRESS 3 /* length of config. option */ + +/* Macros for handling the 3rd byte of the BSD-Compress config option. */ +#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ +#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ +#define BSD_CURRENT_VERSION 1 /* current version number */ +#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) + +#define BSD_MIN_BITS 9 /* smallest code size supported */ +#define BSD_MAX_BITS 15 /* largest code size supported */ + +/* + * Definitions for Deflate. + */ +#define CI_DEFLATE 26 /* config option for Deflate */ +#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */ +#define CILEN_DEFLATE 4 /* length of its config option */ + +#define DEFLATE_MIN_SIZE 8 +#define DEFLATE_MAX_SIZE 15 +#define DEFLATE_METHOD_VAL 8 +#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE) +#define DEFLATE_METHOD(x) ((x) & 0x0F) +#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \ + + DEFLATE_METHOD_VAL) +#define DEFLATE_CHK_SEQUENCE 0 + +/* + * Definitions for other, as yet unsupported, compression methods. + */ +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ + +#endif /* _NET_PPP_COMP_H */ diff --git a/net/ppp_defs.h b/net/ppp_defs.h new file mode 100644 index 0000000..3636bf9 --- /dev/null +++ b/net/ppp_defs.h @@ -0,0 +1,159 @@ +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * $FreeBSD: src/sys/net/ppp_defs.h,v 1.8 2005/01/07 01:45:35 imp Exp $ + */ + + +#ifndef _PPP_DEFS_H_ +#define _PPP_DEFS_H_ + +#include <stdint.h> + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ +#define PPP_MRU 1500 /* default MRU = max length of info field */ + +#define PPP_ADDRESS(p) (((u_char *)(p))[0]) +#define PPP_CONTROL(p) (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef uint32_t ext_accm[8]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics. + */ +struct pppstat { + unsigned int ppp_ibytes; /* bytes received */ + unsigned int ppp_ipackets; /* packets received */ + unsigned int ppp_ierrors; /* receive errors */ + unsigned int ppp_obytes; /* bytes sent */ + unsigned int ppp_opackets; /* packets sent */ + unsigned int ppp_oerrors; /* transmit errors */ +}; + +struct vjstat { + unsigned int vjs_packets; /* outbound packets */ + unsigned int vjs_compressed; /* outbound compressed packets */ + unsigned int vjs_searches; /* searches for connection state */ + unsigned int vjs_misses; /* times couldn't find conn. state */ + unsigned int vjs_uncompressedin; /* inbound uncompressed packets */ + unsigned int vjs_compressedin; /* inbound compressed packets */ + unsigned int vjs_errorin; /* inbound unknown type packets */ + unsigned int vjs_tossed; /* inbound packets tossed because of error */ +}; + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ + struct vjstat vj; /* VJ header compression statistics */ +}; + +struct compstat { + unsigned int unc_bytes; /* total uncompressed bytes */ + unsigned int unc_packets; /* total uncompressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned int comp_packets; /* compressed packets */ + unsigned int inc_bytes; /* incompressible bytes */ + unsigned int inc_packets; /* incompressible packets */ + unsigned int ratio; /* recent compression ratio << 8 */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; + +#ifndef __P +#ifdef __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif +#endif + +#endif /* _PPP_DEFS_H_ */ diff --git a/net/ppp_tty.c b/net/ppp_tty.c new file mode 100644 index 0000000..705c2c1 --- /dev/null +++ b/net/ppp_tty.c @@ -0,0 +1,957 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous + * tty devices. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Drew D. Perkins + * Carnegie Mellon University + * 4910 Forbes Ave. + * Pittsburgh, PA 15213 + * (412) 268-8576 + * ddp@andrew.cmu.edu + * + * Based on: + * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 + * + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Serial Line interface + * + * Rick Adams + * Center for Seismic Studies + * 1300 N 17th Street, Suite 1450 + * Arlington, Virginia 22209 + * (703)276-7900 + * rick@seismo.ARPA + * seismo!rick + * + * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). + * Converted to 4.3BSD Beta by Chris Torek. + * Other changes made at Berkeley, based in part on code by Kirk Smith. + * + * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) + * Added VJ tcp header compression; more unified ioctls + * + * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). + * Cleaned up a lot of the mbuf-related code to fix bugs that + * caused system crashes and packet corruption. Changed pppstart + * so that it doesn't just give up with a "collision" if the whole + * packet doesn't fit in the output ring buffer. + * + * Added priority queueing for interactive IP packets, following + * the model of if_sl.c, plus hooks for bpf. + * Paul Mackerras (paulus@cs.anu.edu.au). + */ + +/* $FreeBSD: src/sys/net/ppp_tty.c,v 1.69 2005/10/16 20:44:18 phk Exp $ */ +/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ +/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opt_ppp.h" /* XXX for ppp_defs.h */ + +#if NPPP > 0 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/filio.h> +#include <sys/file.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/if_types.h> + +#ifdef VJC +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <net/slcompress.h> +#endif + +#include <rtems.h> +#include <rtems/libio.h> +#include <sys/ttycom.h> +#include <termios.h> +#include <rtems/termiostypes.h> + +#ifdef PPP_FILTER +#include <net/bpf.h> +#endif +#include <net/ppp_defs.h> +#include <net/if_ppp.h> +#include <net/if_pppvar.h> + + +void pppasyncattach(void); +int pppopen(struct rtems_termios_tty *tty); +int pppclose(struct rtems_termios_tty *tty); +int pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args); +int pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args); +int ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args); +int pppinput(int c, struct rtems_termios_tty *tty); +int pppstart(struct rtems_termios_tty *tp); +u_short pppfcs(u_short fcs, u_char *cp, int len); +void pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp); + +static void pppasyncstart(struct ppp_softc *); +static void pppasyncctlp(struct ppp_softc *); +static void pppasyncrelinq(struct ppp_softc *); +/*static void ppp_timeout __P((void *)); */ +/*static void pppdumpb __P((u_char *b, int l)); */ +/*static void ppplogchar __P((struct ppp_softc *, int)); */ + +/* + * Some useful mbuf macros not in mbuf.h. + */ +#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) + +#define M_DATASTART(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ + (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) + +#define M_DATASIZE(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ + (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) + +/* + * We steal two bits in the mbuf m_flags, to mark high-priority packets + * for output, and received packets following lost/corrupted packets. + */ +#define M_HIGHPRI 0x2000 /* output packet for sc_fastq */ +#define M_ERRMARK 0x4000 /* steal a bit in mbuf m_flags */ + +/* + * Does c need to be escaped? + */ +#define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) + +/* + * Procedures for using an async tty interface for PPP. + */ + +/* This is a FreeBSD-2.0 kernel. */ +#define CCOUNT(rb) (((rb).Size+(rb).Head-(rb).Tail) % (rb).Size) +#define FCOUNT(rb) ((rb).Size-CCOUNT(rb)-1) +#define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */ +#define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ + +/* + * Define the PPP line discipline. + */ + +static struct rtems_termios_linesw pppdisc = { + pppopen, pppclose, pppread, pppwrite, + pppinput, pppstart, ppptioctl, NULL +}; + +void +pppasyncattach(void) +{ + rtems_termios_linesw[PPPDISC] = pppdisc; +} + +TEXT_SET(pseudo_set, pppasyncattach); + +/* + * Line specific open routine for async tty devices. + * Attach the given tty to the first available ppp unit. + * Called from device open routine or ttioctl. + */ +/* ARGSUSED */ +int +pppopen(struct rtems_termios_tty *tty) +{ + int i; + register struct ppp_softc *sc; + struct mbuf *m = (struct mbuf *)0; + + if (tty->t_line == PPPDISC) { + sc = (struct ppp_softc *)tty->t_sc; + if (sc != NULL && sc->sc_devp == (void *)tty) { + return (0); + } + } + + if ((sc = pppalloc(1)) == NULL) { + return ENXIO; + } + + if (sc->sc_relinq) + (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ + + sc->sc_ilen = 0; + sc->sc_m = NULL; + bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); + sc->sc_asyncmap[0] = 0xffffffff; + sc->sc_asyncmap[3] = 0x60000000; + sc->sc_rasyncmap = 0; + sc->sc_devp = tty; + sc->sc_start = pppasyncstart; + sc->sc_ctlp = pppasyncctlp; + sc->sc_relinq = pppasyncrelinq; + sc->sc_outm = NULL; + sc->sc_outmc = NULL; + + /* preallocate mbufs for free queue */ + rtems_bsdnet_semaphore_obtain(); + for (i=0; i<NUM_MBUFQ; i++) { + pppallocmbuf(sc, &m); + if ( i == 0 ) { + /* use first mbuf for rx iterrupt handling */ + sc->sc_m = m; + } + else { + /* enqueue mbuf for later use */ + IF_ENQUEUE(&sc->sc_freeq, m); + } + m = (struct mbuf *)0; + } + rtems_bsdnet_semaphore_release(); + + /* initialize values */ + sc->sc_if.if_flags |= IFF_RUNNING; + sc->sc_if.if_baudrate = tty->termios.c_ispeed; + + tty->t_sc = (void *)sc; + + return ( RTEMS_SUCCESSFUL ); +} + +/* + * Line specific close routine, called from device close routine + * and from ttioctl. + * Detach the tty from the ppp unit. + * Mimics part of ttyclose(). + */ +int +pppclose(struct rtems_termios_tty *tty) +{ + register struct ppp_softc *sc; + + tty->t_line = 0; + sc = (struct ppp_softc *)tty->t_sc; + if (sc != NULL) { + tty->t_sc = NULL; + if (tty == (struct rtems_termios_tty *)sc->sc_devp) { + rtems_bsdnet_semaphore_obtain(); + pppasyncrelinq(sc); + pppdealloc(sc); + rtems_bsdnet_semaphore_release(); + } + } + return ( RTEMS_SUCCESSFUL ); +} + +/* + * Relinquish the interface unit to another device. + */ +static void +pppasyncrelinq(struct ppp_softc *sc) +{ +#ifdef XXX_XXX + if (sc->sc_outm) { + m_freem(sc->sc_outm); + sc->sc_outm = NULL; + } + if (sc->sc_m) { + m_freem(sc->sc_m); + sc->sc_m = NULL; + } + if (sc->sc_flags & SC_TIMEOUT) { + untimeout(ppp_timeout, (void *) sc); + sc->sc_flags &= ~SC_TIMEOUT; + } +#endif +} + +/* + * Line specific (tty) read routine. + */ +int +pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args) +{ + rtems_status_code status = RTEMS_UNSATISFIED; + int count = 0; + int maximum = rw_args->count; + char *buffer = rw_args->buffer; + register struct ppp_softc *sc = (struct ppp_softc *)tty->t_sc; + struct mbuf *m; + struct mbuf *m0; + u_char *p; + + if (sc == NULL) + return 0; + + /* + * Loop waiting for input, checking that nothing disasterous + * happens in the meantime. + */ + if (tty != (struct rtems_termios_tty *)sc->sc_devp || tty->t_line != PPPDISC) { + return ( status ); + } + if (sc->sc_inq.ifq_head == NULL) { + return ( status ); + } + + /* Get the packet from the input queue */ + rtems_bsdnet_semaphore_obtain(); + IF_DEQUEUE(&sc->sc_inq, m0); + + /* loop over mbuf chain */ + m = m0; + while (( m != NULL ) && ( m->m_len > 0 ) && ( count+m->m_len < maximum )) { + /* copy data into buffer */ + p = mtod(m, u_char *); + memcpy(buffer, p, m->m_len); + memset(p, 0, m->m_len); + count += m->m_len; + buffer += m->m_len; + + /* increment loop index */ + m = m->m_next; + } + + /* free mbuf chain */ + m_freem(m0); + rtems_bsdnet_semaphore_release(); + + /* update return values */ + rw_args->bytes_moved = count; + if ( count >= 0 ) { + status = RTEMS_SUCCESSFUL; + } + + /* check to see if queue is empty */ + if (sc->sc_inq.ifq_head != NULL) { + /* queue is not empty - post another event to ourself */ + rtems_event_send(sc->sc_pppdtask, PPPD_EVENT); + } + + return ( status ); +} + +/* + * Line specific (tty) write routine. + */ +int +pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args) +{ + struct sockaddr dst; + int n; + int len; + int maximum = rw_args->count; + char *out_buffer = rw_args->buffer; + register struct ppp_softc *sc = (struct ppp_softc *)tty->t_sc; + struct mbuf *m; + struct mbuf *m0; + struct mbuf **mp; + + rtems_bsdnet_semaphore_obtain(); + for (mp = &m0; maximum; mp = &m->m_next) { + MGET(m, M_WAIT, MT_DATA); + if ((*mp = m) == NULL) { + m_freem(m0); + return (ENOBUFS); + } + m->m_len = 0; + if (maximum >= MCLBYTES / 2) { + MCLGET(m, M_DONTWAIT); + } + len = M_TRAILINGSPACE(m); + if (len > maximum) { + memcpy(mtod(m, u_char *),out_buffer,maximum); + m->m_len = maximum; + maximum = 0; + } + else { + memcpy(mtod(m, u_char *),out_buffer,len); + m->m_len = len; + maximum -= len; + out_buffer += len; + } + } + + dst.sa_family = AF_UNSPEC; + bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); + m0->m_data += PPP_HDRLEN; + m0->m_len -= PPP_HDRLEN; + + n = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0); + rtems_bsdnet_semaphore_release(); + + return ( n ); +} + +/* + * Line specific (tty) ioctl routine. + * This discipline requires that tty device drivers call + * the line specific l_ioctl routine from their ioctl routines. + */ +/* ARGSUSED */ +int +ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args) +{ +/* int i; */ + int error = RTEMS_SUCCESSFUL; + ioctl_command_t cmd = args->command; + caddr_t data = args->buffer; + struct ppp_softc *sc = tty->t_sc; + + switch (cmd) { + case TIOCGETA: + case TIOCSETA: + case TIOCSETAW: + case TIOCSETAF: + case TIOCDRAIN: + case RTEMS_IO_SNDWAKEUP: + case RTEMS_IO_RCVWAKEUP: + case TIOCGETD: + case TIOCSETD: + error = rtems_termios_ioctl(args); + break; + + case PPPIOCSASYNCMAP: + sc->sc_asyncmap[0] = *(u_int *)data; + break; + + case PPPIOCGASYNCMAP: + *(u_int *)data = sc->sc_asyncmap[0]; + break; + + case PPPIOCSRASYNCMAP: + sc->sc_rasyncmap = *(u_int *)data; + break; + + case PPPIOCGRASYNCMAP: + *(u_int *)data = sc->sc_rasyncmap; + break; + + case PPPIOCSXASYNCMAP: + bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); + sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ + sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ + sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ + break; + + case PPPIOCGXASYNCMAP: + bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); + break; + + default: + rtems_bsdnet_semaphore_obtain(); + error = pppioctl(sc, cmd, data, 0, NULL); + rtems_bsdnet_semaphore_release(); + } + return error; +} + +/* + * FCS lookup table as calculated by genfcstab. + */ +static u_short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/* + * Calculate a new FCS given the current FCS and the new data. + */ +u_short +pppfcs(u_short fcs, u_char *cp, int len) +{ + while (len--) + fcs = PPP_FCS(fcs, *cp++); + return (fcs); +} + +/* + * This gets called at splsoftnet from if_ppp.c at various times + * when there is data ready to be sent. + */ +void pppasyncstart(struct ppp_softc *sc) +{ + /* check to see if output is not active */ + if ( sc->sc_outflag == 0 ) { + /* mark active and post tx event to daemon */ + sc->sc_outflag |= SC_TX_PENDING; + rtems_event_send(sc->sc_txtask, TX_PACKET); + } +} + +/* + * This gets called when a received packet is placed on + * the inq, at splsoftnet. + */ +static void +pppasyncctlp( + struct ppp_softc *sc) +{ + /* check to see if task id was set */ + if ( sc->sc_pppdtask != 0 ) { + /* post event to daemon */ + rtems_event_send(sc->sc_pppdtask, PPPD_EVENT); + } +} + +/* + * Start output on async tty interface. If the transmit queue + * has drained sufficiently, arrange for pppasyncstart to be + * called later at splsoftnet. + * Called at spltty or higher. + */ +int +pppstart(struct rtems_termios_tty *tp) +{ + u_char *sendBegin; + u_long ioffset = (u_long )0; + struct mbuf *m = (struct mbuf *)0; + struct ppp_softc *sc = tp->t_sc; + rtems_termios_device_context *ctx = rtems_termios_get_device_context(tp); + + /* ensure input is valid and we are busy */ + if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) { + /* check to see if we need to get the next buffer */ + + /* Ready with PPP_FLAG Character ? */ + if(sc->sc_outflag & SC_TX_LASTCHAR){ + sc->sc_outflag &= ~(SC_TX_BUSY | SC_TX_FCS | SC_TX_LASTCHAR); + + /* Notify driver that we have nothing to transmit */ + (*tp->handler.write)(ctx, NULL, 0); + + rtems_event_send(sc->sc_txtask, TX_TRANSMIT); /* Ready for the next Packet */ + return(0); + } + + if ( sc->sc_outoff >= sc->sc_outlen ) { + /* loop to get next non-zero length buffer */ + if ( sc->sc_outmc != NULL ) { + m = sc->sc_outmc->m_next; + } + + /* check for next mbuf in chain */ + if ( m != NULL ) { + /* update values to use this mbuf */ + sc->sc_outmc = m; + sc->sc_outbuf = mtod(m, u_char *); + sc->sc_outlen = m->m_len; + sc->sc_outoff = (short)0; + } + else if ( (sc->sc_outflag & SC_TX_FCS) == 0 ) { + /* setup to use FCS buffer */ + sc->sc_outflag |= SC_TX_FCS; + sc->sc_outbuf = sc->sc_outfcsbuf; + sc->sc_outlen = sc->sc_outfcslen; + sc->sc_outoff = (short)0; + } + else { + /* done with this packet */ + sc->sc_outflag |= SC_TX_LASTCHAR; + sc->sc_outflag &=~(SC_TX_FCS); + sc->sc_outchar = (u_char)PPP_FLAG; + (*tp->handler.write)(ctx, (char *)&sc->sc_outchar, 1); + return(0); + } + } + + /* check to see if there is some data to write out */ + if ( sc->sc_outoff < sc->sc_outlen ) { + /* check to see if character needs to be escaped */ + sc->sc_outchar = sc->sc_outbuf[sc->sc_outoff]; + if ( ESCAPE_P(sc->sc_outchar) ) { + if ( sc->sc_outflag & SC_TX_ESCAPE ) { + /* last sent character was the escape character */ + sc->sc_outchar = sc->sc_outchar ^ PPP_TRANS; + + /* clear the escape flag and increment the offset */ + sc->sc_outflag &= ~SC_TX_ESCAPE; + ioffset++; + } + else { + /* need to send the escape character */ + sc->sc_outchar = PPP_ESCAPE; + + /* set the escape flag */ + sc->sc_outflag |= SC_TX_ESCAPE; + } + sendBegin = &sc->sc_outchar; + } + else { + /* escape not needed - increment the offset as much as possible */ + while ((!ESCAPE_P(sc->sc_outchar)) && ((sc->sc_outoff + ioffset) < sc->sc_outlen)) { + ioffset++; + sc->sc_outchar = sc->sc_outbuf[sc->sc_outoff + ioffset]; + } + sendBegin = &sc->sc_outbuf[sc->sc_outoff]; + } + + /* write out the character(s) and update the stats */ + (*tp->handler.write)(ctx, (char *)sendBegin, (ioffset > 0) ? ioffset : 1); + sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1; + sc->sc_outoff += ioffset; + + return (0); + } + } + + /* Notify driver that we have nothing to transmit */ + (*tp->handler.write)(ctx, NULL, 0); + + return (0); +} + +#ifdef XXX_XXX +/* + * Timeout routine - try to start some more output. + */ +static void +ppp_timeout(void *x) +{ + struct rtems_termios_tty *tty = (struct rtems_termios_tty *)x; + struct ppp_softc *sc = tty->t_sc; +/* struct rtems_termios_tty *tp = (struct rtems_termios_tty *)sc->sc_devp; */ + + sc->sc_flags &= ~SC_TIMEOUT; +/* pppstart(tp); */ +} +#endif + +/* + * Allocate enough mbuf to handle current MRU. + */ +#ifdef XXX_XXX +static void +pppgetm(struct ppp_softc *sc) +{ + struct mbuf *m, **mp; + int len; + + mp = &sc->sc_m; + for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ + if ((m = *mp) == NULL) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + break; + *mp = m; + MCLGET(m, M_DONTWAIT); + } + len -= M_DATASIZE(m); + mp = &m->m_next; + } +} +#endif + +void +pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp) +{ + int ilen; + struct mbuf *m; + + /* loop over length value */ + ilen = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; + while ( ilen > 0 ) { + /* see if this is end of the chain */ + m = *mp; + if ( m == NULL ) { + /* get mbuf header */ + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + *mp = m; + } + + /* update loop variables */ + mp = &m->m_next; + ilen -= M_DATASIZE(m); + } +} + +/* + * tty interface receiver interrupt. + */ +static uint32_t paritytab[8] = { + 0x96696996L, 0x69969669L, 0x69969669L, 0x96696996L, + 0x69969669L, 0x96696996L, 0x96696996L, 0x69969669L +}; + +int +pppinput(int c, struct rtems_termios_tty *tp) +{ + register struct ppp_softc *sc = tp->t_sc; + struct mbuf *m; + int ilen; + + if (sc == NULL || tp != (struct rtems_termios_tty *)sc->sc_devp) + return 0; + if (sc->sc_m == NULL) { + rtems_event_send(sc->sc_rxtask, RX_EMPTY); + IF_DEQUEUE(&sc->sc_freeq, sc->sc_m); + if ( sc->sc_m == NULL ) { + return 0; + } + } + + ++sc->sc_stats.ppp_ibytes; + + c &= 0xff; + if (c & 0x80) + sc->sc_flags |= SC_RCV_B7_1; + else + sc->sc_flags |= SC_RCV_B7_0; + if (paritytab[c >> 5] & (1 << (c & 0x1F))) + sc->sc_flags |= SC_RCV_ODDP; + else + sc->sc_flags |= SC_RCV_EVNP; + + if (c == PPP_FLAG) { + ilen = sc->sc_ilen; + sc->sc_ilen = 0; + + /* + * If SC_ESCAPED is set, then we've seen the packet + * abort sequence "}~". + */ + if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) + || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { + sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ + if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ + /* bad fcs error */ + sc->sc_if.if_ierrors++; + sc->sc_stats.ppp_ierrors++; + } else + sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); + return 0; + } + + if (ilen < PPP_HDRLEN + PPP_FCSLEN) { + if (ilen) { + /* too short error */ + sc->sc_if.if_ierrors++; + sc->sc_stats.ppp_ierrors++; + sc->sc_flags |= SC_PKTLOST; + } + return 0; + } + + /* Remove FCS trailer. Somewhat painful... */ + ilen -= 2; + if (--sc->sc_mc->m_len == 0) { + for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next); + sc->sc_mc = m; + } + sc->sc_mc->m_len--; + + /* excise this mbuf chain - place on raw queue */ + m = sc->sc_m; + if ( sc->sc_flags & SC_PKTLOST ) { + m->m_flags |= M_ERRMARK; + sc->sc_flags &= ~SC_PKTLOST; + } + IF_ENQUEUE(&sc->sc_rawq, m); + + /* setup next mbuf chain */ + IF_DEQUEUE(&sc->sc_freeq, sc->sc_m); + + /* send rx packet event */ + rtems_event_send(sc->sc_rxtask, RX_PACKET); + return 0; + } + + if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) + return 0; + + if (sc->sc_flags & SC_ESCAPED) { + sc->sc_flags &= ~SC_ESCAPED; + c ^= PPP_TRANS; + } else if (c == PPP_ESCAPE) { + sc->sc_flags |= SC_ESCAPED; + return 0; + } + + /* + * Initialize buffer on first octet received. + * First octet could be address or protocol (when compressing + * address/control). + * Second octet is control. + * Third octet is first or second (when compressing protocol) + * octet of protocol. + * Fourth octet is second octet of protocol. + */ + if (sc->sc_ilen == 0) { + m = sc->sc_m; + m->m_len = 0; + m->m_data = M_DATASTART(sc->sc_m); + sc->sc_mc = m; + sc->sc_mp = mtod(m, char *); + sc->sc_fcs = PPP_INITFCS; + if (c != PPP_ALLSTATIONS) { + if (sc->sc_flags & SC_REJ_COMP_AC) { + /* garbage received error */ + goto flush; + } + *sc->sc_mp++ = PPP_ALLSTATIONS; + *sc->sc_mp++ = PPP_UI; + sc->sc_ilen += 2; + m->m_len += 2; + } + } + if (sc->sc_ilen == 1 && c != PPP_UI) { + /* missing UI error */ + goto flush; + } + if (sc->sc_ilen == 2 && (c & 1) == 1) { + /* a compressed protocol */ + *sc->sc_mp++ = 0; + sc->sc_ilen++; + sc->sc_mc->m_len++; + } + if (sc->sc_ilen == 3 && (c & 1) == 0) { + /* bad protocol error */ + goto flush; + } + + /* packet beyond configured mru? */ + if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { + /* packet too big error */ + goto flush; + } + + /* is this mbuf full? */ + m = sc->sc_mc; + if (M_TRAILINGSPACE(m) <= 0) { + if (m->m_next == NULL) { + /* get next available mbuf for the chain */ + IF_DEQUEUE(&sc->sc_freeq, m->m_next); + if (m->m_next == NULL) { + /* too few mbufs */ + goto flush; + } + else { + /* send rx mbuf event */ + rtems_event_send(sc->sc_rxtask, RX_MBUF); + } + } + sc->sc_mc = m = m->m_next; + m->m_len = 0; + m->m_next = 0; + m->m_data = M_DATASTART(m); + sc->sc_mp = mtod(m, char *); + } + + ++m->m_len; + *sc->sc_mp++ = c; + sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); + return 0; + + flush: + if (!(sc->sc_flags & SC_FLUSH)) { + sc->sc_if.if_ierrors++; + sc->sc_stats.ppp_ierrors++; + sc->sc_flags |= SC_FLUSH; + } + return 0; +} + +#ifdef XXX_XXX +#define MAX_DUMP_BYTES 128 + +static void +ppplogchar(struct ppp_softc *sc, int c) +{ + if (c >= 0) + sc->sc_rawin[sc->sc_rawin_count++] = c; + if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) + || (c < 0 && sc->sc_rawin_count > 0)) { + printf("ppp%d input: ", sc->sc_if.if_unit); + pppdumpb(sc->sc_rawin, sc->sc_rawin_count); + sc->sc_rawin_count = 0; + } +} + +static void +pppdumpb(u_char *b, int l) +{ + char buf[3*MAX_DUMP_BYTES+4]; + char *bp = buf; + static char digits[] = "0123456789abcdef"; + + while (l--) { + if (bp >= buf + sizeof(buf) - 3) { + *bp++ = '>'; + break; + } + *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ + *bp++ = digits[*b++ & 0xf]; + *bp++ = ' '; + } + + *bp = 0; + printf("%s\n", buf); +} +#endif + +#endif /* NPPP > 0 */ diff --git a/net/radix.c b/net/radix.c new file mode 100644 index 0000000..b098a1c --- /dev/null +++ b/net/radix.c @@ -0,0 +1,1045 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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.5 (Berkeley) 5/19/95 + * $FreeBSD: src/sys/net/radix.c,v 1.36 2004/04/21 15:27:36 luigi Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * 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 int rn_walktree_from(struct radix_node_head *h, void *a, void *m, + walktree_f_t *f, void *w); +static int rn_walktree(struct radix_node_head *, walktree_f_t *, void *); +static struct radix_node + *rn_insert(void *, struct radix_node_head *, int *, + struct radix_node [2]), + *rn_newpair(void *, int, struct radix_node[2]), + *rn_search(void *, struct radix_node *), + *rn_search_m(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(void *m_arg, void *n_arg); +static struct radix_mask * + rn_new_radix_mask(struct radix_node *tt, + struct radix_mask *next); +static int rn_satisfies_leaf(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_bit 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_bit - 1. + * (We say the index of n is rn_bit.) + * + * There is at least one descendant which has a one bit at position rn_bit, + * 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_bit, + * and m is a normal mask, then the route applies to every descendant of n. + * If the index(m) < rn_bit, 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(void *v_arg, struct radix_node *head) +{ + register struct radix_node *x; + register caddr_t v; + + for (x = head, v = v_arg; x->rn_bit >= 0;) { + if (x->rn_bmask & v[x->rn_offset]) + x = x->rn_right; + else + x = x->rn_left; + } + return (x); +} + +static struct radix_node * +rn_search_m(void *v_arg, struct radix_node *head, void *m_arg) +{ + register struct radix_node *x; + register caddr_t v = v_arg, m = m_arg; + + for (x = head; x->rn_bit >= 0;) { + if ((x->rn_bmask & m[x->rn_offset]) && + (x->rn_bmask & v[x->rn_offset])) + x = x->rn_right; + else + x = x->rn_left; + } + return x; +} + +int +rn_refines(void *m_arg, void *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(void *v_arg, void *m_arg, struct radix_node_head *head) +{ + register struct radix_node *x; + caddr_t netmask = 0; + + if (m_arg) { + x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset); + if (x == 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_satisfies_leaf(char *trial, 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(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_offset, vlen = *(u_char *)cp, matched_off; + register int test, b, rn_bit; + + /* + * Open code rn_search(v, top) to avoid overhead of extra + * subroutine call. + */ + for (; t->rn_bit >= 0; ) { + if (t->rn_bmask & cp[t->rn_offset]) + t = t->rn_right; + else + t = t->rn_left; + } + /* + * 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! + * + * Never return the root node itself, it seems to cause a + * lot of confusion. + */ + if (t->rn_flags & RNF_ROOT) + 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_bit = -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_bit <= t->rn_bit) + return t; + } else if (rn_satisfies_leaf(v, t, matched_off)) + return t; + t = saved_t; + /* start searching up the tree */ + do { + register struct radix_mask *m; + t = t->rn_parent; + 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_bit <= m->rm_bit) + return (m->rm_leaf); + } else { + off = min(t->rn_offset, 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_satisfies_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(void *v, int b, struct radix_node nodes[2]) +{ + register struct radix_node *tt = nodes, *t = tt + 1; + t->rn_bit = b; + t->rn_bmask = 0x80 >> (b & 7); + t->rn_left = tt; + t->rn_offset = b >> 3; + tt->rn_bit = -1; + tt->rn_key = (caddr_t)v; + tt->rn_parent = 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(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_offset, 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_offset] & x->rn_bmask) + x = x->rn_right; + else + x = x->rn_left; + } while (b > (unsigned) x->rn_bit); + /* x->rn_bit < b && x->rn_bit >= 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_left; + if ((cp[p->rn_offset] & p->rn_bmask) == 0) + p->rn_left = t; + else + p->rn_right = t; + x->rn_parent = t; + t->rn_parent = p; /* frees x, p as temp vars below */ + if ((cp[t->rn_offset] & t->rn_bmask) == 0) { + t->rn_right = x; + } else { + t->rn_right = tt; + t->rn_left = 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(void *n_arg, int search, int skip) +{ + 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_bit = -1 - b; + if (isnormal) + x->rn_flags |= RNF_NORMAL; + return (x); +} + +static int /* XXX: arbitrary ordering for non-contiguous masks */ +rn_lexobetter(void *m_arg, void *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(struct radix_node *tt, 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_bit = tt->rn_bit; + 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(void *v_arg, void *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_offset)) == 0) + return (0); + b_leaf = x->rn_bit; + b = -1 - x->rn_bit; + 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_bit) /* 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. + * + * We also reverse, or doubly link the list through the + * parent pointer. + */ + 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_parent = x = t->rn_parent; + t->rn_parent = tt; /* parent */ + if (x->rn_left == t) + x->rn_left = tt; + else + x->rn_right = tt; + saved_tt = tt; x = xx; + } else { + (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; + t->rn_dupedkey = tt; + tt->rn_parent = t; /* parent */ + if (tt->rn_dupedkey) /* parent */ + tt->rn_dupedkey->rn_parent = 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_bit = -1; + tt->rn_flags = RNF_ACTIVE; + } + /* + * Put mask in tree. + */ + if (netmask) { + tt->rn_mask = netmask; + tt->rn_bit = x->rn_bit; + tt->rn_flags |= x->rn_flags & RNF_NORMAL; + } + t = saved_tt->rn_parent; + if (keyduplicated) + goto on2; + b_leaf = -1 - t->rn_bit; + if (t->rn_right == saved_tt) + x = t->rn_left; + else + x = t->rn_right; + /* Promote general routes from below */ + if (x->rn_bit < 0) { + for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) + if (x->rn_mask && (x->rn_bit >= 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_bit >= 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_bit )) + return tt; /* can't lift at all */ + b_leaf = tt->rn_bit; + do { + x = t; + t = t->rn_parent; + } while (b <= t->rn_bit && 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_bit < b_leaf) + continue; + if (m->rm_bit > 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\n"); + 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; +} + +struct radix_node * +rn_delete(void *v_arg, void *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_offset; + 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_bit; + t = saved_tt->rn_parent; + if (b > t->rn_bit) + goto on1; /* Wasn't lifted at all */ + do { + x = t; + t = t->rn_parent; + } while (b <= t->rn_bit && 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_parent; + dupedkey = saved_tt->rn_dupedkey; + if (dupedkey) { + /* + * Here, 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_parent = t; + if (t->rn_left == tt) + t->rn_left = x; + else + t->rn_right = 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_parent = 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_parent; +#else + b = t->rn_info; + *++x = *t; + t->rn_info = b; + p = t->rn_parent; +#endif + if (p->rn_left == t) + p->rn_left = x; + else + p->rn_right = x; + x->rn_left->rn_parent = x; + x->rn_right->rn_parent = x; + } + goto out; + } + if (t->rn_left == tt) + x = t->rn_right; + else + x = t->rn_left; + p = t->rn_parent; + if (p->rn_right == t) + p->rn_right = x; + else + p->rn_left = x; + x->rn_parent = p; + /* + * Demote routes attached to us. + */ + if (t->rn_mklist) { + if (x->rn_bit >= 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, + "rn_delete: Orphaned Mask %p at %p\n", + (void *)m, (void *)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_left->rn_parent = t; + t->rn_right->rn_parent = t; + p = x->rn_parent; + if (p->rn_left == x) + p->rn_left = t; + else + p->rn_right = 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(struct radix_node_head *h, void *a, void *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_bit >= 0; ) { + last = rn; + /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n", + rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */ + if (!(rn->rn_bmask & xm[rn->rn_offset])) { + break; + } + if (rn->rn_bmask & xa[rn->rn_offset]) { + rn = rn->rn_right; + } else { + rn = rn->rn_left; + } + } + /* 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_bit; + + /* 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_bit >= 0) + rn = rn->rn_left; + + while (!stopping) { + /* printf("node %p (%d)\n", rn, rn->rn_bit); */ + base = rn; + /* If at right child go back up, otherwise, go right */ + while (rn->rn_parent->rn_right == rn + && !(rn->rn_flags & RNF_ROOT)) { + rn = rn->rn_parent; + + /* if went up beyond last, stop */ + if (rn->rn_bit < lastb) { + stopping = 1; + /* printf("up too far\n"); */ + } + } + + /* Find the next *leaf* since next node might vanish, too */ + for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;) + rn = rn->rn_left; + 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(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_bit >= 0) + rn = rn->rn_left; + for (;;) { + base = rn; + /* If at right child go back up, otherwise, go right */ + while (rn->rn_parent->rn_right == rn + && (rn->rn_flags & RNF_ROOT) == 0) + rn = rn->rn_parent; + /* Find the next *leaf* since next node might vanish, too */ + for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;) + rn = rn->rn_left; + 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(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_right = ttt; + t->rn_parent = t; + tt = t->rn_left; + tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; + tt->rn_bit = -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(void) +{ + 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 **)(void*)&mask_rnhead, 0) == 0) + panic("rn_init 2"); +} diff --git a/net/radix.h b/net/radix.h new file mode 100644 index 0000000..cf132a4 --- /dev/null +++ b/net/radix.h @@ -0,0 +1,162 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/radix.h,v 1.25 2004/04/18 11:48:35 luigi Exp $ + */ + +#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_parent; /* parent */ + short rn_bit; /* 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_offset rn_u.rn_node.rn_Off +#define rn_left rn_u.rn_node.rn_L +#define rn_right rn_u.rn_node.rn_R + +/* + * Annotations to tree concerning potential routes applying to subtrees. + */ + +struct radix_mask { + short rm_bit; /* 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 */ +}; + +#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(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 */ + (void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[]); + struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ + (void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[]); + struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ + (void *v, void *mask, struct radix_node_head *head); + struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ + (void *v, void *mask, struct radix_node_head *head); + struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ + (void *v, struct radix_node_head *head); + struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ + (void *v, void *mask, struct radix_node_head *head); + struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ + (void *v, struct radix_node_head *head); + int (*rnh_walktree) /* traverse tree */ + (struct radix_node_head *head, walktree_f_t *f, void *w); + int (*rnh_walktree_from) /* traverse tree below a */ + (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 */ + (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 R_Zalloc(p, t, n) (p = (t) calloc(1,(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*/ + +void rn_init(void); +int rn_inithead(void **, int); +int rn_refines(void *, void *); +struct radix_node + *rn_addmask(void *, int, int), + *rn_addroute (void *, void *, struct radix_node_head *, + struct radix_node [2]), + *rn_delete(void *, void *, struct radix_node_head *), + *rn_lookup (void *v_arg, void *m_arg, + struct radix_node_head *head), + *rn_match(void *, struct radix_node_head *); + +#endif /* _RADIX_H_ */ diff --git a/net/raw_cb.c b/net/raw_cb.c new file mode 100644 index 0000000..d11ece3 --- /dev/null +++ b/net/raw_cb.c @@ -0,0 +1,154 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/raw_cb.c,v 1.34 2006/06/02 08:27:15 rwatson Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#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/domain.h> +#include <sys/protosw.h> +#include <errno.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/raw_cb.h> +#include <netinet/in.h> + +#ifdef __rtems__ +#define mtx_lock(x) /* UNUSED */ +#define mtx_unlock(x) /* UNUSED */ +#define KASSERT(x,y) /* UNUSED */ +#endif + +/* + * 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_list_head rawcb_list; +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(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; + mtx_lock(&rawcb_mtx); + LIST_INSERT_HEAD(&rawcb_list, rp, list); + mtx_unlock(&rawcb_mtx); + return (0); +} + +/* + * Detach the raw connection block and discard + * socket resources. + */ +void +raw_detach(struct rawcb *rp) +{ + struct socket *so = rp->rcb_socket; + + KASSERT(so->so_pcb == rp, ("raw_detach: so_pcb != rp")); + + so->so_pcb = NULL; + mtx_lock(&rawcb_mtx); + LIST_REMOVE(rp, list); + mtx_unlock(&rawcb_mtx); +#ifdef notdef + if (rp->rcb_laddr) + m_freem(dtom(rp->rcb_laddr)); + rp->rcb_laddr = 0; +#endif + free((caddr_t)(rp), M_PCB); +} + +/* + * Disconnect raw socket. + */ +void +raw_disconnect(struct rawcb *rp) +{ + +#ifdef notdef + if (rp->rcb_faddr) + m_freem(dtom(rp->rcb_faddr)); + rp->rcb_faddr = 0; +#endif +} + +#ifdef notdef +int +raw_bind(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_TRYWAIT); + rp->rcb_laddr = mtod(nam, struct sockaddr *); + return (0); +} +#endif diff --git a/net/raw_cb.h b/net/raw_cb.h new file mode 100644 index 0000000..907e3c0 --- /dev/null +++ b/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. + * 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 + * $FreeBSD: src/sys/net/raw_cb.h,v 1.19 2005/01/07 01:45:35 imp Exp $ + */ + + +#ifndef _NET_RAW_CB_H_ +#define _NET_RAW_CB_H_ + +#include <sys/socket.h> + +#include <sys/queue.h> + +/* + * Raw protocol interface control block. Used + * to tie a socket to the generic raw interface. + */ +struct rawcb { + LIST_ENTRY(rawcb) list; + 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 LIST_HEAD(rawcb_list_head, rawcb) rawcb_list; + +int raw_attach(struct socket *, int); +void raw_ctlinput(int, struct sockaddr *, void *); +void raw_detach(struct rawcb *); +void raw_disconnect(struct rawcb *); +void raw_init(void); +void raw_input(struct mbuf *, + struct sockproto *, struct sockaddr *, struct sockaddr *); +int raw_usrreq(struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *); +#endif + +#endif diff --git a/net/raw_usrreq.c b/net/raw_usrreq.c new file mode 100644 index 0000000..03a4efe --- /dev/null +++ b/net/raw_usrreq.c @@ -0,0 +1,306 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/net/raw_usrreq.c,v 1.44 2006/11/06 13:42:02 rwatson Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <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(void) +{ + + LIST_INIT(&rawcb_list); +} + + +/* + * 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(struct mbuf *m0, struct sockproto *proto, struct sockaddr *src, + struct sockaddr *dst) +{ + register struct rawcb *rp; + register struct mbuf *m = m0; + struct socket *last; + + last = 0; + LIST_FOREACH(rp, &rawcb_list, list) { + 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); + } + } + } + last = rp->rcb_socket; + } + if (last) { + if (sbappendaddr(&last->so_rcv, src, + m, (struct mbuf *)0) == 0) + m_freem(m); + else { + sorwakeup(last); + } + } else + m_freem(m); +} + +void +raw_ctlinput(int cmd, struct sockaddr *arg, void *dummy) +{ + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + /* INCOMPLETE */ +} + +int +raw_usrreq( struct socket *so, int req, struct mbuf *m, struct mbuf *nam, + struct mbuf *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, (intptr_t)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/net/route.c b/net/route.c new file mode 100644 index 0000000..91e248f --- /dev/null +++ b/net/route.c @@ -0,0 +1,948 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/sockio.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(struct sockaddr *, + struct sockaddr *, struct sockaddr *); +static void rtable_init(struct radix_node_head **); + +/* compare two sockaddr structures */ +#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0) + +static void +rtable_init(struct radix_node_head **table) +{ + struct domain *dom; + for (dom = domains; dom; dom = dom->dom_next) + if (dom->dom_rtattach) + dom->dom_rtattach((void *)&table[dom->dom_family], + dom->dom_rtoffset); +} + +void +route_init(void) +{ + rn_init(); /* initialize all zeroes, all ones, mask table */ + rtable_init(rt_tables); +} + +/* + * Packet routing routines. + */ +void +rtalloc(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(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(struct sockaddr *dst, int report, u_long ignflags) +{ + struct radix_node_head *rnh = rt_tables[dst->sa_family]; + struct rtentry *rt; + struct radix_node *rn; + struct rtentry *newrt; + struct rt_addrinfo info; + u_long nflags; + int s = splnet(); + int err = 0, msgtype = RTM_MISS; + + newrt = NULL; + /* + * 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(&info, sizeof(info)); + info.rti_info[RTAX_DST] = dst; + rt_missmsg(msgtype, &info, 0, err); + } + } + splx(s); + return (newrt); +} + +/* + * Remove a reference count from an rtentry. + * If the count gets low enough, take it out of the routing table + */ +void +rtfree(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(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(struct sockaddr *dst, struct sockaddr *gateway, + struct sockaddr *netmask, int flags, struct sockaddr *src, + struct rtentry **rtp) +{ + struct rtentry *rt; + int error = 0; + short *stat = NULL; + struct rt_addrinfo info; + struct ifaddr *ifa; + + /* verify the gateway is directly reachable */ + if ((ifa = ifa_ifwithnet(gateway)) == NULL) { + 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(&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(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(int flags, struct sockaddr *dst, struct sockaddr *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 = NULL; + if (flags & RTF_HOST) { + ifa = ifa_ifwithdstaddr(dst); + } + if (ifa == NULL) + 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(int req, struct sockaddr *dst, struct sockaddr *gateway, + struct sockaddr *netmask, int flags, 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_offset; 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(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *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(struct sockaddr *src, struct sockaddr *dst, + struct sockaddr *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(cp2, (unsigned)(cplim2 - cp2)); +} + +/* + * Set up a routing table entry, normally + * for an interface. + */ +int +rtinit(struct ifaddr *ifa, int cmd, int 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/net/route.h b/net/route.h new file mode 100644 index 0000000..a9a0783 --- /dev/null +++ b/net/route.h @@ -0,0 +1,293 @@ +/* + * 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. + * 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.4 (Berkeley) 1/9/95 + * $FreeBSD: src/sys/net/route.h,v 1.65 2006/03/15 19:39:09 andre Exp $ + */ + + +#ifndef _NET_ROUTE_H_ +#define _NET_ROUTE_H_ + +#include <sys/socket.h> /* struct sockaddr */ +/* + * 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_lite { + u_long rmx_mtu; /* MTU for this path */ + u_long rmx_expire; /* lifetime for route, e.g. redirect */ + u_long rmx_pksent; /* packets sent using this route */ +}; + +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 */ + u_long rt_flags; /* up/down?, host/net */ + struct ifnet *rt_ifp; /* the answer: interface to use */ + struct ifaddr *rt_ifa; /* the answer: interface address to use */ + struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ + long rt_refcnt; /* # held references */ + struct sockaddr *rt_genmask; /* for generation of cloned routes */ + caddr_t rt_llinfo; /* pointer to link level info cache */ + struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ + struct rtentry *rt_parent; /* cloning parent of this route */ +}; + +/* + * 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, was RTF_DELCLONE */ +#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 */ + +/* + * Message types. + */ +#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 RTM_NEWMADDR 0xf /* mcast group membership being added to if */ +#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */ +#define RTM_IFANNOUNCE 0x11 /* iface arrival/departure */ +#define RTM_IEEE80211 0x12 /* IEEE80211 wireless event */ + +/* + * Bitmask values for rtm_inits and rmx_locks. + */ +#define RTV_MTU 0x1 /* init or lock _mtu */ +#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ +#define RTV_EXPIRE 0x4 /* init or lock _expire */ +#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_addrs. + */ +#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) \ + do { \ + if ((rt)->rt_refcnt <= 1) \ + rtfree(rt); \ + else \ + (rt)->rt_refcnt--; \ + } while (0) + +extern struct route_cb route_cb; +extern struct radix_node_head *rt_tables[AF_MAX+1]; + +void route_init(void); +void rt_ifmsg(struct ifnet *); +void rt_missmsg(int, struct rt_addrinfo *, int, int); +void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *); +int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *); +void rtalloc_ign(struct route *, unsigned long); +void rtalloc(struct route *ro); /* XXX deprecated, use rtalloc_ign(ro, 0) */ +struct rtentry * + rtalloc1(struct sockaddr *, int, unsigned long); +void rtfree(struct rtentry *); +int rtinit(struct ifaddr *, int, int); +int rtioctl(int, caddr_t, struct proc *); +void rtredirect(struct sockaddr *, struct sockaddr *, + struct sockaddr *, int, struct sockaddr *, struct rtentry **); +int rtrequest(int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, struct rtentry **); +#endif + +#endif diff --git a/net/rtsock.c b/net/rtsock.c new file mode 100644 index 0000000..54c5eb1 --- /dev/null +++ b/net/rtsock.c @@ -0,0 +1,801 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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.7 (Berkeley) 10/12/95 + * $FreeBSD: src/sys/net/rtsock.c,v 1.122 2005/03/26 21:49:43 sam Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/if_var.h> +#include <net/route.h> +#include <net/raw_cb.h> + +static struct sockaddr route_dst = { 2, PF_ROUTE, { 0 } }; +static struct sockaddr route_src = { 2, PF_ROUTE, { 0 } }; +static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, { 0 } }; +static struct sockproto route_proto = { PF_ROUTE, 0 }; + +struct walkarg { + int w_tmemsize; + int w_op, w_arg; + caddr_t w_tmem; + struct sysctl_req *w_req; +}; + +static struct mbuf *rt_msg1(int type, struct rt_addrinfo *rtinfo); +static int rt_msg2(int type, struct rt_addrinfo *rtinfo, + caddr_t cp, struct walkarg *w); +static int rt_xaddrs(caddr_t cp, caddr_t cplim, + struct rt_addrinfo *rtinfo); +static int sysctl_dumpentry(struct radix_node *rn, void *vw); +static int sysctl_iflist(int af, struct walkarg *w); +static int route_output(struct mbuf *m, struct socket *so); +static int route_usrreq(struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *); +static void rt_setmetrics(u_long which, const struct rt_metrics *in, + struct rt_metrics *out); + +/*ARGSUSED*/ +static int +route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, + struct mbuf *control) +{ + int error = 0; + 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_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_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(struct mbuf *m, struct socket *so) +{ +#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0) + struct rt_msghdr *rtm = NULL; + struct rtentry *rt = NULL; + struct rtentry *saved_nrt = 0; + struct radix_node_head *rnh; + struct rt_addrinfo info; + int len, error = 0; + struct ifnet *ifp = NULL; + struct ifaddr *ifa = NULL; + +#define senderr(e) { error = e; goto flush;} + if (m == NULL || ((m->m_len < sizeof(long)) && + (m = m_pullup(m, sizeof(long))) == NULL)) + 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) { + info.rti_info[RTAX_DST] = NULL; + senderr(EINVAL); + } + R_Malloc(rtm, struct rt_msghdr *, len); + if (rtm == NULL) { + info.rti_info[RTAX_DST] = NULL; + senderr(ENOBUFS); + } + m_copydata(m, 0, len, (caddr_t)rtm); + if (rtm->rtm_version != RTM_VERSION) { + info.rti_info[RTAX_DST] = NULL; + senderr(EPROTONOSUPPORT); + } + info.rti_addrs = rtm->rtm_addrs; + if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) { + info.rti_info[RTAX_DST] = NULL; + senderr(EINVAL); + } + if (info.rti_info[RTAX_DST] == NULL || + info.rti_info[RTAX_DST]->sa_family >= AF_MAX || + (info.rti_info[RTAX_GATEWAY] != NULL && + info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) + senderr(EINVAL); + if (info.rti_info[RTAX_GENMASK]) { + struct radix_node *t; + t = rn_addmask((caddr_t) info.rti_info[RTAX_GENMASK], 0, 1); + if (t != NULL && + Bcmp(info.rti_info[RTAX_GENMASK], t->rn_key, *(u_char *)info.rti_info[RTAX_GENMASK]) == 0) + info.rti_info[RTAX_GENMASK] = + (struct sockaddr *)t->rn_key; + else + senderr(ENOBUFS); + } + switch (rtm->rtm_type) { + + case RTM_ADD: + if (info.rti_info[RTAX_GATEWAY] == NULL) + senderr(EINVAL); + error = rtrequest(RTM_ADD, info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY], info.rti_info[RTAX_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 = info.rti_info[RTAX_GENMASK]; + } + break; + + case RTM_DELETE: + error = rtrequest(RTM_DELETE, info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY], info.rti_info[RTAX_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: + rnh = rt_tables[info.rti_info[RTAX_DST]->sa_family]; + if (rnh == NULL) { + senderr(EAFNOSUPPORT); + } else if ((rt = (struct rtentry *) + rnh->rnh_lookup(info.rti_info[RTAX_DST], info.rti_info[RTAX_NETMASK], rnh))) + rt->rt_refcnt++; + else + senderr(ESRCH); + switch(rtm->rtm_type) { + + case RTM_GET: + report: + info.rti_info[RTAX_DST] = rt_key(rt); + info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; + info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_GENMASK] = rt->rt_genmask; + if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { + ifp = rt->rt_ifp; + if (ifp) { + info.rti_info[RTAX_IFP] = ifp->if_addrlist->ifa_addr; + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; + rtm->rtm_index = ifp->if_index; + } else { + info.rti_info[RTAX_IFP] = NULL; + info.rti_info[RTAX_IFA] = NULL; + } + } + len = rt_msg2(rtm->rtm_type, &info, NULL, NULL); + if (len > rtm->rtm_msglen) { + struct rt_msghdr *new_rtm; + R_Malloc(new_rtm, struct rt_msghdr *, len); + if (new_rtm == NULL) { + senderr(ENOBUFS); + } + Bcopy(rtm, new_rtm, rtm->rtm_msglen); + Free(rtm); rtm = new_rtm; + } + (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL); + rtm->rtm_flags = rt->rt_flags; + rtm->rtm_rmx = rt->rt_rmx; + rtm->rtm_addrs = info.rti_addrs; + break; + + case RTM_CHANGE: + if (info.rti_info[RTAX_GATEWAY] && (error = rt_setgate(rt, rt_key(rt), info.rti_info[RTAX_GATEWAY]))) + 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) && !info.rti_info[RTAX_GATEWAY]) + info.rti_info[RTAX_GATEWAY] = 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 (info.rti_info[RTAX_IFP] && (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP])) && + (ifp = ifa->ifa_ifp) && (info.rti_info[RTAX_IFA] || info.rti_info[RTAX_GATEWAY])) + ifa = ifaof_ifpforaddr(info.rti_info[RTAX_IFA] ? info.rti_info[RTAX_IFA] : info.rti_info[RTAX_GATEWAY], + ifp); + else if ((info.rti_info[RTAX_IFA] && (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || + (info.rti_info[RTAX_GATEWAY] && (ifa = ifa_ifwithroute(rt->rt_flags, + rt_key(rt), info.rti_info[RTAX_GATEWAY])))) + ifp = ifa->ifa_ifp; + if (ifa) { + struct ifaddr *oifa = rt->rt_ifa; + if (oifa != ifa) { + if (oifa && oifa->ifa_rtrequest) + oifa->ifa_rtrequest(RTM_DELETE, + rt, info.rti_info[RTAX_GATEWAY]); + 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, info.rti_info[RTAX_GATEWAY]); + if (info.rti_info[RTAX_GENMASK]) + rt->rt_genmask = info.rti_info[RTAX_GENMASK]; + /* FALLTHROUGH */ + 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) /* XXX can this be true? */ + rtfree(rt); + { + struct rawcb *rp = NULL; + /* + * 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 (info.rti_info[RTAX_DST]) + route_proto.sp_protocol = info.rti_info[RTAX_DST]->sa_family; + raw_input(m, &route_proto, &route_src, &route_dst); + if (rp) + rp->rcb_proto.sp_family = PF_ROUTE; + } + return (error); +#undef sa_equal +} + +static void +rt_setmetrics(u_long which, const struct rt_metrics *in, + struct rt_metrics *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(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) +{ + struct sockaddr *sa; + 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(int type, struct rt_addrinfo *rtinfo) +{ + struct rt_msghdr *rtm; + struct mbuf *m; + int i; + 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 = NULL; + 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(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w) +{ + 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++) { + struct sockaddr *sa; + + if ((sa = rtinfo->rti_info[i]) == NULL) + 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 == NULL && w != NULL && !second_time) { + 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) { + 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(int type, struct rt_addrinfo *rtinfo, int flags, int error) +{ + struct rt_msghdr *rtm; + 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 == NULL) + 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(struct ifnet *ifp) +{ + 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 == NULL) + return; + ifm = mtod(m, struct if_msghdr *); + ifm->ifm_index = ifp->if_index; + ifm->ifm_flags = 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(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) +{ + struct rt_addrinfo info; + struct sockaddr *sa = NULL; + int pass; + struct mbuf *m = NULL; + 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)) { + struct ifa_msghdr *ifam; + int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; + + info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; + info.rti_info[RTAX_IFP] = ifp->if_addrlist->ifa_addr; + info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; + info.rti_info[RTAX_BRD] = 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)) { + struct rt_msghdr *rtm; + + if (rt == NULL) + continue; + info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_DST] = sa = rt_key(rt); + info.rti_info[RTAX_GATEWAY] = 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(struct radix_node *rn, void *vw) +{ + struct walkarg *w = vw; + 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)); + info.rti_info[RTAX_DST] = rt_key(rt); + info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; + info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_GENMASK] = rt->rt_genmask; + size = rt_msg2(RTM_GET, &info, NULL, w); + if (w->w_req && w->w_tmem) { + 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 = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size); + return (error); + } + return (error); +} + +int +sysctl_iflist(int af, struct walkarg *w) +{ + struct ifnet *ifp; + 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; + info.rti_info[RTAX_IFP] = ifa->ifa_addr; + len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); + info.rti_info[RTAX_IFP] = 0; + if (w->w_req && w->w_tmem) { + struct if_msghdr *ifm; + + ifm = (struct if_msghdr *)w->w_tmem; + ifm->ifm_index = ifp->if_index; + ifm->ifm_flags = ifp->if_flags; + ifm->ifm_data = ifp->if_data; + ifm->ifm_addrs = info.rti_addrs; + error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len); + if (error) + return (error); + } + while ((ifa = ifa->ifa_next) != 0) { + if (af && af != ifa->ifa_addr->sa_family) + continue; + info.rti_info[RTAX_IFA] = ifa->ifa_addr; + info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; + info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; + len = rt_msg2(RTM_NEWADDR, &info, NULL, w); + if (w->w_req && w->w_tmem) { + 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 = SYSCTL_OUT(w->w_req, w->w_tmem, len); + if (error) + return (error); + } + } + info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = info.rti_info[RTAX_BRD] = 0; + } + return (0); +} + +static int +sysctl_rtsock(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *)arg1; + u_int namelen = arg2; + 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, NULL, NULL, NULL, + NULL +} +}; + +struct domain routedomain = + { PF_ROUTE, "route", route_init, 0, 0, + routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])], + NULL, NULL, 0, 0 }; + +DOMAIN_SET(route); diff --git a/net/slcompress.c b/net/slcompress.c new file mode 100644 index 0000000..03d1133 --- /dev/null +++ b/net/slcompress.c @@ -0,0 +1,603 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/*- + * 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. + * 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. + * + * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 + * $FreeBSD: src/sys/net/slcompress.c,v 1.19 2004/04/07 20:46:12 imp Exp $ + */ + +/* + * Routines to compress and uncompess tcp packets (for transmission + * over low speed serial lines. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/systm.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#include <net/slcompress.h> + +#ifndef SL_NO_STATS +#define INCR(counter) ++comp->counter; +#else +#define INCR(counter) +#endif + +#define BCMP(p1, p2, n) bcmp((void *)(p1), (void *)(p2), (int)(n)) +#define BCOPY(p1, p2, n) bcopy((void *)(p1), (void *)(p2), (int)(n)) + +void +sl_compress_init(struct slcompress *comp, int max_state) +{ + register u_int i; + register struct cstate *tstate = comp->tstate; + + if (max_state == -1) { + max_state = MAX_STATES - 1; + bzero((char *)comp, sizeof(*comp)); + } else { + /* Don't reset statistics */ + bzero((char *)comp->tstate, sizeof(comp->tstate)); + bzero((char *)comp->rstate, sizeof(comp->rstate)); + } + for (i = max_state; i > 0; --i) { + tstate[i].cs_id = i; + tstate[i].cs_next = &tstate[i - 1]; + } + tstate[0].cs_next = &tstate[max_state]; + tstate[0].cs_id = 0; + comp->last_cs = &tstate[0]; + comp->last_recv = 255; + comp->last_xmit = 255; + comp->flags = SLF_TOSS; +} + + +/* ENCODE encodes a number that is known to be non-zero. ENCODEZ + * checks for zero (since zero has to be encoded in the long, 3 byte + * form). + */ +#define ENCODE(n) { \ + if ((u_int16_t)(n) >= 256) { \ + *cp++ = 0; \ + cp[1] = (n); \ + cp[0] = (n) >> 8; \ + cp += 2; \ + } else { \ + *cp++ = (n); \ + } \ +} +#define ENCODEZ(n) { \ + if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \ + *cp++ = 0; \ + cp[1] = (n); \ + cp[0] = (n) >> 8; \ + cp += 2; \ + } else { \ + *cp++ = (n); \ + } \ +} + +#define DECODEL(f) { \ + if (*cp == 0) {\ + (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ + cp += 3; \ + } else { \ + (f) = htonl(ntohl(f) + (u_int32_t)*cp++); \ + } \ +} + +#define DECODES(f) { \ + if (*cp == 0) {\ + (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ + cp += 3; \ + } else { \ + (f) = htons(ntohs(f) + (u_int32_t)*cp++); \ + } \ +} + +#define DECODEU(f) { \ + if (*cp == 0) {\ + (f) = htons((cp[1] << 8) | cp[2]); \ + cp += 3; \ + } else { \ + (f) = htons((u_int32_t)*cp++); \ + } \ +} + +/* + * Attempt to compress an outgoing TCP packet and return the type of + * the result. The caller must have already verified that the protocol + * is TCP. The first mbuf must contain the complete IP and TCP headers, + * and "ip" must be == mtod(m, struct ip *). "comp" supplies the + * compression state, and "compress_cid" tells us whether it is OK + * to leave out the CID field when feasible. + * + * The caller is responsible for adjusting m->m_pkthdr.len upon return, + * if m is an M_PKTHDR mbuf. + */ +u_int +sl_compress_tcp(struct mbuf *m, struct ip *ip, struct slcompress *comp, + int compress_cid) +{ + register struct cstate *cs = comp->last_cs->cs_next; + register u_int hlen = ip->ip_hl; + register struct tcphdr *oth; + register struct tcphdr *th; + register u_int deltaS, deltaA; + register u_int changes = 0; + u_char new_seq[16]; + register u_char *cp = new_seq; + + /* + * Bail if this is an IP fragment or if the TCP packet isn't + * `compressible' (i.e., ACK isn't set or some other control bit is + * set). (We assume that the caller has already made sure the + * packet is IP proto TCP). + */ + if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) + return (TYPE_IP); + + th = (struct tcphdr *)&((int32_t *)ip)[hlen]; + if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) + return (TYPE_IP); + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need + * to locate (or create) the connection state. Special case the + * most recently used connection since it's most likely to be used + * again & we don't have to do any reordering if it's used. + */ + INCR(sls_packets) + if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || + ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || + *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { + /* + * Wasn't the first -- search for it. + * + * States are kept in a circularly linked list with + * last_cs pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + register struct cstate *lcs; + register struct cstate *lastcs = comp->last_cs; + + do { + lcs = cs; cs = cs->cs_next; + INCR(sls_searches) + if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr + && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr + && *(int32_t *)th == + ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) + goto found; + } while (cs != lastcs); + + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * last_cs to update the lru linkage. + */ + INCR(sls_misses) + comp->last_cs = lcs; + hlen += th->th_off; + hlen <<= 2; + if (hlen > m->m_len) + return TYPE_IP; + goto uncompressed; + + found: + /* + * Found it -- move to the front on the connection list. + */ + if (cs == lastcs) + comp->last_cs = lcs; + else { + lcs->cs_next = cs->cs_next; + cs->cs_next = lastcs->cs_next; + lastcs->cs_next = cs; + } + } + + /* + * Make sure that only what we expect to change changed. The first + * line of the `if' checks the IP protocol version, header length & + * type of service. The 2nd line checks the "Don't fragment" bit. + * The 3rd line checks the time-to-live and protocol (the protocol + * check is unnecessary but costless). The 4th line checks the TCP + * header length. The 5th line checks IP options, if any. The 6th + * line checks TCP options, if any. If any of these things are + * different between the previous & current datagram, we send the + * current datagram `uncompressed'. + */ + oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen]; + deltaS = hlen; + hlen += th->th_off; + hlen <<= 2; + if (hlen > m->m_len) + return TYPE_IP; + + if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] || + ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] || + ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] || + th->th_off != oth->th_off || + (deltaS > 5 && + BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || + (th->th_off > 5 && + BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) + goto uncompressed; + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if (th->th_flags & TH_URG) { + deltaS = ntohs(th->th_urp); + ENCODEZ(deltaS); + changes |= NEW_U; + } else if (th->th_urp != oth->th_urp) + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + + deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win)); + if (deltaS) { + ENCODE(deltaS); + changes |= NEW_W; + } + + deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); + if (deltaA) { + if (deltaA > 0xffff) + goto uncompressed; + ENCODE(deltaA); + changes |= NEW_A; + } + + deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); + if (deltaS) { + if (deltaS > 0xffff) + goto uncompressed; + ENCODE(deltaS); + changes |= NEW_S; + } + + switch(changes) { + + case 0: + /* + * Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if (ip->ip_len != cs->cs_ip.ip_len && + ntohs(cs->cs_ip.ip_len) == hlen) + break; + + /* FALLTHROUGH */ + + case SPECIAL_I: + case SPECIAL_D: + /* + * actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + + case NEW_S|NEW_A: + if (deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + + case NEW_S: + if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + + deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); + if (deltaS != 1) { + ENCODEZ(deltaS); + changes |= NEW_I; + } + if (th->th_flags & TH_PUSH) + changes |= TCP_PUSH_BIT; + /* + * Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = ntohs(th->th_sum); + BCOPY(ip, &cs->cs_ip, hlen); + + /* + * We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how + * many bytes of the original packet to toss so subtract the two to + * get the new packet size. + */ + deltaS = cp - new_seq; + cp = (u_char *)ip; + if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { + comp->last_xmit = cs->cs_id; + hlen -= deltaS + 4; + cp += hlen; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_id; + } else { + hlen -= deltaS + 3; + cp += hlen; + *cp++ = changes; + } + m->m_len -= hlen; + m->m_data += hlen; + *cp++ = deltaA >> 8; + *cp++ = deltaA; + BCOPY(new_seq, cp, deltaS); + INCR(sls_compressed) + return (TYPE_COMPRESSED_TCP); + + /* + * Update connection state cs & send uncompressed packet ('uncompressed' + * means a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + BCOPY(ip, &cs->cs_ip, hlen); + ip->ip_p = cs->cs_id; + comp->last_xmit = cs->cs_id; + return (TYPE_UNCOMPRESSED_TCP); +} + + +int +sl_uncompress_tcp(u_char **bufp, int len, u_int type, struct slcompress *comp) +{ + u_char *hdr, *cp; + u_int hlen; + int vjlen; + + cp = bufp? *bufp: NULL; + vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen); + if (vjlen < 0) + return (0); /* error */ + if (vjlen == 0) + return (len); /* was uncompressed already */ + + cp += vjlen; + len -= vjlen; + + /* + * At this point, cp points to the first byte of data in the + * packet. If we're not aligned on a 4-byte boundary, copy the + * data down so the ip & tcp headers will be aligned. Then back up + * cp by the tcp/ip header length to make room for the reconstructed + * header (we assume the packet we were handed has enough space to + * prepend 128 bytes of header). + */ + if ((intptr_t)cp & 3) { + if (len > 0) + BCOPY(cp, ((intptr_t)cp &~ 3), len); + cp = (u_char *)((intptr_t)cp &~ 3); + } + cp -= hlen; + len += hlen; + BCOPY(hdr, cp, hlen); + + *bufp = cp; + return (len); +} + +/* + * Uncompress a packet of total length total_len. The first buflen + * bytes are at buf; this must include the entire (compressed or + * uncompressed) TCP/IP header. This procedure returns the length + * of the VJ header, with a pointer to the uncompressed IP header + * in *hdrp and its length in *hlenp. + */ +int +sl_uncompress_tcp_core(u_char *buf, int buflen, int total_len, + u_int type, struct slcompress *comp, + u_char **hdrp, u_int *hlenp) +{ + register u_char *cp; + register uint32_t hlen, changes; + register struct tcphdr *th; + register struct cstate *cs; + register struct ip *ip; + register u_int16_t *bp; + register u_int vjlen; + + switch (type) { + + case TYPE_UNCOMPRESSED_TCP: + ip = (struct ip *) buf; + if (ip->ip_p >= MAX_STATES) + goto bad; + cs = &comp->rstate[comp->last_recv = ip->ip_p]; + comp->flags &=~ SLF_TOSS; + ip->ip_p = IPPROTO_TCP; + /* + * Calculate the size of the TCP/IP header and make sure that + * we don't overflow the space we have available for it. + */ + hlen = ip->ip_hl << 2; + if (hlen + sizeof(struct tcphdr) > buflen) + goto bad; + hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2; + if (hlen > MAX_HDR || hlen > buflen) + goto bad; + BCOPY(ip, &cs->cs_ip, hlen); + cs->cs_hlen = hlen; + INCR(sls_uncompressedin) + *hdrp = (u_char *) &cs->cs_ip; + *hlenp = hlen; + return (0); + + default: + goto bad; + + case TYPE_COMPRESSED_TCP: + break; + } + /* We've got a compressed packet. */ + INCR(sls_compressedin) + cp = buf; + changes = *cp++; + if (changes & NEW_C) { + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. */ + if (*cp >= MAX_STATES) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->last_recv = *cp++; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if (comp->flags & SLF_TOSS) { + INCR(sls_tossed) + return (-1); + } + } + cs = &comp->rstate[comp->last_recv]; + hlen = cs->cs_ip.ip_hl << 2; + th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; + th->th_sum = htons((*cp << 8) | cp[1]); + cp += 2; + if (changes & TCP_PUSH_BIT) + th->th_flags |= TH_PUSH; + else + th->th_flags &=~ TH_PUSH; + + switch (changes & SPECIALS_MASK) { + case SPECIAL_I: + { + register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; + th->th_ack = htonl(ntohl(th->th_ack) + i); + th->th_seq = htonl(ntohl(th->th_seq) + i); + } + break; + + case SPECIAL_D: + th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) + - cs->cs_hlen); + break; + + default: + if (changes & NEW_U) { + th->th_flags |= TH_URG; + DECODEU(th->th_urp) + } else + th->th_flags &=~ TH_URG; + if (changes & NEW_W) + DECODES(th->th_win) + if (changes & NEW_A) + DECODEL(th->th_ack) + if (changes & NEW_S) + DECODEL(th->th_seq) + break; + } + if (changes & NEW_I) { + DECODES(cs->cs_ip.ip_id) + } else + cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Fill in the IP total length and update the IP + * header checksum. + */ + vjlen = cp - buf; + buflen -= vjlen; + if (buflen < 0) + /* we must have dropped some characters (crc should detect + * this but the old slip framing won't) */ + goto bad; + + total_len += cs->cs_hlen - vjlen; + cs->cs_ip.ip_len = htons(total_len); + + /* recompute the ip header checksum */ + bp = (u_int16_t *) &cs->cs_ip; + cs->cs_ip.ip_sum = 0; + for (changes = 0; hlen > 0; hlen -= 2) + changes += *bp++; + changes = (changes & 0xffff) + (changes >> 16); + changes = (changes & 0xffff) + (changes >> 16); + cs->cs_ip.ip_sum = ~ changes; + + *hdrp = (u_char *) &cs->cs_ip; + *hlenp = cs->cs_hlen; + return vjlen; + +bad: + comp->flags |= SLF_TOSS; + INCR(sls_errorin) + return (-1); +} diff --git a/net/slcompress.h b/net/slcompress.h new file mode 100644 index 0000000..511a8d8 --- /dev/null +++ b/net/slcompress.h @@ -0,0 +1,161 @@ +/* + * Definitions for tcp compression routines. + * + * 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. + * 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. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * $FreeBSD: src/sys/net/slcompress.h,v 1.19 2005/01/07 01:45:35 imp Exp $ + */ + +#ifndef _NET_SLCOMPRESS_H_ +#define _NET_SLCOMPRESS_H_ + +#include <netinet/ip.h> /* struct ip */ + +struct mbuf; + +#define MAX_STATES 16 /* must be > 2 and < 256 */ +#define MAX_HDR 128 + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgement, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP 0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP 0x80 +#define TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + struct cstate *cs_next; /* next most recently used cstate (xmit only) */ + u_int16_t cs_hlen; /* size of hdr (receive only) */ + u_char cs_id; /* connection # associated with this state */ + u_char cs_filler; + union { + char csu_hdr[MAX_HDR]; + struct ip csu_ip; /* ip/tcp hdr from most recent packet */ + } slcs_u; +}; +#define cs_ip slcs_u.csu_ip +#define cs_hdr slcs_u.csu_hdr + +/* + * all the state data for one serial line (we need one of these + * per line). + */ +struct slcompress { + struct cstate *last_cs; /* most recently used tstate */ + u_char last_recv; /* last rcvd conn. id */ + u_char last_xmit; /* last sent conn. id */ + u_int16_t flags; +#ifndef SL_NO_STATS + int sls_packets; /* outbound packets */ + int sls_compressed; /* outbound compressed packets */ + int sls_searches; /* searches for connection state */ + int sls_misses; /* times couldn't find conn. state */ + int sls_uncompressedin; /* inbound uncompressed packets */ + int sls_compressedin; /* inbound compressed packets */ + int sls_errorin; /* inbound unknown type packets */ + int sls_tossed; /* inbound packets tossed because of error */ +#endif + struct cstate tstate[MAX_STATES]; /* xmit connection states */ + struct cstate rstate[MAX_STATES]; /* receive connection states */ +}; +/* flag values */ +#define SLF_TOSS 1 /* tossing rcvd frames because of input err */ + +void sl_compress_init(struct slcompress *, int); +u_int sl_compress_tcp(struct mbuf *, struct ip *, struct slcompress *, int); +int sl_uncompress_tcp(u_char **, int, u_int, struct slcompress *); +int sl_uncompress_tcp_core(u_char *, int, int, u_int, + struct slcompress *, u_char **, u_int *); + +#endif /* !_NET_SLCOMPRESS_H_ */ diff --git a/netinet/icmp_var.h b/netinet/icmp_var.h new file mode 100644 index 0000000..31eea3b --- /dev/null +++ b/netinet/icmp_var.h @@ -0,0 +1,81 @@ +/* + * 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 + */ + +#ifndef _NETINET_ICMP_VAR_H_ +#define _NETINET_ICMP_VAR_H_ + +#include <netinet/ip_icmp.h> /* ICMP_MAXTYPE */ + +/* + * 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_allecho; /* all echo requests dropped */ + 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 +SYSCTL_DECL(_net_inet_icmp); +extern struct icmpstat icmpstat; +#endif + +#endif diff --git a/netinet/if_ether.c b/netinet/if_ether.c new file mode 100644 index 0000000..e068674 --- /dev/null +++ b/netinet/if_ether.c @@ -0,0 +1,644 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/if_ether.c,v 1.136 2005/03/13 11:23:22 glebius Exp $ + */ + + +/* + * Ethernet address resolution protocol. + * TODO: + * add "inuse/lock" bit (or ref. count) along with valid bit + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opt_inet.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/queue.h> +#include <sys/sysctl.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/if_types.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_DECL(_net_link_ether); +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, 0}; +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(int, struct rtentry *, struct sockaddr *); +static void arprequest(struct arpcom *, struct in_addr *, struct in_addr *, u_char *); +void arpintr(void); +static void arptfree(struct llinfo_arp *); +static void arptimer(void *); +static struct llinfo_arp + *arplookup(u_long, int, int); +#ifdef INET +static void in_arpinput(struct mbuf *); +#endif + +/* + * Timeout routine. Age arp_tab entries periodically. + */ +/* ARGSUSED */ +static void +arptimer(void *ignored_arg) +{ + int s = splnet(); + struct llinfo_arp *la, *ola; + + la = llinfo_arp.lh_first; + 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(int req, struct rtentry *rt, struct sockaddr *sa) +{ + struct sockaddr *gate; + struct llinfo_arp *la; + static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK, 0, 0, 0, 0, 0, { 0 } }; + 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; + gate = rt->rt_gateway; + la = (struct llinfo_arp *)rt->rt_llinfo; + 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 && + rt_mask(rt) != NULL && + 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, + &SIN(rt_key(rt))->sin_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(struct arpcom *ac, struct in_addr *sip, struct in_addr *tip, u_char *enaddr) +{ + struct mbuf *m; + struct ether_header *eh; + 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( + struct arpcom *ac, + struct rtentry *rt, + struct mbuf *m, + struct sockaddr *dst, + u_char *desten, + struct rtentry *rt0) +{ + struct llinfo_arp *la = 0; + 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) { + char addrbuf[INET_ADDRSTRLEN]; + log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n", + inet_ntoa_r(SIN(dst)->sin_addr, addrbuf)); + 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), + &(SIN(dst)->sin_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) +{ + struct mbuf *m; + 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(struct mbuf *m) +{ + struct ether_arp *ea; + struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; + struct ether_header *eh; + struct llinfo_arp *la = 0; + struct rtentry *rt; + struct in_ifaddr *ia; + struct in_ifaddr *maybe_ia = 0; + struct sockaddr_dl *sdl; + struct sockaddr sa; + struct in_addr isaddr, itaddr, myaddr; + int op; + char addrbuf[INET_ADDRSTRLEN]; + + 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_r(isaddr, addrbuf)); + 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_r(isaddr, addrbuf)); + 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_r(isaddr, addrbuf), + (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_r(itaddr, addrbuf)); +#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(struct llinfo_arp *la) +{ + struct rtentry *rt = la->la_rt; + 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(u_long addr, int create, int proxy) +{ + struct rtentry *rt; + static struct sockaddr_inarp sin = {sizeof(sin), AF_INET, 0, { 0 }, { 0 }, 0, 0 }; + const char *why = 0; + + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + 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) { + char addrbuf[INET_ADDRSTRLEN]; + log(LOG_DEBUG, "arplookup %s failed: %s\n", + inet_ntoa_r(sin.sin_addr, addrbuf), why); + return 0; + } else if (why) { + return 0; + } + return ((struct llinfo_arp *)rt->rt_llinfo); +} + +void +arp_ifinit(struct arpcom *ac, struct ifaddr *ifa) +{ + if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) + arprequest(ac, &(IA_SIN(ifa)->sin_addr), + &(IA_SIN(ifa)->sin_addr), ac->ac_enaddr); + ifa->ifa_rtrequest = arp_rtrequest; + ifa->ifa_flags |= RTF_CLONING; +} diff --git a/netinet/if_ether.h b/netinet/if_ether.h new file mode 100644 index 0000000..f45c414 --- /dev/null +++ b/netinet/if_ether.h @@ -0,0 +1,176 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/if_ether.h,v 1.32 2005/02/22 13:04:03 glebius Exp $ + */ + + +#ifndef _NETINET_IF_ETHER_H_ +#define _NETINET_IF_ETHER_H_ + +#include <netinet/in.h> /* struct in_addr */ +#include <net/ethernet.h> +#include <net/if_arp.h> + +#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 + +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(struct arpcom *, struct rtentry *, struct mbuf *, + struct sockaddr *, u_char *, struct rtentry *); +void arp_ifinit(struct arpcom *, struct ifaddr *); +int ether_addmulti(struct ifreq *, struct arpcom *); +int ether_delmulti(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/netinet/igmp.c b/netinet/igmp.c new file mode 100644 index 0000000..7078914 --- /dev/null +++ b/netinet/igmp.c @@ -0,0 +1,473 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +/* + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <rtems/rtems_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 (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(void) +{ + 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(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(struct mbuf *m, 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(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(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(void) +{ + 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(void) +{ + 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(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/netinet/igmp.h b/netinet/igmp.h new file mode 100644 index 0000000..b397ccd --- /dev/null +++ b/netinet/igmp.h @@ -0,0 +1,97 @@ +/* + * 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 + */ + +#ifndef _NETINET_IGMP_H_ +#define _NETINET_IGMP_H_ + +#include <netinet/in.h> /* struct in_addr */ + +/* + * 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/netinet/igmp_var.h b/netinet/igmp_var.h new file mode 100644 index 0000000..d1454e0 --- /dev/null +++ b/netinet/igmp_var.h @@ -0,0 +1,105 @@ +/* + * 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. + * 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: @(#)igmp_var.h 8.1 (Berkeley) 7/19/93 + * $FreeBSD: src/sys/netinet/igmp_var.h,v 1.20 2004/04/07 20:46:13 imp Exp $ + */ + +#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 +#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(void); +void igmp_input(struct mbuf *, int); +void igmp_joingroup(struct in_multi *); +void igmp_leavegroup(struct in_multi *); +void igmp_fasttimo(void); +void igmp_slowtimo(void); + +SYSCTL_DECL(_net_inet_igmp); + +#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/netinet/in.c b/netinet/in.c new file mode 100644 index 0000000..cb08232 --- /dev/null +++ b/netinet/in.c @@ -0,0 +1,711 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/in.c,v 1.75 2004/04/07 20:46:13 imp Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <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(struct sockaddr_in *); +static int in_ifinit(struct ifnet *, + struct in_ifaddr *, struct sockaddr_in *, int); +static void in_ifscrub(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(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(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(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. + */ +int +in_control(struct socket *so, u_long cmd, caddr_t data, 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; + 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: + ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr; + ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr); + 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(struct ifnet *ifp, 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(struct ifnet *ifp, 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(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(struct in_addr *ap, 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(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/netinet/in_cksum.c b/netinet/in_cksum.c new file mode 100644 index 0000000..39dc9ac --- /dev/null +++ b/netinet/in_cksum.c @@ -0,0 +1,186 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/mbuf.h> + +/* + * Try to use a CPU specific version, then punt to the portable C one. + */ + + +#if (defined(__GNUC__) && (defined(__arm__) && !defined(__thumb__))) + +/* This currently does not support Thumb assembly */ +#include "in_cksum_arm.h" + +#elif (defined(__GNUC__) && defined(__i386__)) + +#include "in_cksum_i386.h" + +#elif (defined(__GNUC__) && (defined(__mc68000__) || defined(__m68k__))) + +#include "in_cksum_m68k.h" +#elif (defined(__GNUC__) && defined(__PPC__)) + +#include "in_cksum_powerpc.h" + +#elif (defined(__GNUC__) && defined(__nios2__)) + +#include "in_cksum_nios2.h" + +#elif (defined(__GNUC__) && defined(__sparc__)) + +#include "in_cksum_sparc.h" + +#else + +#include <stdio.h> /* for puts */ + +/* + * 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. + */ + +#define ADDCARRY(x) (x > 65535L ? x -= 65535L : x) +#define REDUCE \ + {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} + +int +in_cksum( + struct mbuf *m, + uint32_t len ) +{ + register u_short *w; + register int32_t sum = 0; + register int32_t 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 & (intptr_t) 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) + puts("cksum: out of data"); + 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/netinet/in_cksum_arm.h b/netinet/in_cksum_arm.h new file mode 100644 index 0000000..d884a0f --- /dev/null +++ b/netinet/in_cksum_arm.h @@ -0,0 +1,236 @@ +/* $NetBSD: in_cksum_arm.c,v 1.3 2001/12/08 21:18:50 chris Exp $ */ + +/* + * ARM version: + * + * Copyright (c) 1997 Mark Brinicome + * Copyright (c) 1997 Causality Limited + * + * Based on the sparc version. + */ + +/* + * Sparc version: + * + * Copyright (c) 1995 Zubin Dittia. + * Copyright (c) 1995 Matthew R. Green. + * Copyright (c) 1994 Charles M. Hannum. + * 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. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * ARM version. + */ + +#define ADD64 __asm __volatile(" \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adds %1,%7,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adcs %1,%1,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adcs %1,%1,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adcs %1,%1,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + adcs %1,%1,#0\n" \ + : "=r" (w), "=r" (sum), "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ + : "0" (w), "r" (sum) \ + : "cc") + +#define ADD32 __asm __volatile(" \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adds %1,%7,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adcs %1,%1,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + adcs %1,%1,#0\n" \ + : "=r" (w), "=r" (sum), "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ + : "0" (w), "r" (sum) \ + : "cc") + +#define ADD16 __asm __volatile(" \n\ + ldmia %0!, {%2, %3, %4, %5} \n\ + adds %1,%7,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,%4; adcs %1,%1,%5 \n\ + adcs %1,%1,#0\n" \ + : "=r" (w), "=r" (sum), "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ + : "0" (w), "r" (sum) \ + : "cc") + +#define ADD8 __asm __volatile(" \n\ + ldmia %0!, {%2, %3} \n\ + adds %1,%5,%2; adcs %1,%1,%3 \n\ + adcs %1,%1,#0\n" \ + : "=r" (w), "=r" (sum), "=&r" (tmp1), "=&r" (tmp2) \ + : "0" (w), "r" (sum) \ + : "cc" ) + +#define ADD4 __asm __volatile(" \n\ + ldr %2,[%0],#4 \n\ + adds %1,%4,%2 \n\ + adcs %1,%1,#0\n" \ + : "=r" (w), "=r" (sum), "=&r" (tmp1) \ + : "0" (w), "r" (sum) \ + : "cc") + +/*#define REDUCE {sum = (sum & 0xffff) + (sum >> 16);}*/ +#define REDUCE __asm __volatile(" \n\ + mov %2, #0x00ff \n\ + orr %2, %2, #0xff00 \n\ + and %2, %0, %2 \n\ + add %0, %2, %0, lsr #16\n" \ + : "=r" (sum) \ + : "0" (sum), "r" (tmp1)) + +#define ADDCARRY {if (sum > 0xffff) sum -= 0xffff;} +#define ROL {sum = sum << 8;} /* depends on recent REDUCE */ +#define ADDBYTE {ROL; sum += (*w << 8); byte_swapped ^= 1;} +#define ADDSHORT {sum += *(u_short *)w;} +#define ADVANCE(n) {w += n; mlen -= n;} +#define ADVANCEML(n) {mlen -= n;} + +static __inline__ int +in_cksum_internal(struct mbuf *m, int off, int len, u_int sum) +{ + u_char *w; + int mlen = 0; + int byte_swapped = 0; + + /* + * Declare four temporary registers for use by the asm code. We + * allow the compiler to pick which specific machine registers to + * use, instead of hard-coding this in the asm code above. + */ + register u_int tmp1=0, tmp2, tmp3, tmp4; + + for (; m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + w = mtod(m, u_char *) + off; + mlen = m->m_len - off; + off = 0; + if (len < mlen) + mlen = len; + len -= mlen; + + /* + * Ensure that we're aligned on a word boundary here so + * that we can do 32 bit operations below. + */ + if ((3 & (long)w) != 0) { + REDUCE; + if ((1 & (long)w) != 0 && mlen >= 1) { + ADDBYTE; + ADVANCE(1); + } + if ((2 & (long)w) != 0 && mlen >= 2) { + ADDSHORT; + ADVANCE(2); + } + } + + /* + * Do as many 32 bit operations as possible using the + * 64/32/16/8/4 macro's above, using as many as possible of + * these. + */ + + while (mlen >= 64) { + ADD64; + ADVANCEML(64); + } + if (mlen >= 32) { + ADD32; + ADVANCEML(32); + } + if (mlen >= 16) { + ADD16; + ADVANCEML(16); + } + if (mlen >= 8) { + ADD8; + ADVANCEML(8); + } + if (mlen >= 4) { + ADD4; + ADVANCEML(4) + } + if (mlen == 0) + continue; + + REDUCE; + if (mlen >= 2) { + ADDSHORT; + ADVANCE(2); + } + if (mlen == 1) { + ADDBYTE; + } + } + if (byte_swapped) { + REDUCE; + ROL; + } + REDUCE; + ADDCARRY; + + return (0xffff ^ sum); +} + +int +in_cksum( + struct mbuf *m, + int len) +{ + int cksum; + cksum =in_cksum_internal(m, 0, len, 0); + return cksum; +} diff --git a/netinet/in_cksum_i386.h b/netinet/in_cksum_i386.h new file mode 100644 index 0000000..1174287 --- /dev/null +++ b/netinet/in_cksum_i386.h @@ -0,0 +1,202 @@ +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * This implementation is 386 version. + */ + +#include <stdio.h> /* for puts */ + +#undef ADDCARRY +#define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff +#define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);} + +/* + * Thanks to gcc we don't have to guess + * which registers contain sum & w. + */ +#define ADD(n) __asm__ volatile \ + ("addl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w)) +#define ADDC(n) __asm__ volatile \ + ("adcl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w)) +#define LOAD(n) __asm__ volatile \ + ("movb " #n "(%1), %0" : "=q" (junk) : "r" (w)) +#define MOP __asm__ volatile \ + ("adcl $0, %0" : "=r" (sum) : "0" (sum)) + +int +in_cksum( + struct mbuf *m, + int len ) +{ + register u_short *w; + register unsigned sum = 0; + register int mlen = 0; + int byte_swapped = 0; + union { char c[2]; u_short s; } su; + + 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. + */ + + /* su.c[0] is already saved when scanning previous + * mbuf. sum was REDUCEd when we found mlen == -1 + */ + su.c[1] = *(u_char *)w; + sum += su.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 long boundary so we do longword aligned + * memory operations + */ + if (3 & (int) w) { + REDUCE; + if ((1 & (int) w) && (mlen > 0)) { + sum <<= 8; + su.c[0] = *(char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + if ((2 & (int) w) && (mlen >= 2)) { + sum += *w++; + mlen -= 2; + } + } + /* + * Advance to a 486 cache line boundary. + */ + if (4 & (int) w && mlen >= 4) { + ADD(0); + MOP; + w += 2; + mlen -= 4; + } + if (8 & (int) w && mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + /* + * Do as much of the checksum as possible 32 bits at at time. + * In fact, this loop is unrolled to make overhead from + * branches &c small. + */ + mlen -= 1; + while ((mlen -= 32) >= 0) { + u_char junk; + /* + * Add with carry 16 words and fold in the last + * carry by adding a 0 with carry. + * + * The early ADD(16) and the LOAD(32) are to load + * the next 2 cache lines in advance on 486's. The + * 486 has a penalty of 2 clock cycles for loading + * a cache line, plus whatever time the external + * memory takes to load the first word(s) addressed. + * These penalties are unavoidable. Subsequent + * accesses to a cache line being loaded (and to + * other external memory?) are delayed until the + * whole load finishes. These penalties are mostly + * avoided by not accessing external memory for + * 8 cycles after the ADD(16) and 12 cycles after + * the LOAD(32). The loop terminates when mlen + * is initially 33 (not 32) to guaranteed that + * the LOAD(32) is within bounds. + */ + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + LOAD(32); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + } + mlen += 32 + 1; + if (mlen >= 32) { + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + mlen -= 32; + } + if (mlen >= 16) { + ADD(0); + ADDC(4); + ADDC(8); + ADDC(12); + MOP; + w += 8; + mlen -= 16; + } + if (mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + if (mlen == 0 && byte_swapped == 0) + continue; /* worth 1% maybe ?? */ + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + if (byte_swapped) { + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + su.c[1] = *(char *)w; + sum += su.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + /* + * This mbuf has odd number of bytes. + * There could be a word split betwen + * this mbuf and the next mbuf. + * Save the last byte (to prepend to next mbuf). + */ + su.c[0] = *(char *)w; + } + + if (len) + puts("cksum: out of data"); + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte is shifted left by 8 bits) */ + su.c[1] = 0; + sum += su.s; + } + REDUCE; + return (~sum & 0xffff); +} diff --git a/netinet/in_cksum_m68k.h b/netinet/in_cksum_m68k.h new file mode 100644 index 0000000..32e6978 --- /dev/null +++ b/netinet/in_cksum_m68k.h @@ -0,0 +1,221 @@ +/* + * 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 + */ + +#include <sys/param.h> +#include <sys/mbuf.h> + +#if defined(__mcoldfire__) +# define IS_COLDFIRE 1 +#else +# define IS_COLDFIRE 0 +#endif + +#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( 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" +#if IS_COLDFIRE + "addql #1,%2 | Clear X (extended carry flag)\n\t" + "subql #1,%2 | \n\t" +#else + "andi #0xf,%%cc | Clear X (extended carry flag)\n\t" +#endif + "jmp %%pc@(2f-.-2:b,%3) | Jump into loop\n" + "1: | 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" + "2: | End of unrolled loop\n\t" +#if IS_COLDFIRE + "moveq #0,%3 | Add in last carry\n\t" + "addxl %3,%0 |\n\t" + "subql #1,%2 | Update loop count\n\t" + "bplb 1b | Loop (with X clear) if not done\n\t" + "movel #0xffff,%2 | Get word mask\n\t" + "movel %0,%3 | Fold 32 bit sum to 16 bits\n\t" + "swap %3 |\n\t" + "andl %2,%0 | Mask to 16-bit sum\n\t" + "andl %2,%3 | Mask to 16-bit sum\n\t" + "addl %3,%0 |\n\t" + "movel %0,%3 | Add in last carry\n\t" + "swap %3 |\n\t" + "addl %3,%0 |\n\t" + "andl %2,%0 | Mask to 16-bit sum\n\t" +#else + "dbf %2,1b | (NB- dbf 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" +#endif + : + "=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); +} diff --git a/netinet/in_cksum_nios2.h b/netinet/in_cksum_nios2.h new file mode 100644 index 0000000..1b34a28 --- /dev/null +++ b/netinet/in_cksum_nios2.h @@ -0,0 +1,248 @@ + +/* + * Altera Nios2 CRC checksum computation + * + * Author: Jeffrey O. Hill + * + * Copyright 2012. Los Alamos National Security, LLC. + * This material was produced under U.S. Government contract + * DE-AC52-06NA25396 for Los Alamos National Laboratory (LANL), + * which is operated by Los Alamos National Security, LLC for + * the U.S. Department of Energy. The U.S. Government has rights + * to use, reproduce, and distribute this software. NEITHER THE + * GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY + * WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR + * THE USE OF THIS SOFTWARE. + * + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * Copyright (c) 1997 Mark Brinicome + * Copyright (c) 1997 Causality Limited + * + * Copyright (c) 1995 Zubin Dittia. + * Copyright (c) 1995 Matthew R. Green. + * Copyright (c) 1994 Charles M. Hannum. + * 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. + * + * Based on the arm / sparc version, but using instead + * mostly inline functions in place of naaasty macros. + * + * It would be a great idea to somehow detect at runtime + * that the Nios2 has a user defined instruction that + * computes the CRC and invoke it here (we could call a + * function in the BSP). + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <machine/in_cksum.h> + +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + */ +static inline uint32_t _NIOS2_Add_ones_complement_64 +( uint32_t sum, const uint32_t * const pWd ) +{ + sum = _NIOS2_Add_ones_complement ( sum, pWd[0] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[1] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[2] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[3] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[4] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[5] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[6] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[7] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[8] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[9] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[10] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[11] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[12] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[13] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[14] ); + return _NIOS2_Add_ones_complement ( sum, pWd[15] ); +} + +static inline uint32_t _NIOS2_Add_ones_complement_32 +( uint32_t sum, const uint32_t * const pWd ) +{ + sum = _NIOS2_Add_ones_complement ( sum, pWd[0] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[1] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[2] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[3] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[4] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[5] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[6] ); + return _NIOS2_Add_ones_complement ( sum, pWd[7] ); +} + +static inline uint32_t _NIOS2_Add_ones_complement_16 +( uint32_t sum, const uint32_t * const pWd ) +{ + sum = _NIOS2_Add_ones_complement ( sum, pWd[0] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[1] ); + sum = _NIOS2_Add_ones_complement ( sum, pWd[2] ); + return _NIOS2_Add_ones_complement ( sum, pWd[3] ); +} + +static inline uint32_t _NIOS2_Add_ones_complement_8 +( uint32_t sum, const uint32_t * const pWd ) +{ + sum = _NIOS2_Add_ones_complement ( sum, pWd[0] ); + return _NIOS2_Add_ones_complement ( sum, pWd[1] ); +} + +static inline uint32_t _NIOS2_Add_ones_complement_4 +( uint32_t sum, const uint32_t * const pWd ) +{ + return _NIOS2_Add_ones_complement ( sum, pWd[0] ); +} + +static inline uint32_t _NIOS2_Reduce_checksum ( uint32_t a ) +{ + uint32_t tmp; + __asm__ __volatile__ ( + " srli %1, %0, 16 \n" /* tmp = a >> 16 */ + " andi %0, %0, 0xffff \n" /* a = a & 0xffff */ + " add %0, %0, %1 \n" /* a = a + tmp */ + : "+&r"(a), "=&r"(tmp) + ); + return a; +} + +#define combineTokens( A, B ) A ## B + +#define ADD_AND_ADVANCE( N ) \ +if ( mlen >= N ) { \ + sum = combineTokens ( _NIOS2_Add_ones_complement_, N ) \ + ( sum, ( uint32_t * ) w ); \ + mlen -= N; \ + w += N; \ +} + +static int +in_cksum_internal(struct mbuf *m, int off, int len, u_int sum) +{ + const uint8_t * w; + int mlen = 0; + int byte_swapped = 0; + + for (; m && len; m = m->m_next) + { + if (m->m_len == 0) + continue; + w = mtod(m, u_char *) + off; + mlen = m->m_len - off; + off = 0; + if (len < mlen) + mlen = len; + len -= mlen; + + /* + * Ensure that we're aligned on a word boundary here so + * that we can do 32 bit operations below. + */ + if ((3 & (uint32_t)w) != 0) + { + sum = _NIOS2_Reduce_checksum ( sum ); + if ((1 & (uint32_t)w) != 0 && mlen >= 1) + { + sum <<= 8u; + sum += *w << 8u; + byte_swapped ^= 1; + w += 1; + mlen -= 1; + } + if ((2 & (uint32_t)w) != 0 && mlen >= 2) + { + sum += *(uint16_t *)w; + w += 2; + mlen -= 2; + } + } + + /* + * instead of using a loop, process in unrolled chunks + */ + while ( mlen >= 64 ) + { + sum = _NIOS2_Add_ones_complement_64 + ( sum, ( uint32_t * ) w ); + mlen -= 64; + w += 64; + } + ADD_AND_ADVANCE ( 32 ); + ADD_AND_ADVANCE ( 16 ); + ADD_AND_ADVANCE ( 8 ); + ADD_AND_ADVANCE ( 4 ); + + if ( mlen > 0 ) + { + sum = _NIOS2_Reduce_checksum ( sum ); + if ( mlen >= 2 ) + { + sum += *(uint16_t *)w; + w += 2; + mlen -= 2; + } + if ( mlen == 1 ) + { + sum <<= 8u; + sum += *w << 8u; + byte_swapped ^= 1; + } + } + } + if ( byte_swapped ) + { + sum = _NIOS2_Reduce_checksum ( sum ); + sum <<= 8u; + } + sum = _NIOS2_Add_ones_complement_word_halves ( sum ); + sum ^= 0xffff; + return sum; +} + +int +in_cksum ( + struct mbuf *m, + int len ) +{ + return in_cksum_internal ( m, 0, len, 0 ); +} diff --git a/netinet/in_cksum_powerpc.h b/netinet/in_cksum_powerpc.h new file mode 100644 index 0000000..ad5e9e1 --- /dev/null +++ b/netinet/in_cksum_powerpc.h @@ -0,0 +1,172 @@ +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * This implementation is the PowerPC version. + */ + +#include <stdio.h> /* for puts */ + +#undef ADDCARRY +#define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff +#define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);} + +/* + * Thanks to gcc we don't have to guess + * which registers contain sum & w. + */ + +#define LDTMP(n) tmp = *((u_int *)((u_char *)w + n)) + +#define ADD(n) \ + LDTMP(n); \ + __asm__ volatile("addc %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp)) + +#define ADDC(n) \ + LDTMP(n); \ + __asm__ volatile("adde %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp)) + +#define MOP \ + tmp = 0; \ + __asm__ volatile("adde %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp)) + +#define LOAD(n) junk = (u_char) *((volatile u_char *) w + n) + + +int +in_cksum( + struct mbuf *m, + int len +) +{ + u_char junk; + register u_short *w; + register unsigned sum = 0; + register unsigned tmp; + register int mlen = 0; + int byte_swapped = 0; + union { char c[2]; u_short s; } su; + + 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. + */ + + /* su.c[0] is already saved when scanning previous + * mbuf. sum was REDUCEd when we found mlen == -1 + */ + su.c[1] = *(u_char *)w; + sum += su.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 long boundary so we do longword aligned + * memory operations + */ + if (3 & (int) w) { + REDUCE; + if ((1 & (int) w) && (mlen > 0)) { + sum <<= 8; + su.c[0] = *(char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + if ((2 & (int) w) && (mlen >= 2)) { + sum += *w++; + mlen -= 2; + } + } + + /* + * Do as much of the checksum as possible 32 bits at at time. + * In fact, this loop is unrolled to keep overhead from + * branches small. + */ + while (mlen >= 32) { + /* + * Add with carry 16 words and fold in the last + * carry by adding a 0 with carry. + * + * The early ADD(16) and the LOAD(32) are intended + * to help get the data into the cache. + */ + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + LOAD(32); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + mlen -= 32; + } + if (mlen >= 16) { + ADD(0); + ADDC(4); + ADDC(8); + ADDC(12); + MOP; + w += 8; + mlen -= 16; + } + if (mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + if (mlen == 0 && byte_swapped == 0) + continue; /* worth 1% maybe ?? */ + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + if (byte_swapped) { + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + su.c[1] = *(char *)w; + sum += su.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + /* + * This mbuf has odd number of bytes. + * There could be a word split betwen + * this mbuf and the next mbuf. + * Save the last byte (to prepend to next mbuf). + */ + su.c[0] = *(char *)w; + } + + if (len) + puts("cksum: out of data"); + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte is shifted left by 8 bits) */ + su.c[1] = 0; + sum += su.s; + } + REDUCE; + return (~sum & 0xffff); +} diff --git a/netinet/in_cksum_sparc.h b/netinet/in_cksum_sparc.h new file mode 100644 index 0000000..b88ce92 --- /dev/null +++ b/netinet/in_cksum_sparc.h @@ -0,0 +1,269 @@ +/* $NetBSD: in_cksum.c,v 1.12.10.4 2005/12/11 10:28:36 christos Exp $ */ + +/* + * Copyright (c) 1995 Matthew R. Green. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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, and it's contributors. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the 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/11/93 + */ + +/* + * Copyright (c) 1995 Zubin Dittia. + * Copyright (c) 1994, 1998 Charles M. Hannum. + * + * 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, and it's contributors. + * + * 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/11/93 + */ + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <netinet/in.h> +#include <rtems/rtems_netinet_in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * SPARC version. + */ + +/* + * The checksum computation code here is significantly faster than its + * vanilla C counterpart (by significantly, I mean 2-3 times faster if + * the data is in cache, and 1.5-2 times faster if the data is not in + * cache). + * We optimize on three fronts: + * 1. By using the add-with-carry (addxcc) instruction, we can use + * 32-bit operations instead of 16-bit operations. + * 2. By unrolling the main loop to reduce branch overheads. + * 3. By doing a sequence of load,load,add,add,load,load,add,add, + * we can avoid the extra stall cycle which is incurred if the + * instruction immediately following a load tries to use the + * target register of the load. + * Another possible optimization is to replace a pair of 32-bit loads + * with a single 64-bit load (ldd) instruction, but I found that although + * this improves performance somewhat on Sun4c machines, it actually + * reduces performance considerably on Sun4m machines (I don't know why). + * So I chose to leave it out. + * + * Zubin Dittia (zubin@dworkin.wustl.edu) + */ + +#define Asm __asm __volatile +#define ADD64 Asm(" ld [%4+ 0],%1; ld [%4+ 4],%2; \ + addcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+ 8],%1; ld [%4+12],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+16],%1; ld [%4+20],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+24],%1; ld [%4+28],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+32],%1; ld [%4+36],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+40],%1; ld [%4+44],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+48],%1; ld [%4+52],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+56],%1; ld [%4+60],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + addxcc %0,0,%0" \ + : "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\ + : "0" (sum), "r" (w)) +#define ADD32 Asm(" ld [%4+ 0],%1; ld [%4+ 4],%2; \ + addcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+ 8],%1; ld [%4+12],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+16],%1; ld [%4+20],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+24],%1; ld [%4+28],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + addxcc %0,0,%0" \ + : "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\ + : "0" (sum), "r" (w)) +#define ADD16 Asm(" ld [%4+ 0],%1; ld [%4+ 4],%2; \ + addcc %0,%1,%0; addxcc %0,%2,%0; \ + ld [%4+ 8],%1; ld [%4+12],%2; \ + addxcc %0,%1,%0; addxcc %0,%2,%0; \ + addxcc %0,0,%0" \ + : "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\ + : "0" (sum), "r" (w)) +#define ADD8 Asm(" ld [%4+ 0],%1; ld [%4+ 4],%2; \ + addcc %0,%1,%0; addxcc %0,%2,%0; \ + addxcc %0,0,%0" \ + : "=r" (sum), "=&r" (tmp1), "=&r" (tmp2)\ + : "0" (sum), "r" (w)) +#define ADD4 Asm(" ld [%3+ 0],%1; \ + addcc %0,%1,%0; \ + addxcc %0,0,%0" \ + : "=r" (sum), "=&r" (tmp1) \ + : "0" (sum), "r" (w)) + +#define REDUCE {sum = (sum & 0xffff) + (sum >> 16);} +#define ADDCARRY {if (sum > 0xffff) sum -= 0xffff;} +#define ROL {sum = sum << 8;} /* depends on recent REDUCE */ +#define ADDBYTE {ROL; sum += *w; byte_swapped ^= 1;} +#define ADDSHORT {sum += *(u_short *)w;} +#define ADVANCE(n) {w += n; mlen -= n;} + +static __inline__ int +in_cksum_internal(struct mbuf *m, int off, int len, u_int sum) +{ + u_char *w; + int mlen = 0; + int byte_swapped = 0; + + /* + * Declare two temporary registers for use by the asm code. We + * allow the compiler to pick which specific machine registers to + * use, instead of hard-coding this in the asm code above. + */ + u_int tmp1, tmp2; + + for (; m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + w = mtod(m, u_char *) + off; + mlen = m->m_len - off; + off = 0; + if (len < mlen) + mlen = len; + len -= mlen; + + /* + * Ensure that we're aligned on a word boundary here so + * that we can do 32 bit operations below. + */ + if ((3 & (long)w) != 0) { + REDUCE; + if ((1 & (long)w) != 0 && mlen >= 1) { + ADDBYTE; + ADVANCE(1); + } + if ((2 & (long)w) != 0 && mlen >= 2) { + ADDSHORT; + ADVANCE(2); + } + } + + /* + * Do as many 32 bit operations as possible using the + * 64/32/16/8/4 macro's above, using as many as possible of + * these. + */ + while (mlen >= 64) { + ADD64; + ADVANCE(64); + } + if (mlen >= 32) { + ADD32; + ADVANCE(32); + } + if (mlen >= 16) { + ADD16; + ADVANCE(16); + } + if (mlen >= 8) { + ADD8; + ADVANCE(8); + } + if (mlen >= 4) { + ADD4; + ADVANCE(4) + } + if (mlen == 0) + continue; + + REDUCE; + if (mlen >= 2) { + ADDSHORT; + ADVANCE(2); + } + if (mlen == 1) { + ADDBYTE; + } + } + if (byte_swapped) { + REDUCE; + ROL; + } + REDUCE; + ADDCARRY; + + return (0xffff ^ sum); +} + +int +in_cksum(struct mbuf *m, int len) +{ + + return (in_cksum_internal(m, 0, len, 0)); +} diff --git a/netinet/in_pcb.c b/netinet/in_pcb.c new file mode 100644 index 0000000..d9d4417 --- /dev/null +++ b/netinet/in_pcb.c @@ -0,0 +1,733 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.158 2005/01/07 01:45:44 imp Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/sockio.h> +#include <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 <rtems/rtems_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 <limits.h> + +struct in_addr zeroin_addr; + +static void in_pcbinshash(struct inpcb *); +static void in_rtchange(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); } + +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; +} + +#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(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_gencnt = ++pcbinfo->ipi_gencnt; + inp->inp_pcbinfo = pcbinfo; + inp->inp_socket = so; + s = splnet(); + LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); + pcbinfo->ipi_count++; + in_pcbinshash(inp); + splx(s); + so->so_pcb = (caddr_t)inp; + return (0); +} + +int +in_pcbbind(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); + 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) { + unsigned short 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(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(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(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(struct inpcb *inp) +{ + struct socket *so = inp->inp_socket; + struct inpcbinfo *ipi = inp->inp_pcbinfo; + int s; + + inp->inp_gencnt = ++ipi->ipi_gencnt; + 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(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(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(struct inpcbhead *head, struct sockaddr *dst, u_int fport_arg, + struct in_addr laddr, u_int lport_arg, int cmd, + void (*notify)(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(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(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(struct inpcbinfo *pcbinfo, + struct in_addr faddr, u_int fport_arg, + struct in_addr laddr, u_int 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(struct inpcbinfo *pcbinfo, + struct in_addr faddr, u_int fport_arg, + struct in_addr laddr, u_int 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(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(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); + inp->inp_pcbinfo->ipi_count--; + splx(s); +} diff --git a/netinet/in_pcb.h b/netinet/in_pcb.h new file mode 100644 index 0000000..ad8b99c --- /dev/null +++ b/netinet/in_pcb.h @@ -0,0 +1,152 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/in_pcb.h,v 1.89 2006/07/18 22:34:27 ups Exp $ + */ + + +#ifndef _NETINET_IN_PCB_H_ +#define _NETINET_IN_PCB_H_ + +#include <sys/queue.h> +#include <netinet/in.h> /* struct in_addr */ +#include <net/route.h> /* struct route */ + +/* + * 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); + +typedef u_int64_t inp_gen_t; + +struct inpcb { + LIST_ENTRY(inpcb) inp_hash; /* hash list */ + LIST_ENTRY(inpcb) inp_list; /* list for all PCBs of this proto */ + 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 route inp_route; /* placeholder for routing entry */ + int inp_flags; /* generic IP/datagram flags */ + u_char inp_vflag; /* IP version flag (v4/v6) */ + u_char inp_ip_ttl; /* time to live proto */ + u_char inp_ip_p; /* protocol proto */ + u_char inp_ip_minttl; /* minimum TTL or drop */ + + /* protocol dependent part; options */ + struct { + u_char inp4_ip_tos; /* type of service proto */ + struct mbuf *inp4_options; /* IP options */ + struct ip_moptions *inp4_moptions; /* IP multicast options */ + } inp_depend4; +#define inp_ip_tos inp_depend4.inp4_ip_tos +#define inp_options inp_depend4.inp4_options +#define inp_moptions inp_depend4.inp4_moptions + inp_gen_t inp_gencnt; /* generation count of this instance */ +}; + +/* + * Interface exported to userland by various protocols which use + * inpcbs. Hack alert -- only define if struct xsocket is in scope. + */ +#ifdef _SYS_SOCKETVAR_H_ +struct xinpcb { + size_t xi_len; /* length of this structure */ + struct inpcb xi_inp; +/* struct xsocket xi_socket; ccj removed */ + u_int64_t xi_alignment_hack; +}; + +struct xinpgen { + size_t xig_len; /* length of this structure */ + u_int xig_count; /* number of PCBs at this time */ + inp_gen_t xig_gen; /* generation count at this time */ + so_gen_t xig_sogen; /* socket generation count at this time */ +}; +#endif /* _SYS_SOCKETVAR_H_ */ + +struct inpcbinfo { /* XXX documentation, prefixes */ + struct inpcbhead *listhead; + struct inpcbhead *hashbase; + unsigned long hashmask; + unsigned short lastport; + unsigned short lastlow; + unsigned short lasthi; + u_int ipi_count; /* number of pcbs in this list */ + u_int64_t ipi_gencnt; /* current generation count */ +}; + +#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(struct inpcb *); +int in_pcballoc(struct socket *, struct inpcbinfo *); +int in_pcbbind(struct inpcb *, struct mbuf *); +int in_pcbconnect(struct inpcb *, struct mbuf *); +void in_pcbdetach(struct inpcb *); +void in_pcbdisconnect(struct inpcb *); +int in_pcbladdr(struct inpcb *, struct mbuf *, + struct sockaddr_in **); +struct inpcb * + in_pcblookup(struct inpcbinfo *, + struct in_addr, u_int, struct in_addr, u_int, int); +struct inpcb * + in_pcblookuphash(struct inpcbinfo *, + struct in_addr, u_int, struct in_addr, u_int, int); +void in_pcbnotify(struct inpcbhead *, struct sockaddr *, + u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int)); +void in_pcbrehash(struct inpcb *); +void in_setpeeraddr(struct inpcb *, struct mbuf *); +void in_setsockaddr(struct inpcb *, struct mbuf *); +#endif /* _KERNEL */ + +#endif /* !_NETINET_IN_PCB_H_ */ diff --git a/netinet/in_proto.c b/netinet/in_proto.c new file mode 100644 index 0000000..558c3e2 --- /dev/null +++ b/netinet/in_proto.c @@ -0,0 +1,217 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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, + NULL +}, +{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR, + udp_input, 0, udp_ctlinput, ip_ctloutput, + udp_usrreq, + udp_init, 0, 0, 0, + NULL +}, +{ 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, + NULL +}, +{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR, + icmp_input, 0, 0, rip_ctloutput, + rip_usrreq, + 0, 0, 0, 0, + NULL +}, +{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR, + igmp_input, 0, 0, rip_ctloutput, + rip_usrreq, + igmp_init, igmp_fasttimo, igmp_slowtimo, 0, + NULL +}, +{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR, + rsvp_input, 0, 0, rip_ctloutput, + rip_usrreq, + 0, 0, 0, 0, + NULL +}, +{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR, + ipip_input, 0, 0, rip_ctloutput, + rip_usrreq, + 0, 0, 0, 0, + NULL +}, +#ifdef IPDIVERT +{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, + div_input, 0, 0, ip_ctloutput, + div_usrreq, + div_init, 0, 0, 0, + NULL +}, +#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, + NULL +}, +#endif +/* EON (ISO CLNL over IP) */ +#ifdef EON +{ SOCK_RAW, &inetdomain, IPPROTO_EON, 0, + eoninput, 0, eonctlinput, 0, + 0, + eonprotoinit, 0, 0, 0, + NULL +}, +#endif +#ifdef IPXIP +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, + ipxip_input, 0, ipxip_ctlinput, 0, + rip_usrreq, + 0, 0, 0, 0, + NULL +}, +#endif +#ifdef NSIP +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, + idpip_input, 0, nsip_ctlinput, 0, + rip_usrreq, + 0, 0, 0, 0, + NULL +}, +#endif + /* raw wildcard */ +{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR, + rip_input, 0, 0, rip_ctloutput, + rip_usrreq, + rip_init, 0, 0, 0, + NULL +}, +}; + +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/netinet/in_rmx.c b/netinet/in_rmx.c new file mode 100644 index 0000000..5dd276a --- /dev/null +++ b/netinet/in_rmx.c @@ -0,0 +1,386 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + */ + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <rtems/rtems_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(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 { + if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr + == sin->sin_addr.s_addr) + rt->rt_flags |= RTF_LOCAL; + } + } + + /* + * 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/netinet/in_systm.h b/netinet/in_systm.h new file mode 100644 index 0000000..f0f3fa9 --- /dev/null +++ b/netinet/in_systm.h @@ -0,0 +1,58 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/in_systm.h,v 1.13 2009/02/13 15:14:43 luigi Exp $ + */ + +#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_int16_t n_short; /* short as received from the net */ +typedef u_int32_t n_long; /* long as received from the net */ + +typedef u_int32_t n_time; /* ms since 00:00 GMT, byte rev */ + +#ifdef _KERNEL +uint32_t iptime(void); +#endif + +#endif diff --git a/netinet/in_var.h b/netinet/in_var.h new file mode 100644 index 0000000..9ade9c4 --- /dev/null +++ b/netinet/in_var.h @@ -0,0 +1,240 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/in_var.h,v 1.52 2004/10/19 21:06:14 andre Exp $ + */ + +#ifndef _NETINET_IN_VAR_H_ +#define _NETINET_IN_VAR_H_ + +#include <sys/queue.h> +#include <net/if_var.h> /* struct ifaddr */ +#include <netinet/in.h> /* struct in_addr */ + +#if !defined(__rtems__) +#include <sys/fnv_hash.h> +#endif + +/* + * Interface address, Internet version. One of these structures + * is allocated for each Internet address on an interface. + * 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[]; + +/* + * 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 + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet_ip); +SYSCTL_DECL(_net_inet_raw); +#endif + +/* + * 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(struct in_addr *, struct ifnet *); +void in_delmulti(struct in_multi *); +int in_control(struct socket *, u_long, caddr_t, struct ifnet *); +void in_rtqdrain(void); +void ip_input(struct mbuf *); + +#endif /* _KERNEL */ + +#endif /* _NETINET_IN_VAR_H_ */ diff --git a/netinet/ip.h b/netinet/ip.h new file mode 100644 index 0000000..6a2dcad --- /dev/null +++ b/netinet/ip.h @@ -0,0 +1,230 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/ip.h,v 1.29 2005/01/07 01:45:44 imp Exp $ + */ + + +#ifndef _NETINET_IP_H_ +#define _NETINET_IP_H_ + +#include <sys/cdefs.h> +#include <netinet/in.h> /* struct in_addr */ +#include <netinet/in_systm.h> /* n_long */ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +#ifndef __packed +#if defined(__GNUC__) +#define __packed __attribute__((packed)) +#define __aligned(x) __attribute__((aligned(x))) +#else +#define __packed +#define __aligned(x) +#endif +#endif + +/* + * Structure of an internet header, naked of options. + */ +struct ip { +#ifdef _IP_VHL + u_char ip_vhl; /* version << 4 | header length >> 2 */ +#else +#if BYTE_ORDER == LITTLE_ENDIAN + u_int ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_int 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 */ +} __packed __aligned(4); + +#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 + +#ifdef CTASSERT +CTASSERT(sizeof (struct ip) == 20); +#endif + +#define IP_MAXPACKET 65535L /* 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 +#if 1 +/* ECN RFC3168 obsoletes RFC2481, and these will be deprecated soon. */ +#define IPTOS_CE 0x01 +#define IPTOS_ECT 0x02 +#endif + +/* + * 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 + +/* + * ECN (Explicit Congestion Notification) codepoints in RFC3168 + * mapped to the lower 2 bits of the TOS field. + */ +#define IPTOS_ECN_NOTECT 0x00 /* not-ECT */ +#define IPTOS_ECN_ECT1 0x01 /* ECN-capable transport (1) */ +#define IPTOS_ECN_ECT0 0x02 /* ECN-capable transport (0) */ +#define IPTOS_ECN_CE 0x03 /* congestion experienced */ +#define IPTOS_ECN_MASK 0x03 /* ECN field mask */ + +/* + * 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_ESO 133 /* extended security */ +#define IPOPT_CIPSO 134 /* commerical security */ +#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_int ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_int 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 */ + +/* + * This is the real IPv4 pseudo header, used for computing the TCP and UDP + * checksums. For the Internet checksum, struct ipovly can be used instead. + * For stronger checksums, the real thing must be used. + */ +struct ippseudo { + struct in_addr ippseudo_src; /* source internet address */ + struct in_addr ippseudo_dst; /* destination internet address */ + u_char ippseudo_pad; /* pad, must be zero */ + u_char ippseudo_p; /* protocol */ + u_short ippseudo_len; /* protocol length */ +}; +#endif diff --git a/netinet/ip_divert.c b/netinet/ip_divert.c new file mode 100644 index 0000000..c34da82 --- /dev/null +++ b/netinet/ip_divert.c @@ -0,0 +1,387 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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. + * + * $FreeBSD: src/sys/netinet/ip_divert.c,v 1.113 2005/05/13 11:44:37 glebius Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <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> + +#ifdef IPDIVERT + +/* + * 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, 0, { 0 }, { 0 } }; + +/* 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(struct socket *so, struct mbuf *m, + struct mbuf *addr, struct mbuf *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( + struct socket *so, + int req, + struct mbuf *m, + struct mbuf *nam, + struct mbuf *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 = (intptr_t)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); +} +#endif /* IPDIVERT */ diff --git a/netinet/ip_fw.c b/netinet/ip_fw.c new file mode 100644 index 0000000..e5f8ab2 --- /dev/null +++ b/netinet/ip_fw.c @@ -0,0 +1,1082 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + */ + +/* + * Implement IP packet firewall + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/if_var.h> +#include <net/route.h> +#include <netinet/in.h> +#include <rtems/rtems_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> +#include <inttypes.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; + +/* + * ccj - No current need for firewall so have provided the MIB. + */ +#if 0 +#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 +#endif + +#define dprintf(a) if (!fw_debug); else printf a + +#define print_ip(a) printf("%"PRId32".%"PRId32".%"PRId32".%"PRId32,\ + (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(struct ip_fw_head *chainptr, struct ip_fw *frwl); +static int del_entry(struct ip_fw_head *chainptr, u_short number); +static int zero_entry(struct mbuf *m); +static struct ip_fw *check_ipfw_struct(struct ip_fw *m); +static struct ip_fw *check_ipfw_mbuf(struct mbuf *fw); +static int ipopts_match(struct ip *ip, struct ip_fw *f); +static int port_match(u_short *portptr, int nports, u_short port, + int range_flag); +static int tcpflg_match(struct tcphdr *tcp, struct ip_fw *f); +static int icmptype_match(struct icmp * icmp, struct ip_fw * f); +static void ipfw_report(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(struct ip **pip, int hlen, + struct ifnet *oif, int ignport, struct mbuf **m); +static int ip_fw_ctl(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/netinet/ip_fw.h b/netinet/ip_fw.h new file mode 100644 index 0000000..c511154 --- /dev/null +++ b/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. + */ + +#ifndef _IP_FW_H +#define _IP_FW_H + +#include <sys/queue.h> /* LIST_ENTRY */ +#include <net/if.h> +#include <netinet/in.h> /* struct in_addr */ + +/* + * 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/netinet/ip_icmp.c b/netinet/ip_icmp.c new file mode 100644 index 0000000..e1c7518 --- /dev/null +++ b/netinet/ip_icmp.c @@ -0,0 +1,771 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/ip_icmp.c,v 1.101 2005/05/04 13:23:54 andre Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/route.h> + +#define _IP_VHL +#include <netinet/in.h> +#include <rtems/rtems_netinet_in.h> +#include <netinet/in_pcb.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/tcp.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#include <netinet/icmp_var.h> + +#ifdef IPSEC +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#endif + +#ifdef FAST_IPSEC +#include <netipsec/ipsec.h> +#include <netipsec/key.h> +#define IPSEC +#endif + +#include <machine/in_cksum.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, ""); + +static int icmpallecho = 1; +SYSCTL_INT(_net_inet_icmp, OID_AUTO, allecho, CTLFLAG_RW, &icmpallecho, + 0, ""); + +#ifdef ICMPPRINTFS +int icmpprintfs = 0; +#endif + +static void icmp_reflect(struct mbuf *); +static void icmp_send(struct mbuf *, struct mbuf *); + +extern struct protosw inetsw[]; +unsigned int icmplenPanicAvoided; + +/* + * Generate an error packet of type error + * in response to bad packet ip. + */ +void +icmp_error(struct mbuf *n, int type, int code, n_long dest, + struct ifnet *destifp) +{ + register struct ip *oip = mtod(n, struct ip *), *nip; +#ifdef _IP_VHL + register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; +#else + register unsigned oiplen = oip->ip_hl << 2; +#endif + 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; + /* Don't send error in response to malicious packet */ + icmplen = min(oiplen + 8, oip->ip_len); + if (icmplen < sizeof(struct ip)) { + icmplenPanicAvoided++; + goto freeit; + } + + /* + * First, formulate icmp message + */ + m = m_gethdr(M_DONTWAIT, MT_HEADER); + if (m == NULL) + goto freeit; +#ifdef MAC + mac_create_mbuf_netlayer(n, m); +#endif + 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; +#ifdef _IP_VHL + nip->ip_vhl = IP_VHL_BORING; +#else + nip->ip_v = IPVERSION; + nip->ip_hl = 5; +#endif + 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, 0, {0}, {0} }; +static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET, 0, {0}, {0} }; +static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET, 0, {0}, {0} }; + +/* + * Process a received ICMP message. + */ +void +icmp_input(struct mbuf *m, int off) +{ + struct icmp *icp; + struct in_ifaddr *ia; + struct ip *ip = mtod(m, struct ip *); + int hlen = off; + int icmplen = ip->ip_len; + int i, code; + void (*ctlfunc)(int, struct sockaddr *, void *); + + /* + * 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)) == NULL) { + 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) || +#ifdef _IP_VHL + IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { +#else + icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { +#endif + 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 (!icmpallecho) { + icmpstat.icps_allecho++; + break; + } + 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 == NULL) + break; + if (ia->ia_ifp == NULL) { + 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) || +#ifdef _IP_VHL + IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { +#else + icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { +#endif + 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(struct mbuf *m) +{ + struct ip *ip = mtod(m, struct ip *); + struct in_ifaddr *ia; + struct in_addr t; + struct mbuf *opts = 0; +#ifdef _IP_VHL + int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip); +#else + int optlen = (ip->ip_hl << 2) - sizeof(struct ip); +#endif + 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 { + if (cnt < IPOPT_OLEN + sizeof(*cp)) + break; + len = cp[IPOPT_OLEN]; + if (len < IPOPT_OLEN + sizeof(*cp) || + 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; +#ifdef _IP_VHL + ip->ip_vhl = IP_VHL_BORING; +#else + ip->ip_v = IPVERSION; + ip->ip_hl = 5; +#endif + 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(struct mbuf *m, struct mbuf *opts) +{ + register struct ip *ip = mtod(m, struct ip *); + register int hlen; + register struct icmp *icp; + struct route ro; + +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + 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); +} + +/* + * Return milliseconds since 00:00 GMT in network format. + */ +uint32_t +iptime(void) +{ + struct timeval atv; + u_long t; + + microtime(&atv); + t = (atv.tv_sec % (24L*60L*60L)) * 1000L + atv.tv_usec / 1000L; + return (htonl(t)); +} + +/* + * 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. + */ +int +ip_next_mtu(int mtu, int dir) +{ + static int mtutab[] = { + 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1280, 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]; + } + } +} diff --git a/netinet/ip_icmp.h b/netinet/ip_icmp.h new file mode 100644 index 0000000..2e66a5f --- /dev/null +++ b/netinet/ip_icmp.h @@ -0,0 +1,212 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.26 2005/05/04 13:09:19 andre Exp $ + */ + + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +#include <netinet/in.h> /* struct in_addr */ +#include <netinet/ip.h> /* struct ip */ + +/* + * 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 { + uint16_t icd_id; /* network format */ + uint16_t icd_seq; /* network format */ + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + uint16_t ipm_void; /* network format */ + uint16_t ipm_nextmtu; /* network format */ + } 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 { /* ICMP Timestamp */ + /* + * The next 3 fields are in network format, + * milliseconds since 00:00 GMT + */ + uint32_t its_otime; /* Originate */ + uint32_t its_rtime; /* Receive */ + uint32_t its_ttime; /* Transmit */ + } 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_int32_t 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 (uint32_t)) /* 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_ALTHOSTADDR 6 /* alternate host address */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERADVERT_NORMAL 0 /* normal advertisement */ +#define ICMP_ROUTERADVERT_NOROUTE_COMMON 16 /* selective routing */ +#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_ERRATPTR 0 /* error at param ptr */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_PARAMPROB_LENGTH 2 /* bad length */ +#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_TRACEROUTE 30 /* traceroute */ +#define ICMP_DATACONVERR 31 /* data conversion error */ +#define ICMP_MOBILE_REDIRECT 32 /* mobile host redirect */ +#define ICMP_IPV6_WHEREAREYOU 33 /* IPv6 where-are-you */ +#define ICMP_IPV6_IAMHERE 34 /* IPv6 i-am-here */ +#define ICMP_MOBILE_REGREQUEST 35 /* mobile registration req */ +#define ICMP_MOBILE_REGREPLY 36 /* mobile registration reply */ +#define ICMP_SKIP 39 /* SKIP */ +#define ICMP_PHOTURIS 40 /* Photuris */ +#define ICMP_PHOTURIS_UNKNOWN_INDEX 1 /* unknown sec index */ +#define ICMP_PHOTURIS_AUTH_FAILED 2 /* auth failed */ +#define ICMP_PHOTURIS_DECRYPT_FAILED 3 /* decrypt failed */ + +#define ICMP_MAXTYPE 40 + +#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(struct mbuf *, int, int, n_long, struct ifnet *); +void icmp_input(struct mbuf *, int); +int ip_next_mtu(int, int); +#endif + +#endif diff --git a/netinet/ip_input.c b/netinet/ip_input.c new file mode 100644 index 0000000..927537f --- /dev/null +++ b/netinet/ip_input.c @@ -0,0 +1,1510 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _IP_VHL + +#include "opt_ipfw.h" + +#include <stddef.h> +#include <inttypes.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <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 <rtems/rtems_netinet_in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.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; + +int ipforwarding = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, + &ipforwarding, 0, "Enable IP forwarding between interfaces"); + +static int ipsendredirects = 1; /* XXX */ +SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, + &ipsendredirects, 0, "Enable sending IP redirects"); + +int ip_defttl = IPDEFTTL; +SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, + &ip_defttl, 0, "Maximum TTL on IP packets"); + +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, + "Number of packets dropped from the IP input queue"); + +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, "Default MTU"); +#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(u_char *, struct in_addr); +static void ip_deq(struct ipasfrag *); +static int ip_dooptions(struct mbuf *); +static void ip_enq(struct ipasfrag *, struct ipasfrag *); +static void ip_forward(struct mbuf *, int); +static void ip_freef(struct ipq *); +static struct ip * + ip_reass(struct ipasfrag *, struct ipq *, struct ipq *); +static struct in_ifaddr * + ip_rtaddr(struct in_addr); +void ipintr(void); +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void +ip_init(void) +{ + register struct protosw *pr; + register int i; + + pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); + if (pr == NULL) + panic("ip_init: PF_INET not found"); + + /* Initialize the entire ip_protox[] array to IPPROTO_RAW. */ + for (i = 0; i < IPPROTO_MAX; i++) + ip_protox[i] = pr - inetsw; + /* + * Cycle through IP protocols and put them into the appropriate place + * in ip_protox[]. + */ + 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; + + /* Initialize various other remaining things. */ + 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, 0, {0}, {0} }; +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 = NULL; + struct ipq *fp; + struct in_ifaddr *ia = NULL; + 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; + +#if defined(DIAGNOSTIC) && defined(ORIGINAL_FREEBSD_CODE) + 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))) == NULL) { + ipstat.ips_toosmall++; + return; + } + ip = mtod(m, struct ip *); + +#ifdef _IP_VHL + if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { +#else + if (ip->ip_v != IPVERSION) { +#endif + ipstat.ips_badvers++; + goto bad; + } + +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + if (hlen < sizeof(struct ip)) { /* minimum header length */ + ipstat.ips_badhlen++; + goto bad; + } + if (hlen > m->m_len) { + if ((m = m_pullup(m, hlen)) == NULL) { + 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. + */ + ip->ip_len = ntohs(ip->ip_len); + if (ip->ip_len < hlen) { + ipstat.ips_badlen++; + goto bad; + } + NTOHS(ip->ip_id); + ip->ip_off = 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 daemon 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(struct ipasfrag *ip, 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; + int32_t 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 == NULL) { + 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. + */ +#ifdef _IP_VHL + if (next + (IP_VHL_HL(((struct ip *)fp->ipq_next)->ip_vhl) << 2) +#else + if (next + ((((struct ip *)fp->ipq_next)->ip_hl) << 2) +#endif + > 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 = NULL; + 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(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(struct ipasfrag *p, struct ipasfrag *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(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(void) +{ + 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(void) +{ + 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(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); +#ifdef _IP_VHL + cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); +#else + cnt = (ip->ip_hl << 2) - sizeof (struct ip); +#endif + 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 buf0[INET_ADDRSTRLEN]; + char buf1[INET_ADDRSTRLEN]; + +nosourcerouting: + log(LOG_WARNING, + "attempted source route from %s to %s\n", + inet_ntoa_r(ip->ip_dst, buf0), + inet_ntoa_r(ip->ip_src, buf1)); + 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: +#ifdef _IP_VHL + ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */ +#else + ip->ip_len -= ip->ip_hl << 2; /* XXX icmp_error adds in hdr length */ +#endif + 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(struct in_addr dst) +{ + 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(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(void) +{ + 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 %"PRIx32, 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(" %"PRIx32, ntohl(q->s_addr)); +#endif + *q++ = *p--; + } + /* + * Last hop goes to final destination. + */ + *q = ip_srcrt.dst; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" %"PRIx32"\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(struct mbuf *m, struct mbuf *mopt) +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register caddr_t opts; + int olen; + +#ifdef _IP_VHL + olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); +#else + olen = (ip->ip_hl << 2) - sizeof (struct ip); +#endif + 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; +#ifdef _IP_VHL + ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); +#else + ip->ip_v = IPVERSION; + ip->ip_hl = (sizeof(struct ip) >> 2); +#endif +} + +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(struct mbuf *m, int srcrt) +{ + 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 %"PRIx32" dst %"PRIx32" 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; + } + } + + 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(struct inpcb *inp, struct mbuf **mp, struct ip *ip, + 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(m), + 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/netinet/ip_mroute.c b/netinet/ip_mroute.c new file mode 100644 index 0000000..3a89497 --- /dev/null +++ b/netinet/ip_mroute.c @@ -0,0 +1,2232 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opt_mrouting.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/sockio.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(int vifi); +extern int _ip_mforward(struct ip *ip, struct ifnet *ifp, + struct mbuf *m, struct ip_moptions *imo); +extern int _ip_mrouter_done(void); +extern int _ip_mrouter_get(int cmd, struct socket *so, + struct mbuf **m); +extern int _ip_mrouter_set(int cmd, struct socket *so, + struct mbuf *m); +extern int _mrt_ioctl(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(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(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(void) +{ + return(0); +} + +int (*ip_mrouter_done)(void) = _ip_mrouter_done; + +int +_ip_mforward(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(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(struct socket *so, struct mbuf *m) +{ + return(EINVAL); +} + +int +ip_rsvp_vif_done(struct socket *so, struct mbuf *m) +{ + return(EINVAL); +} + +void +ip_rsvp_force_done(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(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(int vifi); +static int X_ip_mforward(struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo); +static int X_ip_mrouter_done(void); +static int X_ip_mrouter_get(int cmd, struct socket *so, struct mbuf **m); +static int X_ip_mrouter_set(int cmd, struct socket *so, struct mbuf *m); +static int X_legal_vif_num(int vif); +static int X_mrt_ioctl(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(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(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(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(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(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(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(void) +{ + 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(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(int *i) +{ + if ((*i != 1) && (*i != 0)) + return EINVAL; + + pim_assert = *i; + + return 0; +} + +/* + * Get PIM assert processing global + */ +static int +get_assert(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(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(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(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(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(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(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(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(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, + 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(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(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(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(struct ip *ip, struct vif *vifp, 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(struct mbuf *m, int iphlen) +#else +ipip_input(struct mbuf *m, int iphlen) +#endif +{ + 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(struct vif *vifp, struct mbuf *m, struct ip *ip, 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(struct vif *vifp, 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(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(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(struct vif *vifp, 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(struct vif *vifp, 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(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(struct vif *vifp, 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(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(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(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(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/netinet/ip_mroute.h b/netinet/ip_mroute.h new file mode 100644 index 0000000..9a28574 --- /dev/null +++ b/netinet/ip_mroute.h @@ -0,0 +1,271 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/ip_mroute.h,v 1.31 2007/02/08 23:05:08 bms Exp $ + */ + + +#ifndef _NETINET_IP_MROUTE_H_ +#define _NETINET_IP_MROUTE_H_ + +#include <netinet/in.h> /* struct in_addr */ +#include <net/route.h> /* struct route */ + +/* + * 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. + * Modified by Ahmed Helmy, SGI, June 1996. + * Modified by Pavlin Radoslavov, ICSI, October 2002. + * + * MROUTING Revision: 3.3.1.3 + * and PIM-SMv2 and PIM-DM support, advanced API support, + * bandwidth metering and signaling. + */ + + +/* + * 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 assert processing */ +#define MRT_PIM MRT_ASSERT /* enable PIM processing */ +#define MRT_API_SUPPORT 109 /* supported MRT API */ +#define MRT_API_CONFIG 110 /* config MRT API */ +#define MRT_ADD_BW_UPCALL 111 /* create bandwidth monitor */ +#define MRT_DEL_BW_UPCALL 112 /* delete bandwidth monitor */ + + +#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)(int, struct socket *, struct mbuf *); +extern int (*ip_mrouter_get)(int, struct socket *, struct mbuf **); +extern int (*ip_mrouter_done)(void); +#ifdef MROUTING +extern int (*mrt_ioctl)(int, caddr_t); +#else +extern int (*mrt_ioctl)(int, caddr_t, struct proc *); +#endif + +#endif /* _KERNEL */ + +#endif /* _NETINET_IP_MROUTE_H_ */ diff --git a/netinet/ip_output.c b/netinet/ip_output.c new file mode 100644 index 0000000..5b1c497 --- /dev/null +++ b/netinet/ip_output.c @@ -0,0 +1,1336 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/ip_output.c,v 1.271 2007/03/23 09:43:36 bms Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _IP_VHL + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <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 <rtems/rtems_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 <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(struct mbuf *, struct mbuf *, int *); +static void ip_mloopback + (struct ifnet *, struct mbuf *, struct sockaddr_in *, int); +static int ip_getmoptions + (int, struct ip_moptions *, struct mbuf **); +static int ip_optcopy(struct ip *, struct ip *); +static int ip_pcbopts(struct mbuf **, struct mbuf *); +static int ip_setmoptions + (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(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 = 0, 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) { +#ifdef _IP_VHL + ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2); +#else + ip->ip_v = IPVERSION; + ip->ip_hl = hlen >> 2; +#endif + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); + ipstat.ips_localout++; + } else { +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + } + + 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 == NULL) { + 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 (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && + imo != NULL && imo->imo_multicast_ifp != NULL) { + /* + * Bypass the normal routing lookup for multicast + * packets if the interface is specified. + */ + ifp = imo->imo_multicast_ifp; + IFP_TO_IA(ifp, ia); + isbroadcast = 0; /* fool gcc */ + } 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 + * 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 (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, or the interface will take + * care of the fragmentation for us, we can just send directly. + */ + if ((u_short)ip->ip_len <= ifp->if_mtu) { + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + ip->ip_sum = 0; +#ifdef _IP_VHL + if (ip->ip_vhl == IP_VHL_BORING) { +#else + if ((ip->ip_hl == 5) && (ip->ip_v = IPVERSION)) { +#endif + 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_flags |= (m0->m_flags & M_MCAST); + 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); +#ifdef _IP_VHL + mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2); +#else + mhip->ip_v = IPVERSION; + mhip->ip_hl = mhlen >> 2; +#endif + } + 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 = NULL; + mhip->ip_off = htons(mhip->ip_off); + mhip->ip_sum = 0; +#ifdef _IP_VHL + if (mhip->ip_vhl == IP_VHL_BORING) { +#else + if ((mhip->ip_hl == 5) && (mhip->ip_v == IPVERSION) ) { +#endif + 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 |= IP_MF; + ip->ip_off = htons(ip->ip_off); + ip->ip_sum = 0; +#ifdef _IP_VHL + if (ip->ip_vhl == IP_VHL_BORING) { +#else + if ((ip->ip_hl == 5) && (ip->ip_v == IPVERSION) ) { +#endif + 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(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 *); + uint32_t optlen; + + optlen = opt->m_len - sizeof(p->ipopt_dst); + if (optlen + 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; +#ifdef _IP_VHL + ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2); +#else + ip->ip_v = IPVERSION; + ip->ip_hl = *phlen >> 2; +#endif + ip->ip_len += optlen; + return (m); +} + +/* + * Copy options from ip to jp, + * omitting those not copied during fragmentation. + */ +static int +ip_optcopy(struct ip *ip, struct ip *jp) +{ + register u_char *cp, *dp; + int opt, optlen, cnt; + + cp = (u_char *)(ip + 1); + dp = (u_char *)(jp + 1); +#ifdef _IP_VHL + cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); +#else + cnt = (ip->ip_hl << 2) - sizeof (struct ip); +#endif + 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(int op, struct socket *so, int level, int optname, + struct mbuf **mp) +{ + 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(int optname, struct mbuf **pcbopt, struct mbuf *m) +#else +ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m) +#endif +{ + 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(int optname, struct ip_moptions **imop, struct mbuf *m) +{ + int error = 0; + u_char loop; + int i; + struct in_addr addr; + struct ip_mreq *mreq; + struct ifnet *ifp; + 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(int optname, struct ip_moptions *imo, + 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(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(struct ifnet *ifp, struct mbuf *m, 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(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + ip->ip_sum = 0; +#ifdef _IP_VHL + if (ip->ip_vhl == IP_VHL_BORING) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(copym, hlen); + } +#else + ip->ip_sum = in_cksum(copym, hlen); +#endif + /* + * 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/netinet/ip_var.h b/netinet/ip_var.h new file mode 100644 index 0000000..a6e0bc8 --- /dev/null +++ b/netinet/ip_var.h @@ -0,0 +1,215 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/ip_var.h,v 1.94 2005/01/07 01:45:44 imp Exp $ + */ + + +#ifndef _NETINET_IP_VAR_H_ +#define _NETINET_IP_VAR_H_ + +#include <netinet/in.h> /* struct in_addr */ + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +struct ipovly { + caddr_t ih_next; + caddr_t 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_SENDONES 0x4 /* send all-ones broadcast */ +#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ +#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ + +struct ip; +struct inpcb; +struct route; +struct sockopt; +struct mbuf; + +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)(int); +extern u_long (*ip_mcast_src)(int); +extern int rsvp_on; + +int ip_ctloutput(int, struct socket *, int, int, struct mbuf **); +void ip_drain(void); +void ip_freemoptions(struct ip_moptions *); +void ip_init(void); +extern int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, + struct ip_moptions *); +int ip_output(struct mbuf *, + struct mbuf *, struct route *, int, struct ip_moptions *); +void ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *, + struct mbuf *); +void ip_slowtimo(void); +struct mbuf * + ip_srcroute(void); +void ip_stripoptions(struct mbuf *, struct mbuf *); +int rip_ctloutput(int, struct socket *, int, int, struct mbuf **); +void rip_init(void); +void rip_input(struct mbuf *, int); +int rip_output(struct mbuf *, struct socket *, u_long); +int rip_usrreq(struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *); +void ipip_input(struct mbuf *, int); +void rsvp_input(struct mbuf *, int); +int ip_rsvp_init(struct socket *); +int ip_rsvp_done(void); +int ip_rsvp_vif_init(struct socket *, struct mbuf *); +int ip_rsvp_vif_done(struct socket *, struct mbuf *); +void ip_rsvp_force_done(struct socket *); + +#ifdef IPDIVERT +void div_init(void); +void div_input(struct mbuf *, int); +int div_usrreq(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/netinet/raw_ip.c b/netinet/raw_ip.c new file mode 100644 index 0000000..58b85a9 --- /dev/null +++ b/netinet/raw_ip.c @@ -0,0 +1,492 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/raw_ip.c,v 1.147 2005/01/07 01:45:45 imp Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opt_inet6.h" +#include "opt_ipsec.h" +#include "opt_mac.h" + +#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 <errno.h> +#include <sys/systm.h> + +#include <net/if.h> +#include <net/route.h> + +#define _IP_VHL +#include <netinet/in.h> +#include <rtems/rtems_netinet_in.h> +#include <netinet/in_systm.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip.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(void) +{ + 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, 0, {0}, {0} }; +/* + * Setup generic address and protocol structures + * for raw_input routine, then pass them along with + * mbuf chain. + */ +void +rip_input(struct mbuf *m, int iphlen) +{ + 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(struct mbuf *m, struct socket *so, u_long dst) +{ + struct ip *ip; + struct inpcb *inp = sotoinpcb(so); + int flags = ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) | + 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 */ +#ifdef _IP_VHL + 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))) { +#else + if (((ip->ip_hl != (sizeof (*ip) >> 2)) + && inp->inp_options) + || (ip->ip_len > m->m_pkthdr.len) + || (ip->ip_len < (ip->ip_hl << 2))) { +#endif + 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(int op, struct socket *so, int level, int optname, + struct mbuf **m) +{ + struct inpcb *inp = sotoinpcb(so); + 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(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, + struct mbuf *control) +{ + register int error = 0; + register struct inpcb *inp = sotoinpcb(so); + int s; + + if (req == PRU_CONTROL) + return (in_control(so, (uintptr_t)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 = (uintptr_t)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/netinet/tcp_debug.c b/netinet/tcp_debug.c new file mode 100644 index 0000000..a014158 --- /dev/null +++ b/netinet/tcp_debug.c @@ -0,0 +1,172 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#include "opt_inet.h" +#include "opt_tcpdebug.h" + +#ifdef TCPDEBUG +/* load symbolic names */ +#define PRUREQUESTS +#define TCPSTATES +#define TCPTIMERS +#define TANAMES +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> + +#include <sys/socket.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_fsm.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 + +/* + * Global ring buffer of TCP debugging state. Each entry captures a snapshot + * of TCP connection state at any given moment. tcp_debx addresses at the + * next available slot. There is no explicit export of this data structure; + * it will be read via /dev/kmem by debugging tools. + */ +static struct tcp_debug tcp_debug[TCP_NDEBUG]; +static int tcp_debx; + +/* + * Save TCP state at a given moment; optionally, both tcpcb and TCP packet + * header state will be saved. + */ +void +tcp_trace(short act, short ostate, struct tcpcb *tp, struct tcpiphdr *ti, + int req) +{ +#ifdef TCPDEBUG + tcp_seq seq, ack; + int len, flags; +#endif + struct tcp_debug *td; + + 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 != NULL) + 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 != NULL) + 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 != NULL) + printf(" -> %s", tcpstates[tp->t_state]); + /* print out internal state of tp !?! */ + printf("\n"); + if (tp == NULL) + 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/netinet/tcp_debug.h b/netinet/tcp_debug.h new file mode 100644 index 0000000..55004f3 --- /dev/null +++ b/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. + * 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 + * $FreeBSD: src/sys/netinet/tcp_debug.h,v 1.17 2009/02/13 15:14:43 luigi Exp $ + */ + + +#ifndef _NETINET_TCP_DEBUG_H_ +#define _NETINET_TCP_DEBUG_H_ + +#include <netinet/tcpip.h> /* struct tcpiphdr */ +#include <netinet/tcp_var.h> /* struct tcpcb */ + +struct tcp_debug { + uint32_t td_time; /* network format */ + 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 const 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/netinet/tcp_fsm.h b/netinet/tcp_fsm.h new file mode 100644 index 0000000..ceb053e --- /dev/null +++ b/netinet/tcp_fsm.h @@ -0,0 +1,91 @@ +/* + * 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 + */ + +#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/netinet/tcp_input.c b/netinet/tcp_input.c new file mode 100644 index 0000000..e62f1eb --- /dev/null +++ b/netinet/tcp_input.c @@ -0,0 +1,2151 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <errno.h> +#include <sys/syslog.h> + +#include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ + +#include <net/if.h> +#include <net/if_var.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <rtems/rtems_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(struct tcpcb *, + u_char *, int, struct tcpiphdr *, struct tcpopt *); +static void tcp_pulloutofband(struct socket *, + struct tcpiphdr *, struct mbuf *); +static int tcp_reass(struct tcpcb *, struct tcpiphdr *, struct mbuf *); +static void tcp_xmit_timer(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(struct tcpcb *tp, 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; +#if (defined(__GNUC__) && (defined(__arm__) || defined(__mips__))) + STR32_UNALGN(ti,m); +#else + REASS_MBUF(ti) = m; /* XXX */ +#endif + /* + * 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; +#if (defined(__GNUC__) && (defined(__arm__) || defined(__mips__))) + LD32_UNALGN(q,m); + m_adj(m, i); +#else + m_adj(REASS_MBUF(q), i); +#endif + break; + } + q = (struct tcpiphdr *)q->ti_next; +#if (defined(__GNUC__) && (defined(__arm__) || defined(__mips__))) + LD32_UNALGN((struct tcpiphdr *)q->ti_prev,m); +#else + m = REASS_MBUF((struct tcpiphdr *)q->ti_prev); +#endif + 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); +#if (defined(__GNUC__) && (defined(__arm__) || defined(__mips__))) + LD32_UNALGN(ti,m); +#else + m = REASS_MBUF(ti); +#endif + 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(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 buf0[INET_ADDRSTRLEN]; + char buf1[INET_ADDRSTRLEN]; + + log(LOG_INFO, "Connection attempt to TCP %s:%d" + " from %s:%d\n", + inet_ntoa_r(ti->ti_dst, buf0), ntohs(ti->ti_dport), + inet_ntoa_r(ti->ti_src, buf1), 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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_flags & 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(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_flags |= 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_flags |= 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_flags |= 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_flags |= 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(struct socket *so, struct tcpiphdr *ti, 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(struct tcpcb *tp, int rtt) +{ + 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(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(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/netinet/tcp_output.c b/netinet/tcp_output.c new file mode 100644 index 0000000..0e50329 --- /dev/null +++ b/netinet/tcp_output.c @@ -0,0 +1,757 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <errno.h> + +#include <net/route.h> + +#include <netinet/in.h> +#include <rtems/rtems_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( + 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( + 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/netinet/tcp_seq.h b/netinet/tcp_seq.h new file mode 100644 index 0000000..c24b294 --- /dev/null +++ b/netinet/tcp_seq.h @@ -0,0 +1,99 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/tcp_seq.h,v 1.26 2006/06/18 14:24:12 andre Exp $ + */ + + +#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 (uint32_t)(24L * 24L * 60L * 60L * 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() (((uint32_t)random() >> 14) & 0x3ffffL) +#endif +#define TCP_ISSINCR (uint32_t)(122L*1024L + 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/netinet/tcp_subr.c b/netinet/tcp_subr.c new file mode 100644 index 0000000..69012cc --- /dev/null +++ b/netinet/tcp_subr.c @@ -0,0 +1,729 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/tcp_subr.c,v 1.226 2005/05/07 00:41:36 cperciva Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <errno.h> + +#include <net/route.h> +#include <net/if.h> + +#define _IP_VHL +#include <netinet/in.h> +#include <rtems/rtems_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, "Default TCP Maximum Segment Size"); + +static int tcp_do_rfc1323 = 1; +#if !defined(__rtems__) +static int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; +SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, + CTLFLAG_RW, &tcp_rttdflt , 0, ""); + +SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, + CTLFLAG_RW, &tcp_do_rfc1323 , 0, ""); +#endif + +static void tcp_notify(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(void) +{ + + tcp_iss = random(); /* wrong, but better than a constant */ + tcp_ccgen = 1; + 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(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(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, + tcp_seq ack, tcp_seq 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 == NULL) { + 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 = NULL; + 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(struct inpcb *inp) +{ + 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); + 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(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(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; +#if (defined(__GNUC__) && (defined(__arm__) || defined(__mips__))) + LD32_UNALGN((struct tcpiphdr *)t->ti_prev,m); +#else + m = REASS_MBUF((struct tcpiphdr *)t->ti_prev); +#endif + 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(void) +{ + +} + +/* + * 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(struct inpcb *inp, int error) +{ + struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; + 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); +} + +#ifdef __rtems__ +#define INP_INFO_RLOCK(a) +#define INP_INFO_RUNLOCK(a) +#define INP_LOCK(a) +#define INP_UNLOCK(a) +#endif + +static int +tcp_pcblist(SYSCTL_HANDLER_ARGS) +{ + int error, i, n, s; + struct inpcb *inp, **inp_list; + inp_gen_t gencnt; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == NULL) { + n = tcbinfo.ipi_count; + req->oldidx = 2 * (sizeof xig) + + (n + n/8) * sizeof(struct xtcpcb); + return (0); + } + + if (req->newptr != NULL) + return (EPERM); + + /* + * OK, now we're committed to doing something. + */ + s = splnet(); + INP_INFO_RLOCK(&tcbinfo); + gencnt = tcbinfo.ipi_gencnt; + n = tcbinfo.ipi_count; + INP_INFO_RUNLOCK(&tcbinfo); + splx(s); + + sysctl_wire_old_buffer(req, 2 * (sizeof xig) + + n * sizeof(struct xtcpcb)); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = gencnt; +/* xig.xig_sogen = so_gencnt; remove by ccj */ + error = SYSCTL_OUT(req, &xig, sizeof xig); + if (error) + return error; + + /* ccj add exit if the count is 0 */ + if (!n) + return error; + + inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); + if (inp_list == 0) + return ENOMEM; + + s = splnet(); + INP_INFO_RLOCK(&tcbinfo); + for (inp = LIST_FIRST(tcbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) +#if 0 + && + cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) +#endif + inp_list[i++] = inp; + INP_UNLOCK(inp); + } + INP_INFO_RUNLOCK(&tcbinfo); + splx(s); + n = i; + + error = 0; + for (i = 0; i < n; i++) { + inp = inp_list[i]; + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) { + struct xtcpcb xt; + caddr_t inp_ppcb; + xt.xt_len = sizeof xt; + /* XXX should avoid extra copy */ + bcopy(inp, &xt.xt_inp, sizeof *inp); + inp_ppcb = inp->inp_ppcb; + if (inp_ppcb != NULL) + bcopy(inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp); + else + bzero((char *) &xt.xt_tp, sizeof xt.xt_tp); +#if 0 + if (inp->inp_socket) + sotoxsocket(inp->inp_socket, &xt.xt_socket); +#endif + error = SYSCTL_OUT(req, &xt, sizeof xt); + } + INP_UNLOCK(inp); + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + s = splnet(); + INP_INFO_RLOCK(&tcbinfo); + xig.xig_gen = tcbinfo.ipi_gencnt; +#if 0 + xig.xig_sogen = so_gencnt; +#endif + xig.xig_count = tcbinfo.ipi_count; + INP_INFO_RUNLOCK(&tcbinfo); + splx(s); + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + free(inp_list, M_TEMP); + return error; +} + +SYSCTL_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, + tcp_pcblist, "S,xtcpcb", "List of active TCP connections"); + +void +tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) +{ + struct ip *ip = vip; + struct tcphdr *th; + void (*notify)(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 != NULL) { +#ifdef _IP_VHL + th = (struct tcphdr *)((caddr_t)ip + + (IP_VHL_HL(ip->ip_vhl) << 2)); +#else + th = (struct tcphdr *)((caddr_t)ip + + (ip->ip_hl << 2)); +#endif + 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( struct inpcb *inp, int errnum) +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp) + tp->snd_cwnd = tp->t_maxseg; +} + +/* + * 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(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); + } +} + +/* + * Look-up the routing entry to the peer of this inpcb. If no route + * is found and it cannot be allocated, then 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(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(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); +} diff --git a/netinet/tcp_timer.c b/netinet/tcp_timer.c new file mode 100644 index 0000000..a6df2b2 --- /dev/null +++ b/netinet/tcp_timer.c @@ -0,0 +1,385 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <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(void) +{ + 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(void) +{ + 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(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(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/netinet/tcp_timer.h b/netinet/tcp_timer.h new file mode 100644 index 0000000..4bbbb71 --- /dev/null +++ b/netinet/tcp_timer.h @@ -0,0 +1,133 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/tcp_timer.h,v 1.26 2004/08/16 18:32:07 rwatson Exp $ + */ + +#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_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/netinet/tcp_usrreq.c b/netinet/tcp_usrreq.c new file mode 100644 index 0000000..7f4c110 --- /dev/null +++ b/netinet/tcp_usrreq.c @@ -0,0 +1,845 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/tcp_usrreq.c,v 1.120 2005/05/01 14:01:38 rwatson Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <errno.h> +#include <sys/stat.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <rtems/rtems_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(struct socket *); +static int tcp_connect(struct tcpcb *, struct mbuf *); +static struct tcpcb * + tcp_disconnect(struct tcpcb *); +static struct tcpcb * + tcp_usrclosed(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, intptr_t 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, intptr_t 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, intptr_t 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, intptr_t 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(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(int op, struct socket *so, int level, int 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, ""); + +#if defined(__rtems__) +void rtems_set_tcp_buffer_sizes(u_long sendspace, u_long recvspace) +{ + if ( sendspace != 0 ) + tcp_sendspace = sendspace; + if ( recvspace != 0 ) + tcp_recvspace = recvspace; +} +#endif + +/* + * 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(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(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(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/netinet/tcp_var.h b/netinet/tcp_var.h new file mode 100644 index 0000000..cd70970 --- /dev/null +++ b/netinet/tcp_var.h @@ -0,0 +1,414 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/tcp_var.h,v 1.121 2005/04/21 20:11:01 ps Exp $ + */ + +#ifndef _NETINET_TCP_VAR_H_ +#define _NETINET_TCP_VAR_H_ + +#include <netinet/tcp.h> + +/* + * Kernel variables for tcp. + */ + +#ifdef __BSD_VISIBLE +#include <netinet/tcp_timer.h> /* TCPT_NTIMERS */ + +/* + * 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 */ + u_int t_flags; +#define TF_ACKNOW 0x000001 /* ack peer immediately */ +#define TF_DELACK 0x000002 /* ack, but try to delay it */ +#define TF_NODELAY 0x000004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x000008 /* don't use tcp options */ +#define TF_SENTFIN 0x000010 /* have sent FIN */ +#define TF_REQ_SCALE 0x000020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x000040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x000080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x000100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x000200 /* other side said I could SACK */ +#define TF_NEEDSYN 0x000400 /* send SYN (implicit state) */ +#define TF_NEEDFIN 0x000800 /* send FIN (implicit state) */ +#define TF_NOPUSH 0x001000 /* don't push */ +#define TF_REQ_CC 0x002000 /* have/will request CC */ +#define TF_RCVD_CC 0x004000 /* a CC was received in SYN */ +#define TF_SENDCCNEW 0x008000 /* send CCnew instead of CC in SYN */ +#define TF_MORETOCOME 0x010000 /* More data to be appended to sock */ +#define TF_LQ_OVERFLOW 0x020000 /* listen queue overflow */ +#define TF_LASTIDLE 0x040000 /* connection was previously idle */ +#define TF_RXWIN0SENT 0x080000 /* sent a receiver win 0 in response */ +#define TF_FASTRECOVERY 0x100000 /* in NewReno Fast Recovery */ +#define TF_WASFRECOVERY 0x200000 /* was in NewReno Fast Recovery */ +#define TF_SIGNATURE 0x400000 /* require MD5 digests (RFC2385) */ + int t_force; /* 1 if forcing out a byte */ + 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 */ + 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_max; /* highest sequence number sent; + * used to recognize retransmits + */ + 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 */ + tcp_seq irs; /* initial receive sequence number */ + + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_adv; /* advertised window */ + u_long rcv_wnd; /* receive window */ + tcp_seq rcv_up; /* receive urgent pointer */ + + u_long snd_wnd; /* send window */ +/* + * Additional variables for this implementation. + */ +/* 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 */ + + int t_softerror; /* possible error not yet reported */ +/* out-of-band data */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 +/* 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_flags; /* 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 +#define TOF_MSS 0x0010 +#define TOF_SCALE 0x0020 +#define TOF_SIGNATURE 0x0040 /* signature option present */ +#define TOF_SIGLEN 0x0080 /* signature length valid (RFC2385) */ +#define TOF_SACK 0x0100 /* Peer sent SACK option */ + u_int32_t to_tsval; + u_int32_t 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 */ +}; +#define rmx_taop(r) ((struct rmxp_tao *)(r).rmx_filler) + +#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) +#define intotw(ip) ((struct tcptw *)(ip)->inp_ppcb) +#define sototcpcb(so) (intotcpcb(sotoinpcb(so))) +#endif /* __BSD_VISIBLE */ + +/* + * 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. + */ +#if (defined(__GNUC__) && (defined(__arm__) || defined(__mips__))) +#define STR32_UNALGN(ti,m) \ + (ti)->ti_sport = (unsigned short)(((unsigned int) m & 0xffff0000) >> 16); \ + (ti)->ti_dport = (unsigned short) ((unsigned int) m & 0x0000ffff); +#define LD32_UNALGN(ti,m) \ + m = (struct mbuf *)((((unsigned int) (ti)->ti_sport) << 16) | ( (unsigned int)(ti)->ti_dport)); + +#else +#define REASS_MBUF(ti) (*(struct mbuf **)&((ti)->ti_t)) +#endif + +/* + * 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 */ +}; + +/* + * TCB structure exported to user-land via sysctl(3). + * Evil hack: declare only if in_pcb.h and sys/socketvar.h have been + * included. Not all of our clients do. + */ +#if defined(_NETINET_IN_PCB_H_) && defined(_SYS_SOCKETVAR_H_) +struct xtcpcb { + size_t xt_len; + struct inpcb xt_inp; + struct tcpcb xt_tp; +#if 0 + struct xsocket xt_socket; + u_quad_t xt_alignment_hack; +#endif +}; +#endif + +/* + * 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 /* timeout for establishing syn */ +#define TCPCTL_PCBLIST 11 /* list of all outstanding PCBs */ +#define TCPCTL_MAXID 12 + +#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 +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet_tcp); +#endif + +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(struct tcpcb *); +struct tcpcb * + tcp_close(struct tcpcb *); +void tcp_ctlinput(int, struct sockaddr *, void *); +int tcp_ctloutput(int, struct socket *, int, int, struct mbuf **); +struct tcpcb * + tcp_drop(struct tcpcb *, int); +void tcp_drain(void); +void tcp_fasttimo(void); +struct rmxp_tao * + tcp_gettaocache(struct inpcb *); +void tcp_init(void); +void tcp_input(struct mbuf *, int); +void tcp_mss(struct tcpcb *, int); +int tcp_mssopt(struct tcpcb *); +void tcp_mtudisc(struct inpcb *, int); +struct tcpcb * + tcp_newtcpcb(struct inpcb *); +int tcp_output(struct tcpcb *); +void tcp_quench(struct inpcb *, int); +void tcp_respond(struct tcpcb *, + struct tcpiphdr *, struct mbuf *, tcp_seq, tcp_seq, int); +struct rtentry * + tcp_rtlookup(struct inpcb *); +void tcp_setpersist(struct tcpcb *); +void tcp_slowtimo(void); +struct tcpiphdr * + tcp_template(struct tcpcb *); +struct tcpcb * + tcp_timers(struct tcpcb *, int); +void tcp_trace(short, short, 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/netinet/tcpip.h b/netinet/tcpip.h new file mode 100644 index 0000000..1f16bd0 --- /dev/null +++ b/netinet/tcpip.h @@ -0,0 +1,67 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/tcpip.h,v 1.12.22.1.4.1 2010/06/14 02:09:06 kensmith Exp $ + */ + + +#ifndef _NETINET_TCPIP_H_ +#define _NETINET_TCPIP_H_ + +#ifdef __BSD_VISIBLE +#include <netinet/tcp.h> /* struct tcphdr */ +#include <netinet/ip_var.h> /* struct ipovly */ + +/* + * Tcp+ip header, after ip options removed. + */ +struct tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ +}; +#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 /* __BSD_VISIBLE */ + +#endif diff --git a/netinet/udp.h b/netinet/udp.h new file mode 100644 index 0000000..98fc433 --- /dev/null +++ b/netinet/udp.h @@ -0,0 +1,50 @@ +/* + * 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 + */ + +#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/netinet/udp_usrreq.c b/netinet/udp_usrreq.c new file mode 100644 index 0000000..e4ae5c0 --- /dev/null +++ b/netinet/udp_usrreq.c @@ -0,0 +1,736 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.170 2004/11/08 14:44:53 phk Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <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 <rtems/rtems_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, ""); + +struct inpcbhead udb; /* from udp_var.h */ +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, 0, {0}, {0} }; + +static void udp_detach(struct inpcb *); +static int udp_output(struct inpcb *, struct mbuf *, struct mbuf *, + struct mbuf *); +static void udp_notify(struct inpcb *, int); + +void +udp_init(void) +{ + LIST_INIT(&udb); + udbinfo.listhead = &udb; + udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); +} + +void +udp_input(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 buf0[INET_ADDRSTRLEN]; + char buf1[INET_ADDRSTRLEN]; + + log(LOG_INFO, "Connection attempt to UDP %s:%d" + " from %s:%d\n", + inet_ntoa_r(ip->ip_dst, buf0), ntohs(uh->uh_dport), + inet_ntoa_r(ip->ip_src, buf1), 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(struct inpcb *inp, int errnum) +{ + inp->inp_socket->so_error = errnum; + sorwakeup(inp->inp_socket); + sowwakeup(inp->inp_socket); +} + +void +udp_ctlinput(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(struct inpcb *inp, struct mbuf *m, struct mbuf *addr, + struct mbuf *control) +{ + register struct udpiphdr *ui; + register int len = m->m_pkthdr.len; + struct in_addr laddr; + int s = 0, error = 0; + + laddr.s_addr = 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) { + in_pcbdisconnect(inp); + inp->inp_laddr = laddr; + 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); +} + +#ifdef __rtems__ +#define INP_INFO_RLOCK(a) +#define INP_INFO_RUNLOCK(a) +#define INP_LOCK(a) +#define INP_UNLOCK(a) +#endif + +static int +udp_pcblist(SYSCTL_HANDLER_ARGS) +{ + int error, i, n, s; + struct inpcb *inp, **inp_list; + inp_gen_t gencnt; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == 0) { + n = udbinfo.ipi_count; + req->oldidx = 2 * (sizeof xig) + + (n + n/8) * sizeof(struct xinpcb); + return 0; + } + + if (req->newptr != 0) + return EPERM; + + /* + * OK, now we're committed to doing something. + */ + s = splnet(); + gencnt = udbinfo.ipi_gencnt; + n = udbinfo.ipi_count; + splx(s); + + sysctl_wire_old_buffer(req, 2 * (sizeof xig) + + n * sizeof(struct xinpcb)); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = gencnt; +#if 0 + xig.xig_sogen = so_gencnt; +#endif + error = SYSCTL_OUT(req, &xig, sizeof xig); + if (error) + return error; + + /* ccj add the exit if count is 0 */ + if (!n) + return error; + + inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); + if (inp_list == 0) + return ENOMEM; + + s = splnet(); + INP_INFO_RLOCK(&udbinfo); + for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n; + inp = LIST_NEXT(inp, inp_list)) { + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) +#if 0 + && + cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) +#endif + inp_list[i++] = inp; + INP_UNLOCK(inp); + } + INP_INFO_RUNLOCK(&udbinfo); + splx(s); + n = i; + + error = 0; + for (i = 0; i < n; i++) { + inp = inp_list[i]; + INP_LOCK(inp); + if (inp->inp_gencnt <= gencnt) { + struct xinpcb xi; + xi.xi_len = sizeof xi; + /* XXX should avoid extra copy */ + bcopy(inp, &xi.xi_inp, sizeof *inp); +#if 0 + if (inp->inp_socket) + sotoxsocket(inp->inp_socket, &xi.xi_socket); +#endif + error = SYSCTL_OUT(req, &xi, sizeof xi); + } + INP_UNLOCK(inp); + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + s = splnet(); + INP_INFO_RLOCK(&udbinfo); + xig.xig_gen = udbinfo.ipi_gencnt; +#if 0 + xig.xig_sogen = so_gencnt; +#endif + xig.xig_count = udbinfo.ipi_count; + INP_INFO_RUNLOCK(&udbinfo); + splx(s); + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + free(inp_list, M_TEMP); + return error; +} + +SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, + udp_pcblist, "S,xinpcb", "List of active UDP sockets"); + +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, ""); + +#if defined(__rtems__) +void rtems_set_udp_buffer_sizes(u_long sendspace, u_long recvspace) +{ + if ( sendspace != 0 ) + udp_sendspace = sendspace; + if ( recvspace != 0 ) + udp_recvspace = recvspace; +} +#endif + +/*ARGSUSED*/ +int +udp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr, + struct mbuf *control) +{ + struct inpcb *inp = sotoinpcb(so); + int error = 0; + int s; + + if (req == PRU_CONTROL) + return (in_control(so, (uintptr_t)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(struct inpcb *inp) +{ + int s = splnet(); + + in_pcbdetach(inp); + splx(s); +} diff --git a/netinet/udp_var.h b/netinet/udp_var.h new file mode 100644 index 0000000..c06e12d --- /dev/null +++ b/netinet/udp_var.h @@ -0,0 +1,106 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/netinet/udp_var.h,v 1.29 2005/01/07 01:45:45 imp Exp $ + */ + + +#ifndef _NETINET_UDP_VAR_H_ +#define _NETINET_UDP_VAR_H_ + +#include <netinet/ip_var.h> /* struct ipovly */ +#include <netinet/udp.h> /* struct udphdr */ + +/* + * 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_PCBLIST 5 /* list of PCBs for UDP sockets */ +#define UDPCTL_MAXID 6 + +#define UDPCTL_NAMES { \ + { 0, 0 }, \ + { "checksum", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ + { "maxdgram", CTLTYPE_INT }, \ + { "recvspace", CTLTYPE_INT }, \ +} + +#ifdef _KERNEL +SYSCTL_DECL(_net_inet_udp); + +extern struct inpcbhead udb; +extern struct inpcbinfo udbinfo; +extern struct udpstat udpstat; + +void udp_ctlinput(int, struct sockaddr *, void *); +void udp_init(void); +void udp_input(struct mbuf *, int); +int udp_usrreq(struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *); +#endif + +#endif diff --git a/nfs/bootp_subr.c b/nfs/bootp_subr.c new file mode 100644 index 0000000..03b68ec --- /dev/null +++ b/nfs/bootp_subr.c @@ -0,0 +1,1213 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * 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/ucred.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/sockio.h> +#include <sys/mount.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/reboot.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/uio.h> + +#include <net/if.h> +#include <net/if_var.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/nfsproto.h> +#include <nfsclient/nfsargs.h> +#include <nfsclient/nfsdiskless.h> +#include <nfs/xdr_subs.h> + +#include <fcntl.h> +#include <rtems/mkrootfs.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/bsdnet/servers.h> +#include <inttypes.h> + +#include "rtems/bootp.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 counts up 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 */ +#if !defined(__rtems__) +static int md_mount(struct sockaddr_in *mdsin, char *path, + u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp); +static int md_lookup_swap(struct sockaddr_in *mdsin,char *path, + u_char *fhp, int *fhsizep, + struct nfs_args *args, + struct proc *procp); +static int setfs(struct sockaddr_in *addr, char *path, char *p); +static int getdec(char **ptr); +#endif +#if !defined(__rtems__) +static char *substr(char *a,char *b); +static void mountopts(struct nfs_args *args, char *p); +static int xdr_opaque_decode(struct mbuf **ptr,u_char *buf, + int len); +static int xdr_int_decode(struct mbuf **ptr,int *iptr); +#endif +static void printip(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 + +#ifdef BOOTP_DEBUG +void +bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma) +{ + + if (sa == NULL) { + 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(struct sockaddr *ma) +{ + + if (ma == NULL) { + printf("<null>"); + return; + } + printf("%x", *(int*)ma); +} + +void +bootpboot_p_rtentry(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(struct radix_node *rn) +{ + + while (rn != NULL) { + 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 + +/* + * - determine space needed to store src string + * - allocate or reallocate dst, so that string fits in + * - copy string from src to dest + */ +void *bootp_strdup_realloc(char *dst,const char *src) +{ + size_t len; + + if (dst == NULL) { + /* first allocation, simply use strdup */ + if (src) + dst = strdup(src); + } + else { + /* already allocated, so use realloc/strcpy */ + len = src ? strlen(src) + 1 : 0; + /* src == NULL tells us to effectively free dst */ + dst = realloc(dst,len); + if (dst != NULL) { + strcpy(dst,src); + } + } + return dst; +} + +int +bootpc_call( + struct bootp_packet *call, + struct bootp_packet *reply, /* output */ + struct proc *procp, + const void *exp_vend, + size_t exp_vend_len) +{ + struct socket *so; + struct sockaddr_in *sin; + struct mbuf *m, *nam; + struct uio auio; + struct iovec aio; + int error, rcvflg, timo, secs, len; + + /* 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. + */ + for (timo=1; timo <= MAX_RESEND_DELAY; timo++) { + /* 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); +#ifndef __rtems__ + auio.uio_procp = procp; +#endif + error = sosend(so, nam, &auio, NULL, NULL, 0); + if (error) { + printf("bootpc_call: sosend: %d\n", error); + switch (error) { + case ENOBUFS: /* No buffer space available */ + case ENETUNREACH: /* Network is unreachable */ + case ENETDOWN: /* Network interface is not configured */ + case EHOSTDOWN: /* Host is down */ + case EHOSTUNREACH: /* Host is unreachable */ + case EMSGSIZE: /* Message too long */ + /* This is a possibly transient error. + We can still receive replies from previous attempts. */ + break; + default: + goto out; + } + } + + /* + * 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); +#ifndef __rtems__ + auio.uio_procp = procp; +#endif + + 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; + + if (exp_vend_len > 0 && bcmp(exp_vend, reply->vend, exp_vend_len)) + continue; + + goto gotreply; /* break two levels */ + + } /* while secs */ + } /* send/receive a number of times then return an error */ + { + uint32_t addr = ntohl(sin->sin_addr.s_addr); + printf("BOOTP timeout for server %"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32"\n", + (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); + } + 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) { + printf("bootpc_fakeup_interface: GIFFLAGS, error=%s\n", strerror(error)); + return error; + } + ireq->ifr_flags |= IFF_UP; + error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); + if (error) { + printf("bootpc_fakeup_interface: SIFFLAGS, error=%s\n", strerror(error)); + return 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); + /* + * Ignore a File already exists (EEXIST) error code. This means a + * route for the address is already present and is returned on + * a second pass to here. + */ + if (error && (error != EEXIST)) { + printf("bootpc_fakeup_interface: set if addr, error=%s\n", strerror(error)); + return 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) { + printf("bootpc_fakeup_interface: set if netmask, error=%s\n", strerror(error)); + return 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) { + printf("bootpc_fakeup_interface: set broadcast addr, error=%s\n", strerror(error)); + return 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 && error != EEXIST) + printf("bootpc_fakeup_interface: add default route, error=%s\n", + strerror(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) { + printf("bootpc_adjust_interface: set netmask, error=%s\n", strerror(error)); + return 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) { + printf("bootpc_adjust_interface: set broadcast addr, error=%s\n", strerror(error)); + return error; + } + + bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); + error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); + if (error) { + printf("bootpc_adjust_interface: set if addr, error=%s\n", strerror(error)); + return 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("bootpc_adjust_interface: add net route, error=%d\n", error); + } + + return error; +} + +#if !defined(__rtems__) +static int +setfs(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); +} +#endif + +#if !defined(__rtems__) +static int +getdec(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); +} +#endif + +static void printip(char *prefix,struct in_addr addr) +{ + uint32_t ip; + + ip = ntohl(addr.s_addr); + + printf("%s is %" PRId32" .%" PRId32" .%" PRId32" .%" PRId32" \n",prefix, + ip >> 24, (ip >> 16) & 0xff ,(ip >> 8) & 0xff ,ip & 0xff ); +} + +static int dhcpOptionOverload = 0; +static char dhcp_gotgw = 0; +static char dhcp_gotnetmask = 0; +static char dhcp_gotserver = 0; +static char dhcp_gotlogserver = 0; +static struct sockaddr_in dhcp_netmask; +static struct sockaddr_in dhcp_gw; +static char *dhcp_hostname = NULL; + +static void +processOptions (unsigned char *optbuf, int optbufSize) +{ + int j = 0; + int len; + int code, ncode; + unsigned char *p; + + ncode = optbuf[0]; + while (j < optbufSize) { + code = optbuf[j] = ncode; + if (code == 255) + return; + if (code == 0) { + j++; + continue; + } + len = optbuf[j+1]; + j += 2; + if ((len + j) >= optbufSize) { + printf ("Truncated field for code %d", code); + return; + } + ncode = optbuf[j+len]; + optbuf[j+len] = '\0'; + p = &optbuf[j]; + j += len; + + /* + * Process the option + */ + switch (code) { + case 1: + /* Subnet mask */ + if (len!=4) { + printf("bootpc: subnet mask len is %d\n",len); + continue; + } + bcopy (p, &dhcp_netmask.sin_addr, 4); + dhcp_gotnetmask = 1; + break; + + case 2: + /* Time offset */ + if (len!=4) { + printf("bootpc: time offset len is %d\n",len); + continue; + } + bcopy (p, &rtems_bsdnet_timeoffset, 4); + rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset); + break; + + case 3: + /* Routers */ + if (len % 4) { + printf ("bootpc: Router Len is %d\n", len); + continue; + } + if (len > 0) { + bcopy(p, &dhcp_gw.sin_addr, 4); + dhcp_gotgw = 1; + } + break; + + case 42: + /* NTP servers */ + if (len % 4) { + printf ("bootpc: time server Len is %d\n", len); + continue; + } + { + int tlen = 0; + while ((tlen < len) && + (rtems_bsdnet_ntpserver_count < sizeof rtems_bsdnet_config.ntp_server / + sizeof rtems_bsdnet_config.ntp_server[0])) { + bcopy (p+tlen, + &rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count], + 4); + printip("Time Server", + rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count]); + rtems_bsdnet_ntpserver_count++; + tlen += 4; + } + } + break; + + case 6: + /* Domain Name servers */ + if (len % 4) { + printf ("bootpc: DNS Len is %d", len); + continue; + } + { + int dlen = 0; + while ((dlen < len) && + (rtems_bsdnet_nameserver_count < sizeof rtems_bsdnet_config.name_server / + sizeof rtems_bsdnet_config.name_server[0])) { + bcopy (p+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 12: + /* Host name */ + if (len>=MAXHOSTNAMELEN) { + printf ("bootpc: hostname >=%d bytes", MAXHOSTNAMELEN); + continue; + } + if (sethostname ((char *)p, len) < 0) { + printf("bootpc: Can't set host name"); + } + printf("Hostname is %s\n", p); + dhcp_hostname = bootp_strdup_realloc(dhcp_hostname,(char *)p); + break; + + case 7: + /* Log servers */ + if (len % 4) { + printf ("bootpc: Log server Len is %d", len); + continue; + } + if (len > 0) { + bcopy(p, &rtems_bsdnet_log_host_address, 4); + dhcp_gotlogserver = 1; + } + break; + + case 15: + /* Domain name */ + if (p[0]) { + rtems_bsdnet_domain_name = + bootp_strdup_realloc(rtems_bsdnet_domain_name,(char *)p); + printf("Domain name is %s\n", rtems_bsdnet_domain_name); + } + break; + + case 16: /* Swap server IP address. unused */ + break; + + case 52: + /* DHCP option override */ + if (len != 1) { + printf ("bootpc: DHCP option overload len is %d", len); + continue; + } + dhcpOptionOverload = p[0]; + break; + + case 128: /* Site-specific option for DHCP servers that + * a) don't supply tag 54 + * and + * b) don't supply the server address in siaddr + * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab: + * Bootsrv s Site,128,IP,1,1 + * and use that symbol in the macro that defines the client: + * Bootsrv=<tftp-server-ip-address> + */ + case 54: + /* DHCP server */ + if (len != 4) { + printf ("bootpc: DHCP server len is %d", len); + continue; + } + bcopy(p, &rtems_bsdnet_bootp_server_address, 4); + dhcp_gotserver = 1; + break; + + case 66: + /* DHCP server name option */ + if (p[0]) + rtems_bsdnet_bootp_server_name = + bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,(char *)p); + break; + + case 67: + /* DHCP bootfile option */ + if (p[0]) + rtems_bsdnet_bootp_boot_file_name = + bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,(char *)p); + break; + + case 129: + /* Site specific option; we use this to get + * a 'command line string' + */ + if (p[0]) + rtems_bsdnet_bootp_cmdline = strdup((char *)p); + break; + + default: + printf ("Ignoring BOOTP/DHCP option code %d\n", code); + break; + } + } +} + +#define EALEN 6 + +bool +bootpc_init(bool update_files, bool forever) +{ + struct bootp_packet call; + struct bootp_packet reply; + static u_int32_t xid = ~0xFF; + + struct ifreq ireq; + struct ifnet *ifp; + struct socket *so; + int j; + int error; + struct sockaddr_in myaddr; + 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 true; + + /* + * If we are to update the files create the root + * file structure. + */ + if (update_files) + if (rtems_create_root_fs () < 0) { + printf("Error creating the root filesystem.\nFile not created.\n"); + update_files = 0; + } + + if (dhcp_hostname != NULL) { + /* free it */ + dhcp_hostname=bootp_strdup_realloc(dhcp_hostname,0); + } + + /* + * 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) { + printf("bootpc_init: no suitable interface\n"); + return false; + } + 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) { + printf("bootpc_init: socreate, error=%d", error); + return false; + } + if (bootpc_fakeup_interface(&ireq,so,procp) != 0) { + soclose(so); + return false; + } + + /* 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) { + printf("bootpc: Unable to find HW address\n"); + soclose(so); + return false; + } + if (sdl->sdl_alen != EALEN ) { + printf("bootpc: HW address len is %d, expected value is %d\n", + sdl->sdl_alen,EALEN); + soclose(so); + return false; + } + + 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 + + while (true) { + 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, NULL, 0); + + if (!error) + break; + + printf("BOOTP call failed -- error %d", error); + + if (!forever) { + soclose(so); + return false; + } + } + + /* + * Initialize network address structures + */ + bzero(&myaddr,sizeof(myaddr)); + bzero(&dhcp_netmask,sizeof(dhcp_netmask)); + bzero(&dhcp_gw,sizeof(dhcp_gw)); + myaddr.sin_len = sizeof(myaddr); + myaddr.sin_family = AF_INET; + dhcp_netmask.sin_len = sizeof(dhcp_netmask); + dhcp_netmask.sin_family = AF_INET; + dhcp_gw.sin_len = sizeof(dhcp_gw); + dhcp_gw.sin_family= AF_INET; + + /* + * Set our address + */ + myaddr.sin_addr = reply.yiaddr; + printip("My ip address",myaddr.sin_addr); + + /* + * Process BOOTP/DHCP options + */ + if (reply.vend[0]==99 && reply.vend[1]==130 && + reply.vend[2]==83 && reply.vend[3]==99) { + processOptions (&reply.vend[4], sizeof(reply.vend) - 4); + } + if (dhcpOptionOverload & 1) { + processOptions ((unsigned char *)reply.file, sizeof reply.file); + } + else { + if (reply.file[0]) + rtems_bsdnet_bootp_boot_file_name = + bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,reply.file); + } + if (dhcpOptionOverload & 2) { + processOptions ((unsigned char *)reply.sname, sizeof reply.sname); + } + else { + if (reply.sname[0]) + rtems_bsdnet_bootp_server_name = + bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,reply.sname); + } + if (rtems_bsdnet_bootp_server_name) + printf ("Server name is %s\n", rtems_bsdnet_bootp_server_name); + if (rtems_bsdnet_bootp_boot_file_name) + printf ("Boot file is %s\n", rtems_bsdnet_bootp_boot_file_name); + if (rtems_bsdnet_bootp_cmdline) + printf ("Command line is %s\n", rtems_bsdnet_bootp_cmdline); + + /* + * Use defaults if values were not supplied by BOOTP/DHCP options + */ + if (!dhcp_gotnetmask) { + if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr))) + dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr))) + dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); + else + dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); + } + printip ("Subnet mask", dhcp_netmask.sin_addr); + if (!dhcp_gotserver) + rtems_bsdnet_bootp_server_address = reply.siaddr; + printip ("Server ip address" ,rtems_bsdnet_bootp_server_address); + if (!dhcp_gotgw) + dhcp_gw.sin_addr = reply.giaddr; + printip ("Gateway ip address", dhcp_gw.sin_addr); + if (!dhcp_gotlogserver) + rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address; + printip ("Log server ip address", rtems_bsdnet_log_host_address); + + /* + * Update the files if we are asked too. + */ + if (update_files) { + char *dn = rtems_bsdnet_domain_name; + char *hn = dhcp_hostname; + if (!dn) + dn = "mydomain"; + if (!hn) + hn = "me"; + rtems_rootfs_append_host_rec(myaddr.sin_addr.s_addr, hn, dn); + + /* + * Should the given domainname be used here ? + */ + if (dhcp_gotserver) { + if (rtems_bsdnet_bootp_server_name) + hn = rtems_bsdnet_bootp_server_name; + else + hn = "bootps"; + rtems_rootfs_append_host_rec(rtems_bsdnet_bootp_server_address.s_addr, + hn, dn); + } + + if (dhcp_gotlogserver) { + rtems_rootfs_append_host_rec(rtems_bsdnet_log_host_address.s_addr, + "logs", dn); + } + + /* + * Setup the DNS configuration file /etc/resolv.conf. + */ + if (rtems_bsdnet_nameserver_count) { + int i; + char buf[64]; + const char *bufl[1]; + + bufl[0] = buf; + +#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH) + + if (rtems_bsdnet_domain_name && + (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) { + strcpy(buf, "search "); + strcat(buf, rtems_bsdnet_domain_name); + strcat(buf, "\n"); + rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl); + } + + for (i = 0; i < rtems_bsdnet_nameserver_count; i++) { + char addrbuf[INET_ADDRSTRLEN]; + strcpy(buf, "nameserver "); + strcat(buf, inet_ntoa_r(rtems_bsdnet_nameserver[i], addrbuf)); + strcat(buf, "\n"); + if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl)) + break; + } + } + } + + /* + * Configure the interface with the new settings + */ + error = bootpc_adjust_interface(&ireq,so, + &myaddr,&dhcp_netmask,&dhcp_gw,procp); + soclose(so); + + return true; +} diff --git a/nfs/nfsproto.h b/nfs/nfsproto.h new file mode 100644 index 0000000..6eebd81 --- /dev/null +++ b/nfs/nfsproto.h @@ -0,0 +1,423 @@ +/* + * 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. + * 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.2 (Berkeley) 3/30/95 + * $FreeBSD: src/sys/nfs/nfsproto.h,v 1.11 2005/01/07 01:45:50 imp Exp $ + */ + + +#ifndef _NFS_NFSPROTO_H_ +#define _NFS_NFSPROTO_H_ + +#include <sys/mount.h> /* fhandle_t */ + +/* + * 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, 4 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 +#define NFSPROC_NOOP 22 +#define NFS_NPROCS 23 + +/* 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 + +/* 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_int32_t nfsv2_sec; + u_int32_t nfsv2_usec; +}; +typedef struct nfsv2_time nfstime2; + +struct nfsv3_time { + u_int32_t nfsv3_sec; + u_int32_t 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_int32_t nfsuquad[2]; +}; +typedef struct nfs_uquad nfsuint64; + +/* + * Used to convert between two u_longs and a u_quad_t. + */ +union nfs_quadconvert { + u_int32_t lval[2]; + u_quad_t qval; +}; +typedef union nfs_quadconvert nfsquad_t; + +/* + * NFS Version 3 special file number. + */ +struct nfsv3_spec { + u_int32_t specdata1; + u_int32_t 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_int32_t fa_type; + u_int32_t fa_mode; + u_int32_t fa_nlink; + u_int32_t fa_uid; + u_int32_t fa_gid; + union { + struct { + u_int32_t nfsv2fa_size; + u_int32_t nfsv2fa_blocksize; + u_int32_t nfsv2fa_rdev; + u_int32_t nfsv2fa_blocks; + u_int32_t nfsv2fa_fsid; + u_int32_t 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_int32_t sa_mode; + u_int32_t sa_uid; + u_int32_t sa_gid; + u_int32_t sa_size; + nfstime2 sa_atime; + nfstime2 sa_mtime; +}; + +/* + * NFS Version 3 sattr structure for the new node creation case. + */ +struct nfsv3_sattr { + u_int32_t sa_modetrue; + u_int32_t sa_mode; + u_int32_t sa_uidfalse; + u_int32_t sa_gidfalse; + u_int32_t sa_sizefalse; + u_int32_t sa_atimetype; + nfstime3 sa_atime; + u_int32_t sa_mtimetype; + nfstime3 sa_mtime; +}; + +struct nfs_statfs { + union { + struct { + u_int32_t nfsv2sf_tsize; + u_int32_t nfsv2sf_bsize; + u_int32_t nfsv2sf_blocks; + u_int32_t nfsv2sf_bfree; + u_int32_t nfsv2sf_bavail; + } sf_nfsv2; + struct { + nfsuint64 nfsv3sf_tbytes; + nfsuint64 nfsv3sf_fbytes; + nfsuint64 nfsv3sf_abytes; + nfsuint64 nfsv3sf_tfiles; + nfsuint64 nfsv3sf_ffiles; + nfsuint64 nfsv3sf_afiles; + u_int32_t 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_int32_t fs_rtmax; + u_int32_t fs_rtpref; + u_int32_t fs_rtmult; + u_int32_t fs_wtmax; + u_int32_t fs_wtpref; + u_int32_t fs_wtmult; + u_int32_t fs_dtpref; + nfsuint64 fs_maxfilesize; + nfstime3 fs_timedelta; + u_int32_t fs_properties; +}; + +struct nfsv3_pathconf { + u_int32_t pc_linkmax; + u_int32_t pc_namemax; + u_int32_t pc_notrunc; + u_int32_t pc_chownrestricted; + u_int32_t pc_caseinsensitive; + u_int32_t pc_casepreserving; +}; + +#endif diff --git a/nfs/rpcv2.h b/nfs/rpcv2.h new file mode 100644 index 0000000..9d49133 --- /dev/null +++ b/nfs/rpcv2.h @@ -0,0 +1,108 @@ +/* + * 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. + * 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.2 (Berkeley) 3/30/95 + * $FreeBSD: src/sys/nfs/rpcv2.h,v 1.14 2005/01/07 01:45:50 imp Exp $ + */ + + +#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_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 + +/* msg type */ +#define RPC_CALL 0 +#define RPC_REPLY 1 + +/* reply status */ +#define RPC_MSGACCEPTED 0 +#define RPC_MSGDENIED 1 + +/* accepted status */ +#define RPC_SUCCESS 0 +#define RPC_PROGUNAVAIL 1 +#define RPC_PROGMISMATCH 2 +#define RPC_PROCUNAVAIL 3 +#define RPC_GARBAGE 4 /* I like this one */ +#define RPC_SYSTEMERR 5 + +/* rejected status */ +#define RPC_MISMATCH 0 +#define RPC_AUTHERR 1 + +/* Authentication failures */ +#define AUTH_OK 0 +#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 + +#endif diff --git a/nfs/xdr_subs.h b/nfs/xdr_subs.h new file mode 100644 index 0000000..b29c172 --- /dev/null +++ b/nfs/xdr_subs.h @@ -0,0 +1,87 @@ +/* + * 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. + * 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.3 (Berkeley) 3/30/95 + * $FreeBSD: src/sys/nfs/xdr_subs.h,v 1.15 2005/01/07 01:45:50 imp Exp $ + */ + + +#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((int32_t)(v))) +#define txdr_unsigned(v) (htonl((int32_t)(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) \ + ((((u_quad_t)ntohl(((u_int32_t *)(f))[0])) << 32) | \ + (u_quad_t)(ntohl(((u_int32_t *)(f))[1]))) +#define txdr_hyper(f, t) \ +do { \ + ((u_int32_t *)(t))[0] = htonl((u_int32_t)((f) >> 32)); \ + ((u_int32_t *)(t))[1] = htonl((u_int32_t)((f) & 0xffffffff)); \ +} while (0) + +#endif diff --git a/nfsclient/nfsargs.h b/nfsclient/nfsargs.h new file mode 100644 index 0000000..c860972 --- /dev/null +++ b/nfsclient/nfsargs.h @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 1989, 1993, 1995 + * 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. + * 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.4 (Berkeley) 5/1/95 + * $FreeBSD: src/sys/nfsclient/nfsargs.h,v 1.67 2005/01/07 01:45:51 imp Exp $ + */ + + +#ifndef _NFSCLIENT_NFSARGS_H_ +#define _NFSCLIENT_NFSARGS_H_ + +/* + * 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 retries */ +#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 */ +/* 0x100 free, was NFSMNT_NQNFS */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +/* 0x400 free, was NFSMNT_KERB */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +/* 0x1000 free, was NFSMNT_LEASETERM */ +#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_ACREGMIN 0x00040000 +#define NFSMNT_ACREGMAX 0x00080000 +#define NFSMNT_ACDIRMIN 0x00100000 +#define NFSMNT_ACDIRMAX 0x00200000 +#define NFSMNT_NOLOCKD 0x00400000 /* Locks are local */ +#define NFSMNT_NFSV4 0x00800000 /* Use NFS Version 4 protocol */ +#define NFSMNT_HASWRITEVERF 0x01000000 /* NFSv4 Write verifier */ + +#endif diff --git a/nfsclient/nfsdiskless.h b/nfsclient/nfsdiskless.h new file mode 100644 index 0000000..ee6be12 --- /dev/null +++ b/nfsclient/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. + * 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 + */ + +#ifndef _NFS_NFSDISKLESS_H_ +#define _NFS_NFSDISKLESS_H_ + +#include <netinet/in.h> /* struct sockaddr_in */ +#include <net/if.h> +#include <nfs/nfsproto.h> /* NFSX_V3FHMAX */ +#include <nfsclient/nfsargs.h> /* struct nfs_args */ + +/* + * 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/opt_atalk.h b/opt_atalk.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_atalk.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_bdg.h b/opt_bdg.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_bdg.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_compat.h b/opt_compat.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_compat.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_inet.h b/opt_inet.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_inet.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_inet6.h b/opt_inet6.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_inet6.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_ipfw.h b/opt_ipfw.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_ipfw.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_ipsec.h b/opt_ipsec.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_ipsec.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_ipx.h b/opt_ipx.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_ipx.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_mac.h b/opt_mac.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_mac.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_mrouting.h b/opt_mrouting.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_mrouting.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_netgraph.h b/opt_netgraph.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/opt_netgraph.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/opt_ppp.h b/opt_ppp.h new file mode 100644 index 0000000..37e2068 --- /dev/null +++ b/opt_ppp.h @@ -0,0 +1,10 @@ +#ifndef _PPP_H_ +#define _PPP_H_ + +#define NPPP 1 +#define NBPFILTER 0 +#undef VJC +#undef PPP_FILTER +#undef PPP_COMPRESS + +#endif diff --git a/opt_tcpdebug.h b/opt_tcpdebug.h new file mode 100644 index 0000000..91d7ede --- /dev/null +++ b/opt_tcpdebug.h @@ -0,0 +1,12 @@ +/* intentionally empty file */ + +/* + * Uncomment the following line to turn on debug code. When you define + * this symbol, tcp_trace() is called. If you want tcp_trace() to + * print, then you need to edit netinet/tcp_debug to set the variable + * "tcpconsdebug" to 1. + */ + +/* +#define TCPDEBUG +*/ diff --git a/resolv.h b/resolv.h new file mode 100644 index 0000000..06d3a55 --- /dev/null +++ b/resolv.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 1983, 1987, 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. 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) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 + * $FreeBSD: release/9.0.0/include/resolv.h 203964 2010-02-16 19:39:50Z imp $ + */ + +#ifndef _RESOLV_H_ +#define _RESOLV_H_ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/cdefs.h> +#include <stdio.h> +#include <netinet/in.h> /* struct in_addr */ + +/*% + * 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 + +/*% + * Resolver configuration file. + * Normally not present, but may contain the address of the + * initial name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook)(struct sockaddr_in * const *ns, + const u_char **query, + int *querylen, + u_char *ans, + int anssiz, + int *resplen); + +typedef res_sendhookact (*res_send_rhook)(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 */ + const char * name; /*%< Its symbolic name, like "MX" */ + const char * humanname; /*%< Its fun name, like "mail exchanger" */ +}; + +/*% + * 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; /*%< retransmission 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 */ +}; + +typedef struct __res_state *res_state; + +/*% + * 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 */ + +#define fp_nquery __fp_nquery +#define fp_query __fp_query +#define hostalias __hostalias +#define p_query __p_query +#define res_close __res_close +#define res_init __res_init +#define res_isourserver __res_isourserver +#define res_mkquery __res_mkquery +#define res_query __res_query +#define res_querydomain __res_querydomain +#define res_search __res_search +#define res_send __res_send + +__BEGIN_DECLS +void fp_nquery(const u_char *, int, FILE *); +void fp_query(const u_char *, FILE *); +const char * hostalias(const char *); +void p_query(const u_char *); +void res_close(void); +int res_init(void); +int res_isourserver(const struct sockaddr_in *); +int res_mkquery(int, const char *, int, int, const u_char *, + int, const u_char *, u_char *, int); +int res_query(const char *, int, int, u_char *, int); +int res_querydomain(const char *, const char *, int, int, + u_char *, int); +int res_search(const char *, int, int, u_char *, int); +int res_send(const u_char *, int, u_char *, int); +__END_DECLS + +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 b64_ntop __b64_ntop +#define b64_pton __b64_pton +#define dn_comp __dn_comp +#define dn_count_labels __dn_count_labels +#define dn_expand __dn_expand +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define loc_aton __loc_aton +#define loc_ntoa __loc_ntoa +#define p_cdname __p_cdname +#define p_cdnname __p_cdnname +#define fp_resstat __fp_resstat +#define p_class __p_class +#define p_fqname __p_fqname +#define p_fqnname __p_fqnname +#define p_option __p_option +#define p_secstodate __p_secstodate +#define p_section __p_section +#define p_time __p_time +#define p_type __p_type +#define putlong __putlong +#define putshort __putshort +#define res_dnok __res_dnok +#define res_hnok __res_hnok +#define res_mailok __res_mailok +#define res_nameinquery __res_nameinquery +#define res_ownok __res_ownok +#define res_queriesmatch __res_queriesmatch +#define res_randomid __res_randomid +#define sym_ntop __sym_ntop +#define sym_ntos __sym_ntos +#define sym_ston __sym_ston +#define res_send_setqhook __res_send_setqhook +#define res_send_setrhook __res_send_setrhook +#define res_mkupdate __res_mkupdate +#define res_mkupdrec __res_mkupdrec +#define res_freeupdrec __res_freeupdrec + +__BEGIN_DECLS +int res_hnok(const char *); +int res_ownok(const char *); +int res_mailok(const char *); +int res_dnok(const char *); +int sym_ston(const struct res_sym *, const char *, int *); +const char * sym_ntos(const struct res_sym *, int, int *); +const char * sym_ntop(const struct res_sym *, int, int *); +int b64_ntop(u_char const *, size_t, char *, size_t); +int b64_pton(char const *, u_char *, size_t); +int loc_aton(const char *, u_char *); +const char * loc_ntoa(const u_char *, char *); +int dn_skipname(const u_char *, const u_char *); +void fp_resstat(struct __res_state *, FILE *); +void putlong(u_int32_t, u_char *); +void putshort(u_int16_t, u_char *); +const char * p_class(int); +const char * p_time(u_int32_t); +const char * p_type(int); +const u_char * p_cdnname(const u_char *, const u_char *, int, FILE *); +const u_char * p_cdname(const u_char *, const u_char *, FILE *); +const u_char * p_fqnname(const u_char *, const u_char *, int, char *, int); +const u_char * p_fqname(const u_char *, const u_char *, FILE *); +const char * p_option(u_long); +char * p_secstodate(u_long); +int dn_count_labels(const char *); +int dn_comp(const char *, u_char *, int, u_char **, u_char **); +int dn_expand(const u_char *, const u_char *, const u_char *, + char *, int); +u_int res_randomid(void); +int res_nameinquery(const char *, int, int, const u_char *, + const u_char *); +int res_queriesmatch(const u_char *, const u_char *, + const u_char *, const u_char *); +const char * p_section(int, int); +void res_send_setqhook(res_send_qhook); +void res_send_setrhook(res_send_rhook); + +/* XXX The following depend on the ns_updrec typedef in arpa/nameser.h */ +#ifdef _ARPA_NAMESER_H_ +int res_update (ns_updrec *); +int res_mkupdate (ns_updrec *, u_char *, int); +ns_updrec * res_mkupdrec (int, const char *, u_int, u_int, u_long); +void res_freeupdrec (ns_updrec *); +#endif +__END_DECLS + +#endif /* !_RESOLV_H_ */ diff --git a/rpc/auth.h b/rpc/auth.h new file mode 100644 index 0000000..13432bd --- /dev/null +++ b/rpc/auth.h @@ -0,0 +1,262 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)auth.h 1.17 88/02/08 SMI + * from: @(#)auth.h 2.3 88/08/07 4.0 RPCSRC + * $FreeBSD: src/include/rpc/auth.h,v 1.15 1999/08/27 23:45:02 peter Exp $ + */ + +/* + * auth.h, Authentication interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The data structures are completely opaque to the client. The client + * is required to pass a AUTH * to routines that create rpc + * "sessions". + */ + +#ifndef _RPC_AUTH_H +#define _RPC_AUTH_H +#include <sys/cdefs.h> +#include <sys/socket.h> +#include <rpc/xdr.h> + +#define MAX_AUTH_BYTES 400 +#define MAXNETNAMELEN 255 /* maximum length of network user's name */ + +/* + * Status returned from authentication check + */ +enum auth_stat { + AUTH_OK=0, + /* + * failed at remote end + */ + AUTH_BADCRED=1, /* bogus credentials (seal broken) */ + AUTH_REJECTEDCRED=2, /* client should begin new session */ + AUTH_BADVERF=3, /* bogus verifier (seal broken) */ + AUTH_REJECTEDVERF=4, /* verifier expired or was replayed */ + AUTH_TOOWEAK=5, /* rejected due to security reasons */ + /* + * failed locally + */ + AUTH_INVALIDRESP=6, /* bogus response verifier */ + AUTH_FAILED=7, /* some unknown reason */ + _AUTH_STAT = 0xffffffff +}; + +union des_block { + struct { + u_int32_t high; + u_int32_t low; + } key; + char c[8]; +}; +typedef union des_block des_block; +__BEGIN_DECLS +extern bool_t xdr_des_block (XDR *, des_block *); +__END_DECLS + +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + u_int oa_length; /* not to exceed MAX_AUTH_BYTES */ +}; +__BEGIN_DECLS +bool_t xdr_opaque_auth (XDR *xdrs, struct opaque_auth *ap); +__END_DECLS + + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct __rpc_auth { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + union des_block ah_key; + struct auth_ops { + void (*ah_nextverf) (struct __rpc_auth *); + /* nextverf & serialize */ + int (*ah_marshal) (struct __rpc_auth *, XDR *); + /* validate verifier */ + int (*ah_validate) (struct __rpc_auth *, + struct opaque_auth *); + /* refresh credentials */ + int (*ah_refresh) (struct __rpc_auth *); + /* destroy this structure */ + void (*ah_destroy) (struct __rpc_auth *); + } *ah_ops; + caddr_t ah_private; +} AUTH; + + +/* + * Authentication ops. + * The ops and the auth handle provide the interface to the authenticators. + * + * AUTH *auth; + * XDR *xdrs; + * struct opaque_auth verf; + */ +#define AUTH_NEXTVERF(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) +#define auth_nextverf(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) + +#define AUTH_MARSHALL(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) +#define auth_marshall(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) + +#define AUTH_VALIDATE(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) +#define auth_validate(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) + +#define AUTH_REFRESH(auth) \ + ((*((auth)->ah_ops->ah_refresh))(auth)) +#define auth_refresh(auth) \ + ((*((auth)->ah_ops->ah_refresh))(auth)) + +#define AUTH_DESTROY(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) +#define auth_destroy(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) + + +extern struct opaque_auth _null_auth; + +/* + * These are the various implementations of client side authenticators. + */ + +/* + * Unix style authentication + * AUTH *authunix_create(machname, uid, gid, len, aup_gids) + * char *machname; + * int uid; + * int gid; + * int len; + * int *aup_gids; + */ +__BEGIN_DECLS +struct sockaddr_in; +extern AUTH *authunix_create (char *, int, int, int, int *); +extern AUTH *authunix_create_default (void); +extern AUTH *authnone_create (void); +__END_DECLS + +/* Forward compatibility with TI-RPC */ +#define authsys_create authunix_create +#define authsys_create_default authunix_create_default + +/* + * DES style authentication + * AUTH *authdes_create(servername, window, timehost, ckey) + * char *servername; - network name of server + * u_int window; - time to live + * struct sockaddr *timehost; - optional hostname to sync with + * des_block *ckey; - optional conversation key to use + */ +__BEGIN_DECLS +extern AUTH *authdes_create ( char *, u_int, struct sockaddr *, des_block * ); +#ifdef NOTYET +/* + * TI-RPC supports this call, but it requires the inclusion of + * NIS+-specific headers which would require the inclusion of other + * headers which would result in a tangled mess. For now, the NIS+ + * code prototypes this routine internally. + */ +extern AUTH *authdes_pk_create ( char *, netobj *, u_int, + struct sockaddr *, des_block *, + nis_server * ); +#endif +__END_DECLS + +/* + * Netname manipulation routines. + */ +__BEGIN_DECLS +extern int netname2user ( char *, uid_t *, gid_t *, int *, gid_t *); +extern int netname2host ( char *, char *, int ); +extern int getnetname ( char * ); +extern int user2netname ( char *, uid_t, char * ); +extern int host2netname ( char *, char *, char * ); +extern void passwd2des ( char *, char * ); +__END_DECLS + +/* + * Keyserv interface routines. + * XXX Should not be here. + */ +#ifndef HEXKEYBYTES +#define HEXKEYBYTES 48 +#endif +typedef char kbuf[HEXKEYBYTES]; +typedef char *namestr; + +struct netstarg { + kbuf st_priv_key; + kbuf st_pub_key; + namestr st_netname; +}; + +__BEGIN_DECLS +extern int key_decryptsession ( const char *, des_block * ); +extern int key_decryptsession_pk ( char *, netobj *, des_block * ); +extern int key_encryptsession ( const char *, des_block * ); +extern int key_encryptsession_pk ( char *, netobj *, des_block * ); +extern int key_gendes ( des_block * ); +extern int key_setsecret ( const char * ); +extern int key_secretkey_is_set ( void ); +extern int key_setnet ( struct netstarg * ); +extern int key_get_conv ( char *, des_block * ); +__END_DECLS + +/* + * Publickey routines. + */ +__BEGIN_DECLS +extern int getpublickey ( char *, char * ); +extern int getpublicandprivatekey ( char *, char * ); +extern int getsecretkey ( char *, char *, char * ); +__END_DECLS + + +#define AUTH_NONE 0 /* no authentication */ +#define AUTH_NULL 0 /* backward compatibility */ +#define AUTH_UNIX 1 /* unix style (uid, gids) */ +#define AUTH_SYS 1 /* forward compatibility */ +#define AUTH_SHORT 2 /* short hand unix style */ +#define AUTH_DES 3 /* des style (encrypted timestamps) */ + +#endif /* !_RPC_AUTH_H */ diff --git a/rpc/auth_unix.h b/rpc/auth_unix.h new file mode 100644 index 0000000..f822f3d --- /dev/null +++ b/rpc/auth_unix.h @@ -0,0 +1,85 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)auth_unix.h 1.8 88/02/08 SMI + * from: @(#)auth_unix.h 2.2 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/auth_unix.h,v 1.10 1999/08/27 23:45:03 peter Exp $ + */ + +/* + * auth_unix.h, Protocol for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * The system is very weak. The client uses no encryption for it + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + */ + +#ifndef _RPC_AUTH_UNIX_H +#define _RPC_AUTH_UNIX_H +#include <sys/cdefs.h> +#include <rpc/auth.h> /* opaque_auth */ + +/* The machine name is part of a credential; it may not exceed 255 bytes */ +#define MAX_MACHINE_NAME 255 + +/* gids compose part of a credential; there may not be more than 16 of them */ +#define NGRPS 16 + +/* + * Unix style credentials. + */ +struct authunix_parms { + u_long aup_time; + char *aup_machname; + int aup_uid; + int aup_gid; + u_int aup_len; + int *aup_gids; +}; + +#define authsys_parms authunix_parms + +__BEGIN_DECLS +extern bool_t xdr_authunix_parms(XDR *, struct authunix_parms *); +__END_DECLS + +/* + * If a response verifier has flavor AUTH_SHORT, + * then the body of the response verifier encapsulates the following structure; + * again it is serialized in the obvious fashion. + */ +struct short_hand_verf { + struct opaque_auth new_cred; +}; + +#endif /* !_RPC_AUTH_UNIX_H */ diff --git a/rpc/clnt.h b/rpc/clnt.h new file mode 100644 index 0000000..3042abe --- /dev/null +++ b/rpc/clnt.h @@ -0,0 +1,310 @@ +/* $NetBSD: clnt.h,v 1.14 2000/06/02 22:57:55 fvdl Exp $ */ + +/* + * The contents of this file are subject to the Sun Standards + * License Version 1.0 the (the "License";) You may not use + * this file except in compliance with the License. You may + * obtain a copy of the License at lib/libc/rpc/LICENSE + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is Copyright 1998 by Sun Microsystems, Inc + * + * The Initial Developer of the Original Code is: Sun + * Microsystems, Inc. + * + * All Rights Reserved. + * + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)clnt.h 1.31 94/04/29 SMI + * from: @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/clnt.h,v 1.21 2003/01/24 01:47:55 fjoe Exp $ + */ + +/* + * clnt.h - Client side remote procedure call interface. + * + * Copyright (c) 1986-1991,1994-1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + + +#ifndef _RPC_CLNT_H_ +#define _RPC_CLNT_H_ +#include <rpc/clnt_stat.h> +#include <sys/cdefs.h> +#include <sys/un.h> +#include <rpc/auth.h> /* auth_stat */ + +/* + * Error info. + */ +struct rpc_err { + enum clnt_stat re_status; + union { + int RE_errno; /* related system error */ + enum auth_stat RE_why; /* why the auth error occurred */ + struct { + rpcvers_t low; /* lowest version supported */ + rpcvers_t high; /* highest version supported */ + } RE_vers; + struct { /* maybe meaningful if RPC_FAILED */ + int32_t s1; + int32_t s2; + } RE_lb; /* life boot & debugging only */ + } ru; +#define re_errno ru.RE_errno +#define re_why ru.RE_why +#define re_vers ru.RE_vers +#define re_lb ru.RE_lb +}; + + +/* + * Client rpc handle. + * Created by individual implementations + * Client is responsible for initializing auth, see e.g. auth_none.c. + */ +typedef struct __rpc_client { + AUTH *cl_auth; /* authenticator */ + struct clnt_ops { + /* call remote procedure */ + enum clnt_stat (*cl_call)(struct __rpc_client *, + rpcproc_t, xdrproc_t, void *, xdrproc_t, + void *, struct timeval); + /* abort a call */ + void (*cl_abort)(void); + /* get specific error code */ + void (*cl_geterr)(struct __rpc_client *, + struct rpc_err *); + /* frees results */ + bool_t (*cl_freeres)(struct __rpc_client *, + xdrproc_t, void *); + /* destroy this structure */ + void (*cl_destroy)(struct __rpc_client *); + /* the ioctl() of rpc */ + bool_t (*cl_control)(struct __rpc_client *, int, + char *); + } *cl_ops; + void *cl_private; /* private stuff */ +} CLIENT; + +#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ + +/* + * client side rpc interface ops + * + * Parameter types are: + * + */ + +/* + * enum clnt_stat + * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout) + * CLIENT *rh; + * rpcproc_t proc; + * xdrproc_t xargs; + * void *argsp; + * xdrproc_t xres; + * void *resp; + * struct timeval timeout; + */ +#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \ + argsp, xres, resp, secs)) +#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \ + argsp, xres, resp, secs)) + +/* + * void + * CLNT_ABORT(rh); + * CLIENT *rh; + */ +#define CLNT_ABORT(rh) ((*(rh)->cl_ops->cl_abort)(rh)) +#define clnt_abort(rh) ((*(rh)->cl_ops->cl_abort)(rh)) + +/* + * struct rpc_err + * CLNT_GETERR(rh); + * CLIENT *rh; + */ +#define CLNT_GETERR(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) +#define clnt_geterr(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) + + +/* + * bool_t + * CLNT_FREERES(rh, xres, resp); + * CLIENT *rh; + * xdrproc_t xres; + * void *resp; + */ +#define CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) +#define clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) + +/* + * bool_t + * CLNT_CONTROL(cl, request, info) + * CLIENT *cl; + * u_int request; + * char *info; + */ +#define CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) +#define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) + +/* + * control operations that apply to udp, tcp and unix transports + * + * Note: options marked XXX are no-ops in this implementation of RPC. + * The are present in TI-RPC but can't be implemented here since they + * depend on the presence of STREAMS/TLI, which we don't have. + * + */ +#define CLSET_TIMEOUT 1 /* set timeout (timeval) */ +#define CLGET_TIMEOUT 2 /* get timeout (timeval) */ +#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */ +#define CLGET_FD 6 /* get connections file descriptor */ +#define CLGET_SVC_ADDR 7 /* get server's address (netbuf) */ +#define CLSET_FD_CLOSE 8 /* close fd while clnt_destroy */ +#define CLSET_FD_NCLOSE 9 /* Do not close fd while clnt_destroy */ +#define CLGET_XID 10 /* Get xid */ +#define CLSET_XID 11 /* Set xid */ +#define CLGET_VERS 12 /* Get version number */ +#define CLSET_VERS 13 /* Set version number */ +#define CLGET_PROG 14 /* Get program number */ +#define CLSET_PROG 15 /* Set program number */ +#define CLSET_SVC_ADDR 16 /* get server's address (netbuf) XXX */ +#define CLSET_PUSH_TIMOD 17 /* push timod if not already present XXX */ +#define CLSET_POP_TIMOD 18 /* pop timod XXX */ + +/* + * Connectionless only control operations + */ +#define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */ +#define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */ + +/* + * Operations which GSSAPI needs. (Bletch.) + */ +#define CLGET_LOCAL_ADDR 19 /* get local addr (sockaddr) */ + + +/* + * void + * CLNT_DESTROY(rh); + * CLIENT *rh; + */ +#define CLNT_DESTROY(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) +#define clnt_destroy(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) + + +/* + * RPCTEST is a test program which is accessible on every rpc + * transport/port. It is used for testing, performance evaluation, + * and network administration. + */ + +#define RPCTEST_PROGRAM ((rpcprog_t)1) +#define RPCTEST_VERSION ((rpcvers_t)1) +#define RPCTEST_NULL_PROC ((rpcproc_t)2) +#define RPCTEST_NULL_BATCH_PROC ((rpcproc_t)3) + +/* + * By convention, procedure 0 takes null arguments and returns them + */ + +#define NULLPROC ((rpcproc_t)0) + +/* + * Below are the client handle creation routines for the various + * implementations of client side rpc. They can return NULL if a + * creation failure occurs. + */ + +/* + * Generic client creation routine. Supported protocols are "udp", "tcp" + * and "unix". + */ +__BEGIN_DECLS +extern CLIENT *clnt_create(const char *, const rpcprog_t, const rpcvers_t, + const char *); +__END_DECLS + +/* + * Added for compatibility to old rpc 4.0. Obsoleted by clnt_vc_create(). + */ +__BEGIN_DECLS +extern CLIENT *clntunix_create(struct sockaddr_un *, + u_long, u_long, int *, u_int, u_int); +__END_DECLS + + +/* + * Print why creation failed + */ +__BEGIN_DECLS +extern void clnt_pcreateerror(const char *); /* stderr */ +extern char *clnt_spcreateerror(const char *); /* string */ +__END_DECLS + +/* + * Like clnt_perror(), but is more verbose in its output + */ +__BEGIN_DECLS +extern void clnt_perrno(enum clnt_stat); /* stderr */ +extern char *clnt_sperrno(enum clnt_stat); /* string */ +__END_DECLS + +/* + * Print an English error message, given the client error code + */ +__BEGIN_DECLS +extern void clnt_perror(CLIENT *, const char *); /* stderr */ +extern char *clnt_sperror(CLIENT *, const char *); /* string */ +__END_DECLS + + +/* + * If a creation fails, the following allows the user to figure out why. + */ +struct rpc_createerr { + enum clnt_stat cf_stat; + struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */ +}; + +extern struct rpc_createerr rpc_createerr; + +/* For backward compatibility */ +#include <rpc/clnt_soc.h> + +#endif /* !_RPC_CLNT_H_ */ diff --git a/rpc/clnt_soc.h b/rpc/clnt_soc.h new file mode 100644 index 0000000..9aa99b8 --- /dev/null +++ b/rpc/clnt_soc.h @@ -0,0 +1,109 @@ +/* $NetBSD: clnt_soc.h,v 1.1 2000/06/02 22:57:55 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/clnt_soc.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. + */ + +/* + * clnt.h - Client side remote procedure call interface. + */ + +#ifndef _RPC_CLNT_SOC_H +#define _RPC_CLNT_SOC_H + +#include <time.h> + +/* derived from clnt_soc.h 1.3 88/12/17 SMI */ + +/* + * All the following declarations are only for backward compatibility + * with TS-RPC. + */ + +#include <sys/cdefs.h> +#include <rpc/clnt.h> + +#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long prog; + * u_long version; + * register int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clnttcp_create(struct sockaddr_in *, u_long, u_long, int *, + u_int, u_int); +__END_DECLS + +/* + * Raw (memory) rpc. + */ +__BEGIN_DECLS +extern CLIENT *clntraw_create(u_long, u_long); +__END_DECLS + + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + * struct sockaddr_in *raddr; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * + * Same as above, but you specify max packet sizes. + * CLIENT * + * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clntudp_create(struct sockaddr_in *, u_long, u_long, + struct timeval, int *); +extern CLIENT *clntudp_bufcreate(struct sockaddr_in *, u_long, u_long, + struct timeval, int *, u_int, u_int); +__END_DECLS + +#endif /* _RPC_CLNT_SOC_H */ diff --git a/rpc/clnt_stat.h b/rpc/clnt_stat.h new file mode 100644 index 0000000..2c68745 --- /dev/null +++ b/rpc/clnt_stat.h @@ -0,0 +1,84 @@ +/* $FreeBSD: src/include/rpc/clnt_stat.h,v 1.2 2001/03/20 08:20:50 alfred Exp $ */ +/* + * Copyright (c) 1986 - 1991, 1994, 1996, 1997 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* + * clnt_stat.h - Client side remote procedure call enum + * + */ + +#ifndef _RPC_CLNT_STAT_H +#define _RPC_CLNT_STAT_H + +/* #pragma ident "@(#)clnt_stat.h 1.2 97/04/28 SMI" */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum clnt_stat { + RPC_SUCCESS = 0, /* call succeeded */ + /* + * local errors + */ + RPC_CANTENCODEARGS = 1, /* can't encode arguments */ + RPC_CANTDECODERES = 2, /* can't decode results */ + RPC_CANTSEND = 3, /* failure in sending call */ + RPC_CANTRECV = 4, + /* failure in receiving result */ + RPC_TIMEDOUT = 5, /* call timed out */ + RPC_INTR = 18, /* call interrupted */ + RPC_UDERROR = 23, /* recv got uderr indication */ + /* + * remote errors + */ + RPC_VERSMISMATCH = 6, /* rpc versions not compatible */ + RPC_AUTHERROR = 7, /* authentication error */ + RPC_PROGUNAVAIL = 8, /* program not available */ + RPC_PROGVERSMISMATCH = 9, /* program version mismatched */ + RPC_PROCUNAVAIL = 10, /* procedure unavailable */ + RPC_CANTDECODEARGS = 11, /* decode arguments error */ + RPC_SYSTEMERROR = 12, /* generic "other problem" */ + + /* + * rpc_call & clnt_create errors + */ + RPC_UNKNOWNHOST = 13, /* unknown host name */ + RPC_UNKNOWNPROTO = 17, /* unknown protocol */ + RPC_UNKNOWNADDR = 19, /* Remote address unknown */ + RPC_NOBROADCAST = 21, /* Broadcasting not supported */ + + /* + * rpcbind errors + */ + RPC_RPCBFAILURE = 14, /* the pmapper failed in its call */ +#define RPC_PMAPFAILURE RPC_RPCBFAILURE + RPC_PROGNOTREGISTERED = 15, /* remote program is not registered */ + RPC_N2AXLATEFAILURE = 22, + /* Name to address translation failed */ + /* + * Misc error in the TLI library + */ + RPC_TLIERROR = 20, + /* + * unspecified error + */ + RPC_FAILED = 16, + /* + * asynchronous errors + */ + RPC_INPROGRESS = 24, + RPC_STALERACHANDLE = 25, + RPC_CANTCONNECT = 26, /* couldn't make connection (cots) */ + RPC_XPRTFAILED = 27, /* received discon from remote (cots) */ + RPC_CANTCREATESTREAM = 28, /* can't push rpc module (cots) */ + _CLNT_STAT = 0xffffffff +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !_RPC_CLNT_STAT_H */ diff --git a/rpc/pmap_clnt.h b/rpc/pmap_clnt.h new file mode 100644 index 0000000..86fff6b --- /dev/null +++ b/rpc/pmap_clnt.h @@ -0,0 +1,89 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)pmap_clnt.h 1.11 88/02/08 SMI + * from: @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/pmap_clnt.h,v 1.11 1999/08/27 23:45:04 peter Exp $ + */ + +/* + * pmap_clnt.h + * Supplies C routines to get to portmap services. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Usage: + * success = pmap_set(program, version, protocol, port); + * success = pmap_unset(program, version); + * port = pmap_getport(address, program, version, protocol); + * head = pmap_getmaps(address); + * clnt_stat = pmap_rmtcall(address, program, version, procedure, + * xdrargs, argsp, xdrres, resp, tout, port_ptr) + * (works for udp only.) + * clnt_stat = clnt_broadcast(program, version, procedure, + * xdrargs, argsp, xdrres, resp, eachresult) + * (like pmap_rmtcall, except the call is broadcasted to all + * locally connected nets. For each valid response received, + * the procedure eachresult is called. Its form is: + * done = eachresult(resp, raddr) + * bool_t done; + * caddr_t resp; + * struct sockaddr_in raddr; + * where resp points to the results of the call and raddr is the + * address if the responder to the broadcast. + */ + +#ifndef _RPC_PMAPCLNT_H +#define _RPC_PMAPCLNT_H + +#include <sys/cdefs.h> +#include <netinet/in.h> /* struct sockaddr_in */ +#include <rpc/types.h> +#include <rpc/xdr.h> /* xdrproc_t */ + +__BEGIN_DECLS +extern bool_t pmap_set (u_long, u_long, int, int); +extern bool_t pmap_unset (u_long, u_long); +extern struct pmaplist *pmap_getmaps (struct sockaddr_in *); +extern enum clnt_stat pmap_rmtcall (struct sockaddr_in *, + u_long, u_long, u_long, + xdrproc_t, caddr_t, + xdrproc_t, caddr_t, + struct timeval, u_long *); +extern enum clnt_stat clnt_broadcast (u_long, u_long, u_long, + xdrproc_t, char *, + xdrproc_t, char *, + bool_t (*) (caddr_t, + struct sockaddr_in *)); +extern u_short pmap_getport (struct sockaddr_in *, + u_long, u_long, u_int); +__END_DECLS + +#endif /* !_RPC_PMAPCLNT_H */ diff --git a/rpc/pmap_prot.h b/rpc/pmap_prot.h new file mode 100644 index 0000000..14720e8 --- /dev/null +++ b/rpc/pmap_prot.h @@ -0,0 +1,105 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)pmap_prot.h 1.14 88/02/08 SMI + * from: @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/pmap_prot.h,v 1.10 1999/08/27 23:45:04 peter Exp $ + */ + +/* + * pmap_prot.h + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The following procedures are supported by the protocol: + * + * PMAPPROC_NULL() returns () + * takes nothing, returns nothing + * + * PMAPPROC_SET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Registers the tuple + * [prog, vers, prot, port]. + * + * PMAPPROC_UNSET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Un-registers pair + * [prog, vers]. prot and port are ignored. + * + * PMAPPROC_GETPORT(struct pmap) returns (long unsigned). + * 0 is failure. Otherwise returns the port number where the pair + * [prog, vers] is registered. It may lie! + * + * PMAPPROC_DUMP() RETURNS (struct pmaplist *) + * + * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>) + * RETURNS (port, string<>); + * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs); + * Calls the procedure on the local machine. If it is not registered, + * this procedure is quite; ie it does not return error information!!! + * This procedure only is supported on rpc/udp and calls via + * rpc/udp. This routine only passes null authentication parameters. + * This file has no interface to xdr routines for PMAPPROC_CALLIT. + * + * The service supports remote procedure calls on udp/ip or tcp/ip socket 111. + */ + +#ifndef _RPC_PMAPPROT_H +#define _RPC_PMAPPROT_H +#include <sys/cdefs.h> +#include <rpc/xdr.h> + +#define PMAPPORT ((u_short)111) +#define PMAPPROG ((u_long)100000) +#define PMAPVERS ((u_long)2) +#define PMAPVERS_PROTO ((u_long)2) +#define PMAPVERS_ORIG ((u_long)1) +#define PMAPPROC_NULL ((u_long)0) +#define PMAPPROC_SET ((u_long)1) +#define PMAPPROC_UNSET ((u_long)2) +#define PMAPPROC_GETPORT ((u_long)3) +#define PMAPPROC_DUMP ((u_long)4) +#define PMAPPROC_CALLIT ((u_long)5) + +struct pmap { + long unsigned pm_prog; + long unsigned pm_vers; + long unsigned pm_prot; + long unsigned pm_port; +}; + +struct pmaplist { + struct pmap pml_map; + struct pmaplist *pml_next; +}; + +__BEGIN_DECLS +extern bool_t xdr_pmap (XDR *, struct pmap *); +extern bool_t xdr_pmaplist (XDR *, struct pmaplist **); +__END_DECLS + +#endif /* !_RPC_PMAPPROT_H */ diff --git a/rpc/pmap_rmt.h b/rpc/pmap_rmt.h new file mode 100644 index 0000000..a5ea404 --- /dev/null +++ b/rpc/pmap_rmt.h @@ -0,0 +1,64 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)pmap_rmt.h 1.2 88/02/08 SMI + * from: @(#)pmap_rmt.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/pmap_rmt.h,v 1.10 1999/08/27 23:45:05 peter Exp $ + */ + +/* + * Structures and XDR routines for parameters to and replies from + * the portmapper remote-call-service. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#ifndef _RPC_PMAPRMT_H +#define _RPC_PMAPRMT_H +#include <sys/cdefs.h> +#include <rpc/xdr.h> + +struct rmtcallargs { + u_long prog, vers, proc, arglen; + caddr_t args_ptr; + xdrproc_t xdr_args; +}; + +struct rmtcallres { + u_long *port_ptr; + u_long resultslen; + caddr_t results_ptr; + xdrproc_t xdr_results; +}; + +__BEGIN_DECLS +extern bool_t xdr_rmtcall_args (XDR *, struct rmtcallargs *); +extern bool_t xdr_rmtcallres (XDR *, struct rmtcallres *); +__END_DECLS + +#endif /* !_RPC_PMAPRMT_H */ diff --git a/rpc/rpc.h b/rpc/rpc.h new file mode 100644 index 0000000..20065ef --- /dev/null +++ b/rpc/rpc.h @@ -0,0 +1,118 @@ +/* $NetBSD: rpc.h,v 1.13 2000/06/02 22:57:56 fvdl Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)rpc.h 1.9 88/02/08 SMI + * from: @(#)rpc.h 2.4 89/07/11 4.0 RPCSRC + * $FreeBSD: src/include/rpc/rpc.h,v 1.17 2002/03/23 17:24:55 imp Exp $ + */ + +/* + * rpc.h, Just includes the billions of rpc header files necessary to + * do remote procedure calling. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#ifndef _RPC_RPC_H +#define _RPC_RPC_H + +#include <rpc/types.h> /* some typedefs */ +#include <netinet/in.h> + +/* external data representation interfaces */ +#include <rpc/xdr.h> /* generic (de)serializer */ + +/* Client side only authentication */ +#include <rpc/auth.h> /* generic authenticator (client side) */ + +/* Client side (mostly) remote procedure call */ +#include <rpc/clnt.h> /* generic rpc stuff */ + +/* semi-private protocol headers */ +#include <rpc/rpc_msg.h> /* protocol for rpc messages */ +#include <rpc/auth_unix.h> /* protocol for unix style cred */ + +/* Server side only remote procedure callee */ +#include <rpc/svc.h> /* service manager and multiplexer */ +#include <rpc/svc_auth.h> /* service side authenticator */ + +#include <rpc/rpcent.h> + +__BEGIN_DECLS +extern int get_myaddress(struct sockaddr_in *); +extern int bindresvport(int, struct sockaddr_in *); +extern int bindresvport_sa(int, struct sockaddr *); +__END_DECLS + +int rtems_rpc_task_init (void); +int rtems_rpc_start_portmapper (int priority); + +#ifdef _RTEMS_RPC_INTERNAL_ +/* + * Multi-threaded support + * Group all global and static variables into a single spot. + * This area will be allocated on a per-task basis + */ +struct _rtems_rpc_task_variables { + int svc_svc_maxfd; + fd_set svc_svc_fdset; + SVCXPRT ** svc_xports; + int svc_xportssize; + int svc__svc_fdsetsize; + fd_set *svc__svc_fdset; + struct svc_callout *svc_svc_head; + + char *clnt_perror_buf; + + struct clnt_raw_private *clnt_raw_private; + + void *call_rpc_private; + + struct call_rpc_private *svc_raw_private; + + struct prog_lst *svc_simple_proglst; + struct prog_lst *svc_simple_pl; + SVCXPRT *svc_simple_transp; + + char *rpcdname_default_domain; + + struct authsvc *svc_auths_Auths; +}; + +struct _rtems_rpc_task_variables *rtems_rpc_task_variables_get(void); +#define rtems_rpc_task_variables rtems_rpc_task_variables_get() + +#define svc_maxfd (rtems_rpc_task_variables->svc_svc_maxfd) +#define svc_fdset (rtems_rpc_task_variables->svc_svc_fdset) +#define __svc_fdsetsize (rtems_rpc_task_variables->svc__svc_fdsetsize) +#define __svc_fdset (rtems_rpc_task_variables->svc__svc_fdset) + +#endif /* _RTEMS_RPC_INTERNAL_ */ + +#endif /* !_RPC_RPC_H */ diff --git a/rpc/rpc_com.h b/rpc/rpc_com.h new file mode 100644 index 0000000..9a1ce45 --- /dev/null +++ b/rpc/rpc_com.h @@ -0,0 +1,65 @@ +/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */ +/* $FreeBSD: src/include/rpc/rpc_com.h,v 1.6 2003/01/16 07:13:51 mbr Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpc_com.h, Common definitions for both the server and client side. + * All for the topmost layer of rpc + * + */ + +#ifndef _RPC_RPCCOM_H +#define _RPC_RPCCOM_H + +#include <sys/cdefs.h> + +/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ + +/* + * The max size of the transport, if the size cannot be determined + * by other means. + */ +#define RPC_MAXDATASIZE 9000 +#define RPC_MAXADDRSIZE 1024 + +__BEGIN_DECLS +extern u_int __rpc_get_a_size(int); +extern u_int __rpc_get_t_size(int, long); +extern int __rpc_dtbsize(void); +extern int _rpc_dtablesize(void); +extern int _rpc_get_default_domain(char **); +__END_DECLS + +#endif /* _RPC_RPCCOM_H */ diff --git a/rpc/rpc_msg.h b/rpc/rpc_msg.h new file mode 100644 index 0000000..63a1f36 --- /dev/null +++ b/rpc/rpc_msg.h @@ -0,0 +1,205 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)rpc_msg.h 1.7 86/07/16 SMI + * from: @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/rpc_msg.h,v 1.15 2003/01/01 18:48:42 schweikh Exp $ + */ + +/* + * rpc_msg.h + * rpc message definition + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_RPC_MSG_H +#define _RPC_RPC_MSG_H + +#include <rpc/types.h> +#include <rpc/xdr.h> /* xdrproc_t */ +#include <rpc/auth.h> /* opaque_auth */ + +struct rpc_err; /* forward */ + +#define RPC_MSG_VERSION ((u_int32_t) 2) +#define RPC_SERVICE_PORT ((u_short) 2048) + +/* + * Bottom up definition of an rpc message. + * NOTE: call and reply use the same overall stuct but + * different parts of unions within it. + */ + +enum msg_type { + CALL=0, + REPLY=1, + _MSG_TYPE = 0xffffffff +}; + +enum reply_stat { + MSG_ACCEPTED=0, + MSG_DENIED=1, + _REPLY_STAT = 0xffffffff +}; + +enum accept_stat { + SUCCESS=0, + PROG_UNAVAIL=1, + PROG_MISMATCH=2, + PROC_UNAVAIL=3, + GARBAGE_ARGS=4, + SYSTEM_ERR=5, + _ACCEPT_STAT = 0xffffffff +}; + +enum reject_stat { + RPC_MISMATCH=0, + AUTH_ERROR=1, + _REJECT_STAT = 0xffffffff +}; + +/* + * Reply part of an rpc exchange + */ + +/* + * Reply to an rpc request that was accepted by the server. + * Note: there could be an error even though the request was + * accepted. + */ +struct accepted_reply { + struct opaque_auth ar_verf; + enum accept_stat ar_stat; + union { + struct { + rpcvers_t low; + rpcvers_t high; + } AR_versions; + struct { + caddr_t where; + xdrproc_t proc; + } AR_results; + /* and many other null cases */ + } ru; +#define ar_results ru.AR_results +#define ar_vers ru.AR_versions +}; + +/* + * Reply to an rpc request that was rejected by the server. + */ +struct rejected_reply { + enum reject_stat rj_stat; + union { + struct { + rpcvers_t low; + rpcvers_t high; + } RJ_versions; + enum auth_stat RJ_why; /* why authentication did not work */ + } ru; +#define rj_vers ru.RJ_versions +#define rj_why ru.RJ_why +}; + +/* + * Body of a reply to an rpc request. + */ +struct reply_body { + enum reply_stat rp_stat; + union { + struct accepted_reply RP_ar; + struct rejected_reply RP_dr; + } ru; +#define rp_acpt ru.RP_ar +#define rp_rjct ru.RP_dr +}; + +/* + * Body of an rpc request call. + */ +struct call_body { + rpcvers_t cb_rpcvers; /* must be equal to two */ + rpcprog_t cb_prog; + rpcvers_t cb_vers; + rpcproc_t cb_proc; + struct opaque_auth cb_cred; + struct opaque_auth cb_verf; /* protocol specific - provided by client */ +}; + +/* + * The rpc message + */ +struct rpc_msg { + u_int32_t rm_xid; + enum msg_type rm_direction; + union { + struct call_body RM_cmb; + struct reply_body RM_rmb; + } ru; +#define rm_call ru.RM_cmb +#define rm_reply ru.RM_rmb +}; +#define acpted_rply ru.RM_rmb.ru.RP_ar +#define rjcted_rply ru.RM_rmb.ru.RP_dr + +__BEGIN_DECLS +/* + * XDR routine to handle a rpc message. + * xdr_callmsg(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callmsg(XDR *, struct rpc_msg *); + +/* + * XDR routine to pre-serialize the static part of a rpc message. + * xdr_callhdr(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callhdr(XDR *, struct rpc_msg *); + +/* + * XDR routine to handle a rpc reply. + * xdr_replymsg(xdrs, rmsg) + * XDR *xdrs; + * struct rpc_msg *rmsg; + */ +extern bool_t xdr_replymsg(XDR *, struct rpc_msg *); + +/* + * Fills in the error part of a reply message. + * _seterr_reply(msg, error) + * struct rpc_msg *msg; + * struct rpc_err *error; + */ +extern void _seterr_reply(struct rpc_msg *, struct rpc_err *); +__END_DECLS + +#endif /* !_RPC_RPC_MSG_H */ diff --git a/rpc/rpcent.h b/rpc/rpcent.h new file mode 100644 index 0000000..1cf4161 --- /dev/null +++ b/rpc/rpcent.h @@ -0,0 +1,71 @@ +/* $NetBSD: rpcent.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/rpcent.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpcent.h, + * For converting rpc program numbers to names etc. + * + */ + +#ifndef _RPC_RPCENT_H +#define _RPC_RPCENT_H + +#include <sys/cdefs.h> + +/* #pragma ident "@(#)rpcent.h 1.13 94/04/25 SMI" */ +/* @(#)rpcent.h 1.1 88/12/06 SMI */ + + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +__BEGIN_DECLS +extern struct rpcent *getrpcbyname_r(const char *, struct rpcent *, + char *, int); +extern struct rpcent *getrpcbynumber_r(int, struct rpcent *, char *, int); +extern struct rpcent *getrpcent_r(struct rpcent *, char *, int); + +/* Old interfaces that return a pointer to a static area; MT-unsafe */ +extern struct rpcent *getrpcbyname(char *); +extern struct rpcent *getrpcbynumber(int); +extern struct rpcent *getrpcent(void); +extern void setrpcent(int); +extern void endrpcent(void); +__END_DECLS + +#endif /* !_RPC_CENT_H */ diff --git a/rpc/svc.h b/rpc/svc.h new file mode 100644 index 0000000..0808ddd --- /dev/null +++ b/rpc/svc.h @@ -0,0 +1,297 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)svc.h 1.35 88/12/17 SMI + * from: @(#)svc.h 1.27 94/04/25 SMI + * $FreeBSD: src/include/rpc/svc.h,v 1.24 2003/06/15 10:32:01 mbr Exp $ + */ + +/* + * svc.h, Server-side remote procedure call interface. + * + * Copyright (C) 1986-1993 by Sun Microsystems, Inc. + */ + +#ifndef _RPC_SVC_H +#define _RPC_SVC_H + +#include <sys/cdefs.h> +#include <rpc/types.h> +#include <rpc/xdr.h> /* xdrproc_t */ +#include <sys/select.h> /* fd_set */ +#include <sys/socket.h> /* socklen_t */ +#include <netinet/in.h> /* struct sockaddr_in */ +#include <rpc/auth.h> /* auth_stat */ + +/* + * This interface must manage two items concerning remote procedure calling: + * + * 1) An arbitrary number of transport connections upon which rpc requests + * are received. The two most notable transports are TCP and UDP; they are + * created and registered by routines in svc_tcp.c and svc_udp.c, respectively; + * they in turn call xprt_register and xprt_unregister. + * + * 2) An arbitrary number of locally registered services. Services are + * described by the following four data: program number, version number, + * "service dispatch" function, a transport handle, and a boolean that + * indicates whether or not the exported program should be registered with a + * local binder service; if true the program's number and version and the + * port number from the transport handle are registered with the binder. + * These data are registered with the rpc svc system via svc_register. + * + * A service's dispatch function is called whenever an rpc request comes in + * on a transport. The request's program and version numbers must match + * those of the registered service. The dispatch function is passed two + * parameters, struct svc_req * and SVCXPRT *, defined below. + */ + +enum xprt_stat { + XPRT_DIED, + XPRT_MOREREQS, + XPRT_IDLE, + _XPRT_STAT = 0xffffffff +}; + +struct rpc_msg; + +/* + * Server side transport handle + */ +typedef struct __rpc_svcxprt { + int xp_sock; + u_short xp_port; /* associated port number */ + struct xp_ops { + /* receive incoming requests */ + bool_t (*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *); + /* get transport status */ + enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *); + /* get arguments */ + bool_t (*xp_getargs)(struct __rpc_svcxprt *, xdrproc_t, + caddr_t args_ptr); + /* send reply */ + bool_t (*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *); + /* free mem allocated for args */ + bool_t (*xp_freeargs)(struct __rpc_svcxprt *, xdrproc_t, + caddr_t args_ptr); + /* destroy this struct */ + void (*xp_destroy)(struct __rpc_svcxprt *); + } *xp_ops; + socklen_t xp_addrlen; /* length of remote address */ + struct sockaddr_in xp_raddr; /* remote addr. (backward ABI compat) */ + struct opaque_auth xp_verf; /* raw response verifier */ + void *xp_p1; /* private: for use by svc ops */ + void *xp_p2; /* private: for use by svc ops */ +} SVCXPRT; + +/* + * Service request + */ +struct svc_req { + u_int32_t rq_prog; /* service program number */ + u_int32_t rq_vers; /* service protocol version */ + u_int32_t rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked cred */ + SVCXPRT *rq_xprt; /* associated transport */ +}; + + +/* + * Operations defined on an SVCXPRT handle + * + * SVCXPRT *xprt; + * struct rpc_msg *msg; + * xdrproc_t xargs; + * caddr_t argsp; + */ +#define SVC_RECV(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) +#define svc_recv(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) + +#define SVC_STAT(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) +#define svc_stat(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) + +#define SVC_GETARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) +#define svc_getargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) + +#define SVC_REPLY(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) +#define svc_reply(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) + +#define SVC_FREEARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) +#define svc_freeargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) + +#define SVC_DESTROY(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) +#define svc_destroy(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) + +/* + * Transport registration. + * + * xprt_register(xprt) + * SVCXPRT *xprt; + */ +__BEGIN_DECLS +extern void xprt_register(SVCXPRT *); +__END_DECLS + +/* + * Transport un-register + * + * xprt_unregister(xprt) + * SVCXPRT *xprt; + */ +__BEGIN_DECLS +extern void xprt_unregister(SVCXPRT *); +__END_DECLS + + +/* + * When the service routine is called, it must first check to see if it + * knows about the procedure; if not, it should call svcerr_noproc + * and return. If so, it should deserialize its arguments via + * SVC_GETARGS (defined above). If the deserialization does not work, + * svcerr_decode should be called followed by a return. Successful + * decoding of the arguments should be followed the execution of the + * procedure's code and a call to svc_sendreply. + * + * Also, if the service refuses to execute the procedure due to too- + * weak authentication parameters, svcerr_weakauth should be called. + * Note: do not confuse access-control failure with weak authentication! + * + * NB: In pure implementations of rpc, the caller always waits for a reply + * msg. This message is sent when svc_sendreply is called. + * Therefore pure service implementations should always call + * svc_sendreply even if the function logically returns void; use + * xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows + * for the abuse of pure rpc via batched calling or pipelining. In the + * case of a batched call, svc_sendreply should NOT be called since + * this would send a return message, which is what batching tries to avoid. + * It is the service/protocol writer's responsibility to know which calls are + * batched and which are not. Warning: responding to batch calls may + * deadlock the caller and server processes! + */ + +__BEGIN_DECLS +extern bool_t svc_sendreply(SVCXPRT *, xdrproc_t, void *); +extern void svcerr_decode(SVCXPRT *); +extern void svcerr_weakauth(SVCXPRT *); +extern void svcerr_noproc(SVCXPRT *); +extern void svcerr_progvers(SVCXPRT *, rpcvers_t, rpcvers_t); +extern void svcerr_auth(SVCXPRT *, enum auth_stat); +extern void svcerr_noprog(SVCXPRT *); +extern void svcerr_systemerr(SVCXPRT *); +__END_DECLS + +/* + * Lowest level dispatching -OR- who owns this process anyway. + * Somebody has to wait for incoming requests and then call the correct + * service routine. The routine svc_run does infinite waiting; i.e., + * svc_run never returns. + * Since another (co-existant) package may wish to selectively wait for + * incoming calls or other events outside of the rpc architecture, the + * routine svc_getreq is provided. It must be passed readfds, the + * "in-place" results of a select system call (see select, section 2). + */ + +/* + * Global keeper of rpc service descriptors in use + * dynamic; must be inspected before each call to select + */ +extern int svc_maxfd; +extern fd_set svc_fdset; +#define svc_fds svc_fdset.fds_bits[0] /* compatibility */ + +#ifndef _KERNEL +/* + * a small program implemented by the svc_rpc implementation itself; + * also see clnt.h for protocol numbers. + */ +__BEGIN_DECLS +extern void rpctest_service(void); +__END_DECLS +#endif + +__BEGIN_DECLS +extern void svc_getreq(int); +extern void svc_getreqset(fd_set *); +extern void svc_getreqset2(fd_set *, int); /* XXX: nonstd, undoc */ +extern void svc_run(void); +__END_DECLS + +/* + * Socket to use on svcxxx_create call to get default socket + */ +#define RPC_ANYSOCK -1 +#define RPC_ANYFD RPC_ANYSOCK + +/* + * These are the existing service side transport implementations + */ + +__BEGIN_DECLS +/* + * Transport independent svc_create routine. + */ + +/* + * Connectionless and connectionful create routines + */ + +extern SVCXPRT *svc_vc_create(const int, const u_int, const u_int); +/* + * const int fd; -- open connection end point + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + +/* + * Added for compatibility to old rpc 4.0. Obsoleted by svc_vc_create(). + */ +extern SVCXPRT *svcunix_create(int, u_int, u_int, char *); + +/* + * Added for compatibility to old rpc 4.0. Obsoleted by svc_fd_create(). + */ +extern SVCXPRT *svcunixfd_create(int, u_int, u_int); +__END_DECLS + + +/* for backward compatibility */ +#include <rpc/svc_soc.h> + +#endif /* !_RPC_SVC_H */ diff --git a/rpc/svc_auth.h b/rpc/svc_auth.h new file mode 100644 index 0000000..846752c --- /dev/null +++ b/rpc/svc_auth.h @@ -0,0 +1,58 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)svc_auth.h 1.6 86/07/16 SMI + * from: @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/svc_auth.h,v 1.12 1999/08/27 23:45:05 peter Exp $ + */ + +/* + * svc_auth.h, Service side of rpc authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_SVCAUTH_H +#define _RPC_SVCAUTH_H + +#include <sys/cdefs.h> + +struct rpc_msg; +struct svc_req; + +/* + * Server side authenticator + */ +__BEGIN_DECLS +extern enum auth_stat _authenticate (struct svc_req *, struct rpc_msg *); +extern int svc_auth_reg (int, enum auth_stat (*)(struct svc_req *, + struct rpc_msg *)); +extern enum auth_stat _svcauth_des (struct svc_req *, struct rpc_msg *); +__END_DECLS + +#endif /* !_RPC_SVCAUTH_H */ diff --git a/rpc/svc_soc.h b/rpc/svc_soc.h new file mode 100644 index 0000000..5b36fb4 --- /dev/null +++ b/rpc/svc_soc.h @@ -0,0 +1,125 @@ +/* $NetBSD: svc_soc.h,v 1.1 2000/06/02 22:57:57 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/svc_soc.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * svc.h, Server-side remote procedure call interface. + */ + +#ifndef _RPC_SVC_SOC_H +#define _RPC_SVC_SOC_H +#include <sys/cdefs.h> +#include <rpc/types.h> +#include <rpc/svc.h> /* SVCXPRT */ + +/* #pragma ident "@(#)svc_soc.h 1.11 94/04/25 SMI" */ +/* svc_soc.h 1.8 89/05/01 SMI */ + +/* + * All the following declarations are only for backward compatibility + * with TS-RPC + */ + +/* + * Approved way of getting address of caller + */ +#define svc_getcaller(x) (&(x)->xp_raddr) + +/* + * Service registration + * + * svc_register(xprt, prog, vers, dispatch, protocol) + * SVCXPRT *xprt; + * u_long prog; + * u_long vers; + * void (*dispatch)(); + * int protocol; like TCP or UDP, zero means do not register + */ +__BEGIN_DECLS +extern bool_t svc_register(SVCXPRT *, u_long, u_long, + void (*)(struct svc_req *, SVCXPRT *), int); +__END_DECLS + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + * u_long prog; + * u_long vers; + */ +__BEGIN_DECLS +extern void svc_unregister(u_long, u_long); +__END_DECLS + + +/* + * Memory based rpc for testing and timing. + */ +__BEGIN_DECLS +extern SVCXPRT *svcraw_create(void); +__END_DECLS + + +/* + * Udp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcudp_create(int); +extern SVCXPRT *svcudp_bufcreate(int, u_int, u_int); +__END_DECLS + + +/* + * Tcp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svctcp_create(int, u_int, u_int); +__END_DECLS + +/* + * Fd based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcfd_create(int, u_int, u_int); +__END_DECLS + +/* + * AF_UNIX socket based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcunix_create (int, u_int, u_int, char *); +extern SVCXPRT *svcunixfd_create (int, u_int, u_int); +__END_DECLS + +#endif /* !_RPC_SVC_SOC_H */ diff --git a/rpc/types.h b/rpc/types.h new file mode 100644 index 0000000..05375d3 --- /dev/null +++ b/rpc/types.h @@ -0,0 +1,68 @@ +/* $NetBSD: types.h,v 1.13 2000/06/13 01:02:44 thorpej Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)types.h 1.18 87/07/24 SMI + * from: @(#)types.h 2.3 88/08/15 4.0 RPCSRC + * $FreeBSD: src/include/rpc/types.h,v 1.11 2003/12/07 21:10:06 marcel Exp $ + */ + +/* + * Rpc additions to <sys/types.h> + */ +#ifndef _RPC_TYPES_H +#define _RPC_TYPES_H + +#include <stdint.h> + +typedef int32_t bool_t; +typedef int32_t enum_t; + +typedef uint32_t rpcprog_t; +typedef uint32_t rpcvers_t; +typedef uint32_t rpcproc_t; +typedef uint32_t rpcprot_t; +typedef uint32_t rpcport_t; +typedef int32_t rpc_inline_t; + +#define __dontcare__ -1 + +#ifndef FALSE +# define FALSE (0) +#endif +#ifndef TRUE +# define TRUE (1) +#endif + +#define mem_alloc(bsize) malloc(bsize) +#define mem_free(ptr, bsize) free(ptr) + +#include <sys/time.h> + +#endif /* !_RPC_TYPES_H */ diff --git a/rpc/xdr.h b/rpc/xdr.h new file mode 100644 index 0000000..30f2bcc --- /dev/null +++ b/rpc/xdr.h @@ -0,0 +1,312 @@ +/* $NetBSD: xdr.h,v 1.19 2000/07/17 05:00:45 matt Exp $ */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * + * from: @(#)xdr.h 1.19 87/04/22 SMI + * from: @(#)xdr.h 2.2 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/xdr.h,v 1.23 2003/03/07 13:19:40 nectar Exp $ + */ + +/* + * xdr.h, External Data Representation Serialization Routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_XDR_H +#define _RPC_XDR_H + +#include <sys/cdefs.h> + +#include <rpc/types.h> + +/* + * XDR provides a conventional way for converting between C data + * types and an external bit-string representation. Library supplied + * routines provide for the conversion on built-in C data types. These + * routines and utility routines defined here are used to help implement + * a type encode/decode routine for each user-defined type. + * + * Each data type provides a single procedure which takes two arguments: + * + * bool_t + * xdrproc(xdrs, argresp) + * XDR *xdrs; + * <type> *argresp; + * + * xdrs is an instance of a XDR handle, to which or from which the data + * type is to be converted. argresp is a pointer to the structure to be + * converted. The XDR handle contains an operation field which indicates + * which of the operations (ENCODE, DECODE * or FREE) is to be performed. + * + * XDR_DECODE may allocate space if the pointer argresp is null. This + * data can be freed with the XDR_FREE operation. + * + * We write only one procedure per data type to make it easy + * to keep the encode and decode procedures for a data type consistent. + * In many cases the same code performs all operations on a user defined type, + * because all the hard work is done in the component type routines. + * decode as a series of calls on the nested data types. + */ + +/* + * Xdr operations. XDR_ENCODE causes the type to be encoded into the + * stream. XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { + XDR_ENCODE=0, + XDR_DECODE=1, + XDR_FREE=2 +}; + +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT (4) +#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \ + * BYTES_PER_XDR_UNIT) + +/* + * The XDR handle. + * Contains operation which is being applied to the stream, + * an operations vector for the particular implementation (e.g. see xdr_mem.c), + * and two private fields for the use of the particular implementation. + */ +typedef struct __rpc_xdr { + enum xdr_op x_op; /* operation; fast additional param */ + const struct xdr_ops { + /* get a long from underlying stream */ + bool_t (*x_getlong)(struct __rpc_xdr *, long *); + /* put a long to " */ + bool_t (*x_putlong)(struct __rpc_xdr *, const long *); + /* get some bytes from " */ + bool_t (*x_getbytes)(struct __rpc_xdr *, char *, u_int); + /* put some bytes to " */ + bool_t (*x_putbytes)(struct __rpc_xdr *, const char *, u_int); + /* returns bytes off from beginning */ + u_int (*x_getpostn)(struct __rpc_xdr *); + /* lets you reposition the stream */ + bool_t (*x_setpostn)(struct __rpc_xdr *, u_int); + /* buf quick ptr to buffered data */ + int32_t *(*x_inline)(struct __rpc_xdr *, u_int); + /* free privates of this xdr_stream */ + void (*x_destroy)(struct __rpc_xdr *); + } *x_ops; + char * x_public; /* users' data */ + void * x_private; /* pointer to private data */ + char * x_base; /* private used for position info */ + u_int x_handy; /* extra private word */ +} XDR; + +/* + * A xdrproc_t exists for each data type which is to be encoded or decoded. + * + * The second argument to the xdrproc_t is a pointer to an opaque pointer. + * The opaque pointer generally points to a structure of the data type + * to be decoded. If this pointer is 0, then the type routines should + * allocate dynamic storage of the appropriate size and return it. + */ +typedef bool_t (*xdrproc_t) (XDR *, void *, ...); + +/* + * Operations defined on a XDR handle + * + * XDR *xdrs; + * long *longp; + * caddr_t addr; + * u_int len; + * u_int pos; + */ +#define XDR_GETLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) +#define xdr_getlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) + +#define XDR_PUTLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) +#define xdr_putlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) + +#define XDR_GETBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) +#define xdr_getbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) + +#define XDR_PUTBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) +#define xdr_putbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) + +#define XDR_GETPOS(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) +#define xdr_getpos(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) + +#define XDR_SETPOS(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) +#define xdr_setpos(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) + +#define XDR_INLINE(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) +#define xdr_inline(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) + +#define XDR_DESTROY(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) +#define xdr_destroy(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) + +/* + * Support struct for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * an entry with a null procedure pointer. The xdr_union routine gets + * the discriminant value and then searches the array of structures + * for a matching value. If a match is found the associated xdr routine + * is called to handle that part of the union. If there is + * no match, then a default routine may be called. + * If there is no match and no default routine it is an error. + */ +#define NULL_xdrproc_t ((xdrproc_t)0) +struct xdr_discrim { + int value; + xdrproc_t proc; +}; + +/* + * In-line routines for fast encode/decode of primitive data types. + * Caveat emptor: these use single memory cycles to get the + * data from the underlying buffer, and will fail to operate + * properly if the data is not aligned. The standard way to use these + * is to say: + * if ((buf = XDR_INLINE(xdrs, count)) == NULL) + * return (FALSE); + * <<< macro calls >>> + * where ``count'' is the number of bytes of data occupied + * by the primitive data types. + * + * N.B. and frozen for all time: each data type here uses 4 bytes + * of external representation. + */ +#define IXDR_GET_LONG(buf) ((long)ntohl((u_long)*(buf)++)) +#define IXDR_PUT_LONG(buf, v) (*(buf)++ = (long)htonl((u_long)v)) + +#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf)) +#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_LONG(buf) ((u_long)IXDR_GET_LONG(buf)) +#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_SHORT(buf) ((u_short)IXDR_GET_LONG(buf)) + +#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) + +/* + * These are the "generic" xdr routines. + */ +__BEGIN_DECLS +extern bool_t xdr_void(void); +extern bool_t xdr_int(XDR *, int *); +extern bool_t xdr_u_int(XDR *, u_int *); +extern bool_t xdr_long(XDR *, long *); +extern bool_t xdr_u_long(XDR *, u_long *); +extern bool_t xdr_short(XDR *, short *); +extern bool_t xdr_u_short(XDR *, u_short *); +extern bool_t xdr_int16_t(XDR *, int16_t *); +extern bool_t xdr_u_int16_t(XDR *, u_int16_t *); +extern bool_t xdr_int32_t(XDR *, int32_t *); +extern bool_t xdr_u_int32_t(XDR *, u_int32_t *); +extern bool_t xdr_int64_t(XDR *, int64_t *); +extern bool_t xdr_u_int64_t(XDR *, u_int64_t *); +extern bool_t xdr_bool(XDR *, bool_t *); +extern bool_t xdr_enum(XDR *, enum_t *); +extern bool_t xdr_array(XDR *, char **, u_int *, u_int, u_int, xdrproc_t); +extern bool_t xdr_bytes(XDR *, char **, u_int *, u_int); +extern bool_t xdr_opaque(XDR *, caddr_t, u_int); +extern bool_t xdr_string(XDR *, char **, u_int); +extern bool_t xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t); +extern unsigned long xdr_sizeof (xdrproc_t, void *); +extern bool_t xdr_char(XDR *, char *); +extern bool_t xdr_u_char(XDR *, u_char *); +extern bool_t xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t); +extern bool_t xdr_float(XDR *, float *); +extern bool_t xdr_double(XDR *, double *); +extern bool_t xdr_reference(XDR *, caddr_t *, u_int, xdrproc_t); +extern bool_t xdr_pointer(XDR *, caddr_t *, u_int, xdrproc_t); +extern bool_t xdr_wrapstring(XDR *, char **); +extern void xdr_free(xdrproc_t, char *); +__END_DECLS + +/* + * Common opaque bytes objects used by many rpc protocols; + * declared here due to commonality. + */ +#define MAX_NETOBJ_SZ 1024 +struct netobj { + u_int n_len; + char *n_bytes; +}; +typedef struct netobj netobj; +extern bool_t xdr_netobj(XDR *, struct netobj *); + +/* + * These are the public routines for the various implementations of + * xdr streams. + */ +__BEGIN_DECLS +/* XDR using memory buffers */ +extern void xdrmem_create(XDR *, char *, u_int, enum xdr_op); + +/* XDR using stdio library */ +#ifdef _STDIO_H_ +extern void xdrstdio_create(XDR *, FILE *, enum xdr_op); +#endif + +/* XDR pseudo records for tcp */ +extern void xdrrec_create(XDR *, u_int, u_int, char *, + int (*) (caddr_t, caddr_t, int), + int (*) (caddr_t, caddr_t, int)); + +/* make end of xdr record */ +extern bool_t xdrrec_endofrecord(XDR *, bool_t); + +/* move to beginning of next record */ +extern bool_t xdrrec_skiprecord(XDR *); + +/* true if no more input */ +extern bool_t xdrrec_eof(XDR *); +__END_DECLS + +#endif /* !_RPC_XDR_H */ diff --git a/rtems/bootp.h b/rtems/bootp.h new file mode 100644 index 0000000..4891430 --- /dev/null +++ b/rtems/bootp.h @@ -0,0 +1,44 @@ +/* Subroutines from cpukit/libnetworking/nfs/bootp_subr.c */ + +#if !defined (__RTEMS_BOOTP_H__) +#define __RTEMS_BOOTP_H__ + +#include <stddef.h> +#include <stdbool.h> + +#if __cplusplus +extern "C" +{ +#endif + +struct bootp_packet; +struct proc; +struct ifreq; +struct socket; +struct sockaddr_in; + +bool bootpc_init(bool, bool); + +int bootpc_call( + struct bootp_packet *call, + struct bootp_packet *reply, + struct proc *procp, + const void *exp_vend, + size_t exp_vend_len); +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 *bootp_strdup_realloc(char *dst, const char *src); + +#if __cplusplus +} +#endif + +#endif diff --git a/rtems/bsdnet/_types.h b/rtems/bsdnet/_types.h new file mode 100644 index 0000000..d557e31 --- /dev/null +++ b/rtems/bsdnet/_types.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2002 Mike Barcroft <mike@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. + * + * $FreeBSD: src/sys/sys/_types.h,v 1.21 2005/03/22 01:19:17 das Exp $ + */ + + +#ifndef _RTEMS_BSDNET__TYPES_H_ +#define _RTEMS_BSDNET__TYPES_H_ + +#include <stdint.h> + +/* + * Standard type definitions. + */ +typedef uint8_t __sa_family_t; +typedef uint32_t __socklen_t; + +#endif /* !_RTEMS_BSDNET_TYPES_H_ */ diff --git a/rtems/bsdnet/servers.h b/rtems/bsdnet/servers.h new file mode 100644 index 0000000..a9db74a --- /dev/null +++ b/rtems/bsdnet/servers.h @@ -0,0 +1,18 @@ +/** + * @file + */ + + +#ifndef _RTEMS_BSDNET_SERVERS_H +#define _RTEMS_BSDNET_SERVERS_H + +extern struct in_addr *rtems_bsdnet_ntpserver; +extern int rtems_bsdnet_ntpserver_count; + +/* + * Network configuration + */ +extern struct in_addr *rtems_bsdnet_nameserver; +extern int rtems_bsdnet_nameserver_count; + +#endif /* _RTEMS_BSDNET_SERVERS_H */ diff --git a/rtems/dhcp.h b/rtems/dhcp.h new file mode 100644 index 0000000..eb7f42d --- /dev/null +++ b/rtems/dhcp.h @@ -0,0 +1,47 @@ +/* + ------------------------------------------------------------------------ + + Copyright Cybertec Pty Ltd, 2005 + All rights reserved Cybertec Pty Ltd, 2005 + + This software with is provided ``as is'' and with NO WARRANTY. + + ------------------------------------------------------------------------ + */ + +/** + @file + + DHCP Server interface. +*/ + +#if !defined (__RTEMS_DHCP_H__) +#define __RTEMS_DHCP_H__ + +#if __cplusplus +extern "C" +{ +#endif + +/* + * Perform DHCP. + */ +void rtems_bsdnet_do_dhcp (void); +int rtems_bsdnet_do_dhcp_timeout (void); +void rtems_bsdnet_dhcp_down (void); + +/* + * Maintain a DHCP offer that has already been accepted. + */ +void rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid, + unsigned long lease_time, + unsigned long elapsed_time, + unsigned long ip_address, + unsigned long srv_address, + const char *hostname); + +#if __cplusplus +} +#endif + +#endif diff --git a/rtems/mkrootfs.c b/rtems/mkrootfs.c new file mode 100644 index 0000000..9414eae --- /dev/null +++ b/rtems/mkrootfs.c @@ -0,0 +1,248 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + ------------------------------------------------------------------------ + + Copyright Cybertec Pty Ltd, 2000 + All rights reserved Cybertec Pty Ltd, 2000 + + COPYRIGHT (c) 1989-1998. + On-Line Applications Research Corporation (OAR). + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution or at + + http://www.rtems.org/license/LICENSE. + + This software with is provided ``as is'' and with NO WARRANTY. + + ------------------------------------------------------------------------ + + Set of helpers when creating a root file system. The root filesystem + in RTEMS is the In Memory Filesystem (IMFS). We could copy an exiting + filesystem to here, how-ever a number of files can have target + specific initialisation info which we need to write. + + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <rtems/mkrootfs.h> +#include <rtems/libio.h> +#include <rtems/endian.h> + +/* + * A table a list of names and their modes. + */ + +typedef struct rtems_rootfs_dir_table +{ + const char *name; + mode_t mode; +} rtems_rootfs_dir_table; + +/* + * Table of directorys to make. + */ + +static const rtems_rootfs_dir_table default_directories[] = +{ + { "/bin", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH }, + { "/etc", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH }, + { "/dev", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH }, + { "/usr/bin", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH } +}; + +#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH) +#define MKDIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + +/* + * Create enough files to support the networking stack. + * Points to a table of strings. + */ + +int +rtems_rootfs_file_append (const char *file, + mode_t omode, + const int line_cnt, + const char **lines) +{ + struct stat sb; + int fd; + int i; + + /* + * See is a file exists. If it does not, create the + * file and the path to the file. + */ + + fd = -1; + + if (stat(file, &sb)) + { + if (errno == ENOENT) + { + /* + * Get the path to the file if one exists and create the + * path. If it exists nothing happens. + */ + + size_t i = strlen (file); + + while (i) + { + if (file[i] == '/') + { + char path[128]; + + if (i >= sizeof path) + { + printf ("root fs, path too long `%s'\n", file); + return -1; + } + + strncpy (path, file, i); + path[i] = '\0'; + + if (rtems_mkdir (path, MKDIR_MODE)) + return -1; + break; + } + i--; + } + + if ((fd = open (file, O_CREAT | O_APPEND | O_WRONLY, omode)) < 0) + { + printf ("root fs, cannot create file `%s' : %s\n", + file, strerror (errno)); + return -1; + } + } + } + + if (fd < 0) + { + if ((fd = open (file, O_APPEND | O_WRONLY)) < 0) + { + printf ("root fs, cannot open file `%s' : %s\n", + file, strerror (errno)); + return -1; + } + } + + for (i = 0; i < line_cnt; i++) + { + size_t len = strlen (lines[i]); + + if (len) + { + if (write (fd, lines[i], strlen (lines[i])) < 0) + { + close (fd); + printf ("root fs, cannot write to `%s' : %s\n", + file, strerror (errno)); + return -1; + } + } + } + + return close (fd); +} + +/* + * Write hosts record. + */ + +int +rtems_rootfs_append_host_rec (in_addr_t cip, + const char *cname, + const char *dname) +{ + char buf[128]; + char *bufp = buf; + const char *bufl[1]; + struct in_addr ip; + + ip.s_addr = cip; + + if (cname && strlen (cname)) + { + char addrbuf[INET_ADDRSTRLEN]; + + snprintf (bufp, sizeof (buf), "%s\t\t%s", inet_ntoa_r (ip, addrbuf), cname); + bufp += strlen (buf); + + if (dname && strlen (dname)) + { + snprintf (bufp, sizeof (buf), "\t\t%s.%s", cname, dname); + bufp += strlen (buf); + } + + strcat (buf, "\n"); + + bufl[0] = buf; + + if (rtems_rootfs_file_append ("/etc/hosts", MKFILE_MODE, 1, bufl) < 0) + return -1; + } + else + { + printf ("rootfs hosts rec append, no cname supplied\n"); + return -1; + } + + return 0; +} + +/* + * Create a root file system. + */ + +int +rtems_create_root_fs (void) +{ + const char *lines[1]; + size_t i; + + /* + * Create the directories. + */ + + for (i = 0; + i < (sizeof (default_directories) / sizeof (rtems_rootfs_dir_table)); + i++) + if (rtems_mkdir (default_directories[i].name, + default_directories[i].mode)) + return -1; + + /* + * The TCP/IP stack likes this one. If DNS does not work + * use the host file. + */ + + lines[0] = "hosts,bind\n"; + + if (rtems_rootfs_file_append ("/etc/host.conf", MKFILE_MODE, 1, lines)) + return -1; + + /* + * Create a `/etc/hosts' file. + */ + + if (rtems_rootfs_append_host_rec (htonl (0x7f000001), "localhost", "localdomain")) + return -1; + + return 0; +} diff --git a/rtems/mkrootfs.h b/rtems/mkrootfs.h new file mode 100644 index 0000000..1b1cb29 --- /dev/null +++ b/rtems/mkrootfs.h @@ -0,0 +1,80 @@ +/** + * @file + * + * RTEMS Root FS creation support. + */ + +/* + Copyright Cybertec Pty Ltd, 2000 + All rights reserved Cybertec Pty Ltd, 2000 + + COPYRIGHT (c) 1989-1998. + On-Line Applications Research Corporation (OAR). + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution or at + http://www.rtems.org/license/LICENSE. + + This software with is provided ``as is'' and with NO WARRANTY. +*/ + +#ifndef _RTEMS_MKROOTFS_H +#define _RTEMS_MKROOTFS_H + +#include <sys/types.h> /* in_addr_t */ + +#include <rtems.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Appends the lines to the a file. Create the file + * and builds the path if it does not exist. + * + * @param file + * @param omode + * @param line_cnt + * @param lines + * + * @return 0 on success, -1 on error + */ + +int +rtems_rootfs_file_append (const char *file, + mode_t omode, + const int line_cnt, + const char **lines); + +/** + * @brief Helper for bulding an /etc/hosts file. + * + * @param cip + * @param cname + * @param dname + * + * @return 0 on success, -1 on error + */ + +int +rtems_rootfs_append_host_rec (in_addr_t cip, + const char *cname, + const char *dname); + +/** + * Create a few common directories, plus a: + * /etc/passwd, /etc/group, /etc/host.conf, and + * /etc/hosts file. + * + * @return 0 on success, -1 on error + */ + +int +rtems_create_root_fs ( void ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rtems/rtems_bootp.c b/rtems/rtems_bootp.c new file mode 100644 index 0000000..134ae90 --- /dev/null +++ b/rtems/rtems_bootp.c @@ -0,0 +1,42 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/error.h> +#include <sys/types.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/rtems_bsdnet_internal.h> + +#include "rtems/bootp.h" + +/* + * Perform a BOOTP request + */ +void +rtems_bsdnet_do_bootp (void) +{ + bool ok; + rtems_bsdnet_semaphore_obtain (); + ok = bootpc_init (false, true); + rtems_bsdnet_semaphore_release (); + if (!ok) + panic ("rtems_bsdnet_do_bootp: bootp failed"); +} + +/* + * Perform a BOOTP request and update "standard" files in /etc + * with the results. + */ +void +rtems_bsdnet_do_bootp_and_rootfs (void) +{ + bool ok; + rtems_bsdnet_semaphore_obtain (); + ok = bootpc_init (true, true); + rtems_bsdnet_semaphore_release (); + if (!ok) + panic ("rtems_bsdnet_do_bootp_and_rootfs: bootp failed"); +} diff --git a/rtems/rtems_bsdnet.h b/rtems/rtems_bsdnet.h new file mode 100644 index 0000000..4607f42 --- /dev/null +++ b/rtems/rtems_bsdnet.h @@ -0,0 +1,339 @@ +/** + * @file + */ + + +#ifndef _RTEMS_BSDNET_H +#define _RTEMS_BSDNET_H + +#include <rtems.h> +#include <sys/cpuset.h> +#include <sys/ioccom.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Values that may be obtained by BOOTP + */ +extern struct in_addr rtems_bsdnet_bootp_server_address; +extern char *rtems_bsdnet_bootp_server_name; +extern char *rtems_bsdnet_bootp_boot_file_name; +extern char *rtems_bsdnet_bootp_cmdline; +extern int32_t rtems_bsdnet_timeoffset; + +/* + * 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 three entries must be supplied for each interface. + */ + char *name; + + /* + * This function now handles attaching and detaching an interface. + * The parameter attaching indicates the operation being invoked. + * For older attach functions which do not have the extra parameter + * it will be ignored. + */ + int (*attach)(struct rtems_bsdnet_ifconfig *conf, int attaching); + + /* + * 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; + + /* + * For external ethernet controller board the following + * parameters are needed + */ + unsigned int port; /* port of the board */ + unsigned int irno; /* irq of the board */ + unsigned int bpar; /* memory of the board */ + + /* + * Driver control block pointer. Typcially this points to the driver's + * controlling structure. You set this when you have the structure allocated + * externally to the driver. + */ + void *drv_ctrl; + +}; + +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 */ + char *ntp_server[3]; /* BOOTP */ + /* + * Default "multiplier" on buffer size. This is + * claimed by the TCP/IP implementation to be for + * efficiency but you will have to measure the + * benefit for buffering beyond double buffering + * in your own application. + * + * The default value is 2. + * + * See kern/uipc_socket2.c for details. + */ + unsigned long sb_efficiency; + /* + * Default UDP buffer sizes PER SOCKET!! + * + * TX = 9216 -- max datagram size + * RX = 40 * (1024 + sizeof(struct sockaddr_in)) + * + * See netinet/udp_usrreq.c for details + */ + unsigned long udp_tx_buf_size; + unsigned long udp_rx_buf_size; + /* + * Default UDP buffer sizes PER SOCKET!! + * + * TX = 16 * 1024 + * RX = 16 * 1024 + * + * See netinet/tcp_usrreq.c for details + */ + unsigned long tcp_tx_buf_size; + unsigned long tcp_rx_buf_size; + + /* + * Default Network Tasks CPU Affinity + */ +#ifdef RTEMS_SMP + const cpu_set_t *network_task_cpuset; + size_t network_task_cpuset_size; +#endif +}; + +/* + * Default global device configuration structure. This is scanned + * by the initialize network function. Check the network demo's for + * an example of the structure. Like the RTEMS configuration tables, + * they are not part of RTEMS but part of your application or bsp + * code. + */ +extern struct rtems_bsdnet_config rtems_bsdnet_config; + +/* + * Initialise the BSD stack, attach and `up' interfaces + * in the `rtems_bsdnet_config'. RTEMS must already be initialised. + */ +int rtems_bsdnet_initialize_network (void); + +/* + * Dynamic interface control. Drivers must free any resources such as + * memory, interrupts, io regions claimed during the `attach' and/or + * `up' operations when asked to `detach'. + * You must configure the interface after attaching it. + */ +void rtems_bsdnet_attach (struct rtems_bsdnet_ifconfig *ifconfig); +void rtems_bsdnet_detach (struct rtems_bsdnet_ifconfig *ifconfig); + +/* + * Interface configuration. The commands are listed in `sys/sockio.h'. + */ +int rtems_bsdnet_ifconfig (const char *ifname, uint32_t cmd, void *param); + +void rtems_bsdnet_do_bootp (void); +void rtems_bsdnet_do_bootp_and_rootfs (void); + +/* NTP tuning parameters */ +extern int rtems_bsdnet_ntp_retry_count; +extern int rtems_bsdnet_ntp_timeout_secs; +extern int rtems_bsdnet_ntp_bcast_timeout_secs; + + +struct timestamp { + uint32_t integer; + uint32_t fraction; +}; + +/* Data is passed in network byte order */ +struct ntpPacketSmall { + uint8_t li_vn_mode; + uint8_t stratum; + int8_t poll_interval; + int8_t precision; + int32_t root_delay; + int32_t root_dispersion; + char reference_identifier[4]; + struct timestamp reference_timestamp; + struct timestamp originate_timestamp; + struct timestamp receive_timestamp; + struct timestamp transmit_timestamp; +}; + +/* NOTE: packet data is *only* accessible from the callback + * + * 'callback' is invoked twice, once prior to sending a request + * to the server and one more time after receiving a valid reply. + * This allows for the user to measure round-trip times. + * + * Semantics of the 'state' parameter: + * + * state == 1: 1st call, just prior to sending request. The + * packet has been set up already but may be + * modified by the callback (e.g. to set the originate + * timestamp). + * state == -1: 1st call - no request will be sent but we'll + * wait for a reply from a broadcast server. The + * packet has not been set up. + * state == 0: 2nd call. The user is responsible for keeping track + * of the 'state' during the first call in order to + * know if it makes sense to calculate 'round-trip' times. + * + * RETURN VALUE: the callback should return 0 if processing the packet was + * successful and -1 on error in which case rtems_bsdnet_get_ntp() + * may try another server. + */ +typedef int (*rtems_bsdnet_ntp_callback_t)( + struct ntpPacketSmall *packet, + int state, + void *usr_data); + +/* Obtain time from a NTP server and call user callback to process data; + * socket parameter may be -1 to request the routine to open and close its own socket. + * Networking parameters as configured are used... + * + * It is legal to pass a NULL callback pointer. In this case, a default callback + * is used which determines the current time by contacting an NTP server. The current + * time is converted to a 'struct timespec' (seconds/nanoseconds) and passed into *usr_data. + * The caller is responsible for providing a memory area >= sizeof(struct timespec). + * + * RETURNS: 0 on success, -1 on failure. + */ +int rtems_bsdnet_get_ntp(int socket, rtems_bsdnet_ntp_callback_t callback, void *usr_data); + +int rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority); + +/* + * Callback to report BSD malloc starvation. + * The default implementation just prints a message but an application + * can provide its own version. + */ +void rtems_bsdnet_malloc_starvation(void); + +/* + * mbuf malloc interface to enable custom allocation of mbuf's + * + * May be declared in user code. If not, then the default is to + * malloc. + */ +void* rtems_bsdnet_malloc_mbuf(size_t size, int type); + +/* + * Possible values of the type parameter to rtems_bsdnet_malloc_mbuf to assist + * in allocation of the structure. + */ +#define MBUF_MALLOC_NMBCLUSTERS (0) +#define MBUF_MALLOC_MCLREFCNT (1) +#define MBUF_MALLOC_MBUF (2) + +/* + * RTEMS-specific socket wake-up additions previously part of <sys/socket.h>. + * + * An alternative in the LibBSD network stack for this is KQUEUE(2). + */ + +#define SO_SNDWAKEUP 0x1020 /* wakeup when ready to send */ +#define SO_RCVWAKEUP 0x1021 /* wakeup when ready to receive */ + +/* + * RTEMS additions for setting/getting `tap' function on incoming packets. + */ +struct ifnet; +struct ether_header; +struct mbuf; +struct rtems_tap_ifreq { + char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + int (*ifr_tap)(struct ifnet *, struct ether_header *, struct mbuf *); +}; +#define SIOCSIFTAP _IOW('i', 88, struct rtems_tap_ifreq) /* set tap function */ +#define SIOCGIFTAP _IOW('i', 89, struct rtems_tap_ifreq) /* get tap function */ + +#define OSIOCGIFADDR _IOWR('i', 13, struct ifreq) /* get ifnet address */ +#define OSIOCGIFDSTADDR _IOWR('i', 15, struct ifreq) /* get p-p address */ +#define OSIOCGIFBRDADDR _IOWR('i', 18, struct ifreq) /* get broadcast addr */ +#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */ +#define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */ + +struct socket; + +struct sockwakeup { + void (*sw_pfn)(struct socket *, void *); + void *sw_arg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_BSDNET_H */ diff --git a/rtems/rtems_bsdnet_internal.h b/rtems/rtems_bsdnet_internal.h new file mode 100644 index 0000000..d103c56 --- /dev/null +++ b/rtems/rtems_bsdnet_internal.h @@ -0,0 +1,285 @@ +/* + * Declarations to fit FreeBSD to RTEMS. + * + ******************************************************************* + * WARNING * + * This file should *never* be included by any application program * + ******************************************************************* + */ + +#ifndef _RTEMS_RTEMS_BSDNET_INTERNAL_H +#define _RTEMS_RTEMS_BSDNET_INTERNAL_H + +#include <sys/_types.h> +#include <rtems.h> +#include <rtems/fs.h> +#include <rtems/score/timecounter.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef __uintptr_t vm_offset_t; +typedef __intptr_t vm_ooffset_t; +typedef __uintptr_t vm_pindex_t; +typedef __uintptr_t vm_size_t; + +#define _BSD_OFF_T_ int32_t +#define _BSD_PID_T_ rtems_id +#define _BSD_VA_LIST_ char * + +/* make sure we get the network versions of these */ +#include <machine/types.h> +#include <machine/param.h> +#include <machine/endian.h> +#include <sys/cdefs.h> + +#include <sys/time.h> +#include <sys/ioccom.h> + +struct mdproc { + int md_flags; + int *md_regs; +}; + +/* + * Other RTEMS/BSD glue + */ +struct socket; +extern int soconnsleep (struct socket *so); +extern void soconnwakeup (struct socket *so); +#define splnet() 0 +#define splimp() 0 +#define splx(_s) do { (_s) = 0; (void) (_s); } while(0) + +/* to avoid warnings */ +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); + +#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 + +#define microtime(_tvp) _Timecounter_Microtime(_tvp) + +#define hz rtems_bsdnet_ticks_per_second +#define tick rtems_bsdnet_microseconds_per_tick + +#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.... + */ + +typedef u_int64_t u_quad_t; /* quads */ +typedef int64_t quad_t; +typedef quad_t * qaddr_t; + +typedef void __sighandler_t(int); +typedef __sighandler_t *sig_t; /* type of pointer to a signal function */ +#define NSIG 32 + +#ifdef _KERNEL +typedef int boolean_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 + +#ifndef _BYTEORDER_PROTOTYPED +#define _BYTEORDER_PROTOTYPED +__BEGIN_DECLS +__uint32_t htonl(__uint32_t); +__uint16_t htons(__uint16_t); +__uint32_t ntohl(__uint32_t); +__uint16_t ntohs(__uint16_t); +__END_DECLS +#endif + +#ifndef _BYTEORDER_FUNC_DEFINED +#define _BYTEORDER_FUNC_DEFINED +#define htonl(x) __htonl(x) +#define htons(x) __htons(x) +#define ntohl(x) __ntohl(x) +#define ntohs(x) __ntohs(x) +#endif /* !_BYTEORDER_FUNC_DEFINED */ + +#define NTOHS(x) (x) = ntohs(x) +#define HTONS(x) (x) = htons(x) +#define NTOHL(x) (x) = ntohl(x) +#define HTONL(x) (x) = htonl(x) + +in_addr_t inet_addr(const char *); + +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 buf; +struct tty; +struct uio; +struct rtems_bsdnet_ifconfig; + +/* + * Redo kernel memory allocation + */ +#define malloc(size,type,flags) rtems_bsdnet_malloc(size,type,flags) +#define free(ptr,type) rtems_bsdnet_free(ptr,type) +#define timeout(ftn,arg,ticks) rtems_bsdnet_timeout(ftn,arg,ticks) + +#define M_NOWAIT 0x0001 +void *rtems_bsdnet_malloc (size_t 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_semaphore_obtain_recursive (uint32_t nest_count); +uint32_t rtems_bsdnet_semaphore_release_recursive (void); +void rtems_bsdnet_schednetisr (int n); +int rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep); + +static inline unsigned long rtems_bsdnet_seconds_since_boot(void) +{ + return (unsigned long) rtems_clock_get_uptime_seconds() + 1UL; +} + +unsigned long rtems_bsdnet_random (void); + +rtems_id rtems_bsdnet_newproc ( + char *name, + int stacksize, + void (*entry)(void *), + void *arg +); + +#ifdef RTEMS_SMP +/* As rtems_bsdnet_newproc() but with ability to set CPU affinity too */ +rtems_id rtems_bsdnet_newproc_affinity ( + char *name, + int stacksize, + void (*entry)(void *), + void *arg, + const cpu_set_t *set, + const size_t setsize +); +#endif + +rtems_status_code rtems_bsdnet_event_receive ( + rtems_event_set event_in, + rtems_option option_set, + rtems_interval ticks, + rtems_event_set *event_out +); + +static inline rtems_status_code rtems_bsdnet_event_send ( + rtems_id task_id, + rtems_event_set event_in +) +{ + return rtems_event_system_send (task_id, event_in); +} + +/* + * 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; + +/* + * Internal IOCTL command + */ +#define SIO_RTEMS_SHOW_STATS _IO('i', 250) + +/* + * Some extra prototypes + */ +int sethostname (const char *name, size_t namelen); +void domaininit (void *); +void ifinit (void *); +void ipintr (void); +void arpintr (void); +int socket (int, int, int); +int ioctl (int, ioctl_command_t, ...); + +/* + * 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_SYSTEM_NETWORK_SBWAIT +#define SOSLEEP_EVENT RTEMS_EVENT_SYSTEM_NETWORK_SOSLEEP +#define NETISR_IP_EVENT (1L << NETISR_IP) +#define NETISR_ARP_EVENT (1L << NETISR_ARP) +#define NETISR_EVENTS (NETISR_IP_EVENT|NETISR_ARP_EVENT) +#if (SBWAIT_EVENT & SOSLEEP_EVENT & NETISR_EVENTS & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE) +# error "Network event conflict" +#endif + +struct socket *rtems_bsdnet_fdToSocket(int fd); + +void sysctl_register_all(void *); + +void rtems_set_udp_buffer_sizes(u_long, u_long); + +void rtems_set_tcp_buffer_sizes(u_long, u_long); + +void rtems_set_sb_efficiency(u_long); + +#define IFF_OACTIVE IFF_DRV_OACTIVE +#define IFF_RUNNING IFF_DRV_RUNNING + +struct ifaddr; +void ifafree(struct ifaddr *); + +struct ifnet; +struct mbuf; +struct sockaddr; +struct rtentry; +int looutput(struct ifnet *, + struct mbuf *, struct sockaddr *, struct rtentry *); + +typedef u_long tcp_cc; /* connection count per rfc1644 */ + +#define TCPOPT_TSTAMP_HDR \ + (uint32_t)(((uint32_t)TCPOPT_NOP<<24)| \ + ((uint32_t)TCPOPT_NOP<<16)| \ + ((uint32_t)TCPOPT_TIMESTAMP<<8)| \ + ((uint32_t)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) + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_RTEMS_BSDNET_INTERNAL_H */ diff --git a/rtems/rtems_bsdnet_malloc_starvation.c b/rtems/rtems_bsdnet_malloc_starvation.c new file mode 100644 index 0000000..c5ccd8c --- /dev/null +++ b/rtems/rtems_bsdnet_malloc_starvation.c @@ -0,0 +1,19 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * Routine called when malloc() is not succeeding. This can be overridden + * by a BSP. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <rtems/rtems_bsdnet.h> + +void +rtems_bsdnet_malloc_starvation(void) +{ + printf ("rtems_bsdnet_malloc still waiting.\n"); +} diff --git a/rtems/rtems_dhcp.c b/rtems/rtems_dhcp.c new file mode 100644 index 0000000..6a153a4 --- /dev/null +++ b/rtems/rtems_dhcp.c @@ -0,0 +1,1287 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * DCHP client for RTEMS + * Andrew Bythell, <abythell@nortelnetworks.com> + * based on and uses subroutines from c/src/libnetworking/nfs/bootp_subr.c + */ + +/* + * DHCP task added. + * Brendan Gannon, <bgannon@cybertec.com.au> + */ + +/* + * Added interface to terminate DHCP task, and removed panics. + * Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind + * Maarten Van Es <maarten@mind.be>, Essensium/Mind + */ + +/* + * 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. + * + */ + +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/bsdnet/servers.h> + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sys/sockio.h> +#include <sys/param.h> /* for MAXHOSTNAMELEN */ +#include <sys/systm.h> +#include <sys/socketvar.h> /* for socreat() soclose() */ +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <netinet/in.h> /* for NBO-HBO conversions */ +#include <net/if_types.h> /* for IFT_ETHER */ +#include <net/if_dl.h> /* for LLADDR */ + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rtems/mkrootfs.h> + +#include "rtems/dhcp.h" +#include "rtems/bootp.h" + +#ifndef EALEN +#define EALEN 6 +#endif + +/* + *DHCP flags + */ +#define DHCP_BROADCAST 0x8000 +#define DHCP_UNICAST 0x0000 + +/* + * DHCP Op Codes + */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* + * DHCP Messages + */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NACK 6 +#define DHCP_RELEASE 7 + +/* + * DHCP Options + */ +#define DHCP_OPTION_PAD 0 +#define DHCP_SUBNET 1 +#define DHCP_GATEWAY 3 +#define DHCP_DNS 6 +#define DHCP_HOST 12 +#define DHCP_DOMAIN_NAME 15 +#define DHCP_NETMASK 28 +#define DHCP_REQUESTED_IP 50 +#define DHCP_LEASE 51 +#define DHCP_MESSAGE 53 +#define DHCP_SERVER 54 +#define DHCP_PARAMETERS 55 +#define DHCP_OPTION_END 255 + +/* + * Definitions from RFC + */ +struct dhcp_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[312]; +}; + +/* + * Variables + */ +static int dhcp_option_overload = 0; +static char dhcp_gotgw = 0; +static char dhcp_gotnetmask = 0; +static char dhcp_gotserver = 0; +static char dhcp_gotlogserver = 0; +static struct sockaddr_in dhcp_netmask; +static struct sockaddr_in dhcp_gw; +static char *dhcp_hostname; +static int dhcp_message_type = 0; +static unsigned long dhcp_lease_time; +static unsigned long dhcp_elapsed_time = 0; +static const char dhcp_magic_cookie[4] = { 99, 130, 83, 99 }; +static const char dhcp_request_parameters[5] = { DHCP_SUBNET, + DHCP_GATEWAY, + DHCP_DNS, + DHCP_HOST, + DHCP_DOMAIN_NAME }; +#define NUM_NAMESERVERS \ + (sizeof rtems_bsdnet_config.name_server / sizeof rtems_bsdnet_config.name_server[0]) +static struct in_addr rtems_dhcpd_nameserver[NUM_NAMESERVERS]; +static int rtems_dhcpd_nameserver_count = 0; + +/* + * Clean any DNS entries add by a DHCP request. + */ +static void +clean_dns_entries (void) +{ + int e; + for (e = 0; e < rtems_dhcpd_nameserver_count; ++e) + { + int n; + for (n = 0; n < rtems_bsdnet_nameserver_count; ++ n) + { + if (memcmp (&rtems_dhcpd_nameserver[e], &rtems_bsdnet_nameserver[n], 4) == 0) + { + if (n < (NUM_NAMESERVERS - 1)) + memmove (&rtems_bsdnet_nameserver[n], + &rtems_bsdnet_nameserver[n + 1], + (NUM_NAMESERVERS - n - 1) * 4); + --rtems_bsdnet_nameserver_count; + } + } + } + rtems_dhcpd_nameserver_count = 0; +} + +/* + * Format an IP address in dotted decimal. + */ +static void +format_ip (unsigned long ip, char* buffer) +{ + sprintf (buffer, + "%lu.%lu.%lu.%lu", + (ip >> 24), + (ip >> 16) & 0xff, + (ip >> 8) & 0xff, + (ip & 0xff)); + + return; +} + +/* + * Print the IP setup + */ +static void +printsetup (const char *iface, + struct in_addr ip_addr, + struct in_addr mask_addr, + struct in_addr srv_addr, + struct in_addr gw_addr) +{ + unsigned long ip; + char ip_str[15]; + + printf ("dhcpc: %s: ", iface); + + ip = ntohl (ip_addr.s_addr); + format_ip (ip, ip_str); + printf ("inet: %-15s ", ip_str); + + ip = ntohl (mask_addr.s_addr); + format_ip (ip, ip_str); + printf ("mask: %-15s\n", ip_str); + + ip = ntohl (srv_addr.s_addr); + format_ip (ip, ip_str); + printf (" srv: %-15s ", ip_str); + + ip = ntohl (gw_addr.s_addr); + format_ip (ip, ip_str); + printf (" gw: %-15s\n", ip_str); + + return; +} + +/* + * Process options from the DHCP packet. + * Based on BOOTP routine. + */ +static void +process_options (unsigned char *optbuf, int optbufSize) +{ + int j = 0; + int len; + int code, ncode; + char *p; + + dhcp_message_type = 0; + + ncode = optbuf[0]; + while (j < optbufSize) + { + code = optbuf[j] = ncode; + if (code == 255) + return; + if (code == 0) + { + j++; + continue; + } + len = optbuf[j + 1]; + j += 2; + + if ((len + j) >= optbufSize) + { + printf ("Truncated field for code %d", code); + return; + } + + ncode = optbuf[j + len]; + optbuf[j + len] = '\0'; + p = (char*) &optbuf[j]; + j += len; + + /* + * Process the option + */ + switch (code) + { + case 1: + /* Subnet mask */ + if (len != 4) { + printf ("dhcpc: subnet mask len is %d\n", len); + continue; + } + memcpy (&dhcp_netmask.sin_addr, p, 4); + dhcp_gotnetmask = 1; + break; + + case 2: + /* Time offset */ + if (len != 4) { + printf ("dhcpc: time offset len is %d\n", len); + continue; + } + memcpy (&rtems_bsdnet_timeoffset, p, 4); + rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset); + break; + + case 3: + /* Routers */ + if (len % 4) { + printf ("dhcpc: Router Len is %d\n", len); + continue; + } + if (len > 0) + { + memcpy (&dhcp_gw.sin_addr, p, 4); + dhcp_gotgw = 1; + } + break; + + case 42: + /* NTP servers */ + if (len % 4) { + printf ("dhcpc: time server Len is %d\n", len); + continue; + } + { + int tlen = 0; + while ((tlen < len) && + (rtems_bsdnet_ntpserver_count < + sizeof rtems_bsdnet_config.ntp_server / + sizeof rtems_bsdnet_config.ntp_server[0])) + { + memcpy (&rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count], + p + tlen, 4); + rtems_bsdnet_ntpserver_count++; + tlen += 4; + } + } + break; + + case 6: + /* Domain Name servers */ + if (len % 4) { + printf ("dhcpc: DNS Len is %d\n", len); + continue; + } + { + int dlen = 0; + while ((dlen < len) && + (rtems_dhcpd_nameserver_count < NUM_NAMESERVERS) && + (rtems_bsdnet_nameserver_count < NUM_NAMESERVERS)) + { + memcpy (&rtems_dhcpd_nameserver + [rtems_dhcpd_nameserver_count], p + dlen, 4); + rtems_dhcpd_nameserver_count++; + memcpy (&rtems_bsdnet_nameserver + [rtems_bsdnet_nameserver_count], p + dlen, 4); + rtems_bsdnet_nameserver_count++; + dlen += 4; + } + } + break; + + case 12: + /* Host name */ + if (len >= MAXHOSTNAMELEN) { + printf ("dhcpc: hostname >= %d bytes\n", MAXHOSTNAMELEN); + len = MAXHOSTNAMELEN-1; + } + if (sethostname (p, len) < 0) { + printf ("dhcpc: can't set host name"); + } + if (dhcp_hostname != NULL) + { + char *tmp = realloc (dhcp_hostname, len); + if (tmp != NULL) { + dhcp_hostname = tmp; + strncpy (dhcp_hostname, p, len); + } else { /* realloc failed */ + printf ("dhcpc: realloc failed (%s:%d)", __FILE__, __LINE__); + free (dhcp_hostname, 0); + dhcp_hostname = NULL; + } + } else { /* dhcp_hostname == NULL */ + dhcp_hostname = strndup (p, len); + } + break; + + case 7: + /* Log servers */ + if (len % 4) { + printf ("dhcpc: Log server Len is %d\n", len); + continue; + } + if (len > 0) + { + memcpy (&rtems_bsdnet_log_host_address, p, 4); + dhcp_gotlogserver = 1; + } + break; + + case 15: + /* Domain name */ + if (p[0]) + { + rtems_bsdnet_domain_name = strdup (p); + } + break; + + case 16: /* Swap server IP address. unused */ + break; + + case 50: + /* DHCP Requested IP Address */ + if (len != 4) + printf ("dhcpc: DHCP option requested IP len is %d", len); + /* + * although nothing happens here, this case keeps the client + * from complaining about unknown options. The Requested IP + * is necessary to return to the server for a DHCP REQUEST + */ + break; + + case 51: + /* DHCP Lease Length */ + if (len != 4) { + printf ("dhcpc: DHCP option lease-length len is %d", len); + continue; + } + memcpy (&dhcp_lease_time, &p[0], 4); + dhcp_lease_time = ntohl (dhcp_lease_time); + break; + + case 52: + /* DHCP option override */ + if (len != 1) { + printf ("dhcpc: DHCP option overload len is %d", len); + continue; + } + dhcp_option_overload = p[0]; + break; + + case 53: + /* DHCP message */ + if (len != 1) { + printf ("dhcpc: DHCP message len is %d", len); + continue; + } + dhcp_message_type = p[0]; + break; + + case 128: /* Site-specific option for DHCP servers that + * a) don't supply tag 54 + * and + * b) don't supply the server address in siaddr + * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab: + * Bootsrv s Site,128,IP,1,1 + * and use that symbol in the macro that defines the client: + * Bootsrv=<tftp-server-ip-address> + */ + case 54: + /* DHCP server */ + if (len != 4) { + printf ("dhcpc: DHCP server len is %d", len); + continue; + } + memcpy (&rtems_bsdnet_bootp_server_address, p, 4); + dhcp_gotserver = 1; + break; + + case 66: + /* DHCP server name option */ + if (p[0]) + rtems_bsdnet_bootp_server_name = strdup (p); + break; + + case 67: + /* DHCP bootfile option */ + if (p[0]) + rtems_bsdnet_bootp_boot_file_name = strdup (p); + break; + + default: + break; + } + } +} + +/* + * Generate the packet for a DHCP DISCOVER. + */ +static int +dhcp_discover_req (struct dhcp_packet* call, + struct sockaddr_dl *sdl, + unsigned long *xid) +{ + int len = 0; + + memset (call, 0, sizeof (struct dhcp_packet)); + + /* + * Send a DHCP DISCOVER Message + */ + call->op = DHCP_BOOTREQUEST; + call->htype = 1; /* 10mb ethernet */ + call->hlen = sdl->sdl_alen; /* Hardware address length */ + call->hops = 0; + (*xid)++; + call->xid = htonl (*xid); + call->flags = htons (DHCP_BROADCAST); + + memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen); + + /* + * Magic cookie. + */ + memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)); + len += sizeof (dhcp_magic_cookie); + + /* + * DHCP Message type. + */ + call->vend[len++] = DHCP_MESSAGE; + call->vend[len++] = 1; + call->vend[len++] = DHCP_DISCOVER; + + /* + * If a host name is set add it to the request. + */ + if (rtems_bsdnet_config.hostname && \ + (strlen (rtems_bsdnet_config.hostname) > 1) && + (strlen (rtems_bsdnet_config.hostname) < 32)) { + call->vend[len++] = DHCP_HOST; + call->vend[len++] = strlen (rtems_bsdnet_config.hostname); + memcpy (&call->vend[len], + rtems_bsdnet_config.hostname, + strlen (rtems_bsdnet_config.hostname)); + len += strlen (rtems_bsdnet_config.hostname); + } + + /* + * DHCP Parameter request list + */ + call->vend[len++] = DHCP_PARAMETERS; + call->vend[len++] = sizeof (dhcp_request_parameters); + memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters)); + len += sizeof (dhcp_request_parameters); + + /* + * Lease time. + */ + call->vend[len++] = DHCP_LEASE; + call->vend[len++] = 4; + memset (&call->vend[len], 0xFF, 4); /* request infinite lease time */ + len += 4; + + /* + * End. + */ + call->vend[len++] = DHCP_OPTION_END; + call->secs = 0; + + return len; +} + +/* + * Generate the packet for a DHCP REQUEST. + */ +static int +dhcp_request_req (struct dhcp_packet* call, + struct dhcp_packet* reply, + struct sockaddr_dl *sdl, + int broadcast) +{ + int len = 0; + unsigned long temp; + char *hostname; + + memset (call, 0, sizeof (struct dhcp_packet)); + + /* + * Send a DHCP REQUEST Message + */ + call->op = DHCP_BOOTREQUEST; + call->htype = 1; /* 10mb ethernet */ + call->hlen = sdl->sdl_alen; /* Hardware address length */ + call->hops = 0; + call->xid = reply->xid; + if (broadcast) + call->flags = htons (DHCP_BROADCAST); + else + { + call->flags = htons (DHCP_UNICAST); + call->ciaddr = reply->yiaddr; + } + memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen); + + /* + * Magic cookie. + */ + memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)); + len += sizeof (dhcp_magic_cookie); + + /* + * DHCP Message type. + */ + call->vend[len++] = DHCP_MESSAGE; + call->vend[len++] = 1; + call->vend[len++] = DHCP_REQUEST; + + /* + * DHCP server + */ + if (broadcast) + { + call->vend[len++] = DHCP_SERVER; + call->vend[len++] = sizeof (rtems_bsdnet_bootp_server_address); + memcpy (&call->vend[len], &rtems_bsdnet_bootp_server_address, + sizeof (rtems_bsdnet_bootp_server_address)); + len += sizeof (rtems_bsdnet_bootp_server_address); + } + + /* + * Requested IP + */ + call->vend[len++] = DHCP_REQUESTED_IP; + call->vend[len++] = sizeof (reply->yiaddr); + memcpy (&call->vend[len], &reply->yiaddr, sizeof (reply->yiaddr)); + len += sizeof (reply->yiaddr); + + /* + * DHCP Parameter request list + */ + call->vend[len++] = DHCP_PARAMETERS; + call->vend[len++] = sizeof (dhcp_request_parameters); + memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters)); + len += sizeof (dhcp_request_parameters); + + /* + * Lease time. + * For the REQUEST, return the lease time the server offered. + */ + call->vend[len++] = DHCP_LEASE; + call->vend[len++] = 4; + temp = htonl (dhcp_lease_time); + memcpy (&call->vend[len], &temp, sizeof (unsigned long)); + len += 4; + + /* + * Host name. + */ + hostname = malloc (MAXHOSTNAMELEN, 0, M_NOWAIT); + if (hostname != NULL) + { + if (gethostname (hostname, MAXHOSTNAMELEN) == 0) + { + call->vend[len++] = DHCP_HOST; + call->vend[len++] = strlen (hostname); + strcpy ((char*) &call->vend[len], hostname); + len += strlen (hostname); + } + free (hostname, 0); + } + + /* + * End. + */ + call->vend[len++] = DHCP_OPTION_END; + call->secs = 0; + + return len; +} + +/* + * Variables for the DHCP task. + */ +static struct dhcp_packet dhcp_req; +static rtems_id dhcp_task_id; + +/* + * The DHCP task counts until half the lease time has expired. + * When this period is up, it sends a DHCP REQUEST packet to the + * server again to renew the lease. + * If the lease is renewed, the task starts counting again. + * If the lease is not renewed, the task retries until it is. + * + * The task will not rebind if the lease is not renewed. + */ +static void +dhcp_task (rtems_task_argument _sdl) +{ + unsigned long count; + struct dhcp_packet call; + struct sockaddr_dl *sdl; + rtems_event_set event_out; + unsigned int timeout = 0; + int error; + struct proc *procp = NULL; + rtems_status_code ev_st; + + sdl = (struct sockaddr_dl *) _sdl; + + count = dhcp_elapsed_time; + + while (true) + { + /* + * Sleep until the next poll + */ + timeout = RTEMS_MILLISECONDS_TO_TICKS (1000); + ev_st = rtems_event_receive (RTEMS_EVENT_0, + RTEMS_WAIT | RTEMS_EVENT_ANY, + timeout, &event_out); + + /* + * Check if not a poll timeout. So when ANY event received, exit task. + * Actually, only event RTEMS_EVENT_0 sent from rtem_dhcp_failsafe.c + * if "failsafe" dhcp enabled when interface down. Otherwise, no + * event should occur, just timeout. + */ + if(ev_st != RTEMS_TIMEOUT) + break; + + count++; + + if (count >= (dhcp_lease_time / 2)) + { + rtems_bsdnet_semaphore_obtain (); + + dhcp_request_req (&call, &dhcp_req, sdl, true); + + /* + * Send the Request. + */ + error = bootpc_call ((struct bootp_packet *)&call, + (struct bootp_packet *)&dhcp_req, procp, NULL, 0); + if (error) { + rtems_bsdnet_semaphore_release (); + printf ("DHCP call failed -- error %d", error); + continue; + } + + /* + * Check for DHCP ACK/NACK + */ + if (memcmp (&dhcp_req.vend[0], + dhcp_magic_cookie, + sizeof (dhcp_magic_cookie)) != 0) + { + rtems_bsdnet_semaphore_release (); + printf ("DHCP server did not send Magic Cookie.\n"); + continue; + } + + /* + * We have an ack. Clear the DNS entries that have been assigned by a previous + * DHCP request. + */ + clean_dns_entries (); + + /* + * Process this requests options. + */ + process_options (&dhcp_req.vend[4], sizeof (dhcp_req.vend) - 4); + + if (dhcp_message_type != DHCP_ACK) + { + rtems_bsdnet_semaphore_release (); + printf ("DHCP server did not accept the DHCP request"); + continue; + } + + rtems_bsdnet_semaphore_release (); + + count = 0; + } + } + + + dhcp_task_id = 0; + printf ("dhcpc: exiting lease renewal task.\n"); + rtems_task_exit(); + +} + +/* + * Start the DHCP task. + */ +static rtems_status_code +dhcp_start_task (struct sockaddr_dl *sdl, + struct dhcp_packet *reply, + int priority) +{ + rtems_status_code sc; + + memcpy (&dhcp_req, reply, sizeof (struct dhcp_packet)); + + sc = rtems_task_create (rtems_build_name ('d','h','c','p'), + priority, + 2048, + RTEMS_PREEMPT | + RTEMS_NO_TIMESLICE | + RTEMS_NO_ASR | + RTEMS_INTERRUPT_LEVEL (0), + RTEMS_LOCAL, + &dhcp_task_id); + + if (sc != RTEMS_SUCCESSFUL) + return sc; + + sc = rtems_task_start (dhcp_task_id, + dhcp_task, + (rtems_task_argument) sdl); + + if (sc != RTEMS_SUCCESSFUL) + return sc; + + return RTEMS_SUCCESSFUL; +} + +/* + * Check if the chosen interface already has an IP. + */ +static int +dhcp_interface_has_ip (struct ifreq *ireq, struct socket *so, struct proc *procp) +{ + struct sockaddr_in* sin; + int error; + + /* + * Check if the interface is already up. + */ + error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); + if (error) + return 0; + + if ((ireq->ifr_flags & IFF_UP) == 0) + return 0; + + sin = (struct sockaddr_in *)&ireq->ifr_addr; + bzero ((caddr_t)sin, sizeof (struct sockaddr_in)); + sin->sin_len = sizeof (struct sockaddr_in); + sin->sin_family = AF_INET; + error = ifioctl (so, SIOCGIFADDR, (caddr_t)ireq, procp); + if (error) + return 0; + + if (sin->sin_addr.s_addr != 0) + return 1; + + return 0; +} + +/* + * DCHP Client Routine + * - The first DHCP offer is always accepted + * - No DHCP DECLINE message is sent if ARPing fails + * + * return value: + * 0: ok + * < 0: failed to startup or configure interface + */ +static int +dhcp_init (int update_files) +{ + struct dhcp_packet call; + struct dhcp_packet reply; + static unsigned long xid = ~0xFF; + struct ifreq ireq; + struct ifnet *ifp; + struct socket *so; + int error; + struct sockaddr_in myaddr; + struct ifaddr *ifa; + struct sockaddr_dl *sdl = NULL; + struct proc *procp = NULL; + char expected_dhcp_payload[7]; + + clean_dns_entries(); + + /* + * If we are to update the files create the root + * file structure. + */ + if (update_files) + if (rtems_create_root_fs () < 0) { + printf("Error creating the root filesystem.\nFile not created.\n"); + update_files = 0; + } + + /* + * 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){ + printf ("dhcpc_init: no suitable interface\n"); + return -1; + } + + memset (&ireq, 0, sizeof (ireq)); + sprintf (ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); + + if ((error = socreate (AF_INET, &so, SOCK_DGRAM, 0, procp)) != 0) { + printf ("dhcpc_init: socreate, error: %s\n", strerror(error)); + return -1; + } + + if (!dhcp_interface_has_ip (&ireq, so, procp)) + bootpc_fakeup_interface (&ireq, so, procp); + + /* + * 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){ + printf ("dhcpc_init: Unable to find HW address\n"); + soclose (so); + return -1; + } + if (sdl->sdl_alen != EALEN) { + printf ("dhcpc_init: HW address len is %d, expected value is %d\n", + sdl->sdl_alen, EALEN); + soclose (so); + return -1; + } + + + /* + * Build the DHCP Discover + */ + dhcp_discover_req (&call, sdl, &xid); + + /* + * Expect a DHCP offer as response to DHCP discover + */ + memcpy(expected_dhcp_payload, dhcp_magic_cookie, sizeof(dhcp_magic_cookie)); + expected_dhcp_payload[sizeof(dhcp_magic_cookie) ]=0x35; /* DHCP */ + expected_dhcp_payload[sizeof(dhcp_magic_cookie)+1]=0x01; /* Length : 1 */ + expected_dhcp_payload[sizeof(dhcp_magic_cookie)+2]=0x02; /* DHCP_OFFER */ + + /* + * Send the Discover. + */ + error = bootpc_call ((struct bootp_packet *)&call, + (struct bootp_packet *)&reply, procp, + expected_dhcp_payload, sizeof(expected_dhcp_payload)); + if (error) { + printf ("BOOTP call failed -- %s\n", strerror(error)); + soclose (so); + return -1; + } + + /* + * Check for DHCP OFFER + */ + if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) { + printf ("DHCP server did not send Magic Cookie.\n"); + soclose (so); + return -1; + } + + process_options (&reply.vend[4], sizeof (reply.vend) - 4); + + if (dhcp_message_type != DHCP_OFFER) { + printf ("DHCP server did not send a DHCP Offer.\n"); + soclose (so); + return -1; + } + + /* + * Expect a DHCP_ACK as response to the DHCP REQUEST + * No need to reinitialize the whole expected_dhcp_payload variable, + * header and first two bytes of the payload are filled from DHCP offer + */ + expected_dhcp_payload[sizeof(dhcp_magic_cookie)+2]=0x05; /* DHCP_ACK */ + + /* + * Send a DHCP REQUEST + */ + dhcp_request_req (&call, &reply, sdl, true); + + error = bootpc_call ((struct bootp_packet *)&call, + (struct bootp_packet *)&reply, procp, + expected_dhcp_payload, sizeof(expected_dhcp_payload)); + if (error) { + printf ("BOOTP call failed -- %s\n", strerror(error)); + soclose (so); + return -1; + } + + /* + * Check for DHCP ACK/NACK + */ + if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) { + printf ("DHCP server did not send Magic Cookie.\n"); + soclose (so); + return -1; + } + + process_options (&reply.vend[4], sizeof (reply.vend) - 4); + + if (dhcp_message_type != DHCP_ACK) { + printf ("DHCP server did not accept the DHCP request\n"); + soclose (so); + return -1; + } + + /* + * Initialize network address structures + */ + memset (&myaddr, 0, sizeof (myaddr)); + memset (&dhcp_netmask, 0, sizeof (dhcp_netmask)); + memset (&dhcp_gw, 0, sizeof (dhcp_gw)); + myaddr.sin_len = sizeof (myaddr); + myaddr.sin_family = AF_INET; + dhcp_netmask.sin_len = sizeof (dhcp_netmask); + dhcp_netmask.sin_family = AF_INET; + dhcp_gw.sin_len = sizeof (dhcp_gw); + dhcp_gw.sin_family = AF_INET; + + /* + * Set our address + */ + myaddr.sin_addr = reply.yiaddr; + + /* + * Process BOOTP/DHCP options + */ + if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) == 0) + process_options (&reply.vend[4], sizeof (reply.vend) - 4); + + if (dhcp_option_overload & 1) + process_options ((unsigned char*) reply.file, sizeof reply.file); + else + if (reply.file[0]) + rtems_bsdnet_bootp_boot_file_name = strdup (reply.file); + + if (dhcp_option_overload & 2) + process_options ((unsigned char*) reply.sname, sizeof reply.sname); + else + if (reply.sname[0]) + rtems_bsdnet_bootp_server_name = strdup (reply.sname); + + /* + * Use defaults if values were not supplied by BOOTP/DHCP options + */ + if (!dhcp_gotnetmask) + { + if (IN_CLASSA (ntohl (myaddr.sin_addr.s_addr))) + dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSA_NET); + else if (IN_CLASSB (ntohl (myaddr.sin_addr.s_addr))) + dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSB_NET); + else + dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSC_NET); + } + + if (!dhcp_gotserver) + rtems_bsdnet_bootp_server_address = reply.siaddr; + + if (!dhcp_gotgw) + dhcp_gw.sin_addr = reply.giaddr; + + if (!dhcp_gotlogserver) + rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address; + + printsetup (ifp->if_name, myaddr.sin_addr, dhcp_netmask.sin_addr, + rtems_bsdnet_bootp_server_address, dhcp_gw.sin_addr); + + /* + * Update the files if we are asked too. + */ + if (update_files) { + char *dn = rtems_bsdnet_domain_name; + char *hn = dhcp_hostname; + if (!dn) + dn = "mydomain"; + if (!hn) + { + hn = "me"; + sethostname (hn, strlen (hn)); + } + rtems_rootfs_append_host_rec(myaddr.sin_addr.s_addr, hn, dn); + + /* + * Should the given domainname be used here ? + */ + if (dhcp_gotserver) { + if (rtems_bsdnet_bootp_server_name) + hn = rtems_bsdnet_bootp_server_name; + else + hn = "bootps"; + rtems_rootfs_append_host_rec(rtems_bsdnet_bootp_server_address.s_addr, + hn, dn); + } + + if (dhcp_gotlogserver) { + rtems_rootfs_append_host_rec(rtems_bsdnet_log_host_address.s_addr, + "logs", dn); + } + + /* + * Setup the DNS configuration file /etc/resolv.conf. + */ + if (rtems_bsdnet_nameserver_count) { + int i; + char buf[64]; + const char *bufl[1]; + + bufl[0] = buf; + +#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH) + + if (rtems_bsdnet_domain_name && + (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) { + strcpy(buf, "search "); + strcat(buf, rtems_bsdnet_domain_name); + strcat(buf, "\n"); + rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl); + } + + for (i = 0; i < rtems_bsdnet_nameserver_count; i++) { + char addrbuf[INET_ADDRSTRLEN]; + strcpy(buf, "nameserver "); + strcat(buf, inet_ntoa_r(rtems_bsdnet_ntpserver[i], addrbuf)); + strcat(buf, "\n"); + if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl)) + break; + } + } + } + + /* + * Configure the interface with the new settings + */ + error = bootpc_adjust_interface (&ireq, so, + &myaddr, &dhcp_netmask, &dhcp_gw, procp); + + /* + * Start the DHCP task if the lease isn't infinite. + */ + if (dhcp_lease_time != 0xffffffff) + dhcp_start_task (sdl, &reply, 150); + + soclose (so); + + return 0; +} + +/* + * + * RTEMS Entry point to DHCP client + * + */ +void rtems_bsdnet_do_dhcp (void) +{ + bool update = true; + rtems_bsdnet_semaphore_obtain (); + while( dhcp_init (update) < 0 ) { + update = false; + rtems_bsdnet_semaphore_release(); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(1000)); + rtems_bsdnet_semaphore_obtain (); + } + rtems_bsdnet_semaphore_release (); +} + +int rtems_bsdnet_do_dhcp_timeout( void ) +{ + int return_value; + + rtems_bsdnet_semaphore_obtain (); + return_value = dhcp_init (false); + rtems_bsdnet_semaphore_release (); + + return return_value; +} + +void rtems_bsdnet_dhcp_down (void) +{ + if(dhcp_task_id != 0) { + rtems_event_send (dhcp_task_id, RTEMS_EVENT_0); + } +} + +void +rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid, + unsigned long lease_time, + unsigned long elapsed_time, + unsigned long ip_address, + unsigned long srv_address, + const char* hostname) +{ + struct dhcp_packet reply; + struct ifnet *ifp = NULL; + struct ifaddr *ifa = NULL; + struct sockaddr_dl *sdl = NULL; + struct sockaddr_in *sin = NULL; + int match = 0; + struct ifnet *mtif = NULL; + + /* + * If an infinite lease has been granted, no task is needed. + */ + if (lease_time == 0xffffffff) + return; + + /* + * Find a network interface. + */ + for (ifp = ifnet; (ifp != NULL) && !match; ifp = ifp->if_next) + if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0) + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_INET) + { + sin = (struct sockaddr_in *) ifa->ifa_addr; + if (sin->sin_addr.s_addr == htonl (ip_address)) + { + mtif = ifp; + match = 1; + break; + } + } + + if (!match) { + printf ("dhcpc: no matching interface\n"); + return; + } + + for (ifa = mtif->if_addrlist; ifa != NULL; 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 (!match) { + printf ("dhcpc: no matching interface address\n"); + return; + } + + /* + * Set up given values in a simulated DHCP reply. + */ + memset (&reply, 0x00, sizeof (reply)); + reply.xid = htonl (xid); + reply.yiaddr.s_addr = htonl (ip_address); + reply.siaddr.s_addr = htonl (srv_address); + if (reply.siaddr.s_addr != rtems_bsdnet_bootp_server_address.s_addr) + { + memcpy (&rtems_bsdnet_bootp_server_address, &reply.siaddr, + sizeof (reply.siaddr)); + } + + dhcp_lease_time = lease_time; + dhcp_elapsed_time = elapsed_time; + + if (hostname) + { + sethostname ((char *) hostname, strlen (hostname)); + dhcp_hostname = bootp_strdup_realloc (dhcp_hostname, hostname); + } + + dhcp_start_task (sdl, &reply, 150); +} diff --git a/rtems/rtems_dhcp_failsafe.c b/rtems/rtems_dhcp_failsafe.c new file mode 100644 index 0000000..65c107d --- /dev/null +++ b/rtems/rtems_dhcp_failsafe.c @@ -0,0 +1,380 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + Description: Wrapper around DHCP client to restart it when the interface + moves to another network. + + Authors: Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind + Maarten Van Es <maarten@mind.be>, Essensium/Mind + (C) Septentrio 2008 + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution or at + http://www.rtems.org/license/LICENSE. + + + To use this functionality, call rtems_bsdnet_do_dhcp_failsafe() or set it + as the bootp member of the rtems_bsdnet_config structure. + + The rtems_bsdnet_do_dhcp_failsafe() function provides the following + functionalities: + + * It starts DHCP on the first non-loopback, non-point-to-point interface. + Before DHCP is started, any existing IP address on that interface is + removed, as well as the default route. + + * If DHCP fails to acquire an address for whatever reason, the interface + is reconfigured with the static address provided in its + rtems_bsdnet_ifconfig structure, and the default route from + rtems_bsdnet_config is restored. + It is possible to change the address in the rtems_bsdnet_ifconfig structure + while the system is running. + + * Optionally, after the interface is configured (either with DHCP or + statically), a task is started to monitor it. When the interface remains + disconnected (i.e. its IFF_RUNNING flag is off) for network_fail_timeout + seconds, the dhcp lease renewal is stopped. As soon as the interface is + connected again, DHCP is started again as above. + If network_fail_timeout is set to 0, the monitor task is not started. + + * Optionally, when the interface is disconnected, it is also brought down + for network_down_time seconds. Since this possibly makes the IFF_RUNNING + flag unuseable, the interface is brought up again before the flag is + polled. + If network_down_time is set to 0, the interface is not brought down. + + * Optionally, before DHCP is started, we wait for broadcast_delay seconds. + This is necessary to allow some routers to perform spanning tree discovery. + + Note that DHCP doesn't work well with multiple interfaces: only one of them + is configured using DHCP, and we can't guarantee it's the same one that is + monitored by this function. + +*/ + +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/rtems_bsdnet_internal.h> + +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include <rtems/dhcp.h> +#include <rtems/rtems_dhcp_failsafe.h> + +struct proc; /* Unused parameter of some functions. */ +#include <sys/sockio.h> +#include <sys/socket.h> +#include <net/route.h> +#include <netinet/in.h> /* for sockaddr_in */ +#include <net/if.h> /* for if.h */ +#include <net/if_var.h> /* for in_var.h */ +#include <netinet/in_var.h> /* for in_aliasreq */ +#include <sys/sockio.h> /* for ioctl definitions */ + +static int network_fail_timeout = RTEMS_DHCP_FAILSAFE_NETWORK_FAIL_TIMEOUT; +static int network_down_time = RTEMS_DHCP_FAILSAFE_NETWORK_DOWN_TIME; +static int broadcast_delay = RTEMS_DHCP_FAILSAFE_BROADCAST_DELAY; +static int dhcp_monitor_priority = RTEMS_DHCP_FAILSAFE_DHCP_MONITOR_PRIORITY; + +void rtems_bsdnet_dhcp_failsafe_config( + int network_fail_timeout_, + int network_down_time_, + int broadcast_delay_, + int dhcp_monitor_priority_ +) +{ + network_fail_timeout = network_fail_timeout_; + network_down_time = network_down_time_; + broadcast_delay = broadcast_delay_; + dhcp_monitor_priority = dhcp_monitor_priority_; +} + +/* + * returns 0 when successful, negative value for failure + */ +static int remove_address(const char *if_name) +{ + struct sockaddr_in address; + struct in_aliasreq ifra; + int retval = 0; + + memset (&address, '\0', sizeof (address)); + address.sin_len = sizeof (address); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + + /* Remove old default route to 0.0.0.0 */ + if (rtems_bsdnet_rtrequest (RTM_DELETE, (struct sockaddr *)&address, NULL, + (struct sockaddr *)&address, + (RTF_UP | RTF_STATIC), NULL) < 0 ) { + printf ("Failed to delete default route: %s (%d)\n", strerror (errno), errno); + retval = -1; + } + + /* Remove old ip-address */ + if (rtems_bsdnet_ifconfig(if_name, SIOCGIFADDR, &address) < 0) { + printf ("Failed to get if address: %s (%d)\n", strerror (errno), errno); + return -1; + } + + strncpy (ifra.ifra_name, if_name, IFNAMSIZ); + memcpy (&ifra.ifra_addr, &address, sizeof(address)); + if (rtems_bsdnet_ifconfig(if_name, SIOCDIFADDR, &ifra)) { + printf ("Can't delete if address: %s (%d)\n", strerror (errno), errno); + return -1; + } + + return retval; +} + + +static int +dhcp_if_down (const char* ifname) +{ + int16_t flags; + if (rtems_bsdnet_ifconfig (ifname, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't get flags for %s: %s\n", ifname, strerror (errno)); + return -1; + } + if (flags & IFF_UP) { + flags &= ~IFF_UP; + if (rtems_bsdnet_ifconfig (ifname, SIOCSIFFLAGS, &flags) < 0) { + printf ("Can't bring %s down: %s\n", ifname, strerror (errno)); + return -1; + } + } + + return 0; +} + +static int +dhcp_if_up (const char* ifname) +{ + int16_t flags; + if (rtems_bsdnet_ifconfig (ifname, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't get flags for %s: %s\n", ifname, strerror (errno)); + return -1; + } + if (!(flags & IFF_UP)) { + flags |= IFF_UP; + if (rtems_bsdnet_ifconfig (ifname, SIOCSIFFLAGS, &flags) < 0) { + printf ("Can't bring %s up: %s\n", ifname, strerror (errno)); + return -1; + } + } + + return 0; +} + + +static int +set_static_address (struct rtems_bsdnet_ifconfig *ifp) +{ + int16_t flags; + struct sockaddr_in address; + struct sockaddr_in netmask; + struct sockaddr_in broadcast; + struct sockaddr_in gateway; + + if (ifp->ip_address != NULL) { + printf("Setting static address for interface %s.\n", ifp->name); + + /* + * Bring interface up + */ + if (dhcp_if_up (ifp->name) < 0) + return -1; + + /* + * 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); + if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFNETMASK, &netmask) < 0) { + printf ("Can't set %s netmask: %s\n", ifp->name, strerror (errno)); + return -1; + } + + /* + * 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); + if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFADDR, &address) < 0) { + printf ("Can't set %s address: %s\n", ifp->name, strerror (errno)); + return -1; + } + + /* + * Set interface broadcast address if the interface has the + * broadcast flag set. + */ + if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't read %s flags: %s\n", ifp->name, strerror (errno)); + return -1; + } + if (flags & IFF_BROADCAST) { + 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; + + if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFBRDADDR, &broadcast) < 0) { + struct in_addr in_addr; + char buf[20]; + + in_addr.s_addr = broadcast.sin_addr.s_addr; + if (!inet_ntop (AF_INET, &in_addr, buf, sizeof (buf))) + strcpy (buf, "?.?.?.?"); + printf ("Can't set %s broadcast address %s: %s\n", ifp->name, buf, strerror (errno)); + } + } + } + + /* + * 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) { + printf ("Can't set default route: %s\n", strerror (errno)); + return -1; + } + } + + return 0; +} + +static void +do_dhcp_init (struct rtems_bsdnet_ifconfig *ifp) +{ + if (broadcast_delay) { + /* Wait before sending broadcast. */ + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(broadcast_delay * 1000)); + } + + printf ("starting dhcp client...\n"); + + remove_address(ifp->name); + if (rtems_bsdnet_do_dhcp_timeout () != 0) { + remove_address(ifp->name); + set_static_address (ifp); /* use static ip-address if dhcp failed */ + } + +} + +/* + * Main dhcp monitor thread + */ +static void dhcp_monitor_task (rtems_task_argument ifp_arg) +{ + struct rtems_bsdnet_ifconfig *ifp = (struct rtems_bsdnet_ifconfig *)ifp_arg; + char *ifname = ifp->name; + unsigned int downcount = 0; + int16_t ifflags; + int must_renew = FALSE; + + while (TRUE) { + if (rtems_bsdnet_ifconfig(ifname, SIOCGIFFLAGS, &ifflags) < 0) { + printf ("Failed to get if flags: %s (%d)\n", strerror (errno), errno); + goto error_out; + } + + if ((ifflags & IFF_RUNNING) != 0) { + if(must_renew) { + must_renew = FALSE; + do_dhcp_init(ifp); + } + downcount = 0; + } else { + if (downcount < network_fail_timeout) { + downcount++; + + if (downcount == network_fail_timeout) { + printf ("lost network connection...\n"); + rtems_bsdnet_dhcp_down (); + must_renew = TRUE; + dhcp_if_down(ifname); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(network_down_time * 1000)); + dhcp_if_up(ifname); + downcount = 0; + } + } + } + + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(1000)); + } + +error_out: + printf("Stopping dhcp monitoring application.\n"); + rtems_task_exit(); +} + +/* +* initialize dhcp monitoring application +* start dhcp monitoring thread +*/ +void rtems_bsdnet_do_dhcp_failsafe (void) +{ + rtems_status_code sc; + rtems_id id; + struct rtems_bsdnet_ifconfig *ifp; + int16_t ifflags; + + /* Find a suitable interface */ + for (ifp = rtems_bsdnet_config.ifconfig; ifp; ifp = ifp->next) { + if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &ifflags) < 0) + continue; + if ((ifflags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0) + break; + } + if (ifp == NULL){ + printf ("dhcpc_failsafe: no suitable interface\n"); + return; + } + printf("starting dhcp on interface %s\n", ifp->name); + do_dhcp_init(ifp); + + if (network_fail_timeout) { + sc = rtems_task_create (rtems_build_name ('d','h','c','m'), + dhcp_monitor_priority, + 2048, + RTEMS_PREEMPT | + RTEMS_NO_TIMESLICE | + RTEMS_NO_ASR | + RTEMS_INTERRUPT_LEVEL (0), + RTEMS_LOCAL, + &id); + + if (sc != RTEMS_SUCCESSFUL) { + printf ("Failed to create dhcp monitor task, code %d\n", sc); + return; + } + + sc = rtems_task_start (id, dhcp_monitor_task, (rtems_task_argument) ifp); + + if (sc != RTEMS_SUCCESSFUL) { + printf ("Failed to start dhcp monitor task, code %d\n", sc); + } + } +} + diff --git a/rtems/rtems_dhcp_failsafe.h b/rtems/rtems_dhcp_failsafe.h new file mode 100644 index 0000000..3c5a59f --- /dev/null +++ b/rtems/rtems_dhcp_failsafe.h @@ -0,0 +1,64 @@ +/* + Description: Wrapper around DHCP client to restart it when the interface + moves to another network. + + Authors: Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind + Maarten Van Es <maarten@mind.be>, Essensium/Mind + (C) Septentrio 2008 + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution or at + http://www.rtems.org/license/LICENSE. +*/ + +#ifndef _RTEMS_DHCP_FAILSAFE_H_ +#define _RTEMS_DHCP_FAILSAFE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Default settings for the DHCP failsafe. They can be overridden + * using rtems_bsdnet_dhcp_failsafe_config(); see that for descriptions. + */ +#ifndef RTEMS_DHCP_FAILSAFE_NETWORK_FAIL_TIMEOUT +#define RTEMS_DHCP_FAILSAFE_NETWORK_FAIL_TIMEOUT 5 +#endif + +#ifndef RTEMS_DHCP_FAILSAFE_NETWORK_DOWN_TIME +#define RTEMS_DHCP_FAILSAFE_NETWORK_DOWN_TIME 30 +#endif + +#ifndef RTEMS_DHCP_FAILSAFE_BROADCAST_DELAY +#define RTEMS_DHCP_FAILSAFE_BROADCAST_DELAY 0 +#endif + +#ifndef RTEMS_DHCP_FAILSAFE_DHCP_MONITOR_PRIORITY +#define RTEMS_DHCP_FAILSAFE_DHCP_MONITOR_PRIORITY 250 +#endif + + +void rtems_bsdnet_do_dhcp_failsafe (void); + +/** Set the DHCP fallback options. See the commentary at the top of the + * implementation. + @note Some of these options can be compile-time disabled - see the code. + */ +void rtems_bsdnet_dhcp_failsafe_config( + int network_fail_timeout, /**< The number of seconds before the interface is + * considered disconnected + */ + int network_down_time, /**< The number of seconds the interface + * remains down. + */ + int broadcast_delay, /**< The delay in seconds before broadcasts + * are sent. + */ + int dhcp_monitor_priority /**< The monitor priority.*/ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rtems/rtems_glue.c b/rtems/rtems_glue.c new file mode 100644 index 0000000..ee6c8f5 --- /dev/null +++ b/rtems/rtems_glue.c @@ -0,0 +1,1264 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define RTEMS_FAST_MUTEX + +#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/thread.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 <sys/sockio.h> +#include <sys/systm.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <vm/vm.h> + +#include <net/netisr.h> +#include <net/route.h> + +#include "loop.h" + +/* + * Memory allocation + */ +static uint32_t nmbuf = (64L * 1024L) / _SYS_MBUF_LEGACY_MSIZE; + uint32_t nmbclusters = (128L * 1024L) / MCLBYTES; + +/* + * Network task synchronization + */ +static rtems_recursive_mutex networkMutex = + RTEMS_RECURSIVE_MUTEX_INITIALIZER("_Network"); +static rtems_id networkDaemonTid; +static uint32_t networkDaemonPriority; +#ifdef RTEMS_SMP +static const cpu_set_t *networkDaemonCpuset = 0; +static size_t networkDaemonCpusetSize = 0; +#endif +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; +struct callout *callfree = NULL; +struct callout calltodo; + +/* + * FreeBSD variables + */ +int nfs_diskless_valid; + +/* + * BOOTP values + */ +struct in_addr rtems_bsdnet_log_host_address = {0}; +struct in_addr rtems_bsdnet_bootp_server_address = {0}; +char *rtems_bsdnet_bootp_boot_file_name = 0; +char *rtems_bsdnet_bootp_server_name = 0; +char *rtems_bsdnet_domain_name = 0; +char *rtems_bsdnet_bootp_cmdline = 0; +static struct in_addr _rtems_bsdnet_nameserver[sizeof rtems_bsdnet_config.name_server / + sizeof rtems_bsdnet_config.name_server[0]]; +struct in_addr *rtems_bsdnet_nameserver = _rtems_bsdnet_nameserver; +int rtems_bsdnet_nameserver_count = 0; +static struct in_addr _rtems_bsdnet_ntpserver[sizeof rtems_bsdnet_config.ntp_server / + sizeof rtems_bsdnet_config.ntp_server[0]]; +struct in_addr *rtems_bsdnet_ntpserver = _rtems_bsdnet_ntpserver; +int rtems_bsdnet_ntpserver_count = 0; +int32_t rtems_bsdnet_timeoffset = 0; + +static const struct sockaddr_in address_template = { + sizeof(address_template), + AF_INET, + 0, + { INADDR_ANY }, + { 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +static void +rtems_bsdnet_initialize_sockaddr_in(struct sockaddr_in *addr) +{ + memcpy(addr, &address_template, sizeof(*addr)); +} + +uint32_t +rtems_bsdnet_semaphore_release_recursive(void) +{ + uint32_t nest_count; + + nest_count = networkMutex._nest_level; + networkMutex._nest_level = 0; + rtems_recursive_mutex_unlock(&networkMutex); + return nest_count; +} + +void +rtems_bsdnet_semaphore_obtain_recursive(uint32_t nest_count) +{ + rtems_recursive_mutex_lock(&networkMutex); + networkMutex._nest_level = nest_count; +} + +/* + * 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 (size_t size, int type, int flags) +{ + void *p; + int try = 0; + + for (;;) { + uint32_t nest_count; + + p = malloc (size); + if (p || (flags & M_NOWAIT)) + return p; + nest_count = rtems_bsdnet_semaphore_release_recursive (); + if (++try >= 30) { + rtems_bsdnet_malloc_starvation(); + try = 0; + } + rtems_task_wake_after (rtems_bsdnet_ticks_per_second); + rtems_bsdnet_semaphore_obtain_recursive (nest_count); + } +} + +/* + * Free FreeBSD memory + * FIXME: This should be modified to keep memory allocation statistics. + */ +void +rtems_bsdnet_free (void *addr, int type) +{ + free (addr); +} + +/* + * Externs for BSD data we have to access during initialization + */ +extern struct domain routedomain; +extern struct domain inetdomain; + +/* + * Do the initializations required by the BSD code + */ +static int +bsd_init (void) +{ + int i; + char *p; + + /* + * Set up mbuf cluster data strutures + */ + p = rtems_bsdnet_malloc_mbuf ((nmbclusters*MCLBYTES)+MCLBYTES-1, MBUF_MALLOC_NMBCLUSTERS); + if (p == NULL) { + printf ("Can't get network cluster memory.\n"); + return -1; + } + p = (char *)(((intptr_t)p + (MCLBYTES-1)) & ~(MCLBYTES-1)); + mbutl = (struct mbuf *)p; + for (i = 0; i < nmbclusters; i++) { + ((union mcluster *)p)->mcl_next = mclfree; + mclfree = (union mcluster *)p; + p += MCLBYTES; + mbstat.m_clfree++; + } + mbstat.m_clusters = nmbclusters; + mclrefcnt = rtems_bsdnet_malloc_mbuf (nmbclusters, MBUF_MALLOC_MCLREFCNT); + if (mclrefcnt == NULL) { + printf ("Can't get mbuf cluster reference counts memory.\n"); + return -1; + } + memset (mclrefcnt, '\0', nmbclusters); + + /* + * Set up mbuf data structures + */ + + p = rtems_bsdnet_malloc_mbuf(nmbuf * _SYS_MBUF_LEGACY_MSIZE + _SYS_MBUF_LEGACY_MSIZE - 1,MBUF_MALLOC_MBUF); + p = (char *)(((uintptr_t)p + _SYS_MBUF_LEGACY_MSIZE - 1) & ~(_SYS_MBUF_LEGACY_MSIZE - 1)); + if (p == NULL) { + printf ("Can't get network memory.\n"); + return -1; + } + for (i = 0; i < nmbuf; i++) { + ((struct mbuf *)p)->m_next = mmbfree; + mmbfree = (struct mbuf *)p; + p += _SYS_MBUF_LEGACY_MSIZE; + } + mbstat.m_mbufs = nmbuf; + mbstat.m_mtypes[MT_FREE] = nmbuf; + + /* + * Set up domains + */ + { + + routedomain.dom_next = domains; + domains = &routedomain; + inetdomain.dom_next = domains; + domains = &inetdomain; + domaininit (NULL); + } + + /* + * Setup the sysctl, normally done by a SYSINIT call. + */ + sysctl_register_all(0); + + /* + * Set up interfaces + */ + ifinit (NULL); + return 0; +} + +/* + * Initialize and start network operations + */ +static int +rtems_bsdnet_initialize (void) +{ + rtems_bsdnet_semaphore_obtain (); + + /* + * Set the priority of all network tasks + */ + if (rtems_bsdnet_config.network_task_priority == 0) + networkDaemonPriority = 100; +#ifdef RTEMS_MULTIPROCESSING + /* + * Allow network tasks to run with priority 0 (PRIORITY_PSEUDO_ISR) using + * UINT32_MAX for the network task priority in the network configuration. + * This enables MPCI via a TCP/IP network. + */ + else if (rtems_bsdnet_config.network_task_priority != UINT32_MAX) +#else + else +#endif + networkDaemonPriority = rtems_bsdnet_config.network_task_priority; + + /* + * Default network task CPU affinity + */ +#ifdef RTEMS_SMP + networkDaemonCpuset = rtems_bsdnet_config.network_task_cpuset; + networkDaemonCpusetSize = rtems_bsdnet_config.network_task_cpuset_size; +#endif + + /* + * Set the memory allocation limits + */ + if (rtems_bsdnet_config.mbuf_bytecount) + nmbuf = rtems_bsdnet_config.mbuf_bytecount / _SYS_MBUF_LEGACY_MSIZE; + if (rtems_bsdnet_config.mbuf_cluster_bytecount) + nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES; + + rtems_set_udp_buffer_sizes( + rtems_bsdnet_config.udp_tx_buf_size, + rtems_bsdnet_config.udp_rx_buf_size + ); + + rtems_set_tcp_buffer_sizes( + rtems_bsdnet_config.tcp_tx_buf_size, + rtems_bsdnet_config.tcp_rx_buf_size + ); + + rtems_set_sb_efficiency( rtems_bsdnet_config.sb_efficiency ); + + /* + * Compute clock tick conversion factors + */ + rtems_bsdnet_ticks_per_second = rtems_clock_get_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; + + /* + * Set up BSD-style sockets + */ + if (bsd_init () < 0) { + rtems_bsdnet_semaphore_release (); + return -1; + } + + /* + * Start network daemon + */ + networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL); + + /* + * Let other network tasks begin + */ + rtems_bsdnet_semaphore_release (); + + rtems_bsdnet_initialize_loop(); + + return 0; +} + +/* + * Obtain network mutex + */ +void +rtems_bsdnet_semaphore_obtain (void) +{ + rtems_recursive_mutex_lock(&networkMutex); +} + +/* + * Release network mutex + */ +void +rtems_bsdnet_semaphore_release (void) +{ + rtems_recursive_mutex_unlock(&networkMutex); +} + +static int +rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks) +{ + rtems_status_code sc; + rtems_event_set out; + rtems_event_set out2; + + in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE; + + /* + * Soak up any pending events. The sleep/wakeup synchronization in the + * FreeBSD kernel has no memory. + */ + rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT, &out); + + /* + * Wait for the wakeup event. + */ + sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT, + ticks, &out); + + /* + * Get additional events that may have been received between the + * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain(). + */ + rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT, &out2); + out |= out2; + + if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE) + return (ENXIO); + + if (sc == RTEMS_SUCCESSFUL) + return (0); + + return (EWOULDBLOCK); +} + +/* + * Wait for something to happen to a socket buffer + */ +int +sbwait(struct sockbuf *sb) +{ + int error; + + /* + * Set this task as the target of the wakeup operation. + */ + sb->sb_sel.si_pid = rtems_task_self(); + + /* + * Show that socket is waiting + */ + sb->sb_flags |= SB_WAIT; + + error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo); + if (error != ENXIO) + sb->sb_flags &= ~SB_WAIT; + + return (error); +} + + +/* + * Wake up the task waiting on a socket buffer. + */ +void +sowakeup( + struct socket *so, + struct sockbuf *sb) +{ + if (sb->sb_flags & SB_WAIT) { + rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT); + } + if (sb->sb_wakeup) { + (*sb->sb_wakeup) (so, sb->sb_wakeuparg); + } +} + +/* + * For now, a socket can be used by only one task at a time. + */ +int +sb_lock(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. + */ +int +soconnsleep (struct socket *so) +{ + int error; + + /* + * Set this task as the target of the wakeup operation. + */ + if (so->so_pgid) + rtems_panic ("Another task is already sleeping on that socket"); + so->so_pgid = rtems_task_self(); + + error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo); + if (error != ENXIO) + so->so_pgid = 0; + + return (error); +} + +/* + * Wake up a task waiting for a connection/disconnection to complete. + */ +void +soconnwakeup (struct socket *so) +{ + if (so->so_pgid) + rtems_event_system_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_system_send (networkDaemonTid, 1 << n); +} + +/* + * The network daemon + * This provides a context to run BSD software interrupts + */ +static void +networkDaemon (void *task_argument) +{ + rtems_status_code sc; + rtems_event_set events; + rtems_interval now; + int ticksPassed; + uint32_t timeout; + struct callout *c; + + for (;;) { + c = calltodo.c_next; + if (c) + timeout = c->c_time; + else + timeout = RTEMS_NO_TIMEOUT; + + sc = rtems_bsdnet_event_receive (NETISR_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + timeout, + &events); + if ( sc == RTEMS_SUCCESSFUL ) { + if (events & NETISR_IP_EVENT) + ipintr (); + if (events & NETISR_ARP_EVENT) + arpintr (); + } + + now = rtems_clock_get_ticks_since_boot(); + 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 + */ +#ifdef RTEMS_SMP +rtems_id +rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg) +{ + return rtems_bsdnet_newproc_affinity( name, stacksize, entry, arg, + networkDaemonCpuset, networkDaemonCpusetSize ); +} + +rtems_id +rtems_bsdnet_newproc_affinity (char *name, int stacksize, void(*entry)(void *), + void *arg, const cpu_set_t *set, const size_t setsize) +#else +rtems_id +rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg) +#endif +{ + 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), +#ifdef RTEMS_MULTIPROCESSING + RTEMS_SYSTEM_TASK | +#endif + 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)); + +#ifdef RTEMS_SMP + /* + * Use the default affinity or use the user-provided CPU set + */ + if ( set != 0 ) + rtems_task_set_affinity( tid, setsize, set ); +#endif + + /* + * 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_system_receive (event_in, option_set, ticks, event_out); + rtems_bsdnet_semaphore_obtain (); + return sc; +} + +/* + * Fake random number generator + */ +unsigned long +rtems_bsdnet_random (void) +{ + rtems_interval now; + + now = rtems_clock_get_ticks_since_boot(); + return (now * 99991); +} + +/* + * Callout list processing + */ +void +rtems_bsdnet_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 + * XXX: 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); + } +} + +/* + * IP header checksum routine for processors which don't have an inline version + */ + +struct ip; + +u_int in_cksum_hdr(const struct ip *); + +u_int +in_cksum_hdr (const struct ip *ip) +{ + uint32_t sum; + const uint16_t *sp; + int i; + + sum = 0; + sp = (uint16_t *)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 bool +rtems_bsdnet_setup_interface( + const char *name, + const char *ip_address, + const char *ip_netmask +) +{ + struct sockaddr_in address; + struct sockaddr_in netmask; + short flags; + + /* + * Bring interface up + */ + flags = IFF_UP; + if (rtems_bsdnet_ifconfig (name, SIOCSIFFLAGS, &flags) < 0) { + printf ("Can't bring %s up: %s\n", name, strerror (errno)); + return false; + } + + /* + * Set interface netmask + */ + rtems_bsdnet_initialize_sockaddr_in(&netmask); + netmask.sin_addr.s_addr = inet_addr (ip_netmask); + if (rtems_bsdnet_ifconfig (name, SIOCSIFNETMASK, &netmask) < 0) { + printf ("Can't set %s netmask: %s\n", name, strerror (errno)); + return false; + } + + /* + * Set interface address + */ + rtems_bsdnet_initialize_sockaddr_in(&address); + address.sin_addr.s_addr = inet_addr (ip_address); + if (rtems_bsdnet_ifconfig (name, SIOCSIFADDR, &address) < 0) { + printf ("Can't set %s address: %s\n", name, strerror (errno)); + return false; + } + + /* + * Set interface broadcast address if the interface has the + * broadcast flag set. + */ + if (rtems_bsdnet_ifconfig (name, SIOCGIFFLAGS, &flags) < 0) { + printf ("Can't read %s flags: %s\n", name, strerror (errno)); + return false; + } + + if (flags & IFF_BROADCAST) { + struct sockaddr_in broadcast; + + rtems_bsdnet_initialize_sockaddr_in(&broadcast); + broadcast.sin_addr.s_addr = + address.sin_addr.s_addr | ~netmask.sin_addr.s_addr; + if (rtems_bsdnet_ifconfig (name, SIOCSIFBRDADDR, &broadcast) < 0) { + struct in_addr in_addr; + char buf[20]; + in_addr.s_addr = broadcast.sin_addr.s_addr; + if (!inet_ntop(AF_INET, &in_addr, buf, sizeof(buf))) + strcpy(buf,"?.?.?.?"); + printf ("Can't set %s broadcast address %s: %s\n", + name, buf, strerror (errno)); + } + } + + return true; +} + +static int +rtems_bsdnet_setup (void) +{ + struct rtems_bsdnet_ifconfig *ifp; + int i; + bool any_if_configured = false; + + /* + * 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]); + } + for (i = 0 ; i < sizeof rtems_bsdnet_config.ntp_server / + sizeof rtems_bsdnet_config.ntp_server[0] ; i++) { + if (!rtems_bsdnet_config.ntp_server[i]) + break; + rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count++].s_addr + = inet_addr (rtems_bsdnet_config.ntp_server[i]); + } + + /* + * Configure interfaces + */ + any_if_configured |= rtems_bsdnet_setup_interface( + "lo0", + "127.0.0.1", + "255.0.0.0" + ); + for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) { + if (ifp->ip_address == NULL) + continue; + + any_if_configured |= rtems_bsdnet_setup_interface( + ifp->name, + ifp->ip_address, + ifp->ip_netmask + ); + } + + /* + * Set default route + */ + if (rtems_bsdnet_config.gateway && any_if_configured) { + struct sockaddr_in address; + struct sockaddr_in netmask; + struct sockaddr_in gateway; + + rtems_bsdnet_initialize_sockaddr_in(&address); + rtems_bsdnet_initialize_sockaddr_in(&netmask); + rtems_bsdnet_initialize_sockaddr_in(&gateway); + + 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) { + printf ("Can't set default route: %s\n", strerror (errno)); + return -1; + } + } + return 0; +} + +/* + * Initialize the network + */ +int +rtems_bsdnet_initialize_network(void) +{ + struct rtems_bsdnet_ifconfig *ifp; + + /* + * Start network tasks. + * Initialize BSD network data structures. + */ + if (rtems_bsdnet_initialize () < 0) + return -1; + + /* + * Attach interfaces + */ + for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) { + rtems_bsdnet_attach (ifp); + } + + /* + * Bring up the network + */ + if (rtems_bsdnet_setup () < 0) + return -1; + if (rtems_bsdnet_config.bootp) + (*rtems_bsdnet_config.bootp)(); + return 0; +} + +/* + * Attach a network interface. + */ +void rtems_bsdnet_attach(struct rtems_bsdnet_ifconfig *ifp) +{ + if (ifp) { + rtems_bsdnet_semaphore_obtain (); + (ifp->attach)(ifp, 1); + rtems_bsdnet_semaphore_release (); + } +} + +/* + * Detach a network interface. + */ +void rtems_bsdnet_detach (struct rtems_bsdnet_ifconfig *ifp) +{ + if (ifp) { + rtems_bsdnet_semaphore_obtain (); + (ifp->attach)(ifp, 0); + rtems_bsdnet_semaphore_release (); + } +} + +/* + * Interface Configuration. + */ +int rtems_bsdnet_ifconfig(const char *ifname, uint32_t cmd, void *param) +{ + int s, r = 0; + struct ifreq ifreq; + + /* + * Configure interfaces + */ + s = socket (AF_INET, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + strncpy (ifreq.ifr_name, ifname, IFNAMSIZ); + + rtems_bsdnet_semaphore_obtain (); + + switch (cmd) { + case SIOCSIFADDR: + case SIOCSIFNETMASK: + memcpy (&ifreq.ifr_addr, param, sizeof (struct sockaddr)); + r = ioctl (s, cmd, &ifreq); + break; + + case OSIOCGIFADDR: + case SIOCGIFADDR: + case OSIOCGIFNETMASK: + case SIOCGIFNETMASK: + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + memcpy (param, &ifreq.ifr_addr, sizeof (struct sockaddr)); + break; + + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + if ((r = ioctl (s, SIOCGIFFLAGS, &ifreq)) < 0) + break; + if (cmd == SIOCGIFFLAGS) { + *((short*) param) = ifreq.ifr_flags; + break; + } + ifreq.ifr_flags |= *((short*) param); + if ( (*((short*) param) & IFF_UP ) == 0 ) { + /* set the interface down */ + ifreq.ifr_flags &= ~(IFF_UP); + } + r = ioctl (s, SIOCSIFFLAGS, &ifreq); + break; + + case SIOCSIFDSTADDR: + memcpy (&ifreq.ifr_dstaddr, param, sizeof (struct sockaddr)); + r = ioctl (s, cmd, &ifreq); + break; + + case OSIOCGIFDSTADDR: + case SIOCGIFDSTADDR: + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + memcpy (param, &ifreq.ifr_dstaddr, sizeof (struct sockaddr)); + break; + + case SIOCSIFBRDADDR: + memcpy (&ifreq.ifr_broadaddr, param, sizeof (struct sockaddr)); + r = ioctl (s, cmd, &ifreq); + break; + + case OSIOCGIFBRDADDR: + case SIOCGIFBRDADDR: + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + memcpy (param, &ifreq.ifr_broadaddr, sizeof (struct sockaddr)); + break; + + case SIOCSIFMETRIC: + ifreq.ifr_metric = *((int*) param); + r = ioctl (s, cmd, &ifreq); + break; + + case SIOCGIFMETRIC: + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + *((int*) param) = ifreq.ifr_metric; + break; + + case SIOCSIFMTU: + ifreq.ifr_mtu = *((int*) param); + r = ioctl (s, cmd, &ifreq); + break; + + case SIOCGIFMTU: + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + *((int*) param) = ifreq.ifr_mtu; + break; + + case SIOCSIFPHYS: + ifreq.ifr_phys = *((int*) param); + r = ioctl (s, cmd, &ifreq); + break; + + case SIOCGIFPHYS: + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + *((int*) param) = ifreq.ifr_phys; + break; + + case SIOCSIFMEDIA: + ifreq.ifr_media = *((int*) param); + r = ioctl (s, cmd, &ifreq); + break; + + case SIOCGIFMEDIA: + /* 'param' passes the phy index they want to + * look at... + */ + ifreq.ifr_media = *((int*) param); + if ((r = ioctl (s, cmd, &ifreq)) < 0) + break; + *((int*) param) = ifreq.ifr_media; + break; + + case SIOCAIFADDR: + case SIOCDIFADDR: + r = ioctl(s, cmd, (struct ifreq *) param); + break; + + default: + errno = EOPNOTSUPP; + r = -1; + break; + } + + rtems_bsdnet_semaphore_release (); + + close (s); + return r; +} + +/** + * @brief Splits a network interface name with interface configuration @a + * config into the unit name and number parts. + * + * Memory for the unit name will be allocated from the heap and copied to @a + * namep. If @a namep is NULL nothing will be allocated and copied. + * + * Returns the unit number or -1 on error. + */ +int +rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep) +{ + const char *cp = config->name; + char c; + int unitNumber = 0; + + if (cp == NULL) { + printf ("No network driver name.\n"); + return -1; + } + while ((c = *cp++) != '\0') { + if ((c >= '0') && (c <= '9')) { + int len = cp - config->name; + if ((len < 2) || (len > 50)) + break; + for (;;) { + unitNumber = (unitNumber * 10) + (c - '0'); + c = *cp++; + if (c == '\0') { + if (namep != NULL) { + char *unitName = malloc (len); + if (unitName == NULL) { + printf ("No memory.\n"); + return -1; + } + strncpy (unitName, config->name, len - 1); + unitName[len-1] = '\0'; + *namep = unitName; + } + return unitNumber; + } + if ((c < '0') || (c > '9')) + break; + } + break; + } + } + printf ("Bad network driver name `%s'.\n", config->name); + return -1; +} + +/* + * Handle requests for more network memory + * XXX: Another possibility would be to use a semaphore here with + * a release in the mbuf free macro. I have chosen this `polling' + * approach because: + * 1) It is simpler. + * 2) It adds no complexity to the free macro. + * 3) Running out of mbufs should be a rare + * condition -- predeployment testing of + * an application should indicate the + * required mbuf pool size. + * XXX: Should there be a panic if a task is stuck in the loop for + * more than a minute or so? + */ +int +m_mballoc(int nmb, int nowait) +{ + if (nowait) + return 0; + m_reclaim (); + if (mmbfree == NULL) { + int try = 0; + int print_limit = 30 * rtems_bsdnet_ticks_per_second; + + mbstat.m_wait++; + for (;;) { + uint32_t nest_count = rtems_bsdnet_semaphore_release_recursive (); + rtems_task_wake_after (1); + rtems_bsdnet_semaphore_obtain_recursive (nest_count); + if (mmbfree) + break; + if (++try >= print_limit) { + printf ("Still waiting for mbuf.\n"); + try = 0; + } + } + } + else { + mbstat.m_drops++; + } + return 1; +} + +int +m_clalloc(int ncl, int nowait) +{ + if (nowait) + return 0; + m_reclaim (); + if (mclfree == NULL) { + int try = 0; + int print_limit = 30 * rtems_bsdnet_ticks_per_second; + + mbstat.m_wait++; + for (;;) { + uint32_t nest_count = rtems_bsdnet_semaphore_release_recursive (); + rtems_task_wake_after (1); + rtems_bsdnet_semaphore_obtain_recursive (nest_count); + if (mclfree) + break; + if (++try >= print_limit) { + printf ("Still waiting for mbuf cluster.\n"); + try = 0; + } + } + } + else { + mbstat.m_drops++; + } + return 1; +} + diff --git a/rtems/rtems_malloc_mbuf.c b/rtems/rtems_malloc_mbuf.c new file mode 100644 index 0000000..a12e329 --- /dev/null +++ b/rtems/rtems_malloc_mbuf.c @@ -0,0 +1,33 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define RTEMS_FAST_MUTEX + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> + +/* + * We want to use the REAL system malloc. Do not let the BSD malloc macro + * invade this file. + */ +extern void *malloc(size_t); + +/* + * Default allocator for mbuf data. Over-ride in user code to change + * the way mbuf's are allocated. + */ + +void* rtems_bsdnet_malloc_mbuf(size_t size, int type) +{ + return malloc(size); +} + + diff --git a/rtems/rtems_mii_ioctl.c b/rtems/rtems_mii_ioctl.c new file mode 100644 index 0000000..2559f4b --- /dev/null +++ b/rtems/rtems_mii_ioctl.c @@ -0,0 +1,172 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA + * to be used by ethernet drivers [from their ioctl]. + * + * USERSPACE UTILITIES + * + * NOTE: This much simpler than the BSD ifmedia API + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <inttypes.h> + +#undef _KERNEL + +#include <rtems/rtems_mii_ioctl.h> + +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +static struct ifmedia_description shared_media_strings[] = + IFM_SUBTYPE_SHARED_DESCRIPTIONS; +static struct ifmedia_description ethern_media_strings[] = + IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; +static struct ifmedia_description eth_al_media_strings[] = + IFM_SUBTYPE_ETHERNET_ALIASES; + +static const char * +find_desc (int tag, struct ifmedia_description *list) +{ + while (list->ifmt_string && tag != list->ifmt_word) + list++; + return list->ifmt_string; +} + +#define WHATPRINT(buf,sz,fmt...) \ + ( (sz) > 0 ? snprintf((buf),(sz),fmt) : fprintf((buf) ? (FILE*)(buf) : stdout, fmt) ) + +int +rtems_ifmedia2str (int media, char *buf, int bufsz) +{ + const char *mdesc; + const char *dupdesc = 0; + + /* only ethernet supported, so far */ + if (IFM_ETHER != IFM_TYPE (media)) + return -1; + + if (!(mdesc = find_desc (IFM_SUBTYPE (media), shared_media_strings))) + mdesc = find_desc (IFM_SUBTYPE (media), ethern_media_strings); + + if (!mdesc) + return -1; + + if (IFM_NONE != IFM_SUBTYPE (media)) + dupdesc = IFM_FDX & media ? " full-duplex" : " half-duplex"; + + return WHATPRINT (buf, bufsz, + "Ethernet [phy instance: %" PRId32 "]: (link %s, autoneg %s) -- media: %s%s", + (int32_t) IFM_INST (media), + IFM_LINK_OK & media ? "ok" : "down", + IFM_ANEG_DIS & media ? "off" : "on", + mdesc, dupdesc ? dupdesc : ""); +} + +static int +find_tag (const char *desc, struct ifmedia_description *list) +{ + while (list->ifmt_string) { + if (strstr (desc, list->ifmt_string)) + return list->ifmt_word; + list++; + } + return -1; +} + + +/* convert a string to a media word + * RETURNS: 0 on failure; valid results have always at least IFM_ETHER set + */ +int +rtems_str2ifmedia (const char *str, int phy) +{ + int sub, opt = 0; + char *chpt; + + if (!strncmp (str, "auto", 4)) { + sub = IFM_AUTO; + } else if ((sub = find_tag (str, ethern_media_strings)) < 0) { + if ((sub = find_tag (str, eth_al_media_strings)) < 0) { + /* allow more */ + + /* if no number, 0 is returned which will not pass the test */ + switch (strtol (str, &chpt, 10)) { + case 10: + sub = IFM_10_T; + break; + case 100: + sub = IFM_100_TX; + break; + case 1000: + sub = IFM_1000_T; + break; + default: + return 0; + } + + /* need 'b' or 'base' */ + if ('b' != *chpt++) + return 0; + if (!strncmp (chpt, "ase", 3)) + chpt += 3; + if (toupper ((unsigned char)*chpt++) != 'T') + return 0; + if (IFM_100_TX == sub && toupper ((unsigned char)*chpt++) != 'X') + return 0; + } + } + + if (strstr (str, "full") || strstr (str, "FDX") || strstr (str, "fdx")) + opt |= IFM_FDX; + + return IFM_MAKEWORD (IFM_ETHER, sub, opt, phy); +} diff --git a/rtems/rtems_mii_ioctl.h b/rtems/rtems_mii_ioctl.h new file mode 100644 index 0000000..dfeebf1 --- /dev/null +++ b/rtems/rtems_mii_ioctl.h @@ -0,0 +1,139 @@ +/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA + * to be used by ethernet drivers [from their ioctl]. + * + * NOTE: This much simpler than the BSD ifmedia API + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ +#ifndef RTEMS_MII_IOCTL_H +#define RTEMS_MII_IOCTL_H + +#include <dev/mii/mii.h> /* MII register definitions */ +#include <net/if_media.h> /* media word definitions; rest of API (ifmedia) unused! */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_KERNEL) || defined(KERNEL) || \ + defined(__KERNEL) || defined(__KERNEL__) +/* mdio routines to be provided by driver */ + +/* read mii register 'reg' at 'phy' (-1 meaning any/currently active) + * RETURNS 0 on success, -1 otherwise (e.g., illegal phy) + */ +typedef int (*rtems_mdio_read_func) (int phy, void *uarg, unsigned reg, + uint32_t * pval); + +/* write mii register 'reg' at 'phy' (-1 meaning any/currently active) + * RETURNS 0 on success, -1 otherwise (e.g., illegal phy) + */ +typedef int (*rtems_mdio_write_func) (int phy, void *uarg, unsigned reg, + uint32_t val); + +/* Values to this must be provided by the driver */ +struct rtems_mdio_info { + rtems_mdio_read_func mdio_r; + rtems_mdio_write_func mdio_w; + unsigned has_gmii:1; /* supports gigabit */ +}; + +/* Implement SIOCSIFMEDIA/SIOCGIFMEDIA; get/set the current media word. Note + * that this does NOT implement the full BSD 'ifmedia' API; also, it only + * implements IFM_ETHER... + * + * INPUT: + * SIOCGIFMEDIA: the media word must set the phy instance (-1 for 'any') + * + */ +int +rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, uint32_t cmd, + int *media); + +#endif + +/* The driver flags have the following meaning (SIOCGIFMEDIA only): + */ +#define IFM_LINK_OK IFM_FLAG0 +#define IFM_ANEG_DIS IFM_FLAG1 /* autoneg. disabled; media forced */ + +/* convert a media word to a string; + * + * RETURNS: number of characters written to 'buf' + * + * INPUT: if 'bufsz' is set to IFMEDIA2STR_PRINT_TO_FILE, 'buf' can be a FILE + * pointer where the info is printed insted. This can be NULL in which + * case 'stdout' is used. + */ + +#define IFMEDIA2STR_PRINT_TO_FILE 0 + +int rtems_ifmedia2str (int media, char *buf, int bufsz); + +/* convert a string to a media word + * RETURNS: 0 on failure (unrecognized or invalid mode); + * valid results have always at least IFM_ETHER set. + * + * In addition to IFM_SUBTYPE_ETHERNET_DESCRIPTIONS and + * IFM_SUBTYPE_ETHERNET_ALIASES, the strings + * + * '10' [ '0' [ '0' ]] 'b' [ 'ase' ] ( 't' | 'T' ) + * (* if 100bT [ 'x' | 'X' ] is required here *) + * + * are recognized (e.g., 10bT, 100bTX) + * + * if any of the strings 'full' or 'FDX' or 'fdx' is present, a full-duplex mode + * is selected (half-duplex otherwise). + * e.g., '100bTx-full' + */ + +int rtems_str2ifmedia (const char *str, int phy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rtems/rtems_mii_ioctl_kern.c b/rtems/rtems_mii_ioctl_kern.c new file mode 100644 index 0000000..2944f0a --- /dev/null +++ b/rtems/rtems_mii_ioctl_kern.c @@ -0,0 +1,260 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA + * to be used by ethernet drivers [from their ioctl]. + * + * KERNEL PART (support for drivers) + * + * NOTE: This much simpler than the BSD ifmedia API + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +/* include first to avoid 'malloc' clash with rtems_bsdnet_malloc() hack */ + +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/ethernet.h> +#include <net/if.h> + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include <rtems/rtems_mii_ioctl.h> + +#include <errno.h> + + +#define DEBUG + + +#ifndef MII_1000TCR +#define MII_1000TCR MII_100T2CR +#endif + +#ifndef MII_1000TSR +#define MII_1000TSR MII_100T2SR +#endif + +int +rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, uint32_t cmd, + int *media) +{ + uint32_t bmcr, bmsr, aner, bmcr2 = 0, bmsr2 = 0, anar, lpar; + int phy = IFM_INST (*media); + uint32_t tmp; + int subtype = 0, options = 0; + + switch (cmd) { + default: + return EINVAL; + +#ifdef DEBUG + case 0: +#endif + case SIOCGIFMEDIA: + if (info->mdio_r (phy, uarg, MII_BMCR, &bmcr)) + return EINVAL; + /* read BMSR twice to clear latched link status low */ + if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr)) + return EINVAL; + if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr)) + return EINVAL; + if (info->mdio_r (phy, uarg, MII_ANER, &aner)) + return EINVAL; + if (info->has_gmii) { + if (info->mdio_r (phy, uarg, MII_1000TCR, &bmcr2)) + return EINVAL; + if (info->mdio_r (phy, uarg, MII_1000TSR, &bmsr2)) + return EINVAL; + } + + /* link status */ + if (BMSR_LINK & bmsr) + options |= IFM_LINK_OK; + + /* do we have autonegotiation disabled ? */ + if (!(BMCR_AUTOEN & bmcr)) { + options |= IFM_ANEG_DIS; + + /* duplex is enforced */ + options |= BMCR_FDX & bmcr ? IFM_FDX : IFM_HDX; + + /* determine speed */ + switch (BMCR_SPEED (bmcr)) { + case BMCR_S10: + subtype = IFM_10_T; + break; + case BMCR_S100: + subtype = IFM_100_TX; + break; + case BMCR_S1000: + subtype = IFM_1000_T; + break; + default: + return ENOTSUP; /* ?? */ + } + } else if (!(BMSR_LINK & bmsr) || !(BMSR_ACOMP & bmsr)) { + subtype = IFM_NONE; + } else { + /* everything ok on our side */ + + if ( ! (ANER_LPAN & aner) ) { + /* Link partner doesn't autonegotiate --> our settings are the + * result of 'parallel detect' (in particular: duplex status is HALF + * according to the standard!). + * Let them know that something's fishy... + */ + options |= IFM_ANEG_DIS; + } + + tmp = ((bmcr2 << 2) & bmsr2) & (GTSR_LP_1000THDX | GTSR_LP_1000TFDX); + if (tmp) { + if (GTSR_LP_1000TFDX & tmp) + options |= IFM_FDX; + subtype = IFM_1000_T; + } else { + if (info->mdio_r (phy, uarg, MII_ANAR, &anar)) + return EINVAL; + if (info->mdio_r (phy, uarg, MII_ANLPAR, &lpar)) + return EINVAL; + if (ANLPAR_ACK & lpar) { + /* this is a negotiated link; otherwise we merely detect the partner's ability */ + } + tmp = anar & lpar; + if (ANLPAR_TX_FD & tmp) { + options |= IFM_FDX; + subtype = IFM_100_TX; + } else if (ANLPAR_T4 & tmp) { + subtype = IFM_100_T4; + } else if (ANLPAR_TX & tmp) { + subtype = IFM_100_TX; + } else if (ANLPAR_10_FD & tmp) { + options |= IFM_FDX; + subtype = IFM_10_T; + } else { + subtype = IFM_10_T; + } + } + } + + *media = IFM_MAKEWORD (IFM_ETHER, subtype, options, phy); + + break; + +#ifdef DEBUG + case 1: +#endif + case SIOCSIFMEDIA: + if (IFM_ETHER != IFM_TYPE (*media)) + return EINVAL; + + if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr)) + return EINVAL; + + tmp = (IFM_FDX & *media); + + switch (IFM_SUBTYPE (*media)) { + default: + return ENOTSUP; + + case IFM_AUTO: + bmcr = BMCR_AUTOEN | BMCR_STARTNEG; + tmp = 0; + break; + + case IFM_1000_T: + if (!info->has_gmii) + return ENOTSUP; + + if (info->mdio_r (phy, uarg, MII_EXTSR, &bmsr2)) + return EINVAL; + + if (!(bmsr2 & (tmp ? EXTSR_1000TFDX : EXTSR_1000THDX))) + return EOPNOTSUPP; + + /* NOTE: gige standard demands auto-negotiation for gige links. + * Disabling autoneg did NOT work on the PHYs I tried + * (BCM5421S, intel 82540). + * I've seen drivers that simply change what they advertise + * to the desired gig mode and re-negotiate. + * We could do that here, too, but we don't see the point - + * If autoneg works fine then we can as well use it. + */ + bmcr = BMCR_S1000; + break; + + case IFM_100_TX: + if (!(bmsr & (tmp ? BMSR_100TXFDX : BMSR_100TXHDX))) + return EOPNOTSUPP; + bmcr = BMCR_S100; + break; + + case IFM_10_T: + if (!(bmsr & (tmp ? BMSR_10TFDX : BMSR_10THDX))) + return EOPNOTSUPP; + bmcr = BMCR_S10; + break; + } + + if (tmp) + bmcr |= BMCR_FDX; + + if (info->mdio_w (phy, uarg, MII_BMCR, bmcr)) + return EINVAL; + + /* TODO: should we adapt advertised capabilites ? */ + + break; + } + + return 0; +} diff --git a/rtems/rtems_netdb.h b/rtems/rtems_netdb.h new file mode 100644 index 0000000..ca4d3dd --- /dev/null +++ b/rtems/rtems_netdb.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_RTEMS_NETDB_H +#define _RTEMS_RTEMS_NETDB_H + +#include <netdb.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* DO NOT USE THESE, THEY ARE SUBJECT TO CHANGE AND ARE NOT PORTABLE!!! */ +void _sethosthtent(int); +void _endhosthtent(void); +void _sethostdnsent(int); +void _endhostdnsent(void); +void _setnethtent(int); +void _endnethtent(void); +void _setnetdnsent(int); +void _endnetdnsent(void); +struct hostent * _gethostbyhtname(const char *, int); +struct hostent * _gethostbydnsname(const char *, int); +struct hostent * _gethostbynisname(const char *, int); +struct hostent * _gethostbyhtaddr (const char *, int, int); +struct hostent * _gethostbydnsaddr(const char *, int, int); +struct hostent * _gethostbynisaddr(const char *, int, int); +struct netent * _getnetbyhtname (const char *); +struct netent * _getnetbydnsname(const char *); +struct netent * _getnetbynisname(const char *); +struct netent * _getnetbyhtaddr (unsigned long, int); +struct netent * _getnetbydnsaddr(unsigned long, int); +struct netent * _getnetbynisaddr(unsigned long, int); +void _map_v4v6_address(const char *, char *); +void _map_v4v6_hostent(struct hostent *, char **, int *len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_RTEMS_NETDB_H */ diff --git a/rtems/rtems_netinet_in.h b/rtems/rtems_netinet_in.h new file mode 100644 index 0000000..53240e4 --- /dev/null +++ b/rtems/rtems_netinet_in.h @@ -0,0 +1,80 @@ +/*- + * 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. + * 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. + */ + +#ifndef _RTEMS_RTEMS_NETINET_IN_H +#define _RTEMS_RTEMS_NETINET_IN_H + +#include <rtems.h> +#include <netinet/in.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Ports > IPPORT_USERRESERVED are reserved + * for servers, not necessarily privileged. (IP_PORTRANGE_DEFAULT) + */ +#define IPPORT_USERRESERVED 5000 + +/* Deprecated in current FreeBSD */ +#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 */ + +int in_cksum(struct mbuf *, int); + +/* Firewall hooks */ +struct ip; +typedef int ip_fw_chk_t(struct ip**, int, struct ifnet*, int, struct mbuf**); +typedef int ip_fw_ctl_t(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(struct ip**, struct mbuf**, struct ifnet*, int); +typedef int ip_nat_ctl_t(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 + +/* + * Options for use with [gs]etsockopt at the IP level. + * + * The value is stored in an integer. Use negative numbers to avoid conflicts + * with BSD. + */ +#define IP_NAT (-55) /* set/get NAT opts */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_RTEMS_NETINET_IN_H */ diff --git a/rtems/rtems_select.c b/rtems/rtems_select.c new file mode 100644 index 0000000..0b58b6a --- /dev/null +++ b/rtems/rtems_select.c @@ -0,0 +1,179 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdarg.h> +/* #include <stdlib.h> */ +#include <stdio.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> + +#include <errno.h> +#include <sys/fcntl.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/select.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> + +/* + ********************************************************************* + * RTEMS implementation of select() system call * + ********************************************************************* + */ + +/* + * This implementation is quite restricted: + * Works on sockets only -- no support for other devices! + * A given socket can be in a read-select or a read/recv* by only + * one task at a time. + * A given socket can be in a write-select or a write/send* by only + * one task at a time. + * + * NOTE - select() is a very expensive system call. It should be avoided + * if at all possible. In many cases, rewriting the application + * to use multiple tasks (one per socket) is a better solution. + */ + +static __inline int imin(int a, int b) { return (a < b ? a : b); } +struct socket *rtems_bsdnet_fdToSocket(int fd); + +static int +socket_select (struct socket *so, int which, rtems_id tid) +{ + switch (which) { + + case FREAD: + if (soreadable(so)) + return (1); + so->so_rcv.sb_flags |= SB_WAIT; + so->so_rcv.sb_sel.si_pid = tid; + break; + + case FWRITE: + if (sowriteable(so)) + return (1); + so->so_snd.sb_flags |= SB_WAIT; + so->so_snd.sb_sel.si_pid = tid; + break; + + case 0: + if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) + return (1); + so->so_rcv.sb_sel.si_pid = tid; + break; + } + return (0); +} + +static int +selscan (rtems_id tid, fd_mask **ibits, fd_mask **obits, int nfd, int *retval) +{ + struct socket *so; + int msk, i, fd; + fd_mask bits, bit; + int n = 0; + static int flag[3] = { FREAD, FWRITE, 0 }; + + for (msk = 0; msk < 3; msk++) { + if (ibits[msk] == NULL) + continue; + for (i = 0; i < nfd; i += NFDBITS) { + bits = ibits[msk][i/NFDBITS]; + for (fd = i, bit = 1 ; bits && (fd < nfd) ; fd++, bit <<= 1) { + if ((bits & bit) == 0) + continue; + bits &= ~bit; + so = rtems_bsdnet_fdToSocket (fd); + if (so == NULL) + return (EBADF); + if (socket_select (so, flag[msk], tid)) { + obits[msk][fd/NFDBITS] |= + (1 << (fd % NFDBITS)); + n++; + } + } + } + } + *retval = n; + return (0); +} + +int +select (int nfds, fd_set *__restrict readfds, fd_set *__restrict writefds, + fd_set *__restrict exceptfds, struct timeval *__restrict tv) +{ + fd_mask *ibits[3], *obits[3]; + fd_set ob[3]; + int error, timo; + int retval = 0; + rtems_id tid; + rtems_interval then = 0, now; + rtems_event_set in = SBWAIT_EVENT | RTEMS_EVENT_SYSTEM_NETWORK_CLOSE; + rtems_event_set out; + + if (nfds < 0) + return (EINVAL); + if (tv) { + timo = tv->tv_sec * hz + tv->tv_usec / tick; + if (timo == 0) + timo = 1; + then = rtems_clock_get_ticks_since_boot(); + } + else { + timo = 0; + } + +#define getbits(name,i) if (name) { \ + ibits[i] = &name->fds_bits[0]; \ + obits[i] = &ob[i].fds_bits[0]; \ + FD_ZERO(&ob[i]); \ + } \ + else ibits[i] = NULL + getbits (readfds, 0); + getbits (writefds, 1); + getbits (exceptfds, 2); +#undef getbits + + rtems_task_ident (RTEMS_SELF, 0, &tid); + rtems_event_system_receive (in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &out); + for (;;) { + rtems_bsdnet_semaphore_obtain (); + error = selscan(tid, ibits, obits, nfds, &retval); + rtems_bsdnet_semaphore_release (); + if (error || retval) + break; + if (timo) { + now = rtems_clock_get_ticks_since_boot(); + timo -= now - then; + if (timo <= 0) + break; + then = now; + } + rtems_event_system_receive (in, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &out); + } + +#define putbits(name,i) if (name) *name = ob[i] + putbits (readfds, 0); + putbits (writefds, 1); + putbits (exceptfds, 2); +#undef putbits + if (error) { + errno = error; + retval = -1; + } + return (retval); +} diff --git a/rtems/rtems_showicmpstat.c b/rtems/rtems_showicmpstat.c new file mode 100644 index 0000000..4862d6c --- /dev/null +++ b/rtems/rtems_showicmpstat.c @@ -0,0 +1,70 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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> + +#include <rtems/rtems_bsdnet.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); +} + +/* + * External data we peek at during statistics reporting + */ +extern unsigned int icmplenPanicAvoided; + +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 ("all echo requests dropped", icmpstat.icps_allecho); + 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]); + } + } + showicmpstat ("ICMP panic avoided", icmplenPanicAvoided); + printf ("\n"); +} diff --git a/rtems/rtems_showifstat.c b/rtems/rtems_showifstat.c new file mode 100644 index 0000000..21f21f4 --- /dev/null +++ b/rtems/rtems_showifstat.c @@ -0,0 +1,157 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/sockio.h> +#include <sys/mbuf.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <netinet/in.h> + +#include <rtems/rtems_bsdnet.h> + +/* + * Display an address + */ +static int +showaddress (char *name, struct sockaddr *a) +{ + struct sockaddr_in *sa; + char buf[17]; + + if (!a) + return 0; + printf ("%s:", name); + sa = (struct sockaddr_in *)a; + printf ("%-16s", inet_ntop (AF_INET, &sa->sin_addr, buf, sizeof(buf))); + return 1; +} + +/* + * Display interface statistics + */ +void +rtems_bsdnet_show_if_stats (void) +{ + struct ifnet *ifp; + struct ifaddr *ifa; + unsigned short bit, flags; + + 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) { + + if ( !ifa->ifa_addr ) + continue; + + switch ( ifa->ifa_addr->sa_family ) { + case AF_LINK: + { + struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; + unsigned char *cp = (unsigned char *)LLADDR(sdl); + int i; + + switch ( sdl->sdl_type ) { + case IFT_ETHER: + if ( (i=sdl->sdl_alen) > 0 ) { + printf("Ethernet Address: "); + do { + i--; + printf("%02X%c", *cp++, i ? ':' : '\n'); + } while ( i>0 ); + } + break; + + default: + break; + } + } + break; + + case AF_INET: + { + int printed; + 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"); + } + break; + + default: + break; + } + } + + printf ("Flags:"); + for (bit = 1, flags = ifp->if_flags ; flags ; bit <<= 1) { + char *cp; + char xbuf[20]; + switch (flags & bit) { + case 0: 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; + default: sprintf (xbuf, "%#x", bit); cp = xbuf; 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/rtems/rtems_showipstat.c b/rtems/rtems_showipstat.c new file mode 100644 index 0000000..5b30da5 --- /dev/null +++ b/rtems/rtems_showipstat.c @@ -0,0 +1,68 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <net/if_var.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 <rtems/rtems_bsdnet.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); + showipstat ("ip input queue drops", ipintrq.ifq_drops); + printf ("\n"); +} diff --git a/rtems/rtems_showmbuf.c b/rtems/rtems_showmbuf.c new file mode 100644 index 0000000..27f8cff --- /dev/null +++ b/rtems/rtems_showmbuf.c @@ -0,0 +1,69 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 <rtems/rtems_bsdnet.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/rtems/rtems_showroute.c b/rtems/rtems_showroute.c new file mode 100644 index 0000000..971c364 --- /dev/null +++ b/rtems/rtems_showroute.c @@ -0,0 +1,240 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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/if_var.h> +#include <net/if_dl.h> +#include <net/route.h> + +#include <netinet/in.h> + +/* + * We'll use the application versions of realloc and free. + */ +#undef free +#undef malloc +#undef random +#include <stdlib.h> + +#include <rtems/rtems_bsdnet.h> + +/* + * Information per route + */ +struct rinfo { + struct sockaddr dst; + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_dl sdl; + } un; + 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; +}; + +/* + * Copy address + */ +static void +copyAddress (void *to, void *from, int tolen) +{ + int ncopy; + struct sockaddr dummy; + + if (from == NULL) { + /* + * Create a fake address of unspecified type + */ + from = &dummy; + dummy.sa_len = 4; + dummy.sa_family = AF_UNSPEC; + } + ncopy = ((struct sockaddr *)from)->sa_len; + if (ncopy > tolen) + ncopy = tolen; + memcpy (to, from, ncopy); +} + +/* + * Package everything up before printing it. + * We don't want to block all network operations till + * the printing completes! + */ +static int +show_inet_route ( + 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 + */ + copyAddress (&r->dst, rt_key(rt), sizeof r->dst); + if (rt->rt_flags & (RTF_GATEWAY | RTF_HOST)) { + copyAddress (&r->un, rt->rt_gateway, sizeof r->un); + } + else { + /* + * Create a fake address to hold the mask + */ + struct sockaddr_in dummy; + + dummy.sin_family = AF_INET; + dummy.sin_len = sizeof dummy; + dummy.sin_addr = ((struct sockaddr_in *)rt_mask(rt))->sin_addr; + copyAddress (&r->un, &dummy, sizeof r->un); + } + 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 ? ifp->if_name : ""), sizeof r->ifname); + r->ifunit = ifp->if_unit; + return 0; +} + +/* + * Convert link address to ASCII + */ +static char * +link_ascii (struct sockaddr_dl *sdl, char *buf, int bufsize) +{ + char *cp; + int i; + int first = 1; + int nleft = sdl->sdl_alen; + char *ap = LLADDR (sdl); + static const char hextab[16] = "0123456789ABCDEF"; + + cp = buf; + while (nleft && (bufsize > 4)) { + if (first) { + first = 0; + } + else { + *cp++ = ':'; + bufsize--; + } + i = *ap++; + *cp++ = hextab[(i >> 4) & 0xf]; + *cp++ = hextab[i & 0xf]; + nleft--; + bufsize -= 2; + } + *cp = '\0'; + return buf; +} + +void +rtems_bsdnet_show_inet_routes (void) +{ + struct radix_node_head *rnh; + struct dinfo d; + struct rinfo *r; + int i, error; + + /* + * For now we'll handle only AF_INET + */ + 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/Hw 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]; + const char *addr; + unsigned long flagbit; + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)&r->dst; + if (sin->sin_addr.s_addr == INADDR_ANY) + addr = "default"; + else + addr = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof buf); + printf ("%-16s", addr); + switch (r->un.sa.sa_family) { + case AF_INET: + addr = inet_ntop (AF_INET, &r->un.sin.sin_addr, buf, sizeof buf); + break; + + case AF_LINK: + addr = link_ascii (&r->un.sdl, buf, sizeof buf); + break; + + default: + addr = ""; + break; + } + printf ("%-19s", addr); + 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/rtems/rtems_showtcpstat.c b/rtems/rtems_showtcpstat.c new file mode 100644 index 0000000..3a17809 --- /dev/null +++ b/rtems/rtems_showtcpstat.c @@ -0,0 +1,106 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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> + +#include <rtems/rtems_bsdnet.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/rtems/rtems_showudpstat.c b/rtems/rtems_showudpstat.c new file mode 100644 index 0000000..c6b4560 --- /dev/null +++ b/rtems/rtems_showudpstat.c @@ -0,0 +1,52 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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> + +#include <rtems/rtems_bsdnet.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/rtems/rtems_socketpair.c b/rtems/rtems_socketpair.c new file mode 100644 index 0000000..1dcaf6e --- /dev/null +++ b/rtems/rtems_socketpair.c @@ -0,0 +1,53 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * socketpair() for RTEMS + * + * This file exists primarily to document what is required to provide + * a functional implementation of socketpair() for RTEMS. + * + * The socketpair() service requires that the "local domain" sockets + * be functional. This is denoted by the domain constants AF_LOCAL + * and AF_UNIX and the protocol constants PF_LOCAL and PF_UNIX. The + * local domain functionality is implemented in the file kern/uipc_usrreq.c + * which was not part of the initial port of the FreeBSD stack to + * RTEMS. + * + * The FreeBSD socketpair implementation appears to be dependent on + * file system features which are not available currently in RTEMS. + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> +#include <sys/socket.h> +#include <errno.h> + +#include "rtems_syscall.h" + +int socketpair (int domain, int type, int protocol, int *rsv) +{ + if ( !rsv ) { + errno = EFAULT; + return -1; + } + + /* + * Yes, we do not support socketpair() so this is really paranoid. + * But it ensures that someone calling this routine and ignoring + * the return status will get errors from subsequent socket calls. + */ + rsv[ 0 ] = -1; + rsv[ 1 ] = -1; + errno = ENOSYS; + return -1; +} diff --git a/rtems/rtems_syscall.c b/rtems/rtems_syscall.c new file mode 100644 index 0000000..7f3143b --- /dev/null +++ b/rtems/rtems_syscall.c @@ -0,0 +1,835 @@ +#include <machine/rtems-bsd-kernel-space.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdarg.h> +/* #include <stdlib.h> */ +#include <stdio.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/libio_.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> + +#include <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/fcntl.h> +#include <sys/filio.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/route.h> + +#include "rtems_syscall.h" + +/* + * Hooks to RTEMS I/O system + */ +static const rtems_filesystem_file_handlers_r socket_handlers; + +/* + * Convert an RTEMS file descriptor to a BSD socket pointer. + */ +struct socket * +rtems_bsdnet_fdToSocket (int fd) +{ + rtems_libio_t *iop; + + if ((uint32_t)fd >= rtems_libio_number_iops) { + errno = EBADF; + return NULL; + } + + iop = rtems_libio_iop(fd); + + if ((rtems_libio_iop_flags(iop) & LIBIO_FLAGS_OPEN) == 0) { + errno = EBADF; + return NULL; + } + + if (iop->pathinfo.handlers != &socket_handlers) { + errno = ENOTSOCK; + return NULL; + } + + if (iop->data1 == NULL) + errno = EBADF; + return iop->data1; +} + +/* + * Create an RTEMS file descriptor for a socket + */ +static int +rtems_bsdnet_makeFdForSocket (void *so) +{ + rtems_libio_t *iop; + int fd; + + iop = rtems_libio_allocate(); + if (iop == 0) + rtems_set_errno_and_return_minus_one( ENFILE ); + + fd = rtems_libio_iop_to_descriptor(iop); + iop->data0 = fd; + iop->data1 = so; + iop->pathinfo.handlers = &socket_handlers; + iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry; + rtems_filesystem_location_add_to_mt_entry(&iop->pathinfo); + rtems_libio_iop_flags_set(iop, LIBIO_FLAGS_OPEN | LIBIO_FLAGS_READ_WRITE); + return fd; +} + +/* + * 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; + int error; + struct socket *so; + + rtems_bsdnet_semaphore_obtain (); + error = socreate(domain, &so, type, protocol, NULL); + if (error == 0) { + fd = rtems_bsdnet_makeFdForSocket (so); + if (fd < 0) + soclose (so); + } + else { + errno = error; + fd = -1; + } + rtems_bsdnet_semaphore_release (); + return fd; +} + +int +bind (int s, const struct sockaddr *name, socklen_t namelen) +{ + int error; + int ret = -1; + struct socket *so; + struct mbuf *nam; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_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, const struct sockaddr *name, socklen_t namelen) +{ + int error; + int ret = -1; + struct socket *so; + struct mbuf *nam; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_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) + goto bad; + if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + m_freem(nam); + errno = EINPROGRESS; + rtems_bsdnet_semaphore_release (); + return -1; + } + error = so->so_error; + while (error == 0 && (so->so_state & SS_ISCONNECTING)) { + error = soconnsleep (so); + if (error) + break; + error = so->so_error; + so->so_error = 0; + } + bad: + if (error != ENXIO) + so->so_state &= ~SS_ISCONNECTING; + m_freem (nam); + if (error) + errno = error; + else + 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 = rtems_bsdnet_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, socklen_t *namelen) +{ + int fd; + struct socket *head, *so; + struct mbuf *nam; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((head = rtems_bsdnet_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; + } + error = head->so_error; + while (error == 0 && head->so_comp.tqh_first == NULL) { + if (head->so_state & SS_CANTRCVMORE) { + error = ECONNABORTED; + break; + } + error = soconnsleep (head); + } + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + + so = head->so_comp.tqh_first; + TAILQ_REMOVE(&head->so_comp, so, so_list); + head->so_qlen--; + + fd = rtems_bsdnet_makeFdForSocket (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); + +} + +/* + * Shutdown routine + */ + +int +shutdown (int s, int how) +{ + struct socket *so; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + error = soshutdown(so, how); + rtems_bsdnet_semaphore_release (); + if (error) { + errno = error; + return -1; + } + return 0; +} + +/* + * 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; + struct mbuf *control = NULL; + int i; + int len; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_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, socklen_t 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); +} + +/* + * 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 = rtems_bsdnet_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; + void *ctlbuf; + + len = mp->msg_controllen; + m = control; + mp->msg_controllen = 0; + ctlbuf = 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, struct sockaddr *from, socklen_t *fromlen) +{ + struct msghdr msg; + struct iovec iov; + int ret; + + iov.iov_base = buf; + iov.iov_len = buflen; + msg.msg_name = (caddr_t)from; + if (fromlen) + msg.msg_namelen = *fromlen; + else + msg.msg_namelen = 0; + 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; +} + +int +setsockopt (int s, int level, int name, const void *val, socklen_t len) +{ + struct socket *so; + struct mbuf *m = NULL; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_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, socklen_t *avalsize) +{ + struct socket *so; + struct mbuf *m = NULL, *m0; + char *val = aval; + int i, op, valsize; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_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; +} + +static int +getpeersockname (int s, struct sockaddr *name, socklen_t *namelen, int pflag) +{ + struct socket *so; + struct mbuf *m; + int len = *namelen; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = rtems_bsdnet_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; + } + if (pflag) + error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m); + else + error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m); + if (error) { + m_freem(m); + 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; +} + +int +getpeername (int s, struct sockaddr *name, socklen_t *namelen) +{ + return getpeersockname (s, name, namelen, 1); +} +int +getsockname (int s, struct sockaddr *name, socklen_t *namelen) +{ + return getpeersockname (s, name, namelen, 0); +} + +int +sysctl(const int *name, u_int namelen, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen) +{ + int error; + size_t j; + + rtems_bsdnet_semaphore_obtain (); + error = userland_sysctl (0, name, namelen, oldp, oldlenp, 1, newp, newlen, &j); + rtems_bsdnet_semaphore_release (); + + if (oldlenp) + *oldlenp = j; + + if (error) + { + errno = error; + return -1; + } + return 0; +} + +/* + ************************************************************************ + * RTEMS I/O HANDLER ROUTINES * + ************************************************************************ + */ +static int +rtems_bsdnet_close (rtems_libio_t *iop) +{ + struct socket *so; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = iop->data1) == NULL) { + errno = EBADF; + rtems_bsdnet_semaphore_release (); + return -1; + } + iop->data1 = NULL; + error = soclose (so); + rtems_bsdnet_semaphore_release (); + if (error) { + errno = error; + return -1; + } + return 0; +} + +static ssize_t +rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, size_t count) +{ + return recv (iop->data0, buffer, count, 0); +} + +static ssize_t +rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, size_t count) +{ + return send (iop->data0, buffer, count, 0); +} + +static int +so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t command, void *buffer) +{ + unsigned int nonblock; + + switch (command) { + case FIONBIO: + nonblock = rtems_libio_fcntl_flags (O_NONBLOCK); + + if (*(int *)buffer) { + rtems_libio_iop_flags_set (iop, nonblock); + so->so_state |= SS_NBIO; + } + else { + rtems_libio_iop_flags_clear (iop, nonblock); + 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 (rtems_libio_t *iop, ioctl_command_t command, void *buffer) +{ + struct socket *so; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = iop->data1) == NULL) { + errno = EBADF; + rtems_bsdnet_semaphore_release (); + return -1; + } + error = so_ioctl (iop, so, command, buffer); + rtems_bsdnet_semaphore_release (); + if (error) { + errno = error; + return -1; + } + return 0; +} + +static int +rtems_bsdnet_fcntl (rtems_libio_t *iop, int cmd) +{ + struct socket *so; + + if (cmd == F_SETFL) { + rtems_bsdnet_semaphore_obtain (); + if ((so = iop->data1) == NULL) { + rtems_bsdnet_semaphore_release (); + return EBADF; + } + if (rtems_libio_iop_is_no_delay(iop)) + so->so_state |= SS_NBIO; + else + so->so_state &= ~SS_NBIO; + rtems_bsdnet_semaphore_release (); + } + return 0; +} + +static int +rtems_bsdnet_fstat (const rtems_filesystem_location_info_t *loc, struct stat *sp) +{ + sp->st_mode = S_IFSOCK; + return 0; +} + +static const rtems_filesystem_file_handlers_r socket_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = rtems_bsdnet_close, + .read_h = rtems_bsdnet_read, + .write_h = rtems_bsdnet_write, + .ioctl_h = rtems_bsdnet_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_bsdnet_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_bsdnet_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; diff --git a/rtems/rtems_syscall.h b/rtems/rtems_syscall.h new file mode 100644 index 0000000..b0d38a6 --- /dev/null +++ b/rtems/rtems_syscall.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBNETWORKING_RTEMS_SYSCALL_H_ +#define _LIBNETWORKING_RTEMS_SYSCALL_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> + +__BEGIN_DECLS + +int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); + +int accept(int, struct sockaddr * __restrict, socklen_t * __restrict); + +int bind(int, const struct sockaddr *, socklen_t); + +int connect(int, const struct sockaddr *, socklen_t); + +int getpeername(int, struct sockaddr * __restrict, socklen_t * __restrict); + +int getsockname(int, struct sockaddr * __restrict, socklen_t * __restrict); + +int getsockopt(int, int, int, void * __restrict, socklen_t * __restrict); + +int listen(int, int); + +ssize_t recv(int, void *, size_t, int); + +ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict); + +ssize_t recvmsg(int, struct msghdr *, int); + +ssize_t send(int, const void *, size_t, int); + +ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); + +ssize_t sendmsg(int, const struct msghdr *, int); + +int setsockopt(int, int, int, const void *, socklen_t); + +int shutdown(int, int); + +int socket(int, int, int); + +int socketpair(int, int, int, int *); + +int sysctl(const int *, u_int, void *, size_t *, const void *, size_t); + +int sysctlbyname(const char *, void *, size_t *, const void *, size_t); + +int sysctlnametomib(const char *, int *, size_t *); + +__END_DECLS + +#endif /* _LIBNETWORKING_RTEMS_SYSCALL_H_ */ diff --git a/rtems/rtems_syscall_api.c b/rtems/rtems_syscall_api.c new file mode 100644 index 0000000..6899eba --- /dev/null +++ b/rtems/rtems_syscall_api.c @@ -0,0 +1,22 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Ensure that kernel and user space system call protoypes are identical */ +#include "rtems_syscall.h" diff --git a/rtems/sghostname.c b/rtems/sghostname.c new file mode 100644 index 0000000..df7513d --- /dev/null +++ b/rtems/sghostname.c @@ -0,0 +1,54 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * RTEMS versions of hostname functions + * FIXME: Not thread-safe + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <errno.h> +#include <unistd.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, size_t namelen) +{ + char *cp = rtems_hostname; + + if (cp == NULL) + cp = ""; + strncpy (name, cp, namelen); + return 0; +} + +int +sethostname (const char *name, size_t 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/rtems_waf b/rtems_waf new file mode 160000 +Subproject 945b0b9c069959266c698eeda51cedd2a055b9f diff --git a/sys/callout.h b/sys/callout.h new file mode 100644 index 0000000..150609e --- /dev/null +++ b/sys/callout.h @@ -0,0 +1,53 @@ +/*- + * 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. + * 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 + * $FreeBSD: src/sys/sys/callout.h,v 1.27 2004/04/20 15:49:31 cperciva Exp $ + */ + +#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)(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/sys/conf.h b/sys/conf.h new file mode 100644 index 0000000..45abb1c --- /dev/null +++ b/sys/conf.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2000 + * Poul-Henning Kamp. 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. + * 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 + * $FreeBSD: src/sys/sys/conf.h,v 1.231 2007/02/02 22:27:45 bms Exp $ + */ + + +#ifndef _SYS_CONF_H_ +#define _SYS_CONF_H_ + +#ifdef _KERNEL + +/* + * Definitions of device driver entry switches + */ + +struct buf; +struct proc; +struct tty; +struct uio; +struct vnode; +#endif /* _KERNEL */ + +#endif /* !_SYS_CONF_H_ */ diff --git a/sys/domain.h b/sys/domain.h new file mode 100644 index 0000000..0112f57 --- /dev/null +++ b/sys/domain.h @@ -0,0 +1,70 @@ +/* + * 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. + * 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 + */ + +#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 */ + (void); + int (*dom_externalize) /* externalize access rights */ + (struct mbuf *); + void (*dom_dispose) /* dispose of internalized rights */ + (struct mbuf *); + struct protosw *dom_protosw, *dom_protoswNPROTOSW; + struct domain *dom_next; + int (*dom_rtattach) /* initialize routing table */ + (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/sys/kernel.h b/sys/kernel.h new file mode 100644 index 0000000..045bf19 --- /dev/null +++ b/sys/kernel.h @@ -0,0 +1,188 @@ +/*- + * 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 + */ + +#ifndef _SYS_KERNEL_H_ +#define _SYS_KERNEL_H_ + +#include <sys/linker_set.h> + +#ifdef _KERNEL + +/* Global variables for the kernel. */ + +/* 1.1 */ +extern long hostid; +extern char hostname[MAXHOSTNAMELEN]; +extern char domainname[MAXHOSTNAMELEN]; +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; + +#endif /* _KERNEL */ + +/* + * 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*/ +}; + + +/* + * A system initialization call instance + * + * The subsystem + */ +struct sysinit { + unsigned int subsystem; /* subsystem identifier*/ + unsigned int order; /* init order within subsystem*/ + void (*func)(void *); /* init function*/ + void *udata; /* multiplexer/argument */ +}; + + +/* + * 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)(void); /* "main" for kernel process*/ + struct proc **global_procpp; /* ptr to proc ptr save area*/ +}; + +void kproc_start(void *udata); + +#endif /* !_SYS_KERNEL_H_*/ diff --git a/sys/libkern.h b/sys/libkern.h new file mode 100644 index 0000000..7aa6e8b --- /dev/null +++ b/sys/libkern.h @@ -0,0 +1,93 @@ +/*- + * 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. + * 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 + * $FreeBSD: src/sys/sys/libkern.h,v 1.48 2005/02/10 20:39:39 glebius Exp $ + */ + + +#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(const void *, const void *, size_t); +#ifndef HAVE_INLINE_FFS +int ffs(int); +#endif +#ifndef HAVE_INLINE_FLS +int fls(int); +#endif +int locc(int, char *, u_int); +void qsort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); +#if defined(__rtems__) +u_long rtems_bsdnet_random(void); +#define random() rtems_bsdnet_random() +#else +u_long random(void); +#endif +char *index(const char *, int); +char *rindex(const char *, int); +int scanc(u_int, const u_char *, const u_char *, int); +int skpc(int, int, char *); +#if !defined(__rtems__) +void srandom(u_long); +#endif +char *strcat(char * __restrict, const char * __restrict); +int strcmp(const char *, const char *); +char *strdup(const char *s); +char *strcpy(char * __restrict, const char * __restrict); +size_t strlen(const char *); +int strncmp(const char *, const char *, size_t); +char *strncpy(char * __restrict, const char * __restrict, size_t); +char *strerror(int errnum); + +#endif /* !_SYS_LIBKERN_H_ */ diff --git a/sys/linker_set.h b/sys/linker_set.h new file mode 100644 index 0000000..c83d7c8 --- /dev/null +++ b/sys/linker_set.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 1999 John D. Polstra + * Copyright (c) 1999,2001 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. + * + * $FreeBSD: src/sys/sys/linker_set.h,v 1.13 2002/09/23 06:11:29 peter Exp $ + */ + +#ifndef _SYS_LINKER_SET_H_ +#define _SYS_LINKER_SET_H_ + +/* FIXME: These macros should not be here + * BSD has them macros in sys/cdefs.h + * older rtems had them in rtems/bsd/sys/cdefs.h + * newlib has some of them in sys/cdefs.h + */ + +#if defined(__rtems__) +#ifndef __used +#define __used __attribute__((__used__)) +#endif +#ifndef __CONCAT +#define __CONCAT1(x,y) x ## y +#define __CONCAT(x,y) __CONCAT1(x,y) +#endif +#endif + +/* + * The following macros are used to declare global sets of objects, which + * are collected by the linker into a `linker_set' as defined below. + * For ELF, this is done by constructing a separate segment for each set. + */ + +/* + * Private macros, not to be used outside this header file. + */ +#ifdef __GNUC__ +#define __MAKE_SET(set, sym) \ + static void const * const __set_##set##_sym_##sym \ + __attribute((section("set_" #set))) __used = &sym +#else /* !__GNUC__ */ +#ifndef lint +#error "This file needs to be compiled by GCC or lint" +#endif /* lint */ +#define __MAKE_SET(set, sym) extern void const * const (__set_##set##_sym_##sym) +#endif /* __GNUC__ */ + +/* + * Public macros. + */ +#define TEXT_SET(set, sym) __MAKE_SET(set, sym) +#define DATA_SET(set, sym) __MAKE_SET(set, sym) +#define BSS_SET(set, sym) __MAKE_SET(set, sym) +#define ABS_SET(set, sym) __MAKE_SET(set, sym) +#define SET_ENTRY(set, sym) __MAKE_SET(set, sym) + +/* + * Initialize before referring to a give linker set + */ +#define SET_DECLARE(set, ptype) \ + extern ptype *__CONCAT(__start_set_,set)[]; \ + extern ptype *__CONCAT(__stop_set_,set)[] + +#define SET_BEGIN(set) \ + (__CONCAT(__start_set_,set)) +#define SET_LIMIT(set) \ + (__CONCAT(__stop_set_,set)) + +/* + * Iterate over all the elements of a set. + * + * Sets always contain addresses of things, and "pvar" points to words + * containing those addresses. Thus is must be declared as "type **pvar", + * and the address of each set item is obtained inside the loop by "*pvar". + */ +#define SET_FOREACH(pvar, set) \ + for (pvar = SET_BEGIN(set); pvar < SET_LIMIT(set); pvar++) + +#define SET_ITEM(set, i) \ + ((SET_BEGIN(set))[i]) + +/* + * Provide a count of the items in a set. + */ +#define SET_COUNT(set) \ + (SET_LIMIT(set) - SET_BEGIN(set)) + +#endif /* _SYS_LINKER_SET_H_ */ diff --git a/sys/malloc.h b/sys/malloc.h new file mode 100644 index 0000000..2341053 --- /dev/null +++ b/sys/malloc.h @@ -0,0 +1,354 @@ +/* + * 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 + */ + +#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 free (void *addr, int type); +void *malloc (size_t size, int type, int flags); +/* standard realloc but we cannot include stdlib.h */ +void *realloc(void * __r, size_t __size); + +#endif /* _KERNEL */ + +#endif /* !_SYS_MALLOC_H_ */ diff --git a/sys/mbuf.h b/sys/mbuf.h new file mode 100644 index 0000000..c54b760 --- /dev/null +++ b/sys/mbuf.h @@ -0,0 +1,438 @@ +/* + * 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. 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 + * $FreeBSD: src/sys/sys/mbuf.h,v 1.169 2005/03/17 19:34:57 jmg Exp $ + */ + + +#ifndef _SYS_MBUF_H_ +#define _SYS_MBUF_H_ + +#ifndef M_WAITOK +#include <sys/malloc.h> +#endif + +/* + * Mbufs are of a single size, _SYS_MBUF_LEGACY_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 _SYS_MBUF_LEGACY_MSIZE 128 +#define MLEN (_SYS_MBUF_LEGACY_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 *)((intptr_t)(x) & ~(_SYS_MBUF_LEGACY_MSIZE-1))) +#define mtocl(x) (((uintptr_t)(x) - (uintptr_t)mbutl) >> MCLSHIFT) +#define cltom(x) ((caddr_t)((u_long)mbutl + ((u_long)(x) << MCLSHIFT))) + +/* + * Header present at the beginning of every 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 */ + int mh_flags; /* flags; see below */ + short mh_type; /* type of data in this mbuf */ +}; + +/* + * Record/packet header in first mbuf of chain; valid only if M_PKTHDR is set. + */ +struct pkthdr { + struct ifnet *rcvif; /* rcv interface */ + int32_t len; /* total packet length */ +}; + +/* + * Description of external storage mapped into mbuf; valid only if M_EXT is set. + */ +struct m_ext { + caddr_t ext_buf; /* start of buffer */ + void (*ext_free) /* free routine if not the usual */ + (caddr_t, u_int); + u_int ext_size; /* size of buffer, for ext_free */ + void (*ext_ref) /* add a reference to the ext object */ + (caddr_t, u_int); +}; + +/* + * The core of the mbuf object along with some shortcut defines for + * practical purposes. + */ +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 stored 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 */ + +/* + * General mbuf allocator statistics structure. + */ +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 */ +}; + + +/* 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) do { \ + (m)->m_data += (MLEN - (len)) & ~(sizeof(long) - 1); \ +} while (0) + +/* + * As above, for mbufs allocated with m_gethdr/MGETHDR + * or initialized by M_COPY_PKTHDR. + */ +#define MH_ALIGN(m, len) do { \ + (m)->m_data += (MHLEN - (len)) & ~(sizeof(long) - 1); \ +} while (0) + +/* + * 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. + * This is a relatively expensive operation and should be avoided. + */ +#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 (uint32_t)1000000000L + +/* Compatibility with 4.3. */ +#define m_copy(m, o, l) m_copym((m), (o), (l), M_DONTWAIT) + +#ifdef _KERNEL +extern struct mbuf *mbutl; /* virtual address of mclusters */ +extern char *mclrefcnt; /* cluster reference counts */ +extern struct mbstat mbstat; +extern uint32_t nmbclusters; +extern uint32_t 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 */ + +struct mbuf *m_copym(struct mbuf *, int, uint32_t, int); +struct mbuf *m_copypacket(struct mbuf *, int); +struct mbuf *m_devget(char *, int, int, struct ifnet *, + void (*copy)(char *, caddr_t, u_int)); +struct mbuf *m_free(struct mbuf *); +struct mbuf *m_get(int, int); +struct mbuf *m_getclr(int, int); +struct mbuf *m_gethdr(int, int); +struct mbuf *m_prepend(struct mbuf *,int,int); +struct mbuf *m_pullup(struct mbuf *, int); +struct mbuf *m_retry(int, int); +struct mbuf *m_retryhdr(int, int); +struct mbuf *m_split(struct mbuf *,int,int); +void m_adj(struct mbuf *, int); +void m_cat(struct mbuf *,struct mbuf *); +int m_mballoc(int, int); +int m_clalloc(int, int); +int m_copyback(struct mbuf *, int, int, caddr_t); +int m_copydata(const struct mbuf *, int, int, caddr_t); +void m_freem(struct mbuf *); +void m_reclaim(void); + +#endif /* _KERNEL */ + +#endif /* !_SYS_MBUF_H_ */ diff --git a/sys/mount.h b/sys/mount.h new file mode 100644 index 0000000..c422c7f --- /dev/null +++ b/sys/mount.h @@ -0,0 +1,120 @@ +/* + * 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. + * 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.21 (Berkeley) 5/20/95 + * $FreeBSD: src/sys/sys/mount.h,v 1.198 2005/08/06 01:42:04 ssouhlal Exp $ + */ + + +#ifndef _SYS_MOUNT_H_ +#define _SYS_MOUNT_H_ + +#ifndef _KERNEL +#include <sys/ucred.h> +#endif +#include <sys/queue.h> + +typedef struct fsid { int32_t val[2]; } fsid_t; /* filesystem 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) */ +}; + +/* + * filesystem statistics + */ +#define MFSNAMELEN 16 /* length of type name including null */ +#define MNAMELEN 88 /* size of on/from name bufs */ + +/* + * User specifiable flags. + */ +#define MNT_RDONLY 0x00000001 /* read only filesystem */ +#define MNT_SYNCHRONOUS 0x00000002 /* filesystem 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 /* filesystem written asynchronously */ +#define MNT_NOATIME 0x10000000 /* disable update of file access time */ + +/* + * NFS export related mount flags. + */ +#define MNT_EXRDONLY 0x00000080 /* exported read only */ +#define MNT_EXPORTED 0x00000100 /* filesystem 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 */ +#define MNT_EXPUBLIC 0x20000000 /* public export (WebNFS) */ + +/* + * Flags set by internal operations, + * but visible to the user. + */ +#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 */ +#define MNT_IGNORE 0x00800000 /* do not show entry in df */ + +/* + * External filesystem command modifier flags. + * Unmount can use the MNT_FORCE flag. + */ +#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 */ + +/* + * Generic file handle + */ +struct fhandle { + fsid_t fh_fsid; /* Filesystem id of mount point */ + struct fid fh_fid; /* Filesys specific id */ +}; +typedef struct fhandle fhandle_t; + +#ifdef _KERNEL + +#else /* !_KERNEL */ + +#include <sys/cdefs.h> + +#endif /* _KERNEL */ + +#endif /* !_SYS_MOUNT_H_ */ diff --git a/sys/proc.h b/sys/proc.h new file mode 100644 index 0000000..8b8b7dc --- /dev/null +++ b/sys/proc.h @@ -0,0 +1,6 @@ +/* + * Dummy structure + */ +struct proc { + int this_should_never_be_referenced; +}; diff --git a/sys/protosw.h b/sys/protosw.h new file mode 100644 index 0000000..e1119f9 --- /dev/null +++ b/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. + * 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 + * $FreeBSD: src/sys/sys/protosw.h,v 1.43 2004/04/07 04:19:49 imp Exp $ + */ + +#ifndef _SYS_PROTOSW_H_ +#define _SYS_PROTOSW_H_ + +/* Forward declare these structures referenced from prototypes below. */ +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)(struct mbuf *, int len); + /* input to protocol (from below) */ + int (*pr_output)(struct mbuf *m, struct socket *so); + /* output to protocol (from above) */ + void (*pr_ctlinput)(int, struct sockaddr *, void *); + /* control input (from below) */ + int (*pr_ctloutput)(int, struct socket *, int, int, + struct mbuf **); + /* control output (from above) */ +/* user-protocol hook */ + int (*pr_ousrreq)(struct socket *, int, struct mbuf *, + struct mbuf *, struct mbuf *); + /* user request: see list below */ +/* utility hooks */ + void (*pr_init)(void); /* initialization hook */ + void (*pr_fasttimo)(void); + /* fast timeout (200ms) */ + void (*pr_slowtimo)(void); + /* slow timeout (500ms) */ + void (*pr_drain)(void); + /* flush any excess space possible */ + struct pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */ +}; + +#define PR_SLOWHZ 2L /* 2 slow timeouts per second */ +#define PR_FASTHZ 5L /* 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 */ +#define PR_LASTHDR 0x40 /* enforce ipsec policy; last header */ + +/* + * 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 an 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 +const 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)(struct socket *so); + int (*pru_accept)(struct socket *so, struct mbuf *nam); + int (*pru_attach)(struct socket *so, intptr_t proto); + int (*pru_bind)(struct socket *so, struct mbuf *nam); + int (*pru_connect)(struct socket *so, struct mbuf *nam); + int (*pru_connect2)(struct socket *so1, struct socket *so2); + int (*pru_control)(struct socket *so, intptr_t cmd, caddr_t data, + struct ifnet *ifp); + int (*pru_detach)(struct socket *so); + int (*pru_disconnect)(struct socket *so); + int (*pru_listen)(struct socket *so); + int (*pru_peeraddr)(struct socket *so, struct mbuf *nam); + int (*pru_rcvd)(struct socket *so, intptr_t flags); + int (*pru_rcvoob)(struct socket *so, struct mbuf *m, + intptr_t 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)(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)(struct socket *so, struct stat *sb); + int (*pru_shutdown)(struct socket *so); + int (*pru_sockaddr)(struct socket *so, struct mbuf *nam); +}; + +int pru_accept_notsupp(struct socket *so, struct mbuf *nam); +int pru_connect2_notsupp(struct socket *so1, struct socket *so2); +int pru_control_notsupp(struct socket *so, int cmd, caddr_t data, + struct ifnet *ifp); +int pru_listen_notsupp(struct socket *so); +int pru_rcvd_notsupp(struct socket *so, int flags); +int pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags); +int pru_sense_null(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_IFUP 2 /* interface has come back up */ +#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_UNREACH_ADMIN_PROHIB 21 /* packet administrativly prohibited */ + +#define PRC_NCMDS 22 + +#define PRC_IS_REDIRECT(cmd) \ + ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST) + +#ifdef PRCREQUESTS +char *prcrequests[] = { + "IFDOWN", "ROUTEDEAD", "IFUP", "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", "ADMIN-UNREACH" +}; +#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 +void pfctlinput(int, struct sockaddr *); +struct protosw *pffindproto(int family, int protocol, int type); +struct protosw *pffindtype(int family, int type); +#endif + +#endif diff --git a/sys/reboot.h b/sys/reboot.h new file mode 100644 index 0000000..191f3a4 --- /dev/null +++ b/sys/reboot.h @@ -0,0 +1,105 @@ +/* + * 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 + */ + +#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/sys/resourcevar.h b/sys/resourcevar.h new file mode 100644 index 0000000..87fc204 --- /dev/null +++ b/sys/resourcevar.h @@ -0,0 +1 @@ +/* intentionally empty file */ diff --git a/sys/selinfo.h b/sys/selinfo.h new file mode 100644 index 0000000..68ec92a --- /dev/null +++ b/sys/selinfo.h @@ -0,0 +1,55 @@ +/*- + * 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. + * 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 + */ + +#ifndef _SYS_SELINFO_H_ +#define _SYS_SELINFO_H_ + +#include <sys/types.h> /* pid_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * 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 __cplusplus +} +#endif + +#endif /* !_SYS_SELINFO_H_ */ diff --git a/sys/signalvar.h b/sys/signalvar.h new file mode 100644 index 0000000..c2311cf --- /dev/null +++ b/sys/signalvar.h @@ -0,0 +1,176 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/sys/signalvar.h,v 1.91 2010/07/08 19:15:26 jhb Exp $ + */ + + +#ifndef _SYS_SIGNALVAR_H_ +#define _SYS_SIGNALVAR_H_ + +/* + * Kernel signal definitions and data structures, + * not exported to user programs. + */ + +#if !defined(__rtems__) +/* + * 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 */ +}; +#endif + +/* 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) + +#if !defined(__rtems__) +/* + * get signal action for process and signal; currently only for current process + */ +#define SIGACTION(p, sig) (p->p_sigacts->ps_sigact[(sig)]) +#endif + +/* + * 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(struct proc *p); +void gsignal(int pgid, int sig); +int issignal(struct proc *p); +void killproc(struct proc *p, char *why); +void pgsignal(struct pgrp *pgrp, int sig, int checkctty); +void postsig(int sig); +#ifndef __rtems__ +/* clashes with psignal(3) */ +void psignal(struct proc *p, int sig); +#endif +void setsigvec(struct proc *p, int signum, struct sigaction *sa); +void sigexit(struct proc *p, int signum); +void siginit(struct proc *p); +void trapsignal(struct proc *p, int sig, u_long code); + +/* + * Machine-dependent functions: + */ +void sendsig(sig_t action, int sig, int returnmask, u_long code); +#endif /* _KERNEL */ + +#endif /* !_SYS_SIGNALVAR_H_ */ diff --git a/sys/socketvar.h b/sys/socketvar.h new file mode 100644 index 0000000..2cdd515 --- /dev/null +++ b/sys/socketvar.h @@ -0,0 +1,271 @@ +/*- + * 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. + * 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 + * $FreeBSD: src/sys/sys/socketvar.h,v 1.135 2004/10/18 22:19:43 rwatson Exp $ + */ + +#ifndef _SYS_SOCKETVAR_H_ +#define _SYS_SOCKETVAR_H_ + +#include <sys/queue.h> /* for TAILQ macros */ +#include <sys/selinfo.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. + */ +typedef u_quad_t so_gen_t; + +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 */ + void *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_int sb_cc; /* actual chars in buffer */ + u_int sb_hiwat; /* max actual char count */ + u_int sb_mbcnt; /* chars of mbufs used */ + u_int sb_mbmax; /* max chars of mbufs to use */ + int 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 */ + int sb_timeo; /* timeout for read/write */ + void (*sb_wakeup)(struct socket *, void *); + void *sb_wakeuparg; /* arg for above */ + } so_rcv, so_snd; +#define SB_MAX (256L*1024L) /* 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)(struct socket *, void *arg, int); + void *so_upcallarg; /* Arg for above */ +}; + +/* + * 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 += _SYS_MBUF_LEGACY_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 -= _SYS_MBUF_LEGACY_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; +struct uio; + +/* + * From uipc_socket and friends + */ +int sockargs(struct mbuf **mp, caddr_t buf, int buflen, int type); +void sbappend(struct sockbuf *sb, struct mbuf *m); +int sbappendaddr(struct sockbuf *sb, struct sockaddr *asa, + struct mbuf *m0, struct mbuf *control); +int sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, + struct mbuf *control); +void sbappendrecord(struct sockbuf *sb, struct mbuf *m0); +void sbcheck(struct sockbuf *sb); +void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n); +struct mbuf * + sbcreatecontrol(caddr_t p, int size, int type, int level); +void sbdrop(struct sockbuf *sb, int len); +void sbdroprecord(struct sockbuf *sb); +void sbflush(struct sockbuf *sb); +void sbinsertoob(struct sockbuf *sb, struct mbuf *m0); +void sbrelease(struct sockbuf *sb); +int sbreserve(struct sockbuf *sb, u_long cc); +int sbwait(struct sockbuf *sb); +int sb_lock(struct sockbuf *sb); +int soabort(struct socket *so); +int soaccept(struct socket *so, struct mbuf *nam); +int sobind(struct socket *so, struct mbuf *nam); +void socantrcvmore(struct socket *so); +void socantsendmore(struct socket *so); +int soclose(struct socket *so); +int soconnect(struct socket *so, struct mbuf *nam); +int soconnect2(struct socket *so1, struct socket *so2); +int socreate(int dom, struct socket **aso, int type, int proto, + struct proc *p); +int sodisconnect(struct socket *so); +void sofree(struct socket *so); +int sogetopt(struct socket *so, int level, int optname, + struct mbuf **mp); +void sohasoutofband(struct socket *so); +void soisconnected(struct socket *so); +void soisconnecting(struct socket *so); +void soisdisconnected(struct socket *so); +void soisdisconnecting(struct socket *so); +int solisten(struct socket *so, int backlog); +struct socket * + sodropablereq(struct socket *head); +struct socket * + sonewconn1(struct socket *head, int connstatus); +int soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio, + struct mbuf **mp0, struct mbuf **controlp, int *flagsp); +int soreserve(struct socket *so, u_long sndcc, u_long rcvcc); +void sorflush(struct socket *so); +int sosend(struct socket *so, struct mbuf *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags); +int sosetopt(struct socket *so, int level, int optname, + struct mbuf *m0); +int soshutdown(struct socket *so, int how); +void sowakeup(struct socket *so, struct sockbuf *sb); +#endif /* _KERNEL */ + +#endif /* !_SYS_SOCKETVAR_H_ */ diff --git a/sys/sysctl.h b/sys/sysctl.h new file mode 100644 index 0000000..12e3845 --- /dev/null +++ b/sys/sysctl.h @@ -0,0 +1,642 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/sys/sysctl.h,v 1.133 2004/10/11 22:04:16 peter Exp $ + */ + +#ifndef _SYS_SYSCTL_H_ +#define _SYS_SYSCTL_H_ + +#include <stdint.h> +#include <sys/queue.h> + +struct thread; +/* + * 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 24 /* 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(8) 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 CTLTYPE_UINT 6 /* name describes an unsigned integer */ +#define CTLTYPE_LONG 7 /* name describes a long */ +#define CTLTYPE_ULONG 8 /* name describes an unsigned long */ + +#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 */ +#define CTLFLAG_SECURE 0x08000000 /* Permit set only if securelevel<=0 */ +#define CTLFLAG_PRISON 0x04000000 /* Prisoned roots can fiddle */ +#define CTLFLAG_DYN 0x02000000 /* Dynamic oid - can be freed */ +#define CTLFLAG_SKIP 0x01000000 /* Skip this sysctl when listing */ +#define CTLMASK_SECURE 0x00F00000 /* Secure level */ +#define CTLFLAG_TUN 0x00080000 /* Tunable variable */ +#define CTLFLAG_RDTUN (CTLFLAG_RD|CTLFLAG_TUN) + +/* + * Secure level. Note that CTLFLAG_SECURE == CTLFLAG_SECURE1. + * + * Secure when the securelevel is raised to at least N. + */ +#define CTLSHIFT_SECURE 20 +#define CTLFLAG_SECURE1 (CTLFLAG_SECURE | (0 << CTLSHIFT_SECURE)) +#define CTLFLAG_SECURE2 (CTLFLAG_SECURE | (1 << CTLSHIFT_SECURE)) +#define CTLFLAG_SECURE3 (CTLFLAG_SECURE | (2 << CTLSHIFT_SECURE)) + +/* + * 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 implemented. + * e.g. SYSCTL_INT(_parent, OID_AUTO, name, CTLFLAG_RW, &variable, 0, ""); + */ +#define OID_AUTO (-1) + +/* + * The starting number for dynamically-assigned entries. WARNING! + * ALL static sysctl entries should have numbers LESS than this! + */ +#define CTL_AUTO_START 0x100 + +#ifdef _KERNEL +#define SYSCTL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, int arg2, \ + struct sysctl_req *req + +/* definitions for sysctl_req 'lock' member */ +#define REQ_UNLOCKED 0 /* not locked and not wired */ +#define REQ_LOCKED 1 /* locked and not wired */ +#define REQ_WIRED 2 /* locked and wired */ + +/* + * 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 thread *td; /* used for access checking */ + int lock; /* locking/wiring state */ + void *oldptr; + size_t oldlen; + size_t oldidx; + int (*oldfunc)(struct sysctl_req *, const void *, size_t); + const void *newptr; + size_t newlen; + size_t newidx; + int (*newfunc)(struct sysctl_req *, void *, size_t); + size_t validlen; +}; + +SLIST_HEAD(sysctl_oid_list, sysctl_oid); + +/* + * This describes one "oid" in the MIB tree. Potentially more nodes can + * be hidden behind it, expanded by the handler. + */ +struct sysctl_oid { + struct sysctl_oid_list *oid_parent; + SLIST_ENTRY(sysctl_oid) oid_link; + int oid_number; + uint32_t oid_kind; + void *oid_arg1; + int32_t oid_arg2; + const char *oid_name; + int (*oid_handler)(SYSCTL_HANDLER_ARGS); + const char *oid_fmt; + int oid_refcnt; + const char *descr; +}; + +#define SYSCTL_IN(r, p, l) (r->newfunc)(r, p, l) +#define SYSCTL_OUT(r, p, l) (r->oldfunc)(r, p, l) + +int sysctl_handle_int(SYSCTL_HANDLER_ARGS); +int sysctl_handle_long(SYSCTL_HANDLER_ARGS); +int sysctl_handle_intptr(SYSCTL_HANDLER_ARGS); +int sysctl_handle_string(SYSCTL_HANDLER_ARGS); +int sysctl_handle_opaque(SYSCTL_HANDLER_ARGS); + +/* + * These functions are used to add/remove an oid from the mib. + */ +void sysctl_register_oid(struct sysctl_oid *oidp); +void sysctl_unregister_oid(struct sysctl_oid *oidp); + +/* Declare a static oid to allow child oids to be added to it. */ +#define SYSCTL_DECL(name) \ + extern struct sysctl_oid_list sysctl_##name##_children + +/* Hide these in macros */ +#define SYSCTL_CHILDREN(oid_ptr) (struct sysctl_oid_list *) \ + (oid_ptr)->oid_arg1 +#define SYSCTL_CHILDREN_SET(oid_ptr, val) \ + (oid_ptr)->oid_arg1 = (val); +#define SYSCTL_STATIC_CHILDREN(oid_name) \ + (&sysctl_##oid_name##_children) + +/* === Structs and macros related to context handling === */ + +/* All dynamically created sysctls can be tracked in a context list. */ +struct sysctl_ctx_entry { + struct sysctl_oid *entry; + TAILQ_ENTRY(sysctl_ctx_entry) link; +}; + +TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); + +#define SYSCTL_NODE_CHILDREN(parent, name) \ + sysctl_##parent##_##name##_children + +/* This constructs a "raw" MIB oid. */ +#define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) \ + static struct sysctl_oid sysctl__##parent##_##name = { \ + &sysctl_##parent##_children, { 0 }, \ + nbr, kind, a1, a2, #name, handler, fmt, 0, descr }; \ + DATA_SET(sysctl_set, sysctl__##parent##_##name) + +#define SYSCTL_ADD_OID(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr) + +/* This constructs a node from which other oids can hang. */ +#define SYSCTL_NODE(parent, nbr, name, access, handler, descr) \ + struct sysctl_oid_list SYSCTL_NODE_CHILDREN(parent, name); \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_NODE|(access), \ + (void*)&SYSCTL_NODE_CHILDREN(parent, name), 0, handler, \ + "N", descr) + +#define SYSCTL_ADD_NODE(ctx, parent, nbr, name, access, handler, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_NODE|(access), \ + 0, 0, handler, "N", descr) + +/* Oid for a string. len can be 0 to indicate '\0' termination. */ +#define SYSCTL_STRING(parent, nbr, name, access, arg, len, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_STRING|(access), \ + arg, len, sysctl_handle_string, "A", descr) + +#define SYSCTL_ADD_STRING(ctx, parent, nbr, name, access, arg, len, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_STRING|(access), \ + arg, len, sysctl_handle_string, "A", descr) + +/* Oid for an int. If ptr is NULL, val is returned. */ +#define SYSCTL_INT(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|(access), \ + ptr, val, sysctl_handle_int, "I", descr) + +#define SYSCTL_ADD_INT(ctx, parent, nbr, name, access, ptr, val, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_INT|(access), \ + ptr, val, sysctl_handle_int, "I", descr) + +/* Oid for an unsigned int. If ptr is NULL, val is returned. */ +#define SYSCTL_UINT(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_UINT|(access), \ + ptr, val, sysctl_handle_int, "IU", descr) + +#define SYSCTL_ADD_UINT(ctx, parent, nbr, name, access, ptr, val, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_UINT|(access), \ + ptr, val, sysctl_handle_int, "IU", descr) + +/* Oid for a long. The pointer must be non NULL. */ +#define SYSCTL_LONG(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_LONG|(access), \ + ptr, val, sysctl_handle_long, "L", descr) + +#define SYSCTL_ADD_LONG(ctx, parent, nbr, name, access, ptr, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_LONG|(access), \ + ptr, 0, sysctl_handle_long, "L", descr) + +/* Oid for an unsigned long. The pointer must be non NULL. */ +#define SYSCTL_ULONG(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_ULONG|(access), \ + ptr, val, sysctl_handle_long, "LU", descr) + +#define SYSCTL_ADD_ULONG(ctx, parent, nbr, name, access, ptr, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_ULONG|(access), \ + ptr, 0, sysctl_handle_long, "LU", descr) + +/* Oid for an opaque object. Specified by a pointer and a length. */ +#define SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, len, sysctl_handle_opaque, fmt, descr) + +#define SYSCTL_ADD_OPAQUE(ctx, parent, nbr, name, access, ptr, len, fmt, descr)\ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, len, sysctl_handle_opaque, fmt, descr) + +/* Oid for a struct. Specified by a pointer and a type. */ +#define SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, sizeof(struct type), sysctl_handle_opaque, \ + "S," #type, descr) + +#define SYSCTL_ADD_STRUCT(ctx, parent, nbr, name, access, ptr, type, descr) \ + sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_OPAQUE|(access), \ + ptr, sizeof(struct type), sysctl_handle_opaque, "S," #type, descr) + +/* Oid for a procedure. Specified by a pointer and an arg. */ +#define SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) \ + SYSCTL_OID(parent, nbr, name, (access), \ + ptr, arg, handler, fmt, descr) + +#define SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr) \ + sysctl_add_oid(ctx, 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 /* filesystem, 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_P1003_1B 9 /* POSIX 1003.1B */ +#define CTL_MAXID 10 /* 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 }, \ + { "p1003_1b", 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: kernel 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 /* struct cdev *: device to dump on */ +#define KERN_IPC 30 /* node: anything related to IPC */ +#define KERN_DUMMY 31 /* unused */ +#define KERN_PS_STRINGS 32 /* int: address of PS_STRINGS */ +#define KERN_USRSTACK 33 /* int: address of USRSTACK */ +#define KERN_LOGSIGEXIT 34 /* int: do we log sigexit procs? */ +#define KERN_IOV_MAX 35 /* int: value of UIO_MAXIOV */ +#define KERN_MAXID 36 /* 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_UINT }, \ + { "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 }, \ + { "ipc", CTLTYPE_NODE }, \ + { "dummy", CTLTYPE_INT }, \ + { "ps_strings", CTLTYPE_INT }, \ + { "usrstack", CTLTYPE_INT }, \ + { "logsigexit", CTLTYPE_INT }, \ + { "iov_max", CTLTYPE_INT }, \ +} + +/* + * CTL_VFS identifiers + */ +#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 */ +#define KERN_PROC_ARGS 7 /* get/set arguments/proctitle */ +#define KERN_PROC_PROC 8 /* only return procs */ +#define KERN_PROC_SV_NAME 9 /* get syscall vector name */ +#define KERN_PROC_RGID 10 /* by real group id */ +#define KERN_PROC_GID 11 /* by effective group id */ +#define KERN_PROC_INC_THREAD 0x10 /* + * modifier for pid, pgrp, tty, + * uid, ruid, gid, rgid and proc + */ + +/* + * KERN_IPC identifiers + */ +#define KIPC_MAXSOCKBUF 1 /* int: max size of a socket buffer */ +#define KIPC_SOCKBUF_WASTE 2 /* int: wastage factor in sockbuf */ +#define KIPC_SOMAXCONN 3 /* int: max length of connection q */ +#define KIPC_MAX_LINKHDR 4 /* int: max length of link header */ +#define KIPC_MAX_PROTOHDR 5 /* int: max length of network header */ +#define KIPC_MAX_HDR 6 /* int: max total length of headers */ +#define KIPC_MAX_DATALEN 7 /* int: max length of data? */ + +/* + * 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_ULONG }, \ + { "usermem", CTLTYPE_ULONG }, \ + { "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 }, \ +} + +#define CTL_P1003_1B_ASYNCHRONOUS_IO 1 /* boolean */ +#define CTL_P1003_1B_MAPPED_FILES 2 /* boolean */ +#define CTL_P1003_1B_MEMLOCK 3 /* boolean */ +#define CTL_P1003_1B_MEMLOCK_RANGE 4 /* boolean */ +#define CTL_P1003_1B_MEMORY_PROTECTION 5 /* boolean */ +#define CTL_P1003_1B_MESSAGE_PASSING 6 /* boolean */ +#define CTL_P1003_1B_PRIORITIZED_IO 7 /* boolean */ +#define CTL_P1003_1B_PRIORITY_SCHEDULING 8 /* boolean */ +#define CTL_P1003_1B_REALTIME_SIGNALS 9 /* boolean */ +#define CTL_P1003_1B_SEMAPHORES 10 /* boolean */ +#define CTL_P1003_1B_FSYNC 11 /* boolean */ +#define CTL_P1003_1B_SHARED_MEMORY_OBJECTS 12 /* boolean */ +#define CTL_P1003_1B_SYNCHRONIZED_IO 13 /* boolean */ +#define CTL_P1003_1B_TIMERS 14 /* boolean */ +#define CTL_P1003_1B_AIO_LISTIO_MAX 15 /* int */ +#define CTL_P1003_1B_AIO_MAX 16 /* int */ +#define CTL_P1003_1B_AIO_PRIO_DELTA_MAX 17 /* int */ +#define CTL_P1003_1B_DELAYTIMER_MAX 18 /* int */ +#define CTL_P1003_1B_MQ_OPEN_MAX 19 /* int */ +#define CTL_P1003_1B_PAGESIZE 20 /* int */ +#define CTL_P1003_1B_RTSIG_MAX 21 /* int */ +#define CTL_P1003_1B_SEM_NSEMS_MAX 22 /* int */ +#define CTL_P1003_1B_SEM_VALUE_MAX 23 /* int */ +#define CTL_P1003_1B_SIGQUEUE_MAX 24 /* int */ +#define CTL_P1003_1B_TIMER_MAX 25 /* int */ + +#define CTL_P1003_1B_MAXID 26 + +#define CTL_P1003_1B_NAMES { \ + { 0, 0 }, \ + { "asynchronous_io", CTLTYPE_INT }, \ + { "mapped_files", CTLTYPE_INT }, \ + { "memlock", CTLTYPE_INT }, \ + { "memlock_range", CTLTYPE_INT }, \ + { "memory_protection", CTLTYPE_INT }, \ + { "message_passing", CTLTYPE_INT }, \ + { "prioritized_io", CTLTYPE_INT }, \ + { "priority_scheduling", CTLTYPE_INT }, \ + { "realtime_signals", CTLTYPE_INT }, \ + { "semaphores", CTLTYPE_INT }, \ + { "fsync", CTLTYPE_INT }, \ + { "shared_memory_objects", CTLTYPE_INT }, \ + { "synchronized_io", CTLTYPE_INT }, \ + { "timers", CTLTYPE_INT }, \ + { "aio_listio_max", CTLTYPE_INT }, \ + { "aio_max", CTLTYPE_INT }, \ + { "aio_prio_delta_max", CTLTYPE_INT }, \ + { "delaytimer_max", CTLTYPE_INT }, \ + { "mq_open_max", CTLTYPE_INT }, \ + { "pagesize", CTLTYPE_INT }, \ + { "rtsig_max", CTLTYPE_INT }, \ + { "nsems_max", CTLTYPE_INT }, \ + { "sem_value_max", CTLTYPE_INT }, \ + { "sigqueue_max", CTLTYPE_INT }, \ + { "timer_max", CTLTYPE_INT }, \ +} + +#ifdef _KERNEL + +/* + * Declare some common oids. + */ +extern struct sysctl_oid_list sysctl__children; +SYSCTL_DECL(_kern); +SYSCTL_DECL(_sysctl); +SYSCTL_DECL(_vm); +SYSCTL_DECL(_vfs); +SYSCTL_DECL(_net); +SYSCTL_DECL(_debug); +SYSCTL_DECL(_debug_sizeof); +SYSCTL_DECL(_hw); +SYSCTL_DECL(_machdep); +SYSCTL_DECL(_user); +SYSCTL_DECL(_compat); + +extern char machine[]; +extern char osrelease[]; +extern char ostype[]; +extern char kern_ident[]; + +/* Dynamic oid handling */ +struct sysctl_oid *sysctl_add_oid(struct sysctl_ctx_list *clist, + struct sysctl_oid_list *parent, int nbr, const char *name, + int kind, void *arg1, int arg2, + int (*handler) (SYSCTL_HANDLER_ARGS), + const char *fmt, const char *descr); +int sysctl_move_oid(struct sysctl_oid *oidp, + struct sysctl_oid_list *parent); +int sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse); +int sysctl_ctx_init(struct sysctl_ctx_list *clist); +int sysctl_ctx_free(struct sysctl_ctx_list *clist); +struct sysctl_ctx_entry *sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, + struct sysctl_oid *oidp); +struct sysctl_ctx_entry *sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, + struct sysctl_oid *oidp); +int sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, + struct sysctl_oid *oidp); + +int kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old, + size_t *oldlenp, void *new, size_t newlen, + size_t *retval); +int kernel_sysctlbyname(struct thread *td, char *name, + void *old, size_t *oldlenp, void *new, size_t newlen, + size_t *retval); +int userland_sysctl(struct thread *td, const int *name, u_int namelen, void *old, + size_t *oldlenp, int inkernel, const void *new, size_t newlen, + size_t *retval); +int sysctl_find_oid(const int *name, u_int namelen, struct sysctl_oid **noid, + int *nindx, struct sysctl_req *req); +int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len); + +#else /* !_KERNEL */ +#include <sys/cdefs.h> + +__BEGIN_DECLS +int sysctl(int *, u_int, void *, size_t *, void *, size_t); +int sysctlbyname(const char *, void *, size_t *, void *, size_t); +int sysctlnametomib(const char *, int *, size_t *); +__END_DECLS +#endif /* _KERNEL */ + +#endif /* !_SYS_SYSCTL_H_ */ diff --git a/sys/systm.h b/sys/systm.h new file mode 100644 index 0000000..ae70148 --- /dev/null +++ b/sys/systm.h @@ -0,0 +1,108 @@ +/*- + * 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. + * 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 + * $FreeBSD: src/sys/sys/systm.h,v 1.248 2007/01/15 15:06:27 rrs Exp $ + */ + + +#ifndef _SYS_SYSTM_H_ +#define _SYS_SYSTM_H_ + +#include <rtems/rtems_bsdnet_internal.h> /* for __BSD_VA_LIST__ */ +#include <machine/cpufunc.h> + +#if !defined(__dead2) +#define __dead2 __attribute__((__noreturn__)) +#endif + +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 physmem; /* physical memory */ + +/* + * General function declarations. + */ +int nullop(void); +int ureadc(int, struct uio *); +void *hashinit(int count, int type, u_long *hashmask); +void *phashinit(int count, int type, u_long *nentries); + +void panic(const char *, ...) __dead2; +void boot(int) __dead2; +void cpu_boot(int); +int kvprintf(char const *, void (*)(int, void*), void *, int, + _BSD_VA_LIST_); +void log(int, const char *, ...); +int printf(const char *, ...); +int sprintf(char *buf, const char *, ...); +void uprintf(const char *, ...); +void ttyprintf(struct tty *, const char *, ...); + +#define bcopy(f,t,n) memcpy((t),(f),(n)) +#define bzero(p,n) memset((p),(0),(n)) + +int copystr(const void *kfaddr, void *kdaddr, size_t len, + size_t *lencopied); +int copyinstr(const void *udaddr, void *kaddr, size_t len, + size_t *lencopied); +#ifndef __rtems__ +/* FIXME: these clash with defines in rtems_bsdnet_internal.h */ +int copyin(const void *udaddr, void *kaddr, size_t len); +int copyout(const void *kaddr, void *udaddr, size_t len); +#endif + +int hzto(struct timeval *tv); + +#include <sys/libkern.h> + +/* 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 *); + +/* + * Common `proc' functions are declared here so that proc.h can be included + * less often. + */ +int tsleep(void *chan, int pri, char *wmesg, int timo); +void wakeup(void *chan); + +#endif /* !_SYS_SYSTM_H_ */ diff --git a/sys/ucred.h b/sys/ucred.h new file mode 100644 index 0000000..84c4ebc --- /dev/null +++ b/sys/ucred.h @@ -0,0 +1,60 @@ +/* + * 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 + */ + +#ifndef _SYS_UCRED_H_ +#define _SYS_UCRED_H_ + +#if defined(__rtems__) +#include <sys/param.h> /* NGROUPS */ +#endif + +/* + * 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 +int suser(struct ucred *cred, u_short *acflag); +#endif /* _KERNEL */ + +#endif /* !_SYS_UCRED_H_ */ @@ -0,0 +1,97 @@ +/* + * 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. + * 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 + * @(#)vm_prot.h 8.1 (Berkeley) 6/11/93 + * @(#)vm_inherit.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. + * + * $FreeBSD: src/sys/vm/vm.h,v 1.28 2007/12/27 17:08:11 alc Exp $ + */ + +#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 /* _KERNEL */ + +#endif /* VM_H */ diff --git a/vm/vm_extern.h b/vm/vm_extern.h new file mode 100644 index 0000000..c495af6 --- /dev/null +++ b/vm/vm_extern.h @@ -0,0 +1,42 @@ +/* + * 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. + * 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 + * $FreeBSD: src/sys/vm/vm_extern.h,v 1.78 2006/05/29 21:28:56 tegge Exp $ + */ + +#ifndef _VM_EXTERN_H_ +#define _VM_EXTERN_H_ + +struct buf; +struct proc; +struct vmtotal; +struct mount; +struct vnode; + +#endif /* !_VM_EXTERN_H_ */ diff --git a/vm/vm_kern.h b/vm/vm_kern.h new file mode 100644 index 0000000..f020f2d --- /dev/null +++ b/vm/vm_kern.h @@ -0,0 +1,78 @@ +/* + * 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. + * 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. + * + * $FreeBSD: src/sys/vm/vm_kern.h,v 1.28 2005/01/07 02:29:27 imp Exp $ + */ + + +#ifndef _VM_VM_KERN_H_ +#define _VM_VM_KERN_H_ 1 + +#if !defined(__rtems__) +/* 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 clean_map; +extern vm_map_t exec_map; +extern vm_map_t pipe_map; +extern u_int vm_kmem_size; +#endif + +#endif /* _VM_VM_KERN_H_ */ diff --git a/vm/vm_param.h b/vm/vm_param.h new file mode 100644 index 0000000..41c52ef --- /dev/null +++ b/vm/vm_param.h @@ -0,0 +1,130 @@ +/* + * 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. + * 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. + * + * $FreeBSD: src/sys/vm/vm_param.h,v 1.21 2005/01/07 02:29:27 imp Exp $ + */ + + +/* + * Machine independent virtual memory parameters. + */ + +#ifndef _VM_PARAM_ +#define _VM_PARAM_ + +#include <machine/vmparam.h> + +/* + * CTL_VM identifiers + */ +#define VM_TOTAL 1 /* struct vmtotal */ +#define VM_METER VM_TOTAL/* deprecated, use VM_TOTAL */ +#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 }, \ + { "vmtotal", 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 +#ifdef _KERNEL +#define num_pages(x) \ + ((vm_offset_t)((((vm_offset_t)(x)) + PAGE_MASK) >> PAGE_SHIFT)) +extern unsigned long maxtsiz; +extern unsigned long dfldsiz; +extern unsigned long maxdsiz; +extern unsigned long dflssiz; +extern unsigned long maxssiz; +extern unsigned long sgrowsiz; +#endif /* _KERNEL */ +#endif /* ASSEMBLER */ +#endif /* _VM_PARAM_ */ |